To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

ir.rs 20.8 KB
Newer Older
1
use ast::ptr::P;
qinsoon's avatar
qinsoon committed
2
use ast::op::*;
3
4
use ast::types::*;

5
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
6
use std::fmt;
qinsoon's avatar
qinsoon committed
7
use std::cell::Cell;
qinsoon's avatar
qinsoon committed
8

qinsoon's avatar
qinsoon committed
9
10
11
12
13
pub type WPID  = usize;
pub type MuID  = usize;
pub type MuTag = &'static str;
pub type Address = usize; // TODO: replace this with Address(usize)

14
#[derive(Debug)]
qinsoon's avatar
qinsoon committed
15
16
17
pub struct MuFunction {
    pub fn_name: MuTag,
    pub sig: P<MuFuncSig>,
18
    pub content: Option<FunctionContent>,
qinsoon's avatar
qinsoon committed
19
    pub context: FunctionContext
20
21
22
23
}

#[derive(Debug)]
pub struct FunctionContent {
qinsoon's avatar
qinsoon committed
24
25
    pub entry: MuTag,
    pub blocks: Vec<(MuTag, Block)>
qinsoon's avatar
qinsoon committed
26
27
}

qinsoon's avatar
qinsoon committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#[derive(Debug)]
pub struct FunctionContext {
    pub values: HashMap<MuID, ValueEntry>
}

impl FunctionContext {
    fn new() -> FunctionContext {
        FunctionContext {
            values: HashMap::new()
        }
    }
    
    pub fn get_value(&self, id: MuID) -> Option<&ValueEntry> {
        self.values.get(&id)
    }
}

45
46
impl MuFunction {
    pub fn new(fn_name: MuTag, sig: P<MuFuncSig>) -> MuFunction {
qinsoon's avatar
qinsoon committed
47
        MuFunction{fn_name: fn_name, sig: sig, content: None, context: FunctionContext::new()}
48
49
50
51
52
53
54
    }
    
    pub fn define(&mut self, content: FunctionContent) {
        self.content = Some(content)
    }
    
    pub fn new_ssa(&mut self, id: MuID, tag: MuTag, ty: P<MuType>) -> P<TreeNode> {
qinsoon's avatar
qinsoon committed
55
        self.context.values.insert(id, ValueEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0)});
56
57
        
        P(TreeNode {
qinsoon's avatar
qinsoon committed
58
59
60
61
62
            v: TreeNode_::Value(P(Value{
                tag: tag,
                ty: ty,
                v: Value_::SSAVar(id)
            }))
63
64
65
        })
    }
    
qinsoon's avatar
qinsoon committed
66
    pub fn new_constant(&mut self, tag: MuTag, ty: P<MuType>, v: Constant) -> P<TreeNode> {
67
        P(TreeNode{
qinsoon's avatar
qinsoon committed
68
69
70
71
72
73
            v: TreeNode_::Value(P(Value{
                tag: tag,
                ty: ty, 
                v: Value_::Constant(v)
            }))
        })
74
75
76
77
    }
    
    pub fn new_value(&mut self, v: P<Value>) -> P<TreeNode> {
        P(TreeNode{
qinsoon's avatar
qinsoon committed
78
79
            v: TreeNode_::Value(v)
        })
80
81
82
    }    
}

83
#[derive(Debug)]
84
pub struct Block {
85
86
    pub label: MuTag,
    pub content: Option<BlockContent>
qinsoon's avatar
qinsoon committed
87
88
}

89
90
91
92
93
94
impl Block {
    pub fn new(label: MuTag) -> Block {
        Block{label: label, content: None}
    }
}

95
#[derive(Debug)]
96
pub struct BlockContent {
qinsoon's avatar
qinsoon committed
97
98
99
    pub args: Vec<P<TreeNode>>,
    pub body: Vec<P<TreeNode>>,
    pub keepalives: Option<Vec<P<TreeNode>>>    
100
101
}

102
103
104
105
pub trait OperandIteratable {
    fn list_operands(&self) -> Vec<P<TreeNode>>;
}

qinsoon's avatar
qinsoon committed
106
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
107
108
/// always use with P<TreeNode>
pub struct TreeNode {
qinsoon's avatar
qinsoon committed
109
//    pub op: OpCode,
110
    pub v: TreeNode_
qinsoon's avatar
qinsoon committed
111
112
}

113
114
115
impl TreeNode {   
    pub fn new_inst(v: Instruction) -> P<TreeNode> {
        P(TreeNode{v: TreeNode_::Instruction(v)})
qinsoon's avatar
qinsoon committed
116
117
118
119
120
    }
}

impl fmt::Debug for TreeNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121
122
123
        match self.v {
            TreeNode_::Value(ref pv) => {
                match pv.v {
124
125
                    Value_::SSAVar(id) => {
                        write!(f, "{:?} %{}#{}", pv.ty, pv.tag, id)
126
127
128
129
130
131
132
133
134
                    },
                    Value_::Constant(ref c) => {
                        write!(f, "{:?} {:?}", pv.ty, c) 
                    }
                }
            },
            TreeNode_::Instruction(ref inst) => {
                write!(f, "{:?}", inst)
            }
qinsoon's avatar
qinsoon committed
135
        }
qinsoon's avatar
qinsoon committed
136
    }
qinsoon's avatar
qinsoon committed
137
138
}

139
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
140
pub enum TreeNode_ {
qinsoon's avatar
qinsoon committed
141
142
143
144
145
    Value(P<Value>),
    Instruction(Instruction),
}

/// always use with P<Value>
146
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
147
pub struct Value {
148
    pub tag: MuTag,
qinsoon's avatar
qinsoon committed
149
150
    pub ty: P<MuType>,
    pub v: Value_
qinsoon's avatar
qinsoon committed
151
152
}

153
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
154
pub enum Value_ {
155
    SSAVar(MuID),
qinsoon's avatar
qinsoon committed
156
    Constant(Constant)
qinsoon's avatar
qinsoon committed
157
158
}

159
160
161
162
163
164
165
166
167
168
169
170
171
172
#[derive(Clone)]
pub struct ValueEntry {
    pub id: MuID,
    pub tag: MuTag,
    pub ty: P<MuType>,
    pub use_count: Cell<usize>  // how many times this entry is used
}

impl fmt::Debug for ValueEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?} {}({})", self.ty, self.tag, self.id)
    }
}

173
#[derive(Clone)]
174
pub enum Constant {
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
    Int(usize),
    Float(f32),
    Double(f64),
    IRef(Address),
    FuncRef(Address),
    UFuncRef(Address),
    Vector(Vec<Constant>),    
}

impl fmt::Debug for Constant {
    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),
            &Constant::Vector(ref v) => write!(f, "{:?}", v)
        }
    }
qinsoon's avatar
qinsoon committed
196
197
}

198
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
199
pub enum Instruction {
qinsoon's avatar
qinsoon committed
200
201
202
203
204
    // non-terminal instruction
    Assign{
        left: Vec<P<TreeNode>>,
        right: Expression_
    },
205

qinsoon's avatar
qinsoon committed
206
207
208
    Fence(MemoryOrder),
    
    // terminal instruction
qinsoon's avatar
qinsoon committed
209
    Return(Vec<P<TreeNode>>),
210
    ThreadExit, // TODO:  common inst
qinsoon's avatar
qinsoon committed
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
    Throw(Vec<P<TreeNode>>),
    TailCall(CallData),
    Branch1(Destination),
    Branch2{
        cond: P<TreeNode>,
        true_dest: Destination,
        false_dest: Destination
    },
    Watchpoint{ // Watchpoint NONE ResumptionData
                //   serves as an unconditional trap. Trap to client, and resume with ResumptionData
                // Watchpoint (WPID dest) ResumptionData
                //   when disabled, jump to dest
                //   when enabled, trap to client and resume
        id: Option<WPID>,
        disable_dest: Option<Destination>,
        resume: ResumptionData
    }, 
    WPBranch{
        wp: WPID, 
        disable_dest: Destination,
        enable_dest: Destination
    },
    Call{
        data: CallData,
        resume: ResumptionData
    },
    SwapStack{
        stack: P<TreeNode>,
        is_exception: bool,
        args: Vec<P<TreeNode>>,
        resume: ResumptionData
    },
    Switch{
        cond: P<TreeNode>,
        default: Destination,
246
        branches: Vec<(P<TreeNode>, Destination)>
qinsoon's avatar
qinsoon committed
247
248
    },
    ExnInstruction{
qinsoon's avatar
qinsoon committed
249
        inner: P<Instruction>,
qinsoon's avatar
qinsoon committed
250
251
252
253
        resume: ResumptionData
    }
}

qinsoon's avatar
qinsoon committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
impl fmt::Debug for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Instruction::Assign{ref left, ref right} => {
                write!(f, "{:?} = {:?}", left, right)
            },
            &Instruction::Fence(order) => {
                write!(f, "FENCE {:?}", order)
            }            
            
            &Instruction::Return(ref vals) => write!(f, "RET {:?}", vals),
            &Instruction::ThreadExit => write!(f, "THREADEXIT"),
            &Instruction::Throw(ref vals) => write!(f, "THROW {:?}", vals),
            &Instruction::TailCall(ref call) => write!(f, "TAILCALL {:?}", call),
            &Instruction::Branch1(ref dest) => write!(f, "BRANCH {:?}", dest),
            &Instruction::Branch2{ref cond, ref true_dest, ref false_dest} => {
                write!(f, "BRANCH2 {:?} {:?} {:?}", cond, true_dest, false_dest)
            },
            &Instruction::Watchpoint{id, ref disable_dest, ref resume} => {
                match id {
                    Some(id) => {
                        write!(f, "WATCHPOINT {:?} {:?} {:?}", id, disable_dest.as_ref().unwrap(), resume)
                    },
                    None => {
                        write!(f, "TRAP {:?}", resume)
                    }
                }
            },
            &Instruction::WPBranch{wp, ref disable_dest, ref enable_dest} => {
                write!(f, "WPBRANCH {:?} {:?} {:?}", wp, disable_dest, enable_dest)
            },
            &Instruction::Call{ref data, ref resume} => write!(f, "CALL {:?} {:?}", data, resume),
            &Instruction::SwapStack{ref stack, is_exception, ref args, ref resume} => {
                write!(f, "SWAPSTACK {:?} {:?} {:?} {:?}", stack, is_exception, args, resume)
            },
            &Instruction::Switch{ref cond, ref default, ref branches} => {
                write!(f, "SWITCH {:?} {:?} {{{:?}}}", cond, default, branches)
            },
            &Instruction::ExnInstruction{ref inner, ref resume} => {
                write!(f, "{:?} {:?}", inner, resume)
            }
        }
    }    
}

impl OperandIteratable for Instruction {
300
    fn list_operands(&self) -> Vec<P<TreeNode>> {
qinsoon's avatar
qinsoon committed
301
        use ast::ir::Instruction::*;
302
        match self {
qinsoon's avatar
qinsoon committed
303
304
305
            &Assign{ref right, ..} => right.list_operands(),
            &Fence(_) => vec![],
                        
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
            &Return(ref vals) => vals.to_vec(),
            &Throw(ref vals) => vals.to_vec(),
            &TailCall(ref call) => call.list_operands(),
            &Branch1(ref dest) => dest.list_operands(),
            &Branch2{ref cond, ref true_dest, ref false_dest} => {
                let mut ret = vec![];
                ret.push(cond.clone());
                ret.append(&mut true_dest.list_operands());
                ret.append(&mut false_dest.list_operands());
                ret
            },
            &Watchpoint{ref disable_dest, ref resume, ..} => {
                let mut ret = vec![];
                if disable_dest.is_some() {
                    ret.append(&mut disable_dest.as_ref().unwrap().list_operands())
                }
                ret.append(&mut resume.list_operands());
                ret
            },
            &WPBranch{ref disable_dest, ref enable_dest, ..} => {
                let mut ret = vec![];
                ret.append(&mut disable_dest.list_operands());
                ret.append(&mut enable_dest.list_operands());
                ret
            },
            &Call{ref data, ref resume} => {
                let mut ret = vec![];
                ret.append(&mut data.list_operands());
                ret.append(&mut resume.list_operands());
                ret
            },
            &SwapStack{ref stack, ref args, ref resume, ..} => {
                let mut ret = vec![];
                ret.push(stack.clone());
                ret.append(&mut args.to_vec());
                ret.append(&mut resume.list_operands());
                ret
            },
            &Switch{ref cond, ref default, ref branches} => {
                let mut ret = vec![];
                ret.push(cond.clone());
                ret.append(&mut default.list_operands());
                for entry in branches.iter() {
                    ret.push(entry.0.clone());
                    ret.append(&mut entry.1.list_operands());
                }
                
                ret
            },
            &ExnInstruction{ref inner, ref resume} => {
                let mut ret = vec![];
                ret.append(&mut inner.list_operands());
                ret.append(&mut resume.list_operands());
                ret
            },
            
            &ThreadExit => vec![]
        }
    }
}

367
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
368
369
370
pub enum Expression_ {
    BinOp(BinOp, P<TreeNode>, P<TreeNode>), 
    CmpOp(CmpOp, P<TreeNode>, P<TreeNode>),
qinsoon's avatar
qinsoon committed
371
372
373
374
375
376
377
378
379
    
    // yields a tuple of results from the call
    ExprCall{
        data: CallData,
        is_abort: bool, // T to abort, F to rethrow
    },
    
    // yields the memory value
    Load{
380
381
382
        is_ptr: bool,
        order: MemoryOrder,
        mem_loc: P<TreeNode>
qinsoon's avatar
qinsoon committed
383
    },
qinsoon's avatar
qinsoon committed
384
    
qinsoon's avatar
qinsoon committed
385
386
    // yields nothing
    Store{
387
388
389
390
        is_ptr: bool,
        order: MemoryOrder,        
        mem_loc: P<TreeNode>,
        value: P<TreeNode>
qinsoon's avatar
qinsoon committed
391
392
393
    },
    
    // yields pair (oldvalue, boolean (T = success, F = failure))
qinsoon's avatar
qinsoon committed
394
    CmpXchg{
395
396
        is_ptr: bool,
        is_weak: bool,
qinsoon's avatar
qinsoon committed
397
398
        success_order: MemoryOrder,
        fail_order: MemoryOrder,
qinsoon's avatar
qinsoon committed
399
400
401
        mem_loc: P<TreeNode>,
        expected_value: P<TreeNode>,
        desired_value: P<TreeNode>
qinsoon's avatar
qinsoon committed
402
403
    },
    
qinsoon's avatar
qinsoon committed
404
    // yields old memory value
qinsoon's avatar
qinsoon committed
405
    AtomicRMW{
406
        is_ptr: bool, // T for iref, F for ptr
qinsoon's avatar
qinsoon committed
407
408
        order: MemoryOrder,
        op: AtomicRMWOp,
qinsoon's avatar
qinsoon committed
409
410
        mem_loc: P<TreeNode>,
        value: P<TreeNode> // operand for op
qinsoon's avatar
qinsoon committed
411
412
    },
    
qinsoon's avatar
qinsoon committed
413
    // yields a reference of the type
qinsoon's avatar
qinsoon committed
414
    New(P<MuType>),
qinsoon's avatar
qinsoon committed
415
416
    
    // yields an iref of the type
qinsoon's avatar
qinsoon committed
417
    AllocA(P<MuType>),
qinsoon's avatar
qinsoon committed
418
419
    
    // yields ref
420
    NewHybrid(P<MuType>, P<TreeNode>),
qinsoon's avatar
qinsoon committed
421
422
    
    // yields iref
423
    AllocAHybrid(P<MuType>, P<TreeNode>),
qinsoon's avatar
qinsoon committed
424
425
    
    // yields stack ref
426
427
    NewStack(P<TreeNode>), // func
                           // TODO: common inst
qinsoon's avatar
qinsoon committed
428
429
    
    // yields thread reference
430
    NewThread(P<TreeNode>, Vec<P<TreeNode>>), // stack, args
qinsoon's avatar
qinsoon committed
431
432
    
    // yields thread reference (thread resumes with exceptional value)
433
    NewThreadExn(P<TreeNode>, P<TreeNode>), // stack, exception
qinsoon's avatar
qinsoon committed
434
    
qinsoon's avatar
qinsoon committed
435
    // yields frame cursor
qinsoon's avatar
qinsoon committed
436
    NewFrameCursor(P<TreeNode>), // stack
qinsoon's avatar
qinsoon committed
437
    
438
    // ref<T> -> iref<T>
qinsoon's avatar
qinsoon committed
439
    GetIRef(P<TreeNode>),
qinsoon's avatar
qinsoon committed
440
    
441
    // iref|uptr<struct|hybrid<T>> int<M> -> iref|uptr<U>
qinsoon's avatar
qinsoon committed
442
    GetFieldIRef{
443
444
445
        is_ptr: bool,
        base: P<TreeNode>, // iref or uptr
        index: P<TreeNode> // constant
qinsoon's avatar
qinsoon committed
446
    },
qinsoon's avatar
qinsoon committed
447
    
448
    // iref|uptr<array<T N>> int<M> -> iref|uptr<T>
qinsoon's avatar
qinsoon committed
449
    GetElementIRef{
450
        is_ptr: bool,
qinsoon's avatar
qinsoon committed
451
        base: P<TreeNode>,
452
        index: P<TreeNode> // can be constant or ssa var
qinsoon's avatar
qinsoon committed
453
454
    },
    
455
    // iref|uptr<T> int<M> -> iref|uptr<T>
qinsoon's avatar
qinsoon committed
456
    ShiftIRef{
457
        is_ptr: bool,
qinsoon's avatar
qinsoon committed
458
459
        base: P<TreeNode>,
        offset: P<TreeNode>
qinsoon's avatar
qinsoon committed
460
461
    },
    
462
463
464
465
466
    // iref|uptr<hybrid<T U>> -> iref|uptr<U>
    GetVarPartIRef{
        is_ptr: bool,
        base: P<TreeNode>
    },
qinsoon's avatar
qinsoon committed
467
468
469
470
471
472
473
474
    
//    PushFrame{
//        stack: P<Value>,
//        func: P<Value>
//    },
//    PopFrame{
//        stack: P<Value>
//    }
qinsoon's avatar
qinsoon committed
475
476
}

477
478
479
480
481
482
483
484
485
486
macro_rules! select {
    ($cond: expr, $res1 : expr, $res2 : expr) => {
        if $cond {
            $res1
        } else {
            $res2
        }
    }
}

487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
impl OperandIteratable for Expression_ {
    fn list_operands(&self) -> Vec<P<TreeNode>> {
        match self {
            &Expression_::BinOp(_, ref op1, ref op2) => vec![op1.clone(), op2.clone()],
            &Expression_::CmpOp(_, ref op1, ref op2) => vec![op1.clone(), op2.clone()],
            &Expression_::ExprCall{ref data, ..} => data.list_operands(),
            &Expression_::Load{ref mem_loc, ..} => vec![mem_loc.clone()],
            &Expression_::Store{ref value, ref mem_loc, ..} => vec![value.clone(), mem_loc.clone()],
            &Expression_::CmpXchg{ref mem_loc, ref expected_value, ref desired_value, ..} => vec![mem_loc.clone(), expected_value.clone(), desired_value.clone()],
            &Expression_::AtomicRMW{ref mem_loc, ref value, ..} => vec![mem_loc.clone(), value.clone()],
            &Expression_::NewHybrid(_, ref len) => vec![len.clone()],
            &Expression_::AllocAHybrid(_, ref len) => vec![len.clone()],
            &Expression_::NewStack(ref func) => vec![func.clone()],
            &Expression_::NewThread(ref stack, ref args) => {
                let mut ret = vec![];
                ret.push(stack.clone());
                ret.append(&mut args.to_vec());
                ret
            },
            &Expression_::NewThreadExn(ref stack, ref exception) => vec![stack.clone(), exception.clone()],
            &Expression_::NewFrameCursor(ref stack) => vec![stack.clone()],
            &Expression_::GetIRef(ref reference) => vec![reference.clone()],
            &Expression_::GetFieldIRef{ref base, ref index, ..} => vec![base.clone(), index.clone()],
            &Expression_::GetElementIRef{ref base, ref index, ..} => vec![base.clone(), index.clone()],
            &Expression_::ShiftIRef{ref base, ref offset, ..} => vec![base.clone(), offset.clone()],
            &Expression_::GetVarPartIRef{ref base, ..} => vec![base.clone()], 
            
            &Expression_::New(_) | &Expression_::AllocA(_) => vec![]
        }
    }
}

519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
impl fmt::Debug for Expression_ {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expression_::BinOp(op, ref op1, ref op2) => write!(f, "{:?} {:?} {:?}", op, op1, op2),
            &Expression_::CmpOp(op, ref op1, ref op2) => write!(f, "{:?} {:?} {:?}", op, op1, op2),
            &Expression_::ExprCall{ref data, is_abort} => {
                let abort = select!(is_abort, "ABORT_ON_EXN", "RETHROW");
                write!(f, "CALL {:?} {}", data, abort)
            },
            &Expression_::Load{is_ptr, ref mem_loc, order} => {
                let ptr = select!(is_ptr, "PTR", "");
                write!(f, "LOAD {} {:?} {:?}", ptr, order, mem_loc) 
            },
            &Expression_::Store{ref value, is_ptr, ref mem_loc, order} => {
                let ptr = select!(is_ptr, "PTR", "");
                write!(f, "STORE {} {:?} {:?} {:?}", ptr, order, mem_loc, value)
            },
            &Expression_::CmpXchg{is_ptr, is_weak, success_order, fail_order, 
                ref mem_loc, ref expected_value, ref desired_value} => {
                let ptr = select!(is_ptr, "PTR", "");
                let weak = select!(is_weak, "WEAK", "");
                write!(f, "CMPXCHG {} {} {:?} {:?} {:?} {:?} {:?}", 
                    ptr, weak, success_order, fail_order, mem_loc, expected_value, desired_value)  
            },
            &Expression_::AtomicRMW{is_ptr, order, op, ref mem_loc, ref value} => {
                let ptr = select!(is_ptr, "PTR", "");
                write!(f, "ATOMICRMW {} {:?} {:?} {:?} {:?}", ptr, order, op, mem_loc, value)
            },
            &Expression_::New(ref ty) => write!(f, "NEW {:?}", ty),
            &Expression_::AllocA(ref ty) => write!(f, "ALLOCA {:?}", ty),
            &Expression_::NewHybrid(ref ty, ref len) => write!(f, "NEWHYBRID {:?} {:?}", ty, len),
            &Expression_::AllocAHybrid(ref ty, ref len) => write!(f, "ALLOCAHYBRID {:?} {:?}", ty, len),
            &Expression_::NewStack(ref func) => write!(f, "NEWSTACK {:?}", func),
            &Expression_::NewThread(ref stack, ref args) => write!(f, "NEWTHREAD {:?} PASS_VALUES {:?}", stack, args),
            &Expression_::NewThreadExn(ref stack, ref exn) => write!(f, "NEWTHREAD {:?} THROW_EXC {:?}", stack, exn),
            &Expression_::NewFrameCursor(ref stack) => write!(f, "NEWFRAMECURSOR {:?}", stack),
            &Expression_::GetIRef(ref reference) => write!(f, "GETIREF {:?}", reference),
            &Expression_::GetFieldIRef{is_ptr, ref base, ref index} => {
                let ptr = select!(is_ptr, "PTR", "");
                write!(f, "GETFIELDIREF {} {:?} {:?}", ptr, base, index)
            },
            &Expression_::GetElementIRef{is_ptr, ref base, ref index} => {
                let ptr = select!(is_ptr, "PTR", "");
                write!(f, "GETELEMENTIREF {} {:?} {:?}", ptr, base, index)
            },
            &Expression_::ShiftIRef{is_ptr, ref base, ref offset} => {
                let ptr = select!(is_ptr, "PTR", "");
                write!(f, "SHIFTIREF {} {:?} {:?}", ptr, base, offset)
            },
            &Expression_::GetVarPartIRef{is_ptr, ref base} => {
                let ptr = select!(is_ptr, "PTR", "");
                write!(f, "GETVARPARTIREF {} {:?}", ptr, base)
            }
        }
    }
}

qinsoon's avatar
qinsoon committed
576
577
578
579
580
581
582
583
584
#[derive(Copy, Clone, Debug)]
pub enum MemoryOrder {
    NotAtomic,
    Relaxed,
    Consume,
    Acquire,
    Release,
    AcqRel,
    SeqCst
585
586
}

qinsoon's avatar
qinsoon committed
587
588
589
590
#[derive(Copy, Clone, Debug)]
pub enum CallConvention {
    Mu,
    Foreign(ForeignFFI)
qinsoon's avatar
qinsoon committed
591
592
}

qinsoon's avatar
qinsoon committed
593
594
595
#[derive(Copy, Clone, Debug)]
pub enum ForeignFFI {
    C
qinsoon's avatar
qinsoon committed
596
597
}

598
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
599
600
601
602
pub struct CallData {
    pub func: P<TreeNode>,
    pub args: Vec<P<TreeNode>>,
    pub convention: CallConvention
603
604
}

605
606
607
608
609
610
impl fmt::Debug for CallData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?} {:?} ({:?})", self.convention, self.func, self.args)
    }    
}

611
612
613
614
615
616
617
618
619
620
621
impl OperandIteratable for CallData {
    fn list_operands(&self) -> Vec<P<TreeNode>> {
        let mut ret = vec![];
        
        ret.push(self.func.clone());
        ret.append(&mut self.args.to_vec());
        
        ret
    }
}

622
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
623
624
625
pub struct ResumptionData {
    pub normal_dest: Destination,
    pub exn_dest: Destination
626
627
}

628
629
630
631
impl fmt::Debug for ResumptionData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "normal: {:?}, exception: {:?}", self.normal_dest, self.exn_dest)
    }
632
633
}

634
635
636
637
638
639
640
641
642
643
impl OperandIteratable for ResumptionData {
    fn list_operands(&self) -> Vec<P<TreeNode>> {
        let mut ret = vec![];
        ret.append(&mut self.normal_dest.list_operands());
        ret.append(&mut self.exn_dest.list_operands());
        
        ret
    }
}

644
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
645
646
647
pub struct Destination {
    pub target: MuTag,
    pub args: Vec<DestArg>
648
649
}

650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
impl OperandIteratable for Destination {
    fn list_operands(&self) -> Vec<P<TreeNode>> {
        let mut ret = vec![];
        
        for arg in self.args.iter() {
            match arg {
                &DestArg::Normal(ref op) => ret.push(op.clone()),
                _ => {}
            }
        }
        
        ret
    }
}

665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
impl fmt::Debug for Destination {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{:?}", self.target, self.args)
    }
}

#[derive(Clone)]
pub enum DestArg {
    Normal(P<TreeNode>),
    Freshbound(usize)
}

impl fmt::Debug for DestArg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &DestArg::Normal(ref pv) => write!(f, "{:?}", pv),
            &DestArg::Freshbound(n) => write!(f, "${}", n)
        }
    }    
684
}