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

ir.rs 14.8 KB
Newer Older
1
use ast::ptr::P;
qinsoon's avatar
qinsoon committed
2
use ast::op::{BinOp, CmpOp, AtomicRMWOp};
3
4
use ast::types::*;

qinsoon's avatar
qinsoon committed
5
6
use std::fmt;

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

12
#[derive(Debug)]
qinsoon's avatar
qinsoon committed
13
14
15
16
17
pub struct MuFunction {
    pub fn_name: MuTag,
    pub sig: P<MuFuncSig>,
    pub entry: MuTag,
    pub blocks: Vec<(MuTag, Block)>
qinsoon's avatar
qinsoon committed
18
19
}

20
#[derive(Debug)]
21
pub struct Block {
22
23
    pub label: MuTag,
    pub content: Option<BlockContent>
qinsoon's avatar
qinsoon committed
24
25
}

26
27
28
29
30
31
impl Block {
    pub fn new(label: MuTag) -> Block {
        Block{label: label, content: None}
    }
}

32
#[derive(Debug)]
33
pub struct BlockContent {
qinsoon's avatar
qinsoon committed
34
35
36
    pub args: Vec<P<TreeNode>>,
    pub body: Vec<P<TreeNode>>,
    pub keepalives: Option<Vec<P<TreeNode>>>    
37
38
}

qinsoon's avatar
qinsoon committed
39
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
40
41
/// always use with P<TreeNode>
pub struct TreeNode {
qinsoon's avatar
qinsoon committed
42
43
44
    pub id: MuID,
    pub tag: MuTag,
    pub v: TreeNode_,
qinsoon's avatar
qinsoon committed
45
46
}

qinsoon's avatar
qinsoon committed
47
impl TreeNode {
qinsoon's avatar
qinsoon committed
48
49
50
51
    pub fn new_ssa(id: MuID, tag: MuTag, ty: P<MuType>) -> P<TreeNode> {
        P(TreeNode{
                id: id, 
                tag: tag, 
52
53
                v: TreeNode_::Value(P(Value{ty: ty, v: Value_::SSAVar}))
        })
qinsoon's avatar
qinsoon committed
54
55
56
57
58
59
    }
    
    pub fn new_constant(id: MuID, tag: MuTag, ty: P<MuType>, v: Constant) -> P<TreeNode> {
        P(TreeNode{
                id: id,
                tag: tag,
60
                v: TreeNode_::Value(P(Value{ty: ty, v: Value_::Constant(v)}))
qinsoon's avatar
qinsoon committed
61
            })
qinsoon's avatar
qinsoon committed
62
63
    }
    
qinsoon's avatar
qinsoon committed
64
65
66
67
    pub fn new_value(id: MuID, tag: MuTag, v: P<Value>) -> P<TreeNode> {
        P(TreeNode{
                id: id,
                tag: tag,
68
                v: TreeNode_::Value(v)
qinsoon's avatar
qinsoon committed
69
70
71
72
73
            }
        )
    }
    
    pub fn new_inst(id: MuID, tag: MuTag, v: Instruction) -> P<TreeNode> {
74
75
76
77
78
79
80
81
        P(TreeNode{id: id, tag: tag, v: TreeNode_::Instruction(v)})
    }
    
    pub fn as_value(&self) -> Option<&P<Value>> {
        match self.v {
            TreeNode_::Value(ref pv) => Some(&pv),
            _ => None
        }
qinsoon's avatar
qinsoon committed
82
83
84
85
86
    }
}

impl fmt::Debug for TreeNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87
88
89
90
91
92
93
94
95
96
97
98
99
100
        match self.v {
            TreeNode_::Value(ref pv) => {
                match pv.v {
                    Value_::SSAVar => {
                        write!(f, "{:?} %{}#{}", pv.ty, self.tag, self.id)
                    },
                    Value_::Constant(ref c) => {
                        write!(f, "{:?} {:?}", pv.ty, c) 
                    }
                }
            },
            TreeNode_::Instruction(ref inst) => {
                write!(f, "{:?}", inst)
            }
qinsoon's avatar
qinsoon committed
101
        }
qinsoon's avatar
qinsoon committed
102
    }
qinsoon's avatar
qinsoon committed
103
104
}

105
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
106
pub enum TreeNode_ {
qinsoon's avatar
qinsoon committed
107
108
109
110
111
    Value(P<Value>),
    Instruction(Instruction),
}

/// always use with P<Value>
112
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
113
114
115
pub struct Value {
    pub ty: P<MuType>,
    pub v: Value_
qinsoon's avatar
qinsoon committed
116
117
}

118
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
119
120
121
pub enum Value_ {
    SSAVar,
    Constant(Constant)
qinsoon's avatar
qinsoon committed
122
123
}

124
#[derive(Clone)]
125
pub enum Constant {
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    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
147
148
}

149
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
150
151
152
153
154
pub enum Instruction {
    NonTerm(NonTermInstruction),
    Term(Terminal)
}

155
156
157
158
159
160
161
162
163
164
impl fmt::Debug for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Instruction::NonTerm(ref inst) => write!(f, "{:?}", inst),
            &Instruction::Term(ref inst) => write!(f, "{:?}", inst)
        }
    }    
}

#[derive(Clone)]
qinsoon's avatar
qinsoon committed
165
166
pub enum Terminal {
    Return(Vec<P<TreeNode>>),
167
    ThreadExit, // TODO:  common inst
qinsoon's avatar
qinsoon committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    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,
203
        branches: Vec<(P<TreeNode>, Destination)>
qinsoon's avatar
qinsoon committed
204
205
206
207
208
209
210
    },
    ExnInstruction{
        inner: NonTermInstruction,
        resume: ResumptionData
    }
}

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
246
247
248
249
impl fmt::Debug for Terminal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Terminal::Return(ref vals) => write!(f, "RET {:?}", vals),
            &Terminal::ThreadExit => write!(f, "THREADEXIT"),
            &Terminal::Throw(ref vals) => write!(f, "THROW {:?}", vals),
            &Terminal::TailCall(ref call) => write!(f, "TAILCALL {:?}", call),
            &Terminal::Branch1(ref dest) => write!(f, "BRANCH {:?}", dest),
            &Terminal::Branch2{ref cond, ref true_dest, ref false_dest} => {
                write!(f, "BRANCH2 {:?} {:?} {:?}", cond, true_dest, false_dest)
            },
            &Terminal::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)
                    }
                }
            },
            &Terminal::WPBranch{wp, ref disable_dest, ref enable_dest} => {
                write!(f, "WPBRANCH {:?} {:?} {:?}", wp, disable_dest, enable_dest)
            },
            &Terminal::Call{ref data, ref resume} => write!(f, "CALL {:?} {:?}", data, resume),
            &Terminal::SwapStack{ref stack, is_exception, ref args, ref resume} => {
                write!(f, "SWAPSTACK {:?} {:?} {:?} {:?}", stack, is_exception, args, resume)
            },
            &Terminal::Switch{ref cond, ref default, ref branches} => {
                write!(f, "SWITCH {:?} {:?} {{{:?}}}", cond, default, branches)
            },
            &Terminal::ExnInstruction{ref inner, ref resume} => {
                write!(f, "{:?} {:?}", inner, resume)
            }
        }
    }
}

#[derive(Clone)]
qinsoon's avatar
qinsoon committed
250
251
252
253
254
255
256
257
258
pub enum NonTermInstruction {
    Assign{
        left: Vec<P<TreeNode>>,
        right: Expression_
    },

    Fence(MemoryOrder),
}

259
260
261
262
263
264
265
266
267
268
269
270
271
272
impl fmt::Debug for NonTermInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &NonTermInstruction::Assign{ref left, ref right} => {
                write!(f, "{:?} = {:?}", left, right)
            },
            &NonTermInstruction::Fence(order) => {
                write!(f, "FENCE {:?}", order)
            }
        }
    }
}

#[derive(Clone)]
qinsoon's avatar
qinsoon committed
273
274
275
pub enum Expression_ {
    BinOp(BinOp, P<TreeNode>, P<TreeNode>), 
    CmpOp(CmpOp, P<TreeNode>, P<TreeNode>),
qinsoon's avatar
qinsoon committed
276
277
278
279
280
281
282
283
284
    
    // 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{
285
286
287
        is_ptr: bool,
        order: MemoryOrder,
        mem_loc: P<TreeNode>
qinsoon's avatar
qinsoon committed
288
    },
qinsoon's avatar
qinsoon committed
289
    
qinsoon's avatar
qinsoon committed
290
291
    // yields nothing
    Store{
292
293
294
295
        is_ptr: bool,
        order: MemoryOrder,        
        mem_loc: P<TreeNode>,
        value: P<TreeNode>
qinsoon's avatar
qinsoon committed
296
297
298
    },
    
    // yields pair (oldvalue, boolean (T = success, F = failure))
qinsoon's avatar
qinsoon committed
299
    CmpXchg{
300
301
        is_ptr: bool,
        is_weak: bool,
qinsoon's avatar
qinsoon committed
302
303
        success_order: MemoryOrder,
        fail_order: MemoryOrder,
qinsoon's avatar
qinsoon committed
304
305
306
        mem_loc: P<TreeNode>,
        expected_value: P<TreeNode>,
        desired_value: P<TreeNode>
qinsoon's avatar
qinsoon committed
307
308
    },
    
qinsoon's avatar
qinsoon committed
309
    // yields old memory value
qinsoon's avatar
qinsoon committed
310
    AtomicRMW{
311
        is_ptr: bool, // T for iref, F for ptr
qinsoon's avatar
qinsoon committed
312
313
        order: MemoryOrder,
        op: AtomicRMWOp,
qinsoon's avatar
qinsoon committed
314
315
        mem_loc: P<TreeNode>,
        value: P<TreeNode> // operand for op
qinsoon's avatar
qinsoon committed
316
317
    },
    
qinsoon's avatar
qinsoon committed
318
    // yields a reference of the type
qinsoon's avatar
qinsoon committed
319
    New(P<MuType>),
qinsoon's avatar
qinsoon committed
320
321
    
    // yields an iref of the type
qinsoon's avatar
qinsoon committed
322
    AllocA(P<MuType>),
qinsoon's avatar
qinsoon committed
323
324
    
    // yields ref
325
    NewHybrid(P<MuType>, P<TreeNode>),
qinsoon's avatar
qinsoon committed
326
327
    
    // yields iref
328
    AllocAHybrid(P<MuType>, P<TreeNode>),
qinsoon's avatar
qinsoon committed
329
330
    
    // yields stack ref
331
332
    NewStack(P<TreeNode>), // func
                           // TODO: common inst
qinsoon's avatar
qinsoon committed
333
334
    
    // yields thread reference
335
    NewThread(P<TreeNode>, Vec<P<TreeNode>>), // stack, args
qinsoon's avatar
qinsoon committed
336
337
    
    // yields thread reference (thread resumes with exceptional value)
338
    NewThreadExn(P<TreeNode>, P<TreeNode>), // stack, exception
qinsoon's avatar
qinsoon committed
339
    
qinsoon's avatar
qinsoon committed
340
    // yields frame cursor
qinsoon's avatar
qinsoon committed
341
    NewFrameCursor(P<TreeNode>), // stack
qinsoon's avatar
qinsoon committed
342
    
343
    // ref<T> -> iref<T>
qinsoon's avatar
qinsoon committed
344
    GetIRef(P<TreeNode>),
qinsoon's avatar
qinsoon committed
345
    
346
    // iref|uptr<struct|hybrid<T>> int<M> -> iref|uptr<U>
qinsoon's avatar
qinsoon committed
347
    GetFieldIRef{
348
349
350
        is_ptr: bool,
        base: P<TreeNode>, // iref or uptr
        index: P<TreeNode> // constant
qinsoon's avatar
qinsoon committed
351
    },
qinsoon's avatar
qinsoon committed
352
    
353
    // iref|uptr<array<T N>> int<M> -> iref|uptr<T>
qinsoon's avatar
qinsoon committed
354
    GetElementIRef{
355
        is_ptr: bool,
qinsoon's avatar
qinsoon committed
356
        base: P<TreeNode>,
357
        index: P<TreeNode> // can be constant or ssa var
qinsoon's avatar
qinsoon committed
358
359
    },
    
360
    // iref|uptr<T> int<M> -> iref|uptr<T>
qinsoon's avatar
qinsoon committed
361
    ShiftIRef{
362
        is_ptr: bool,
qinsoon's avatar
qinsoon committed
363
364
        base: P<TreeNode>,
        offset: P<TreeNode>
qinsoon's avatar
qinsoon committed
365
366
    },
    
367
368
369
370
371
    // iref|uptr<hybrid<T U>> -> iref|uptr<U>
    GetVarPartIRef{
        is_ptr: bool,
        base: P<TreeNode>
    },
qinsoon's avatar
qinsoon committed
372
373
374
375
376
377
378
379
    
//    PushFrame{
//        stack: P<Value>,
//        func: P<Value>
//    },
//    PopFrame{
//        stack: P<Value>
//    }
qinsoon's avatar
qinsoon committed
380
381
}

382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
macro_rules! select {
    ($cond: expr, $res1 : expr, $res2 : expr) => {
        if $cond {
            $res1
        } else {
            $res2
        }
    }
}

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
449
450
451
452
453
454
455
456
457
#[derive(Copy, Clone, Debug)]
pub enum MemoryOrder {
    NotAtomic,
    Relaxed,
    Consume,
    Acquire,
    Release,
    AcqRel,
    SeqCst
458
459
}

qinsoon's avatar
qinsoon committed
460
461
462
463
#[derive(Copy, Clone, Debug)]
pub enum CallConvention {
    Mu,
    Foreign(ForeignFFI)
qinsoon's avatar
qinsoon committed
464
465
}

qinsoon's avatar
qinsoon committed
466
467
468
#[derive(Copy, Clone, Debug)]
pub enum ForeignFFI {
    C
qinsoon's avatar
qinsoon committed
469
470
}

471
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
472
473
474
475
pub struct CallData {
    pub func: P<TreeNode>,
    pub args: Vec<P<TreeNode>>,
    pub convention: CallConvention
476
477
}

478
479
480
481
482
483
484
impl fmt::Debug for CallData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?} {:?} ({:?})", self.convention, self.func, self.args)
    }    
}

#[derive(Clone)]
qinsoon's avatar
qinsoon committed
485
486
487
pub struct ResumptionData {
    pub normal_dest: Destination,
    pub exn_dest: Destination
488
489
}

490
491
492
493
impl fmt::Debug for ResumptionData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "normal: {:?}, exception: {:?}", self.normal_dest, self.exn_dest)
    }
494
495
}

496
#[derive(Clone)]
qinsoon's avatar
qinsoon committed
497
498
499
pub struct Destination {
    pub target: MuTag,
    pub args: Vec<DestArg>
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
}

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)
        }
    }    
521
}