ir.rs 19.7 KB
Newer Older
1
use ast::ptr::P;
2
use ast::types::*;
3
use ast::inst::*;
4
use ast::op::*;
5
use utils::vec_utils::as_str as vector_as_str;
6
use utils::vec_utils;
7

8
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
9
use std::fmt;
10
use std::default;
11
use std::sync::RwLock;
qinsoon's avatar
qinsoon committed
12
use std::cell::Cell;
qinsoon's avatar
qinsoon committed
13
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
qinsoon's avatar
qinsoon committed
14

qinsoon's avatar
qinsoon committed
15 16
pub type WPID  = usize;
pub type MuID  = usize;
qinsoon's avatar
qinsoon committed
17
pub type MuName = &'static str;
qinsoon's avatar
qinsoon committed
18 19
pub type Address = usize; // TODO: replace this with Address(usize)

20 21
pub type OpIndex = usize;

qinsoon's avatar
qinsoon committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
lazy_static! {
    pub static ref MACHINE_ID : AtomicUsize = {
        let a = ATOMIC_USIZE_INIT;
        a.store(MACHINE_ID_START, Ordering::SeqCst);
        a
    };
    pub static ref INTERNAL_ID : AtomicUsize = {
        let a = ATOMIC_USIZE_INIT;
        a.store(INTERNAL_ID_START, Ordering::SeqCst);
        a
    };
} 
pub const  MACHINE_ID_START : usize = 0;
pub const  MACHINE_ID_END   : usize = 100;

pub const  INTERNAL_ID_START: usize = 101;
pub const  INTERNAL_ID_END  : usize = 200;
pub const  USER_ID_START    : usize = 201;

pub fn new_machine_id() -> MuID {
    let ret = MACHINE_ID.fetch_add(1, Ordering::SeqCst);
    if ret >= MACHINE_ID_END {
        panic!("machine id overflow")
    }
    ret
}

pub fn new_internal_id() -> MuID {
    let ret = INTERNAL_ID.fetch_add(1, Ordering::SeqCst);
    if ret >= INTERNAL_ID_END {
        panic!("internal id overflow")
    }
    ret
}
qinsoon's avatar
qinsoon committed
56

57 58
#[derive(Debug)]
pub struct MuFunction {
59
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
60
    
61
    pub sig: P<MuFuncSig>,
qinsoon's avatar
qinsoon committed
62 63
    pub cur_ver: Option<MuID>,
    pub all_vers: Vec<MuID>
64 65 66
}

impl MuFunction {
qinsoon's avatar
qinsoon committed
67
    pub fn new(id: MuID, sig: P<MuFuncSig>) -> MuFunction {
68
        MuFunction {
69
            hdr: MuEntityHeader::unnamed(id),
70 71 72 73 74 75 76
            sig: sig,
            cur_ver: None,
            all_vers: vec![]
        }
    }
}

qinsoon's avatar
qinsoon committed
77 78
impl fmt::Display for MuFunction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79
        write!(f, "Func {}", self.hdr)
qinsoon's avatar
qinsoon committed
80 81 82
    }
}

83
#[derive(Debug)]
84
pub struct MuFunctionVersion {
85
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
86 87
         
    pub func_id: MuID,
qinsoon's avatar
qinsoon committed
88
    pub sig: P<MuFuncSig>,
89
    pub content: Option<FunctionContent>,
90
    pub context: FunctionContext,
91

qinsoon's avatar
qinsoon committed
92 93 94 95 96
    pub block_trace: Option<Vec<MuID>> // only available after Trace Generation Pass
}

impl fmt::Display for MuFunctionVersion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97
        write!(f, "FuncVer {} of Func #{}", self.hdr, self.func_id)
qinsoon's avatar
qinsoon committed
98
    }
99 100
}

101
impl MuFunctionVersion {
qinsoon's avatar
qinsoon committed
102
    pub fn new(id: MuID, func: MuID, sig: P<MuFuncSig>) -> MuFunctionVersion {
103
        MuFunctionVersion{
104
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
105
            func_id: func,
106 107 108
            sig: sig,
            content: None,
            context: FunctionContext::new(),
109 110
            block_trace: None}
    }
111

112 113 114
    pub fn define(&mut self, content: FunctionContent) {
        self.content = Some(content)
    }
115

qinsoon's avatar
qinsoon committed
116
    pub fn new_ssa(&mut self, id: MuID, tag: MuName, ty: P<MuType>) -> P<TreeNode> {
117
        self.context.value_tags.insert(tag, id);
qinsoon's avatar
qinsoon committed
118
        self.context.values.insert(id, SSAVarEntry{id: id, name: Some(tag), ty: ty.clone(), use_count: Cell::new(0), expr: None});
119

120
        P(TreeNode {
121
            hdr: MuEntityHeader::unnamed(id),
122
            op: pick_op_code_for_ssa(&ty),
qinsoon's avatar
qinsoon committed
123
            v: TreeNode_::Value(P(Value{
124
                hdr: MuEntityHeader::named(id, tag),
qinsoon's avatar
qinsoon committed
125 126 127
                ty: ty,
                v: Value_::SSAVar(id)
            }))
128 129
        })
    }
130

131
    pub fn new_constant(&mut self, id: MuID, v: P<Value>) -> P<TreeNode> {
132
        P(TreeNode{
133
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
134 135 136 137 138
            op: pick_op_code_for_value(&v.ty),
            v: TreeNode_::Value(v)
        })
    }
    
139
    pub fn new_global(&mut self, id: MuID, v: P<Value>) -> P<TreeNode> {
qinsoon's avatar
qinsoon committed
140
        P(TreeNode{
141
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
142
            op: pick_op_code_for_value(&v.ty),
qinsoon's avatar
qinsoon committed
143 144
            v: TreeNode_::Value(v)
        })
145
    }
146

147
    pub fn new_inst(&mut self, id: MuID, v: Instruction) -> P<TreeNode> {
148
        P(TreeNode{
149
            hdr: MuEntityHeader::unnamed(id),
150
            op: pick_op_code_for_inst(&v),
151 152
            v: TreeNode_::Instruction(v),
        })
153
    }
154 155
}

156 157
#[derive(Debug)]
pub struct FunctionContent {
qinsoon's avatar
qinsoon committed
158 159
    pub entry: MuID,
    pub blocks: HashMap<MuID, Block>
160 161 162 163
}

impl FunctionContent {
    pub fn get_entry_block(&self) -> &Block {
qinsoon's avatar
qinsoon committed
164
        self.get_block(self.entry)
qinsoon's avatar
qinsoon committed
165
    } 
166

167
    pub fn get_entry_block_mut(&mut self) -> &mut Block {
qinsoon's avatar
qinsoon committed
168 169
        let entry = self.entry;
        self.get_block_mut(entry)
170
    }
171

qinsoon's avatar
qinsoon committed
172 173
    pub fn get_block(&self, id: MuID) -> &Block {
        let ret = self.blocks.get(&id);
qinsoon's avatar
qinsoon committed
174 175
        match ret {
            Some(b) => b,
qinsoon's avatar
qinsoon committed
176
            None => panic!("cannot find block #{}", id)
qinsoon's avatar
qinsoon committed
177
        }
178
    }
179

qinsoon's avatar
qinsoon committed
180 181
    pub fn get_block_mut(&mut self, id: MuID) -> &mut Block {
        let ret = self.blocks.get_mut(&id);
qinsoon's avatar
qinsoon committed
182 183
        match ret {
            Some(b) => b,
qinsoon's avatar
qinsoon committed
184
            None => panic!("cannot find block #{}", id)
qinsoon's avatar
qinsoon committed
185
        }
186
    }
187 188 189 190
}

#[derive(Debug)]
pub struct FunctionContext {
qinsoon's avatar
qinsoon committed
191
    pub value_tags: HashMap<MuName, MuID>,
192
    pub values: HashMap<MuID, SSAVarEntry>
193 194 195 196 197
}

impl FunctionContext {
    fn new() -> FunctionContext {
        FunctionContext {
198
            value_tags: HashMap::new(),
199 200 201
            values: HashMap::new()
        }
    }
202

qinsoon's avatar
qinsoon committed
203
    pub fn get_value_by_tag(&self, tag: MuName) -> Option<&SSAVarEntry> {
204 205 206 207 208
        match self.value_tags.get(tag) {
            Some(id) => self.get_value(*id),
            None => None
        }
    }
209

qinsoon's avatar
qinsoon committed
210
    pub fn get_value_mut_by_tag(&mut self, tag: MuName) -> Option<&mut SSAVarEntry> {
211 212 213 214
        let id : MuID = match self.value_tags.get(tag) {
            Some(id) => *id,
            None => return None
        };
215

216 217
        self.get_value_mut(id)
    }
218

219
    pub fn get_value(&self, id: MuID) -> Option<&SSAVarEntry> {
220 221
        self.values.get(&id)
    }
222

223
    pub fn get_value_mut(&mut self, id: MuID) -> Option<&mut SSAVarEntry> {
224 225 226 227
        self.values.get_mut(&id)
    }
}

228
#[derive(Debug)]
229
pub struct Block {
230
    pub hdr: MuEntityHeader,
231 232
    pub content: Option<BlockContent>,
    pub control_flow: ControlFlow
qinsoon's avatar
qinsoon committed
233 234
}

235
impl Block {
qinsoon's avatar
qinsoon committed
236
    pub fn new(id: MuID) -> Block {
237
        Block{hdr: MuEntityHeader::unnamed(id), content: None, control_flow: ControlFlow::default()}
238 239 240
    }
}

241 242
#[derive(Debug)]
pub struct ControlFlow {
qinsoon's avatar
qinsoon committed
243
    pub preds : Vec<MuID>,
244 245 246
    pub succs : Vec<BlockEdge>
}

247
impl ControlFlow {
qinsoon's avatar
qinsoon committed
248
    pub fn get_hottest_succ(&self) -> Option<MuID> {
249 250 251 252 253
        if self.succs.len() == 0 {
            None
        } else {
            let mut hot_blk = self.succs[0].target;
            let mut hot_prob = self.succs[0].probability;
254

255 256 257 258 259 260
            for edge in self.succs.iter() {
                if edge.probability > hot_prob {
                    hot_blk = edge.target;
                    hot_prob = edge.probability;
                }
            }
261

262 263 264 265 266
            Some(hot_blk)
        }
    }
}

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
impl fmt::Display for ControlFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "preds: [{}], ", vector_as_str(&self.preds)).unwrap();
        write!(f, "succs: [{}]", vector_as_str(&self.succs))
    }
}

impl default::Default for ControlFlow {
    fn default() -> ControlFlow {
        ControlFlow {preds: vec![], succs: vec![]}
    }
}

#[derive(Copy, Clone, Debug)]
pub struct BlockEdge {
qinsoon's avatar
qinsoon committed
282
    pub target: MuID,
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
    pub kind: EdgeKind,
    pub is_exception: bool,
    pub probability: f32
}

impl fmt::Display for BlockEdge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({:?}{} - {})", self.target, self.kind, select_value!(self.is_exception, ", exceptional", ""), self.probability)
    }
}

#[derive(Copy, Clone, Debug)]
pub enum EdgeKind {
    Forward, Backward
}

299
#[derive(Debug)]
300
pub struct BlockContent {
301
    pub args: Vec<P<Value>>,
qinsoon's avatar
qinsoon committed
302
    pub body: Vec<P<TreeNode>>,
303
    pub keepalives: Option<Vec<P<Value>>>
304 305
}

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
impl BlockContent {
    pub fn get_out_arguments(&self) -> Vec<P<Value>> {
        let n_insts = self.body.len();
        let ref last_inst = self.body[n_insts - 1];
        
        let mut ret : Vec<P<Value>> = vec![];
        
        match last_inst.v {
            TreeNode_::Instruction(ref inst) => {
                let ops = inst.ops.borrow();
                match inst.v {
                    Instruction_::Return(_)
                    | Instruction_::ThreadExit
                    | Instruction_::Throw(_)
                    | Instruction_::TailCall(_) => {
                        // they do not have explicit liveouts
                    }
                    Instruction_::Branch1(ref dest) => {
                        let mut live_outs = dest.get_arguments(&ops);
                        vec_utils::append_unique(&mut ret, &mut live_outs);
                    }
                    Instruction_::Branch2{ref true_dest, ref false_dest, ..} => {
                        let mut live_outs = true_dest.get_arguments(&ops);
                        live_outs.append(&mut false_dest.get_arguments(&ops));
                        
                        vec_utils::append_unique(&mut ret, &mut live_outs);
                    }
                    Instruction_::Watchpoint{ref disable_dest, ref resume, ..} => {
                        let mut live_outs = vec![];
                        
                        if disable_dest.is_some() {
                            live_outs.append(&mut disable_dest.as_ref().unwrap().get_arguments(&ops));
                        }
                        live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
                        live_outs.append(&mut resume.exn_dest.get_arguments(&ops));
                        
                        vec_utils::append_unique(&mut ret, &mut live_outs);
                    }
                    Instruction_::WPBranch{ref disable_dest, ref enable_dest, ..} => {
                        let mut live_outs = vec![];
                        live_outs.append(&mut disable_dest.get_arguments(&ops));
                        live_outs.append(&mut enable_dest.get_arguments(&ops));
                        vec_utils::append_unique(&mut ret, &mut live_outs);
                    }
                    Instruction_::Call{ref resume, ..}
                    | Instruction_::SwapStack{ref resume, ..}
                    | Instruction_::ExnInstruction{ref resume, ..} => {
                        let mut live_outs = vec![];
                        live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
                        live_outs.append(&mut resume.exn_dest.get_arguments(&ops));
                        vec_utils::append_unique(&mut ret, &mut live_outs);
                    }
                    Instruction_::Switch{ref default, ref branches, ..} => {
                        let mut live_outs = vec![];
                        live_outs.append(&mut default.get_arguments(&ops));
                        for &(_, ref dest) in branches {
                            live_outs.append(&mut dest.get_arguments(&ops));
                        }
                        vec_utils::append_unique(&mut ret, &mut live_outs);
                    }
                    
                    _ => panic!("didn't expect last inst as {:?}", inst) 
                }
            },
            _ => panic!("expect last treenode of block is a inst")
        }
        
        ret
    }
}

377
#[derive(Debug)]
qinsoon's avatar
qinsoon committed
378 379
/// always use with P<TreeNode>
pub struct TreeNode {
380
    pub hdr: MuEntityHeader,
381 382
    pub op: OpCode,
    pub v: TreeNode_,
qinsoon's avatar
qinsoon committed
383 384
}

385
impl TreeNode {
386
    // this is a hack to allow creating TreeNode without using a &mut MuFunctionVersion
qinsoon's avatar
qinsoon committed
387 388
    pub fn new_inst(id: MuID, v: Instruction) -> P<TreeNode> {
        P(TreeNode{
389
            hdr: MuEntityHeader::unnamed(id),
390
            op: pick_op_code_for_inst(&v),
qinsoon's avatar
qinsoon committed
391 392
            v: TreeNode_::Instruction(v),
        })
393 394
    }

395 396 397 398 399 400 401 402 403 404 405
    pub fn extract_ssa_id(&self) -> Option<MuID> {
        match self.v {
            TreeNode_::Value(ref pv) => {
                match pv.v {
                    Value_::SSAVar(id) => Some(id),
                    _ => None
                }
            },
            _ => None
        }
    }
406

qinsoon's avatar
qinsoon committed
407
    pub fn clone_value(&self) -> P<Value> {
qinsoon's avatar
qinsoon committed
408
        match self.v {
qinsoon's avatar
qinsoon committed
409
            TreeNode_::Value(ref val) => val.clone(),
410 411 412 413 414 415 416 417
            TreeNode_::Instruction(ref inst) => {
                info!("expecting a value, but we found an inst. Instead we use its first value");
                let vals = inst.value.as_ref().unwrap();
                if vals.len() != 1 {
                    panic!("we expect an inst with 1 value, but found multiple or zero (it should not be here - folded as a child)");
                }
                vals[0].clone()
            }
qinsoon's avatar
qinsoon committed
418
        }
419 420
    }

qinsoon's avatar
qinsoon committed
421 422 423
    pub fn into_value(self) -> Option<P<Value>> {
        match self.v {
            TreeNode_::Value(val) => Some(val),
424
            _ => None
qinsoon's avatar
qinsoon committed
425 426
        }
    }
qinsoon's avatar
qinsoon committed
427 428
}

429 430
/// use +() to display a node
impl fmt::Display for TreeNode {
qinsoon's avatar
qinsoon committed
431
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
432
        match self.v {
qinsoon's avatar
qinsoon committed
433
            TreeNode_::Value(ref pv) => pv.fmt(f),
434
            TreeNode_::Instruction(ref inst) => {
435
                write!(f, "+({})", inst)
436
            }
qinsoon's avatar
qinsoon committed
437
        }
qinsoon's avatar
qinsoon committed
438
    }
qinsoon's avatar
qinsoon committed
439 440
}

441
#[derive(Debug, Clone)]
qinsoon's avatar
qinsoon committed
442
pub enum TreeNode_ {
qinsoon's avatar
qinsoon committed
443
    Value(P<Value>),
444
    Instruction(Instruction)
qinsoon's avatar
qinsoon committed
445 446 447
}

/// always use with P<Value>
448
#[derive(Debug, PartialEq)]
qinsoon's avatar
qinsoon committed
449
pub struct Value {
450
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
451 452
    pub ty: P<MuType>,
    pub v: Value_
qinsoon's avatar
qinsoon committed
453 454
}

455 456 457 458 459 460 461 462 463 464 465 466 467
impl Value {
    pub fn is_int_reg(&self) -> bool {
        match self.v {
            Value_::SSAVar(_) => {
                if is_scalar(&self.ty) && !is_fp(&self.ty) {
                    true
                } else {
                    false
                }
            }
            _ => false
        }
    }
468

469 470 471 472 473 474 475 476 477 478 479 480
    pub fn is_fp_reg(&self) -> bool {
        match self.v {
            Value_::SSAVar(_) => {
                if is_scalar(&self.ty) && is_fp(&self.ty) {
                    true
                } else {
                    false
                }
            },
            _ => false
        }
    }
481

482 483 484
    pub fn is_int_const(&self) -> bool {
        match self.v {
            Value_::Constant(_) => {
qinsoon's avatar
qinsoon committed
485 486 487
                let ty : &MuType = &self.ty;
                match ty.v {
                    MuType_::Int(_) => true,
488 489 490 491 492
                    _ => false
                }
            }
            _ => false
        }
qinsoon's avatar
qinsoon committed
493
    }
494

qinsoon's avatar
qinsoon committed
495 496 497 498 499 500 501 502 503 504 505
    pub fn extract_ssa_id(&self) -> Option<MuID> {
        match self.v {
            Value_::SSAVar(id) => Some(id),
            _ => None
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.v {
qinsoon's avatar
qinsoon committed
506
            Value_::SSAVar(_) => {
507
                write!(f, "+({} %{})", self.ty, self.hdr)
qinsoon's avatar
qinsoon committed
508 509
            },
            Value_::Constant(ref c) => {
510
                write!(f, "+({} {} @{})", self.ty, c, self.hdr)
qinsoon's avatar
qinsoon committed
511
            },
512 513
            Value_::Global(ref ty) => {
                write!(f, "+(GLOBAL {} @{})", ty, self.hdr)
514 515
            },
            Value_::Memory(ref mem) => {
516
                write!(f, "+(MEM {} %{})", mem, self.hdr)
qinsoon's avatar
qinsoon committed
517 518 519
            }
        }
    }
520 521
}

522
#[derive(Debug, Clone, PartialEq)]
qinsoon's avatar
qinsoon committed
523
pub enum Value_ {
524
    SSAVar(MuID),
qinsoon's avatar
qinsoon committed
525
    Constant(Constant),
526
    Global(P<MuType>), // what type is this global (without IRef)
527
    Memory(MemoryLocation)
qinsoon's avatar
qinsoon committed
528 529
}

530
#[derive(Debug, Clone)]
531
pub struct SSAVarEntry {
532
    pub id: MuID,
qinsoon's avatar
qinsoon committed
533
    pub name: Option<MuName>,
534
    pub ty: P<MuType>,
535

536 537 538
    // how many times this entry is used
    // availalbe after DefUse pass
    pub use_count: Cell<usize>,
539

540
    // this field is only used during TreeGeneration pass
541 542 543
    pub expr: Option<Instruction>
}

544
impl SSAVarEntry {
545 546 547
    pub fn assign_expr(&mut self, expr: Instruction) {
        self.expr = Some(expr)
    }
548 549
}

550
impl fmt::Display for SSAVarEntry {
551
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
552 553 554 555 556
        if self.name.is_some() {
            write!(f, "{} {}#{}", self.ty, self.name.unwrap(), self.id)
        } else {
            write!(f, "{} {}#{}", self.ty, "???", self.id)
        }
557 558 559
    }
}

560
#[derive(Debug, Clone, PartialEq)]
561
pub enum Constant {
qinsoon's avatar
qinsoon committed
562
    Int(u64),
563 564 565
    Float(f32),
    Double(f64),
    IRef(Address),
qinsoon's avatar
qinsoon committed
566 567
    FuncRef(MuID),
    UFuncRef(MuID),
568
    Vector(Vec<Constant>),
569 570
}

571
impl fmt::Display for Constant {
572 573 574 575 576 577 578 579
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Constant::Int(v) => write!(f, "{}", v),
            &Constant::Float(v) => write!(f, "{}", v),
            &Constant::Double(v) => write!(f, "{}", v),
            &Constant::IRef(v) => write!(f, "{}", v),
            &Constant::FuncRef(v) => write!(f, "{}", v),
            &Constant::UFuncRef(v) => write!(f, "{}", v),
580 581 582 583 584 585 586 587 588 589
            &Constant::Vector(ref v) => {
                write!(f, "[").unwrap();
                for i in 0..v.len() {
                    write!(f, "{}", v[i]).unwrap();
                    if i != v.len() - 1 {
                        write!(f, ", ").unwrap();
                    }
                }
                write!(f, "]")
            }
590 591
        }
    }
qinsoon's avatar
qinsoon committed
592 593
}

594 595 596 597 598 599 600 601 602 603
#[derive(Debug, Clone, PartialEq)]
pub enum MemoryLocation {
    Address{
        base: P<Value>,
        offset: Option<P<Value>>,
        index: Option<P<Value>>,
        scale: Option<u8>
    },
    Symbolic{
        base: Option<P<Value>>,
qinsoon's avatar
qinsoon committed
604
        label: MuName
605 606 607 608 609 610 611 612 613 614 615
    }
}

impl fmt::Display for MemoryLocation {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &MemoryLocation::Address{ref base, ref offset, ref index, scale} => {
                write!(f, "{} + {} + {} * {}", base, offset.as_ref().unwrap(), index.as_ref().unwrap(), scale.unwrap())
            }
            &MemoryLocation::Symbolic{ref base, ref label} => {
                if base.is_some() {
616
                    write!(f, "{}({})", label, base.as_ref().unwrap())
617 618 619 620 621 622 623 624
                } else {
                    write!(f, "{}", label)
                }
            }
        }
    }
}

625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
#[derive(Debug)] // Display, PartialEq
pub struct MuEntityHeader {
    id: MuID,
    name: RwLock<Option<MuName>>
}

impl MuEntityHeader {
    pub fn unnamed(id: MuID) -> MuEntityHeader {
        MuEntityHeader {
            id: id,
            name: RwLock::new(None)
        }
    }
    
    pub fn named(id: MuID, name: MuName) -> MuEntityHeader {
        MuEntityHeader {
            id: id,
            name: RwLock::new(Some(name))
        }
    }
    
    pub fn id(&self) -> MuID {
        self.id
    }
    
    pub fn name(&self) -> Option<MuName> {
        *self.name.read().unwrap()
    }
}

impl PartialEq for MuEntityHeader {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl fmt::Display for MuEntityHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.name().is_none() {
            write!(f, "#{}", self.id)
        } else {
            write!(f, "{} #{}", self.name().unwrap(), self.id)
        }
    }
}

qinsoon's avatar
qinsoon committed
671 672 673
pub trait MuEntity {
    fn id(&self) -> MuID;
    fn name(&self) -> Option<MuName>;
674
    fn set_name(&self, name: MuName);
qinsoon's avatar
qinsoon committed
675 676 677 678 679 680 681
    fn as_entity(&self) -> &MuEntity;
}

macro_rules! impl_mu_entity {
    ($entity: ty) => {
        impl MuEntity for $entity {
            #[inline(always)]
682
            fn id(&self) -> MuID {self.hdr.id}
qinsoon's avatar
qinsoon committed
683
            #[inline(always)]
684 685 686 687 688
            fn name(&self) -> Option<MuName> {self.hdr.name()}
            fn set_name(&self, name: MuName) {
                let mut write_guard = self.hdr.name.write().unwrap();
                *write_guard = Some(name);
            }
qinsoon's avatar
qinsoon committed
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
            fn as_entity(&self) -> &MuEntity {
                let ref_ty : &$entity = self;
                ref_ty as &MuEntity
            }
        }
    }
}

impl_mu_entity!(MuFunction);
impl_mu_entity!(MuFunctionVersion);
impl_mu_entity!(Block);
impl_mu_entity!(TreeNode);
impl_mu_entity!(MuType);
impl_mu_entity!(Value);
impl_mu_entity!(MuFuncSig);

705
pub fn op_vector_str(vec: &Vec<OpIndex>, ops: &Vec<P<TreeNode>>) -> String {
706 707 708 709 710 711
    let mut ret = String::new();
    for i in 0..vec.len() {
        let index = vec[i];
        ret.push_str(format!("{}", ops[index]).as_str());
        if i != vec.len() - 1 {
            ret.push_str(", ");
712
        }
713 714
    }
    ret
715
}