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

mod.rs 16.2 KB
Newer Older
qinsoon's avatar
qinsoon committed
1
2
3
#![allow(dead_code)]
#![allow(non_upper_case_globals)]

4
5
6
7
8
pub mod inst_sel;

mod codegen;
pub use compiler::backend::x86_64::codegen::CodeGenerator;

qinsoon's avatar
qinsoon committed
9
pub mod asm_backend;
10
pub use compiler::backend::x86_64::asm_backend::ASMCodeGen;
11
12
pub use compiler::backend::x86_64::asm_backend::emit_code;
pub use compiler::backend::x86_64::asm_backend::emit_context;
qinsoon's avatar
qinsoon committed
13
pub use compiler::backend::x86_64::asm_backend::emit_context_with_reloc;
14
15
#[cfg(feature = "aot")]
pub use compiler::backend::x86_64::asm_backend::spill_rewrite;
16
use utils::Address;
17
18
19

use ast::ptr::P;
use ast::ir::*;
qinsoon's avatar
qinsoon committed
20
use ast::types::*;
qinsoon's avatar
qinsoon committed
21
use compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
22

23
use utils::LinkedHashMap;
24
25
use std::collections::HashMap;

26
27
28
// Number of nromal callee saved registers (excluding RSP and RBP)
pub const CALLEE_SAVED_COUNT : usize = 5;

qinsoon's avatar
qinsoon committed
29
macro_rules! GPR_ALIAS {
qinsoon's avatar
qinsoon committed
30
31
32
33
34
35
36
37
38
39
40
41
    ($alias: ident: ($id64: expr, $r64: ident) -> $r32: ident, $r16: ident, $r8l: ident, $r8h: ident) => {
        lazy_static!{
            pub static ref $r64 : P<Value> = GPR!($id64,    stringify!($r64), UINT64_TYPE);
            pub static ref $r32 : P<Value> = GPR!($id64 +1, stringify!($r32), UINT32_TYPE);
            pub static ref $r16 : P<Value> = GPR!($id64 +2, stringify!($r16), UINT16_TYPE);
            pub static ref $r8l : P<Value> = GPR!($id64 +3, stringify!($r8l), UINT8_TYPE);
            pub static ref $r8h : P<Value> = GPR!($id64 +4, stringify!($r8h), UINT8_TYPE);

            pub static ref $alias : [P<Value>; 5] = [$r64.clone(), $r32.clone(), $r16.clone(), $r8l.clone(), $r8h.clone()];
        }
    };

qinsoon's avatar
qinsoon committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    ($alias: ident: ($id64: expr, $r64: ident) -> $r32: ident, $r16: ident, $r8: ident) => {
        lazy_static!{
            pub static ref $r64 : P<Value> = GPR!($id64,    stringify!($r64), UINT64_TYPE);
            pub static ref $r32 : P<Value> = GPR!($id64 +1, stringify!($r32), UINT32_TYPE);
            pub static ref $r16 : P<Value> = GPR!($id64 +2, stringify!($r16), UINT16_TYPE);
            pub static ref $r8  : P<Value> = GPR!($id64 +3, stringify!($r8) , UINT8_TYPE );

            pub static ref $alias : [P<Value>; 4] = [$r64.clone(), $r32.clone(), $r16.clone(), $r8.clone()];
        }
    };

    ($alias: ident: ($id64: expr, $r64: ident)) => {
        lazy_static!{
            pub static ref $r64 : P<Value> = GPR!($id64,    stringify!($r64), UINT64_TYPE);

            pub static ref $alias : [P<Value>; 4] = [$r64.clone(), $r64.clone(), $r64.clone(), $r64.clone()];
        }
    };
}

62
macro_rules! GPR {
qinsoon's avatar
qinsoon committed
63
    ($id:expr, $name: expr, $ty: ident) => {
qinsoon's avatar
qinsoon committed
64
65
        {
            P(Value {
qinsoon's avatar
qinsoon committed
66
                hdr: MuEntityHeader::named($id, $name.to_string()),
qinsoon's avatar
qinsoon committed
67
                ty: $ty.clone(),
qinsoon's avatar
qinsoon committed
68
                v: Value_::SSAVar($id)
qinsoon's avatar
qinsoon committed
69
70
            })
        }
qinsoon's avatar
qinsoon committed
71
72
73
74
    };
}

macro_rules! FPR {
qinsoon's avatar
qinsoon committed
75
    ($id:expr, $name: expr) => {
qinsoon's avatar
qinsoon committed
76
77
        {
            P(Value {
qinsoon's avatar
qinsoon committed
78
                hdr: MuEntityHeader::named($id, $name.to_string()),
qinsoon's avatar
qinsoon committed
79
                ty: DOUBLE_TYPE.clone(),
qinsoon's avatar
qinsoon committed
80
                v: Value_::SSAVar($id)
qinsoon's avatar
qinsoon committed
81
82
            })
        }
qinsoon's avatar
qinsoon committed
83
84
85
    };
}

86
87
GPR_ALIAS!(RAX_ALIAS: (0, RAX)  -> EAX, AX , AL, AH);
GPR_ALIAS!(RCX_ALIAS: (5, RCX)  -> ECX, CX , CL, CH);
88
GPR_ALIAS!(RDX_ALIAS: (10,RDX)  -> EDX, DX , DL, DH);
89
90
91
92
93
94
95
96
97
98
99
100
101
102
GPR_ALIAS!(RBX_ALIAS: (15,RBX)  -> EBX, BX , BL, BH);
GPR_ALIAS!(RSP_ALIAS: (20,RSP)  -> ESP, SP , SPL);
GPR_ALIAS!(RBP_ALIAS: (24,RBP)  -> EBP, BP , BPL);
GPR_ALIAS!(RSI_ALIAS: (28,RSI)  -> ESI, SI , SIL);
GPR_ALIAS!(RDI_ALIAS: (32,RDI)  -> EDI, DI , DIL);
GPR_ALIAS!(R8_ALIAS : (36,R8 )  -> R8D, R8W, R8B);
GPR_ALIAS!(R9_ALIAS : (40,R9 )  -> R9D, R9W, R9B);
GPR_ALIAS!(R10_ALIAS: (44,R10) -> R10D,R10W,R10B);
GPR_ALIAS!(R11_ALIAS: (48,R11) -> R11D,R11W,R11B);
GPR_ALIAS!(R12_ALIAS: (52,R12) -> R12D,R12W,R12B);
GPR_ALIAS!(R13_ALIAS: (56,R13) -> R13D,R13W,R13B);
GPR_ALIAS!(R14_ALIAS: (60,R14) -> R14D,R14W,R14B);
GPR_ALIAS!(R15_ALIAS: (64,R15) -> R15D,R15W,R15B);
GPR_ALIAS!(RIP_ALIAS: (68,RIP));
qinsoon's avatar
qinsoon committed
103

qinsoon's avatar
qinsoon committed
104
lazy_static! {
105
106
    pub static ref GPR_ALIAS_TABLE : LinkedHashMap<MuID, Vec<P<Value>>> = {
        let mut ret = LinkedHashMap::new();
qinsoon's avatar
qinsoon committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

        ret.insert(RAX.id(), RAX_ALIAS.to_vec());
        ret.insert(RCX.id(), RCX_ALIAS.to_vec());
        ret.insert(RDX.id(), RDX_ALIAS.to_vec());
        ret.insert(RBX.id(), RBX_ALIAS.to_vec());
        ret.insert(RSP.id(), RSP_ALIAS.to_vec());
        ret.insert(RBP.id(), RBP_ALIAS.to_vec());
        ret.insert(RSI.id(), RSI_ALIAS.to_vec());
        ret.insert(RDI.id(), RDI_ALIAS.to_vec());
        ret.insert(R8.id() , R8_ALIAS.to_vec() );
        ret.insert(R9.id() , R9_ALIAS.to_vec() );
        ret.insert(R10.id(), R10_ALIAS.to_vec());
        ret.insert(R11.id(), R11_ALIAS.to_vec());
        ret.insert(R12.id(), R12_ALIAS.to_vec());
        ret.insert(R13.id(), R13_ALIAS.to_vec());
        ret.insert(R14.id(), R14_ALIAS.to_vec());
        ret.insert(R15.id(), R15_ALIAS.to_vec());
        ret.insert(RIP.id(), RIP_ALIAS.to_vec());

        ret
    };

qinsoon's avatar
qinsoon committed
129
130
131
132
133
134
135
136
137
138
139
140
141
    // e.g. given eax, return rax
    pub static ref GPR_ALIAS_LOOKUP : HashMap<MuID, P<Value>> = {
        let mut ret = HashMap::new();

        for vec in GPR_ALIAS_TABLE.values() {
            let colorable = vec[0].clone();

            for gpr in vec {
                ret.insert(gpr.id(), colorable.clone());
            }
        }

        ret
qinsoon's avatar
qinsoon committed
142
    };
qinsoon's avatar
qinsoon committed
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
}

pub fn get_alias_for_length(id: MuID, length: usize) -> P<Value> {
    if id < FPR_ID_START {
        let vec = match GPR_ALIAS_TABLE.get(&id) {
            Some(vec) => vec,
            None => panic!("didnt find {} as GPR", id)
        };

        match length {
            64 => vec[0].clone(),
            32 => vec[1].clone(),
            16 => vec[2].clone(),
            8 => vec[3].clone(),
            1 => vec[3].clone(),
            _ => panic!("unexpected length {} for {}", length, vec[0])
        }
    } else {
        for r in ALL_FPRs.iter() {
            if r.id() == id {
                return r.clone();
            }
        }

        panic!("didnt find {} as FPR", id)
    }
}
qinsoon's avatar
qinsoon committed
170

171
pub fn is_aliased(id1: MuID, id2: MuID) -> bool {
qinsoon's avatar
qinsoon committed
172
    if get_color_for_precolored(id1) == get_color_for_precolored(id2) {
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
        macro_rules! is_match {
            ($a1: expr, $a2: expr; $b: expr) => {
                $a1 == $b.id() || $a2 == $b.id()
            }
        };

        if is_match!(id1, id2; AH) {
            return false;
        } else if is_match!(id1, id2; BH) {
            return false;
        } else if is_match!(id1, id2; CH) {
            return false;
        } else if is_match!(id1, id2; DH) {
            return false;
        } else {
            return true;
        }
    } else {
        return false;
    }
}

qinsoon's avatar
qinsoon committed
195
196
197
pub fn get_color_for_precolored(id: MuID) -> MuID {
    debug_assert!(id < MACHINE_ID_END);

qinsoon's avatar
qinsoon committed
198
199
200
201
202
203
204
205
    if id < FPR_ID_START {
        match GPR_ALIAS_LOOKUP.get(&id) {
            Some(val) => val.id(),
            None => panic!("cannot find GPR {}", id)
        }
    } else {
        // we do not have alias for FPRs
        id
qinsoon's avatar
qinsoon committed
206
207
    }
}
qinsoon's avatar
qinsoon committed
208

qinsoon's avatar
qinsoon committed
209
210
211
212
213
214
215
216
217
218
219
220
#[inline(always)]
pub fn check_op_len(op: &P<Value>) -> usize {
    match op.ty.get_int_length() {
        Some(64) => 64,
        Some(32) => 32,
        Some(16) => 16,
        Some(8)  => 8,
        Some(1)  => 8,
        _ => panic!("unimplemented int types: {}", op.ty)
    }
}

qinsoon's avatar
qinsoon committed
221
lazy_static! {
qinsoon's avatar
qinsoon committed
222
223
224
225
    pub static ref RETURN_GPRs : [P<Value>; 2] = [
        RAX.clone(),
        RDX.clone(),
    ];
226

qinsoon's avatar
qinsoon committed
227
228
229
230
231
232
233
234
    pub static ref ARGUMENT_GPRs : [P<Value>; 6] = [
        RDI.clone(),
        RSI.clone(),
        RDX.clone(),
        RCX.clone(),
        R8.clone(),
        R9.clone()
    ];
235

qinsoon's avatar
qinsoon committed
236
237
238
239
240
241
242
243
    pub static ref CALLEE_SAVED_GPRs : [P<Value>; 6] = [
        RBX.clone(),
        RBP.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone()
    ];
qinsoon's avatar
qinsoon committed
244
245
246
247
248
249
250
251
252
253
254
255

    pub static ref CALLER_SAVED_GPRs : [P<Value>; 9] = [
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone()
    ];
256

qinsoon's avatar
qinsoon committed
257
    static ref ALL_GPRs : [P<Value>; 15] = [
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RBX.clone(),
        RSP.clone(),
//        RBP.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone()
    ];
qinsoon's avatar
qinsoon committed
275
276
}

277
pub const FPR_ID_START : usize = 100;
qinsoon's avatar
qinsoon committed
278

qinsoon's avatar
qinsoon committed
279
lazy_static!{
qinsoon's avatar
qinsoon committed
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
    pub static ref XMM0  : P<Value> = FPR!(FPR_ID_START,    "xmm0");
    pub static ref XMM1  : P<Value> = FPR!(FPR_ID_START + 1,"xmm1");
    pub static ref XMM2  : P<Value> = FPR!(FPR_ID_START + 2,"xmm2");
    pub static ref XMM3  : P<Value> = FPR!(FPR_ID_START + 3,"xmm3");
    pub static ref XMM4  : P<Value> = FPR!(FPR_ID_START + 4,"xmm4");
    pub static ref XMM5  : P<Value> = FPR!(FPR_ID_START + 5,"xmm5");
    pub static ref XMM6  : P<Value> = FPR!(FPR_ID_START + 6,"xmm6");
    pub static ref XMM7  : P<Value> = FPR!(FPR_ID_START + 7,"xmm7");
    pub static ref XMM8  : P<Value> = FPR!(FPR_ID_START + 8,"xmm8");
    pub static ref XMM9  : P<Value> = FPR!(FPR_ID_START + 9,"xmm9");
    pub static ref XMM10 : P<Value> = FPR!(FPR_ID_START + 10,"xmm10");
    pub static ref XMM11 : P<Value> = FPR!(FPR_ID_START + 11,"xmm11");
    pub static ref XMM12 : P<Value> = FPR!(FPR_ID_START + 12,"xmm12");
    pub static ref XMM13 : P<Value> = FPR!(FPR_ID_START + 13,"xmm13");
    pub static ref XMM14 : P<Value> = FPR!(FPR_ID_START + 14,"xmm14");
    pub static ref XMM15 : P<Value> = FPR!(FPR_ID_START + 15,"xmm15");
296

qinsoon's avatar
qinsoon committed
297
298
299
300
    pub static ref RETURN_FPRs : [P<Value>; 2] = [
        XMM0.clone(),
        XMM1.clone()
    ];
301

qinsoon's avatar
qinsoon committed
302
303
304
    pub static ref ARGUMENT_FPRs : [P<Value>; 8] = [
        XMM0.clone(),
        XMM1.clone(),
qinsoon's avatar
qinsoon committed
305
306
307
308
309
310
311
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone()
    ];
312

qinsoon's avatar
qinsoon committed
313
    pub static ref CALLEE_SAVED_FPRs : [P<Value>; 0] = [];
qinsoon's avatar
qinsoon committed
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

    pub static ref CALLER_SAVED_FPRs : [P<Value>; 16] = [
        XMM0.clone(),
        XMM1.clone(),
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone(),
        XMM8.clone(),
        XMM9.clone(),
        XMM10.clone(),
        XMM11.clone(),
        XMM12.clone(),
        XMM13.clone(),
        XMM14.clone(),
        XMM15.clone(),
    ];
333

qinsoon's avatar
qinsoon committed
334
    static ref ALL_FPRs : [P<Value>; 16] = [
qinsoon's avatar
qinsoon committed
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
        XMM0.clone(),
        XMM1.clone(),
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone(),
        XMM8.clone(),
        XMM9.clone(),
        XMM10.clone(),
        XMM11.clone(),
        XMM12.clone(),
        XMM13.clone(),
        XMM14.clone(),
        XMM15.clone(),
    ];
qinsoon's avatar
qinsoon committed
352
353
}

qinsoon's avatar
qinsoon committed
354
lazy_static! {
355
356
    pub static ref ALL_MACHINE_REGs : LinkedHashMap<MuID, P<Value>> = {
        let mut map = LinkedHashMap::new();
qinsoon's avatar
qinsoon committed
357
358
359
360
361
362
363

        for vec in GPR_ALIAS_TABLE.values() {
            for reg in vec {
                map.insert(reg.id(), reg.clone());
            }
        }

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
        map.insert(XMM0.id(), XMM0.clone());
        map.insert(XMM1.id(), XMM1.clone());
        map.insert(XMM2.id(), XMM2.clone());
        map.insert(XMM3.id(), XMM3.clone());
        map.insert(XMM4.id(), XMM4.clone());
        map.insert(XMM5.id(), XMM5.clone());
        map.insert(XMM6.id(), XMM6.clone());
        map.insert(XMM7.id(), XMM7.clone());
        map.insert(XMM8.id(), XMM8.clone());
        map.insert(XMM9.id(), XMM9.clone());
        map.insert(XMM10.id(), XMM10.clone());
        map.insert(XMM11.id(), XMM11.clone());
        map.insert(XMM12.id(), XMM12.clone());
        map.insert(XMM13.id(), XMM13.clone());
        map.insert(XMM14.id(), XMM14.clone());
        map.insert(XMM15.id(), XMM15.clone());

        map
    };
383

384
385
386
387
388
389
390
391
392
393
394
    // put caller saved regs first (they imposes no overhead if there is no call instruction)
    pub static ref ALL_USABLE_MACHINE_REGs : Vec<P<Value>> = vec![
        RAX.clone(),
        RCX.clone(),
        RDX.clone(),
        RSI.clone(),
        RDI.clone(),
        R8.clone(),
        R9.clone(),
        R10.clone(),
        R11.clone(),
395

396
397
398
399
400
        RBX.clone(),
        R12.clone(),
        R13.clone(),
        R14.clone(),
        R15.clone(),
401

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
        XMM0.clone(),
        XMM1.clone(),
        XMM2.clone(),
        XMM3.clone(),
        XMM4.clone(),
        XMM5.clone(),
        XMM6.clone(),
        XMM7.clone(),
        XMM8.clone(),
        XMM9.clone(),
        XMM10.clone(),
        XMM11.clone(),
        XMM12.clone(),
        XMM13.clone(),
        XMM14.clone(),
        XMM15.clone()
    ];
qinsoon's avatar
qinsoon committed
419
420
}

qinsoon's avatar
qinsoon committed
421
pub fn init_machine_regs_for_func (func_context: &mut FunctionContext) {
422
    for reg in ALL_MACHINE_REGs.values() {
qinsoon's avatar
qinsoon committed
423
        let reg_id = reg.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
424
        let entry = SSAVarEntry::new(reg.clone());
425

qinsoon's avatar
qinsoon committed
426
427
428
429
430
431
        func_context.values.insert(reg_id, entry);
    }
}

pub fn number_of_regs_in_group(group: RegGroup) -> usize {
    match group {
432
433
434
        RegGroup::GPR   => ALL_GPRs.len(),
        RegGroup::GPREX => ALL_GPRs.len(),
        RegGroup::FPR   => ALL_FPRs.len()
qinsoon's avatar
qinsoon committed
435
436
437
    }
}

qinsoon's avatar
qinsoon committed
438
439
440
441
pub fn number_of_all_regs() -> usize {
    ALL_MACHINE_REGs.len()
}

442
pub fn all_regs() -> &'static LinkedHashMap<MuID, P<Value>> {
qinsoon's avatar
qinsoon committed
443
444
445
    &ALL_MACHINE_REGs
}

446
447
448
449
pub fn all_usable_regs() -> &'static Vec<P<Value>> {
    &ALL_USABLE_MACHINE_REGs
}

450
pub fn pick_group_for_reg(reg_id: MuID) -> RegGroup {
451
    let reg = all_regs().get(&reg_id).unwrap();
452
    RegGroup::get_from_value(reg)
453
454
}

455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495

// Gets the previouse frame pointer with respect to the current
#[inline(always)]
pub fn get_previous_frame_pointer(frame_pointer: Address) -> Address {
    unsafe { frame_pointer.load::<Address>() }
}

// Gets the return address for the current frame pointer
#[inline(always)]
pub fn get_return_address(frame_pointer: Address) -> Address {
    unsafe { frame_pointer.plus(8).load::<Address>() }
}

// Gets the stack pointer before the current frame was created
#[inline(always)]
pub fn get_previous_stack_pointer(frame_pointer: Address) -> Address {
    frame_pointer.plus(16)
}

#[inline(always)]
pub fn set_previous_frame_pointer(frame_pointer: Address, value: Address) {
    unsafe { frame_pointer.store::<Address>(value) }
}

// Gets the return address for the current frame pointer
#[inline(always)]
pub fn set_return_address(frame_pointer: Address, value: Address) {
    unsafe { frame_pointer.plus(8).store::<Address>(value) }
}

// Reg should be a 64-bit callee saved GPR or FPR
pub fn get_callee_saved_offset(reg: MuID) -> isize {
    debug_assert!(is_callee_saved(reg) && reg != RBP.id());

    let id = if reg == RBX.id() {
        0
    } else {
        (reg - R12.id())/4 + 1
    };
    (id as isize + 1)*(-8)
}
496
497
498
499
500
501
pub fn is_callee_saved(reg_id: MuID) -> bool {
    for reg in CALLEE_SAVED_GPRs.iter() {
        if reg_id == reg.extract_ssa_id().unwrap() {
            return true;
        }
    }
502
503

    false
504
505
}

506
pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
qinsoon's avatar
qinsoon committed
507
    use std::u32;
qinsoon's avatar
qinsoon committed
508
    match op.v {
qinsoon's avatar
qinsoon committed
509
        Value_::Constant(Constant::Int(val)) if val <= u32::MAX as u64 => {
qinsoon's avatar
qinsoon committed
510
511
            true
        },
512
513
        _ => false
    }
qinsoon's avatar
qinsoon committed
514
515
516
517
518
519
520
521
522
}

use ast::inst::*;
pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
    use ast::inst::Instruction_::*;

    match inst.v {
        // simple
        BinOp(_, _, _)  => 1,
qinsoon's avatar
qinsoon committed
523
        BinOpWithStatus(_, _, _, _) => 2,
qinsoon's avatar
qinsoon committed
524
        CmpOp(_, _, _)  => 1,
qinsoon's avatar
qinsoon committed
525
        ConvOp{..}      => 0,
qinsoon's avatar
qinsoon committed
526
527

        // control flow
qinsoon's avatar
qinsoon committed
528
529
530
        Branch1(_)     => 1,
        Branch2{..}    => 1,
        Select{..}     => 2,
qinsoon's avatar
qinsoon committed
531
        Watchpoint{..} => 1,
qinsoon's avatar
qinsoon committed
532
533
        WPBranch{..}   => 2,
        Switch{..}     => 3,
qinsoon's avatar
qinsoon committed
534
535
536

        // call
        ExprCall{..} | ExprCCall{..} | Call{..} | CCall{..} => 5,
qinsoon's avatar
qinsoon committed
537
        Return(_)   => 1,
qinsoon's avatar
qinsoon committed
538
539
540
541
        TailCall(_) => 1,

        // memory access
        Load{..} | Store{..} => 1,
qinsoon's avatar
qinsoon committed
542
543
544
545
546
        CmpXchg{..}          => 1,
        AtomicRMW{..}        => 1,
        AllocA(_)            => 1,
        AllocAHybrid(_, _)   => 1,
        Fence(_)             => 1,
qinsoon's avatar
qinsoon committed
547
548
549
550
551
552
553

        // memory addressing
        GetIRef(_) | GetFieldIRef{..} | GetElementIRef{..} | ShiftIRef{..} | GetVarPartIRef{..} => 0,

        // runtime
        New(_) | NewHybrid(_, _) => 10,
        NewStack(_) | NewThread(_, _) | NewThreadExn(_, _) | NewFrameCursor(_) => 10,
qinsoon's avatar
qinsoon committed
554
555
        ThreadExit    => 10,
        Throw(_)      => 10,
qinsoon's avatar
qinsoon committed
556
557
        SwapStack{..} => 10,
        CommonInst_GetThreadLocal | CommonInst_SetThreadLocal(_) => 10,
qinsoon's avatar
qinsoon committed
558
        CommonInst_Pin(_) | CommonInst_Unpin(_) => 10,
qinsoon's avatar
qinsoon committed
559
560
561

        // others
        Move(_) => 0,
562
563
        PrintHex(_)  => 10,
        SetRetval(_) => 10,
qinsoon's avatar
qinsoon committed
564
565
        ExnInstruction{ref inner, ..} => estimate_insts_for_ir(&inner)
    }
566
}