ir.rs 22.8 KB
Newer Older
1 2 3 4 5
use ptr::P;
use types::*;
use inst::*;
use op::*;

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::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
qinsoon's avatar
qinsoon committed
13

qinsoon's avatar
qinsoon committed
14 15
pub type WPID  = usize;
pub type MuID  = usize;
16
pub type MuName = String;
17
pub type CName  = MuName;
qinsoon's avatar
qinsoon committed
18

19 20 21
#[allow(non_snake_case)]
pub fn Mu(str: &'static str) -> MuName {str.to_string()}

22 23
pub type OpIndex = usize;

qinsoon's avatar
qinsoon committed
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 56 57
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
58

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

impl MuFunction {
qinsoon's avatar
qinsoon committed
69
    pub fn new(id: MuID, sig: P<MuFuncSig>) -> MuFunction {
70
        MuFunction {
71
            hdr: MuEntityHeader::unnamed(id),
72 73 74 75 76
            sig: sig,
            cur_ver: None,
            all_vers: vec![]
        }
    }
77 78 79 80 81 82 83 84 85
    
    pub fn new_version(&mut self, fv: MuID) {
        if self.cur_ver.is_some() {
            let obsolete_ver = self.cur_ver.unwrap();
            self.all_vers.push(obsolete_ver);
        }
        
        self.cur_ver = Some(fv);
    }
86 87
}

qinsoon's avatar
qinsoon committed
88 89
impl fmt::Display for MuFunction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90
        write!(f, "Func {}", self.hdr)
qinsoon's avatar
qinsoon committed
91 92 93
    }
}

qinsoon's avatar
qinsoon committed
94
#[derive(Debug, RustcEncodable, RustcDecodable)]
95
pub struct MuFunctionVersion {
96
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
97 98
         
    pub func_id: MuID,
qinsoon's avatar
qinsoon committed
99
    pub sig: P<MuFuncSig>,
100
    pub content: Option<FunctionContent>,
101
    pub context: FunctionContext,
102

qinsoon's avatar
qinsoon committed
103 104 105 106 107
    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 {
108
        write!(f, "FuncVer {} of Func #{}", self.hdr, self.func_id)
qinsoon's avatar
qinsoon committed
109
    }
110 111
}

112
impl MuFunctionVersion {
qinsoon's avatar
qinsoon committed
113
    pub fn new(id: MuID, func: MuID, sig: P<MuFuncSig>) -> MuFunctionVersion {
114
        MuFunctionVersion{
115
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
116
            func_id: func,
117 118 119
            sig: sig,
            content: None,
            context: FunctionContext::new(),
120 121
            block_trace: None}
    }
122

123 124 125
    pub fn define(&mut self, content: FunctionContent) {
        self.content = Some(content)
    }
126

qinsoon's avatar
qinsoon committed
127 128
    pub fn new_ssa(&mut self, id: MuID, ty: P<MuType>) -> P<TreeNode> {
        self.context.values.insert(id, SSAVarEntry::new(id, ty.clone()));
129

130
        P(TreeNode {
131
            hdr: MuEntityHeader::unnamed(id),
132
            op: pick_op_code_for_ssa(&ty),
qinsoon's avatar
qinsoon committed
133
            v: TreeNode_::Value(P(Value{
qinsoon's avatar
qinsoon committed
134
                hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
135 136 137
                ty: ty,
                v: Value_::SSAVar(id)
            }))
138 139
        })
    }
140

141
    pub fn new_constant(&mut self, id: MuID, v: P<Value>) -> P<TreeNode> {
142
        P(TreeNode{
143
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
144 145 146 147 148
            op: pick_op_code_for_value(&v.ty),
            v: TreeNode_::Value(v)
        })
    }
    
149
    pub fn new_global(&mut self, id: MuID, v: P<Value>) -> P<TreeNode> {
qinsoon's avatar
qinsoon committed
150
        P(TreeNode{
151
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
152
            op: pick_op_code_for_value(&v.ty),
qinsoon's avatar
qinsoon committed
153 154
            v: TreeNode_::Value(v)
        })
155
    }
156

qinsoon's avatar
qinsoon committed
157 158
    pub fn new_inst(&mut self, id: MuID, v: Instruction) -> Box<TreeNode> {
        Box::new(TreeNode{
159
            hdr: MuEntityHeader::unnamed(id),
160
            op: pick_op_code_for_inst(&v),
161 162
            v: TreeNode_::Instruction(v),
        })
163
    }
164 165
}

qinsoon's avatar
qinsoon committed
166
#[derive(Debug, RustcEncodable, RustcDecodable)]
167
pub struct FunctionContent {
qinsoon's avatar
qinsoon committed
168 169
    pub entry: MuID,
    pub blocks: HashMap<MuID, Block>
170 171 172 173
}

impl FunctionContent {
    pub fn get_entry_block(&self) -> &Block {
qinsoon's avatar
qinsoon committed
174
        self.get_block(self.entry)
qinsoon's avatar
qinsoon committed
175
    } 
176

177
    pub fn get_entry_block_mut(&mut self) -> &mut Block {
qinsoon's avatar
qinsoon committed
178 179
        let entry = self.entry;
        self.get_block_mut(entry)
180
    }
181

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

qinsoon's avatar
qinsoon committed
190 191
    pub fn get_block_mut(&mut self, id: MuID) -> &mut Block {
        let ret = self.blocks.get_mut(&id);
qinsoon's avatar
qinsoon committed
192 193
        match ret {
            Some(b) => b,
qinsoon's avatar
qinsoon committed
194
            None => panic!("cannot find block #{}", id)
qinsoon's avatar
qinsoon committed
195
        }
196
    }
197 198
}

qinsoon's avatar
qinsoon committed
199
#[derive(Debug, RustcEncodable, RustcDecodable)]
200
pub struct FunctionContext {
201
    pub values: HashMap<MuID, SSAVarEntry>
202 203 204 205 206 207 208 209
}

impl FunctionContext {
    fn new() -> FunctionContext {
        FunctionContext {
            values: HashMap::new()
        }
    }
210 211 212 213 214 215 216 217 218 219 220 221 222 223
    
    pub fn make_temporary(&mut self, id: MuID, ty: P<MuType>) -> P<TreeNode> {
        self.values.insert(id, SSAVarEntry::new(id, ty.clone()));

        P(TreeNode {
            hdr: MuEntityHeader::unnamed(id),
            op: pick_op_code_for_ssa(&ty),
            v: TreeNode_::Value(P(Value{
                hdr: MuEntityHeader::unnamed(id),
                ty: ty,
                v: Value_::SSAVar(id)
            }))
        })
    }    
224

225
    pub fn get_value(&self, id: MuID) -> Option<&SSAVarEntry> {
226 227
        self.values.get(&id)
    }
228

229
    pub fn get_value_mut(&mut self, id: MuID) -> Option<&mut SSAVarEntry> {
230 231 232 233
        self.values.get_mut(&id)
    }
}

qinsoon's avatar
qinsoon committed
234
#[derive(Debug, RustcEncodable, RustcDecodable)]
235
pub struct Block {
236
    pub hdr: MuEntityHeader,
237 238
    pub content: Option<BlockContent>,
    pub control_flow: ControlFlow
qinsoon's avatar
qinsoon committed
239 240
}

241
impl Block {
qinsoon's avatar
qinsoon committed
242
    pub fn new(id: MuID) -> Block {
243
        Block{hdr: MuEntityHeader::unnamed(id), content: None, control_flow: ControlFlow::default()}
244 245 246
    }
}

qinsoon's avatar
qinsoon committed
247
#[derive(Debug, RustcEncodable, RustcDecodable)]
248
pub struct ControlFlow {
qinsoon's avatar
qinsoon committed
249
    pub preds : Vec<MuID>,
250 251 252
    pub succs : Vec<BlockEdge>
}

253
impl ControlFlow {
qinsoon's avatar
qinsoon committed
254
    pub fn get_hottest_succ(&self) -> Option<MuID> {
255 256 257 258 259
        if self.succs.len() == 0 {
            None
        } else {
            let mut hot_blk = self.succs[0].target;
            let mut hot_prob = self.succs[0].probability;
260

261 262 263 264 265 266
            for edge in self.succs.iter() {
                if edge.probability > hot_prob {
                    hot_blk = edge.target;
                    hot_prob = edge.probability;
                }
            }
267

268 269 270 271 272
            Some(hot_blk)
        }
    }
}

273 274
impl fmt::Display for ControlFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
275 276
        write!(f, "preds: [{}], ", vec_utils::as_str(&self.preds)).unwrap();
        write!(f, "succs: [{}]", vec_utils::as_str(&self.succs))
277 278 279 280 281 282 283 284 285
    }
}

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

qinsoon's avatar
qinsoon committed
286
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
287
pub struct BlockEdge {
qinsoon's avatar
qinsoon committed
288
    pub target: MuID,
289 290 291 292 293 294 295 296 297 298 299
    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)
    }
}

qinsoon's avatar
qinsoon committed
300
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
301 302 303 304
pub enum EdgeKind {
    Forward, Backward
}

qinsoon's avatar
qinsoon committed
305
#[derive(Debug, RustcEncodable, RustcDecodable)]
306
pub struct BlockContent {
307
    pub args: Vec<P<Value>>,
qinsoon's avatar
qinsoon committed
308
    pub body: Vec<Box<TreeNode>>,
309
    pub keepalives: Option<Vec<P<Value>>>
310 311
}

312 313 314 315 316 317 318 319 320
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) => {
qinsoon's avatar
qinsoon committed
321
                let ops = inst.ops.read().unwrap();
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 377 378 379 380 381 382
                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
    }
}

qinsoon's avatar
qinsoon committed
383
#[derive(Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
384 385
/// always use with P<TreeNode>
pub struct TreeNode {
386
    pub hdr: MuEntityHeader,
387 388
    pub op: OpCode,
    pub v: TreeNode_,
qinsoon's avatar
qinsoon committed
389 390
}

391
impl TreeNode {
392
    // this is a hack to allow creating TreeNode without using a &mut MuFunctionVersion
qinsoon's avatar
qinsoon committed
393 394
    pub fn new_inst(id: MuID, v: Instruction) -> P<TreeNode> {
        P(TreeNode{
395
            hdr: MuEntityHeader::unnamed(id),
396
            op: pick_op_code_for_inst(&v),
qinsoon's avatar
qinsoon committed
397 398
            v: TreeNode_::Instruction(v),
        })
399 400
    }

401 402 403 404 405 406 407 408 409 410 411
    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
        }
    }
412

qinsoon's avatar
qinsoon committed
413
    pub fn clone_value(&self) -> P<Value> {
qinsoon's avatar
qinsoon committed
414
        match self.v {
qinsoon's avatar
qinsoon committed
415
            TreeNode_::Value(ref val) => val.clone(),
416 417 418 419 420 421 422 423
            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
424
        }
425 426
    }

qinsoon's avatar
qinsoon committed
427 428 429
    pub fn into_value(self) -> Option<P<Value>> {
        match self.v {
            TreeNode_::Value(val) => Some(val),
430
            _ => None
qinsoon's avatar
qinsoon committed
431 432
        }
    }
qinsoon's avatar
qinsoon committed
433 434
}

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

qinsoon's avatar
qinsoon committed
447
#[derive(Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
448
pub enum TreeNode_ {
qinsoon's avatar
qinsoon committed
449
    Value(P<Value>),
450
    Instruction(Instruction)
qinsoon's avatar
qinsoon committed
451 452 453
}

/// always use with P<Value>
qinsoon's avatar
qinsoon committed
454
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
455
pub struct Value {
456
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
457 458
    pub ty: P<MuType>,
    pub v: Value_
qinsoon's avatar
qinsoon committed
459 460
}

461
impl Value {
462 463 464 465 466 467 468
    pub fn is_mem(&self) -> bool {
        match self.v {
            Value_::Memory(_) => true,
            _ => false
        }
    }
    
469 470 471 472 473 474 475 476 477 478 479 480
    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
        }
    }
481

482 483 484 485 486 487 488 489 490 491 492 493
    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
        }
    }
494

495 496 497
    pub fn is_int_const(&self) -> bool {
        match self.v {
            Value_::Constant(_) => {
qinsoon's avatar
qinsoon committed
498 499 500
                let ty : &MuType = &self.ty;
                match ty.v {
                    MuType_::Int(_) => true,
501 502 503 504 505
                    _ => false
                }
            }
            _ => false
        }
qinsoon's avatar
qinsoon committed
506
    }
507 508 509 510 511 512 513 514 515 516 517 518
    
    pub fn extract_int_const(&self) -> u64 {
        match self.v {
            Value_::Constant(ref c) => {
                match c {
                    &Constant::Int(val) => val,
                    _ => panic!("expect int const")
                }
            },
            _ => panic!("expect int const")
        }
    }
519

qinsoon's avatar
qinsoon committed
520 521 522 523 524 525 526 527 528 529 530
    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
531
            Value_::SSAVar(_) => {
532
                write!(f, "+({} %{})", self.ty, self.hdr)
qinsoon's avatar
qinsoon committed
533 534
            },
            Value_::Constant(ref c) => {
535
                write!(f, "+({} {} @{})", self.ty, c, self.hdr)
qinsoon's avatar
qinsoon committed
536
            },
537 538
            Value_::Global(ref ty) => {
                write!(f, "+(GLOBAL {} @{})", ty, self.hdr)
539 540
            },
            Value_::Memory(ref mem) => {
541
                write!(f, "+(MEM {} %{})", mem, self.hdr)
qinsoon's avatar
qinsoon committed
542 543 544
            }
        }
    }
545 546
}

qinsoon's avatar
qinsoon committed
547
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
548
pub enum Value_ {
549
    SSAVar(MuID),
qinsoon's avatar
qinsoon committed
550
    Constant(Constant),
551
    Global(P<MuType>), // what type is this global (without IRef)
552
    Memory(MemoryLocation)
qinsoon's avatar
qinsoon committed
553 554
}

qinsoon's avatar
qinsoon committed
555
#[derive(Debug)]
556
pub struct SSAVarEntry {
qinsoon's avatar
qinsoon committed
557
    id: MuID,
558
    pub ty: P<MuType>,
559

560 561
    // how many times this entry is used
    // availalbe after DefUse pass
qinsoon's avatar
qinsoon committed
562
    pub use_count: AtomicUsize,
563

564
    // this field is only used during TreeGeneration pass
565 566 567
    pub expr: Option<Instruction>
}

qinsoon's avatar
qinsoon committed
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
impl Encodable for SSAVarEntry {
    fn encode<S: Encoder> (&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("SSAVarEntry", 4, |s| {
            try!(s.emit_struct_field("id", 0, |s| self.id.encode(s)));
            try!(s.emit_struct_field("ty", 1, |s| self.ty.encode(s)));
            let count = self.use_count.load(Ordering::SeqCst);
            try!(s.emit_struct_field("use_count", 2, |s| s.emit_usize(count)));
            try!(s.emit_struct_field("expr", 3, |s| self.expr.encode(s)));
            Ok(())
        })
    }
}

impl Decodable for SSAVarEntry {
    fn decode<D: Decoder>(d: &mut D) -> Result<SSAVarEntry, D::Error> {
        d.read_struct("SSAVarEntry", 4, |d| {
            let id = try!(d.read_struct_field("id", 0, |d| Decodable::decode(d)));
            let ty = try!(d.read_struct_field("ty", 1, |d| Decodable::decode(d)));
            let count = try!(d.read_struct_field("use_count", 2, |d| d.read_usize()));
            let expr = try!(d.read_struct_field("expr", 3, |d| Decodable::decode(d)));
            
            let ret = SSAVarEntry {
                id: id,
                ty: ty,
                use_count: ATOMIC_USIZE_INIT,
                expr: expr
            };
            
            ret.use_count.store(count, Ordering::SeqCst);
            
            Ok(ret)
        })
    }
}

603
impl SSAVarEntry {
qinsoon's avatar
qinsoon committed
604 605 606 607 608 609 610 611 612 613 614 615
    pub fn new(id: MuID, ty: P<MuType>) -> SSAVarEntry {
        let ret = SSAVarEntry {
            id: id,
            ty: ty,
            use_count: ATOMIC_USIZE_INIT,
            expr: None
        };
        
        ret.use_count.store(0, Ordering::SeqCst);
        
        ret
    }
616 617 618
    pub fn assign_expr(&mut self, expr: Instruction) {
        self.expr = Some(expr)
    }
619 620
}

621
impl fmt::Display for SSAVarEntry {
622
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
623
        write!(f, "{} #{}", self.ty, self.id)
624 625 626
    }
}

qinsoon's avatar
qinsoon committed
627
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
628
pub enum Constant {
qinsoon's avatar
qinsoon committed
629
    Int(u64),
630 631
    Float(f32),
    Double(f64),
qinsoon's avatar
qinsoon committed
632
//    IRef(Address),
qinsoon's avatar
qinsoon committed
633 634
    FuncRef(MuID),
    UFuncRef(MuID),
635
    Vector(Vec<Constant>),
636 637
}

638
impl fmt::Display for Constant {
639 640 641 642 643
    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),
qinsoon's avatar
qinsoon committed
644
//            &Constant::IRef(v) => write!(f, "{}", v),
645 646
            &Constant::FuncRef(v) => write!(f, "{}", v),
            &Constant::UFuncRef(v) => write!(f, "{}", v),
647 648 649 650 651 652 653 654 655 656
            &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, "]")
            }
657 658
        }
    }
qinsoon's avatar
qinsoon committed
659 660
}

qinsoon's avatar
qinsoon committed
661
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
662 663 664 665 666 667 668 669 670
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
671
        label: MuName
672 673 674 675 676 677 678
    }
}

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} => {
679 680 681 682 683 684 685 686 687 688 689
                // base
                write!(f, "[{}", base).unwrap();
                // offset
                if offset.is_some() {
                    write!(f, " + {}", offset.as_ref().unwrap()).unwrap();
                }
                // index/scale
                if index.is_some() && scale.is_some() {
                    write!(f, " + {} * {}", index.as_ref().unwrap(), scale.unwrap()).unwrap();
                }
                write!(f, "]")
690 691 692
            }
            &MemoryLocation::Symbolic{ref base, ref label} => {
                if base.is_some() {
693
                    write!(f, "{}({})", label, base.as_ref().unwrap())
694 695 696 697 698 699 700 701
                } else {
                    write!(f, "{}", label)
                }
            }
        }
    }
}

702
#[repr(C)]
703 704
#[derive(Debug)] // Display, PartialEq
pub struct MuEntityHeader {
qinsoon's avatar
qinsoon committed
705 706
    pub id: MuID,
    pub name: RwLock<Option<MuName>>
707 708
}

709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
impl Encodable for MuEntityHeader {
    fn encode<S: Encoder> (&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("MuEntityHeader", 2, |s| {
            try!(s.emit_struct_field("id", 0, |s| self.id.encode(s)));
            
            let name = &self.name.read().unwrap();
            try!(s.emit_struct_field("name", 1, |s| name.encode(s)));
            
            Ok(())
        })
    }
}

impl Decodable for MuEntityHeader {
    fn decode<D: Decoder>(d: &mut D) -> Result<MuEntityHeader, D::Error> {
        d.read_struct("MuEntityHeader", 2, |d| {
            let id = try!(d.read_struct_field("id", 0, |d| {d.read_usize()}));
            let name = try!(d.read_struct_field("name", 1, |d| Decodable::decode(d)));
            
            Ok(MuEntityHeader{
                    id: id,
                    name: RwLock::new(name)
                })
        })
    }
}

737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
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> {
757
        self.name.read().unwrap().clone()
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
    }
}

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
777 778 779
pub trait MuEntity {
    fn id(&self) -> MuID;
    fn name(&self) -> Option<MuName>;
780
    fn set_name(&self, name: MuName);
qinsoon's avatar
qinsoon committed
781 782 783 784 785 786 787 788 789 790 791
    fn as_entity(&self) -> &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);

792
pub fn op_vector_str(vec: &Vec<OpIndex>, ops: &Vec<P<TreeNode>>) -> String {
793 794 795 796 797 798
    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(", ");
799
        }
800 801
    }
    ret
802
}