WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

inst_sel.rs 185 KB
Newer Older
1
use ast::ir::*;
2
use ast::ptr::*;
qinsoon's avatar
qinsoon committed
3
use ast::inst::*;
4
use ast::op;
qinsoon's avatar
qinsoon committed
5
use ast::op::*;
qinsoon's avatar
qinsoon committed
6
use ast::types;
qinsoon's avatar
qinsoon committed
7
use ast::types::*;
qinsoon's avatar
qinsoon committed
8
use vm::VM;
qinsoon's avatar
qinsoon committed
9
use runtime::mm;
10
11
use runtime::mm::objectmodel::OBJECT_HEADER_SIZE;
use runtime::mm::objectmodel::OBJECT_HEADER_OFFSET;
12
13
14
15
use runtime::ValueLocation;
use runtime::thread;
use runtime::entrypoints;
use runtime::entrypoints::RuntimeEntrypoint;
16
17

use compiler::CompilerPass;
18
use compiler::backend;
19
use compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
20
use compiler::backend::PROLOGUE_BLOCK_NAME;
qinsoon's avatar
qinsoon committed
21
22
23
use compiler::backend::x86_64;
use compiler::backend::x86_64::CodeGenerator;
use compiler::backend::x86_64::ASMCodeGen;
qinsoon's avatar
qinsoon committed
24
25
use compiler::machine_code::CompiledFunction;
use compiler::frame::Frame;
26

27
28
use utils::math;

29
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
30
use std::any::Any;
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
lazy_static! {
    pub static ref LONG_4_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::mustruct(Mu("long_4"), vec![UINT32_TYPE.clone(); 4]))
    );

    pub static ref UITOFP_C0 : P<Value> = P(Value{
        hdr: MuEntityHeader::named(new_internal_id(), Mu("UITOFP_C0")),
        ty : LONG_4_TYPE.clone(),
        v  : Value_::Constant(Constant::List(vec![
            P(Value{
                hdr: MuEntityHeader::unnamed(new_internal_id()),
                ty: UINT32_TYPE.clone(),
                v : Value_::Constant(Constant::Int(1127219200u64))
            }),
            P(Value{
                hdr: MuEntityHeader::unnamed(new_internal_id()),
                ty: UINT32_TYPE.clone(),
                v : Value_::Constant(Constant::Int(1160773632u64))
            }),
            P(Value{
                hdr: MuEntityHeader::unnamed(new_internal_id()),
                ty: UINT32_TYPE.clone(),
                v : Value_::Constant(Constant::Int(0u64))
            }),
            P(Value{
                hdr: MuEntityHeader::unnamed(new_internal_id()),
                ty: UINT32_TYPE.clone(),
                v : Value_::Constant(Constant::Int(0u64))
            })
        ]))
    });

    pub static ref QUAD_2_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::mustruct(Mu("quad_2"), vec![UINT64_TYPE.clone(); 2]))
    );

    pub static ref UITOFP_C1 : P<Value> = P(Value{
        hdr: MuEntityHeader::named(new_internal_id(), Mu("UITOFP_C1")),
        ty : QUAD_2_TYPE.clone(),
        v  : Value_::Constant(Constant::List(vec![
            P(Value{
                hdr: MuEntityHeader::unnamed(new_internal_id()),
                ty: UINT64_TYPE.clone(),
                v : Value_::Constant(Constant::Int(4841369599423283200u64))
            }),
            P(Value{
                hdr: MuEntityHeader::unnamed(new_internal_id()),
                ty: UINT64_TYPE.clone(),
                v : Value_::Constant(Constant::Int(4985484787499139072u64))
            })
        ]))
    });
84

qinsoon's avatar
qinsoon committed
85
86
    pub static ref FPTOUI_C_DOUBLE : P<Value> = P(Value{
        hdr: MuEntityHeader::named(new_internal_id(), Mu("FPTOUI_C_DOUBLE")),
87
88
89
        ty : UINT64_TYPE.clone(),
        v  : Value_::Constant(Constant::Int(4890909195324358656u64))
    });
qinsoon's avatar
qinsoon committed
90
91
92
93
94
95

    pub static ref FPTOUI_C_FLOAT : P<Value> = P(Value{
        hdr: MuEntityHeader::named(new_internal_id(), Mu("FPTOUI_C_FLOAT")),
        ty : UINT32_TYPE.clone(),
        v  : Value_::Constant(Constant::Int(1593835520u64))
    });
96
97
}

98
99
const INLINE_FASTPATH : bool = false;

100
pub struct InstructionSelection {
101
    name: &'static str,
102
    backend: Box<CodeGenerator>,
103
104

    current_fv_id: MuID,
qinsoon's avatar
qinsoon committed
105
    current_callsite_id: usize,
qinsoon's avatar
qinsoon committed
106
107
    current_frame: Option<Frame>,
    current_block: Option<MuName>,
qinsoon's avatar
qinsoon committed
108
109
110
111
    current_func_start: Option<ValueLocation>,
    // key: block id, val: callsite that names the block as exception block
    current_exn_callsites: HashMap<MuID, Vec<ValueLocation>>,
    // key: block id, val: block location
112
113
114
115
    current_exn_blocks: HashMap<MuID, ValueLocation>,

    current_constants: HashMap<MuID, P<Value>>,
    current_constants_locs: HashMap<MuID, P<Value>>
116
117
}

118
impl <'a> InstructionSelection {
qinsoon's avatar
qinsoon committed
119
    #[cfg(feature = "aot")]
120
    pub fn new() -> InstructionSelection {
121
122
        InstructionSelection{
            name: "Instruction Selection (x64)",
123
            backend: Box::new(ASMCodeGen::new()),
124

125
            current_fv_id: 0,
qinsoon's avatar
qinsoon committed
126
            current_callsite_id: 0,
qinsoon's avatar
qinsoon committed
127
128
129
            current_frame: None,
            current_block: None,
            current_func_start: None,
qinsoon's avatar
qinsoon committed
130
131
            // key: block id, val: callsite that names the block as exception block
            current_exn_callsites: HashMap::new(), 
132
133
134
135
            current_exn_blocks: HashMap::new(),

            current_constants: HashMap::new(),
            current_constants_locs: HashMap::new()
136
137
        }
    }
qinsoon's avatar
qinsoon committed
138
139
140
141
142

    #[cfg(feature = "jit")]
    pub fn new() -> InstructionSelection {
        unimplemented!()
    }
143
144
    
    // in this pass, we assume that
qinsoon's avatar
qinsoon committed
145
    // * we do not need to backup/restore caller-saved registers
146
147
    // if any of these assumption breaks, we will need to re-emit the code
    #[allow(unused_variables)]
148
    fn instruction_select(&mut self, node: &'a TreeNode, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) {
149
        trace!("instsel on node#{} {}", node.id(), node);
qinsoon's avatar
qinsoon committed
150
151
        
        match node.v {
152
153
            TreeNode_::Instruction(ref inst) => {
                match inst.v {
qinsoon's avatar
qinsoon committed
154
                    Instruction_::Branch2{cond, ref true_dest, ref false_dest, true_prob} => {
qinsoon's avatar
qinsoon committed
155
                        trace!("instsel on BRANCH2");
156
157
                        // 'branch_if_true' == true, we emit cjmp the same as CmpOp  (je  for EQ, jne for NE)
                        // 'branch_if_true' == false, we emit opposite cjmp as CmpOp (jne for EQ, je  for NE)
158
159
160
161
162
                        let (fallthrough_dest, branch_dest, branch_if_true) = {
                            if true_prob > 0.5f32 {
                                (true_dest, false_dest, false)
                            } else {
                                (false_dest, true_dest, true)
163
                            }
164
                        };
165
                        
qinsoon's avatar
qinsoon committed
166
                        let ops = inst.ops.read().unwrap();
167
                        
168
169
                        self.process_dest(&ops, fallthrough_dest, f_content, f_context, vm);
                        self.process_dest(&ops, branch_dest, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
170
                        
171
                        let branch_target = f_content.get_block(branch_dest.target).name().unwrap();
172
173
174
    
                        let ref cond = ops[cond];
                        
qinsoon's avatar
qinsoon committed
175
                        if self.match_cmp_res(cond) {
176
                            trace!("emit cmp_res-branch2");
177
                            match self.emit_cmp_res(cond, f_content, f_context, vm) {
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
203
204
205
206
207
208
209
210
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
                                op::CmpOp::EQ => {
                                    if branch_if_true {
                                        self.backend.emit_je(branch_target);
                                    } else {
                                        self.backend.emit_jne(branch_target);
                                    }
                                },
                                op::CmpOp::NE => {
                                    if branch_if_true {
                                        self.backend.emit_jne(branch_target);
                                    } else {
                                        self.backend.emit_je(branch_target);
                                    }
                                },
                                op::CmpOp::UGE => {
                                    if branch_if_true {
                                        self.backend.emit_jae(branch_target);
                                    } else {
                                        self.backend.emit_jb(branch_target);
                                    }
                                },
                                op::CmpOp::UGT => {
                                    if branch_if_true {
                                        self.backend.emit_ja(branch_target);
                                    } else {
                                        self.backend.emit_jbe(branch_target);
                                    }
                                },
                                op::CmpOp::ULE => {
                                    if branch_if_true {
                                        self.backend.emit_jbe(branch_target);
                                    } else {
                                        self.backend.emit_ja(branch_target);
                                    }
                                },
                                op::CmpOp::ULT => {
                                    if branch_if_true {
                                        self.backend.emit_jb(branch_target);
                                    } else {
                                        self.backend.emit_jae(branch_target);
                                    }
                                },
                                op::CmpOp::SGE => {
                                    if branch_if_true {
                                        self.backend.emit_jge(branch_target);
                                    } else {
                                        self.backend.emit_jl(branch_target);
                                    }
                                },
                                op::CmpOp::SGT => {
                                    if branch_if_true {
                                        self.backend.emit_jg(branch_target);
                                    } else {
                                        self.backend.emit_jle(branch_target);
                                    }
                                },
                                op::CmpOp::SLE => {
                                    if branch_if_true {
                                        self.backend.emit_jle(branch_target);
                                    } else {
                                        self.backend.emit_jg(branch_target);
                                    }
                                },
                                op::CmpOp::SLT => {
                                    if branch_if_true {
                                        self.backend.emit_jl(branch_target);
                                    } else {
                                        self.backend.emit_jge(branch_target);
                                    }
                                },
qinsoon's avatar
qinsoon committed
248
249
250
251
252
253
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

                                // floating point

                                op::CmpOp::FOEQ | op::CmpOp::FUEQ => {
                                    if branch_if_true {
                                        self.backend.emit_je(branch_target);
                                    } else {
                                        self.backend.emit_jne(branch_target);
                                    }
                                },
                                op::CmpOp::FONE | op::CmpOp::FUNE => {
                                    if branch_if_true {
                                        self.backend.emit_jne(branch_target);
                                    } else {
                                        self.backend.emit_je(branch_target);
                                    }
                                },
                                op::CmpOp::FOGT | op::CmpOp::FUGT => {
                                    if branch_if_true {
                                        self.backend.emit_ja(branch_target);
                                    } else {
                                        self.backend.emit_jbe(branch_target);
                                    }
                                },
                                op::CmpOp::FOGE | op::CmpOp::FUGE => {
                                    if branch_if_true {
                                        self.backend.emit_jae(branch_target);
                                    } else {
                                        self.backend.emit_jb(branch_target);
                                    }
                                },
                                op::CmpOp::FOLT | op::CmpOp::FULT => {
                                    if branch_if_true {
                                        self.backend.emit_jb(branch_target);
                                    } else {
                                        self.backend.emit_jae(branch_target);
                                    }
                                },
                                op::CmpOp::FOLE | op::CmpOp::FULE => {
                                    if branch_if_true {
                                        self.backend.emit_jbe(branch_target);
                                    } else {
                                        self.backend.emit_ja(branch_target);
                                    }
                                },

qinsoon's avatar
qinsoon committed
294
295
296
297
                                _ => unimplemented!()
                            }
                        } else if self.match_ireg(cond) {
                            trace!("emit ireg-branch2");
298
                            
299
                            let cond_reg = self.emit_ireg(cond, f_content, f_context, vm);
300
                            
qinsoon's avatar
qinsoon committed
301
                            // emit: cmp cond_reg 1
qinsoon's avatar
qinsoon committed
302
                            self.backend.emit_cmp_imm_r(1, &cond_reg);
qinsoon's avatar
qinsoon committed
303
                            // emit: je #branch_dest
304
305
306
307
308
                            if branch_if_true {
                                self.backend.emit_je(branch_target);
                            } else {
                                self.backend.emit_jne(branch_target);
                            }
qinsoon's avatar
qinsoon committed
309
310
                        } else {
                            unimplemented!();
311
                        }
312
                    },
qinsoon's avatar
qinsoon committed
313
314

                    Instruction_::Select{cond, true_val, false_val} => {
qinsoon's avatar
qinsoon committed
315
316
                        use ast::op::CmpOp::*;

qinsoon's avatar
qinsoon committed
317
                        trace!("instsel on SELECT");
qinsoon's avatar
qinsoon committed
318
319
320
321
322
323
324
325
326
                        let ops = inst.ops.read().unwrap();

                        let ref cond = ops[cond];
                        let ref true_val = ops[true_val];
                        let ref false_val = ops[false_val];

                        if self.match_ireg(true_val) {
                            // moving integers/pointers
                            let tmp_res   = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
327

qinsoon's avatar
qinsoon committed
328
329
330
                            // generate compare
                            let cmpop = if self.match_cmp_res(cond) {
                                self.emit_cmp_res(cond, f_content, f_context, vm)
qinsoon's avatar
qinsoon committed
331
332
333
                            } else if self.match_ireg(cond) {
                                let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);
                                // emit: cmp cond_reg 1
qinsoon's avatar
qinsoon committed
334
                                self.backend.emit_cmp_imm_r(1, &tmp_cond);
qinsoon's avatar
qinsoon committed
335

qinsoon's avatar
qinsoon committed
336
                                EQ
qinsoon's avatar
qinsoon committed
337
                            } else {
qinsoon's avatar
qinsoon committed
338
339
340
                                panic!("expected ireg, found {}", cond)
                            };

341
                            // use cmov for 16/32/64bit integer
qinsoon's avatar
qinsoon committed
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
                            // use jcc  for 8 bit
                            match tmp_res.ty.get_int_length() {
                                // cmov
                                Some(len) if len > 8 => {
                                    let tmp_true  = self.emit_ireg(true_val, f_content, f_context, vm);
                                    let tmp_false = self.emit_ireg(false_val, f_content, f_context, vm);

                                    // mov tmp_false -> tmp_res
                                    self.backend.emit_mov_r_r(&tmp_res, &tmp_false);

                                    match cmpop {
                                        EQ  => self.backend.emit_cmove_r_r (&tmp_res, &tmp_true),
                                        NE  => self.backend.emit_cmovne_r_r(&tmp_res, &tmp_true),
                                        SGE => self.backend.emit_cmovge_r_r(&tmp_res, &tmp_true),
                                        SGT => self.backend.emit_cmovg_r_r (&tmp_res, &tmp_true),
                                        SLE => self.backend.emit_cmovle_r_r(&tmp_res, &tmp_true),
                                        SLT => self.backend.emit_cmovl_r_r (&tmp_res, &tmp_true),
                                        UGE => self.backend.emit_cmovae_r_r(&tmp_res, &tmp_true),
                                        UGT => self.backend.emit_cmova_r_r (&tmp_res, &tmp_true),
                                        ULE => self.backend.emit_cmovbe_r_r(&tmp_res, &tmp_true),
                                        ULT => self.backend.emit_cmovb_r_r (&tmp_res, &tmp_true),

                                        FOEQ | FUEQ => self.backend.emit_cmove_r_r (&tmp_res, &tmp_true),
                                        FONE | FUNE => self.backend.emit_cmovne_r_r(&tmp_res, &tmp_true),
                                        FOGT | FUGT => self.backend.emit_cmova_r_r (&tmp_res, &tmp_true),
                                        FOGE | FUGE => self.backend.emit_cmovae_r_r(&tmp_res, &tmp_true),
                                        FOLT | FULT => self.backend.emit_cmovb_r_r (&tmp_res, &tmp_true),
                                        FOLE | FULE => self.backend.emit_cmovbe_r_r(&tmp_res, &tmp_true),

                                        _ => unimplemented!()
                                    }
                                }
                                // jcc
                                _ => {
376
377
                                    let blk_true  = format!("{}_select_true", node.id());
                                    let blk_false = format!("{}_select_false", node.id());
qinsoon's avatar
qinsoon committed
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
                                    let blk_end   = format!("{}_select_end", node.id());

                                    // jump to blk_true if true
                                    match cmpop {
                                        EQ  => self.backend.emit_je (blk_true.clone()),
                                        NE  => self.backend.emit_jne(blk_true.clone()),
                                        SGE => self.backend.emit_jge(blk_true.clone()),
                                        SGT => self.backend.emit_jg (blk_true.clone()),
                                        SLE => self.backend.emit_jle(blk_true.clone()),
                                        SLT => self.backend.emit_jl (blk_true.clone()),
                                        UGE => self.backend.emit_jae(blk_true.clone()),
                                        UGT => self.backend.emit_ja (blk_true.clone()),
                                        ULE => self.backend.emit_jbe(blk_true.clone()),
                                        ULT => self.backend.emit_jb (blk_true.clone()),

                                        FOEQ | FUEQ => self.backend.emit_je (blk_true.clone()),
                                        FONE | FUNE => self.backend.emit_jne(blk_true.clone()),
                                        FOGT | FUGT => self.backend.emit_ja (blk_true.clone()),
                                        FOGE | FUGE => self.backend.emit_jae(blk_true.clone()),
                                        FOLT | FULT => self.backend.emit_jb (blk_true.clone()),
                                        FOLE | FULE => self.backend.emit_jbe(blk_true.clone()),

                                        _ => unimplemented!()
                                    }

403
404
405
406
407
408
409
410
                                    // finishing current block
                                    let cur_block = self.current_block.as_ref().unwrap().clone();
                                    self.backend.end_block(cur_block.clone());

                                    // blk_false:
                                    self.current_block = Some(blk_false.clone());
                                    self.backend.start_block(blk_false.clone());

qinsoon's avatar
qinsoon committed
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
                                    // mov false result here
                                    self.emit_move_node_to_value(&tmp_res, &false_val, f_content, f_context, vm);

                                    // jmp to end
                                    self.backend.emit_jmp(blk_end.clone());

                                    // finishing current block
                                    let cur_block = self.current_block.as_ref().unwrap().clone();
                                    self.backend.end_block(cur_block.clone());

                                    // blk_true:
                                    self.current_block = Some(blk_true.clone());
                                    self.backend.start_block(blk_true.clone());
                                    // mov true value -> result
                                    self.emit_move_node_to_value(&tmp_res, &true_val, f_content, f_context, vm);

                                    self.backend.end_block(blk_true.clone());

                                    // blk_end:
                                    self.backend.start_block(blk_end.clone());
                                    self.current_block = Some(blk_end.clone());
                                }
qinsoon's avatar
qinsoon committed
433
434
435
436
437
438
439
                            }
                        } else {
                            // moving vectors, floatingpoints
                            unimplemented!()
                        }
                    },

440
                    Instruction_::CmpOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
441
442
                        use ast::op::CmpOp::*;

qinsoon's avatar
qinsoon committed
443
                        trace!("instsel on CMPOP");
444
445
446
447
                        let ops = inst.ops.read().unwrap();
                        let ref op1 = ops[op1];
                        let ref op2 = ops[op2];

qinsoon's avatar
qinsoon committed
448
                        let tmp_res = self.get_result_value(node);
449
450
451
                        
                        debug_assert!(tmp_res.ty.get_int_length().is_some());
                        debug_assert!(tmp_res.ty.get_int_length().unwrap() == 1);
qinsoon's avatar
qinsoon committed
452

453
                        // set byte to result
qinsoon's avatar
qinsoon committed
454
                        match self.emit_cmp_res(node, f_content, f_context, vm) {
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
                            EQ  => self.backend.emit_sete_r (&tmp_res),
                            NE  => self.backend.emit_setne_r(&tmp_res),
                            SGE => self.backend.emit_setge_r(&tmp_res),
                            SGT => self.backend.emit_setg_r (&tmp_res),
                            SLE => self.backend.emit_setle_r(&tmp_res),
                            SLT => self.backend.emit_setl_r (&tmp_res),
                            UGE => self.backend.emit_setae_r(&tmp_res),
                            UGT => self.backend.emit_seta_r (&tmp_res),
                            ULE => self.backend.emit_setbe_r(&tmp_res),
                            ULT => self.backend.emit_setb_r (&tmp_res),

                            FOEQ | FUEQ => self.backend.emit_sete_r (&tmp_res),
                            FONE | FUNE => self.backend.emit_setne_r(&tmp_res),
                            FOGT | FUGT => self.backend.emit_seta_r (&tmp_res),
                            FOGE | FUGE => self.backend.emit_setae_r(&tmp_res),
                            FOLT | FULT => self.backend.emit_setb_r (&tmp_res),
                            FOLE | FULE => self.backend.emit_setbe_r(&tmp_res),
qinsoon's avatar
qinsoon committed
472
473

                            _ => unimplemented!()
474
475
476
                        }
                    }

qinsoon's avatar
qinsoon committed
477
                    Instruction_::Branch1(ref dest) => {
qinsoon's avatar
qinsoon committed
478
                        trace!("instsel on BRANCH1");
qinsoon's avatar
qinsoon committed
479
                        let ops = inst.ops.read().unwrap();
480
                                            
481
                        self.process_dest(&ops, dest, f_content, f_context, vm);
482
                        
483
                        let target = f_content.get_block(dest.target).name().unwrap();
qinsoon's avatar
qinsoon committed
484
                        
qinsoon's avatar
qinsoon committed
485
                        trace!("emit branch1");
486
                        // jmp
qinsoon's avatar
qinsoon committed
487
                        self.backend.emit_jmp(target);
488
                    },
qinsoon's avatar
qinsoon committed
489
490

                    Instruction_::Switch{cond, ref default, ref branches} => {
qinsoon's avatar
qinsoon committed
491
                        trace!("instsel on SWITCH");
qinsoon's avatar
qinsoon committed
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
                        let ops = inst.ops.read().unwrap();

                        let ref cond = ops[cond];

                        if self.match_ireg(cond) {
                            let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);

                            // emit each branch
                            for &(case_op_index, ref case_dest) in branches {
                                let ref case_op = ops[case_op_index];

                                // process dest
                                self.process_dest(&ops, case_dest, f_content, f_context, vm);

                                let target = f_content.get_block(case_dest.target).name().unwrap();

                                if self.match_iimm(case_op) {
                                    let imm = self.node_iimm_to_i32(case_op);

                                    // cmp case cond
qinsoon's avatar
qinsoon committed
512
                                    self.backend.emit_cmp_imm_r(imm, &tmp_cond);
qinsoon's avatar
qinsoon committed
513
514
515
516
517
518
                                    // je dest
                                    self.backend.emit_je(target);
                                } else if self.match_ireg(case_op) {
                                    let tmp_case_op = self.emit_ireg(case_op, f_content, f_context, vm);

                                    // cmp case cond
qinsoon's avatar
qinsoon committed
519
                                    self.backend.emit_cmp_r_r(&tmp_case_op, &tmp_cond);
qinsoon's avatar
qinsoon committed
520
521
522
523
524
                                    // je dest
                                    self.backend.emit_je(target);
                                } else {
                                    panic!("expecting ireg cond to be either iimm or ireg: {}", cond);
                                }
525
526
527

                                self.finish_block();
                                self.start_block(format!("{}_switch_not_met_case_{}", node.id(), case_op_index));
qinsoon's avatar
qinsoon committed
528
529
530
531
532
533
534
535
536
537
538
                            }

                            // emit default
                            self.process_dest(&ops, default, f_content, f_context, vm);
                            
                            let default_target = f_content.get_block(default.target).name().unwrap();
                            self.backend.emit_jmp(default_target);
                        } else {
                            panic!("expecting cond in switch to be ireg: {}", cond);
                        }
                    }
539
                    
qinsoon's avatar
qinsoon committed
540
                    Instruction_::ExprCall{ref data, is_abort} => {
qinsoon's avatar
qinsoon committed
541
542
                        trace!("instsel on EXPRCALL");

qinsoon's avatar
qinsoon committed
543
544
                        if is_abort {
                            unimplemented!()
545
                        }
546
                        
qinsoon's avatar
qinsoon committed
547
548
549
550
551
                        self.emit_mu_call(
                            inst, // inst: &Instruction,
                            data, // calldata: &CallData,
                            None, // resumption: Option<&ResumptionData>,
                            node, // cur_node: &TreeNode, 
552
                            f_content, f_context, vm);
553
554
                    },
                    
qinsoon's avatar
qinsoon committed
555
                    Instruction_::Call{ref data, ref resume} => {
qinsoon's avatar
qinsoon committed
556
557
                        trace!("instsel on CALL");

qinsoon's avatar
qinsoon committed
558
559
560
561
562
563
                        self.emit_mu_call(
                            inst, 
                            data, 
                            Some(resume), 
                            node, 
                            f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
564
565
566
                    },

                    Instruction_::ExprCCall{ref data, is_abort} => {
qinsoon's avatar
qinsoon committed
567
568
                        trace!("instsel on EXPRCCALL");

qinsoon's avatar
qinsoon committed
569
570
571
572
573
574
575
576
                        if is_abort {
                            unimplemented!()
                        }

                        self.emit_c_call_ir(inst, data, None, node, f_content, f_context, vm);
                    }

                    Instruction_::CCall{ref data, ref resume} => {
qinsoon's avatar
qinsoon committed
577
578
                        trace!("instsel on CCALL");

qinsoon's avatar
qinsoon committed
579
                        self.emit_c_call_ir(inst, data, Some(resume), node, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
580
581
                    }
                    
582
                    Instruction_::Return(_) => {
qinsoon's avatar
qinsoon committed
583
584
                        trace!("instsel on RETURN");

585
                        self.emit_common_epilogue(inst, f_content, f_context, vm);
586
                        
qinsoon's avatar
qinsoon committed
587
                        self.backend.emit_ret();
588
589
                    },
                    
qinsoon's avatar
qinsoon committed
590
                    Instruction_::BinOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
591
592
                        trace!("instsel on BINOP");

qinsoon's avatar
qinsoon committed
593
594
                        self.emit_binop(node, inst, op, op1, op2, f_content, f_context, vm);
                    },
qinsoon's avatar
qinsoon committed
595

qinsoon's avatar
qinsoon committed
596
597
                    Instruction_::BinOpWithStatus(op, status, op1, op2) => {
                        trace!("instsel on BINOP_STATUS");
qinsoon's avatar
qinsoon committed
598

qinsoon's avatar
qinsoon committed
599
                        self.emit_binop(node, inst, op, op1, op2, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
600

qinsoon's avatar
qinsoon committed
601
602
                        let values = inst.value.as_ref().unwrap();
                        let mut status_value_index = 1;
qinsoon's avatar
qinsoon committed
603

604
                        // status flags only works with int operations
605
                        if RegGroup::get_from_value(&values[0]) == RegGroup::GPR {
606
607
608
609
610
611
612
                            // negative flag
                            if status.flag_n {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;

                                self.backend.emit_sets_r8(&tmp_status);
                            }
qinsoon's avatar
qinsoon committed
613

614
615
616
617
                            // zero flag
                            if status.flag_z {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
618

619
620
                                self.backend.emit_setz_r8(&tmp_status);
                            }
qinsoon's avatar
qinsoon committed
621

622
623
624
625
                            // unsigned overflow
                            if status.flag_c {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
626

627
628
629
630
631
                                match op {
                                    BinOp::Add | BinOp::Sub | BinOp::Mul => {
                                        self.backend.emit_setb_r8(&tmp_status);
                                    }
                                    _ => panic!("Only Add/Sub/Mul has #C flag")
qinsoon's avatar
qinsoon committed
632
633
                                }
                            }
qinsoon's avatar
qinsoon committed
634

635
636
637
                            // signed overflow
                            if status.flag_v {
                                let tmp_status = values[status_value_index].clone();
qinsoon's avatar
qinsoon committed
638

639
640
641
642
643
                                match op {
                                    BinOp::Add | BinOp::Sub | BinOp::Mul => {
                                        self.backend.emit_seto_r8(&tmp_status);
                                    }
                                    _ => panic!("Only Add/Sub/Mul has #V flag")
qinsoon's avatar
qinsoon committed
644
645
                                }
                            }
646
647
                        }
                    }
qinsoon's avatar
qinsoon committed
648
649

                    Instruction_::ConvOp{operation, ref from_ty, ref to_ty, operand} => {
qinsoon's avatar
qinsoon committed
650
651
                        trace!("instsel on CONVOP");

qinsoon's avatar
qinsoon committed
652
653
654
655
656
657
658
659
                        let ops = inst.ops.read().unwrap();

                        let ref op = ops[operand];

                        match operation {
                            op::ConvOp::TRUNC => {
                                if self.match_ireg(op) {
                                    let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
660

qinsoon's avatar
qinsoon committed
661
                                    let tmp_res = self.get_result_value(node);
662
663
664
665
                                    let dst_length = match tmp_res.ty.get_int_length() {
                                        Some(len) => len,
                                        None => panic!("dst of TRUNC is not int: {}", tmp_res)
                                    };
qinsoon's avatar
qinsoon committed
666
667

                                    // mov op -> result
668
669
670
671
672
673
674
675
                                    match dst_length {
                                        1  => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT8_TYPE.clone())}),
                                        8  => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT8_TYPE.clone())}),
                                        16 => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT16_TYPE.clone())}),
                                        32 => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT32_TYPE.clone())}),
                                        64 => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT64_TYPE.clone())}),
                                        _  => panic!("unsupported int length: {}", dst_length)
                                    }
qinsoon's avatar
qinsoon committed
676
677
678
679
680
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
                                }
                            }
                            op::ConvOp::ZEXT => {
681
682
683
                                if self.match_ireg(op) {
                                    let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
                                    let tmp_res = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
684

685
686
687
                                    // movz op -> result
                                    let from_ty_size = vm.get_backend_type_info(from_ty.id()).size;
                                    let to_ty_size   = vm.get_backend_type_info(to_ty.id()).size;
qinsoon's avatar
qinsoon committed
688

689
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
690
691
692
693
694
695
696
697
698
699
700
701
702
                                        if from_ty_size == 4 && to_ty_size == 8 {
                                            // zero extend from 32 bits to 64 bits is a mov instruction
                                            // x86 does not have movzlq (32 to 64)

                                            // tmp_op is int32, but tmp_res is int64
                                            // we want to force a 32-to-32 mov, so high bits of the destination will be zeroed

                                            let tmp_res32 = unsafe {tmp_res.as_type(UINT32_TYPE.clone())};

                                            self.backend.emit_mov_r_r(&tmp_res32, &tmp_op);
                                        } else {
                                            self.backend.emit_movz_r_r(&tmp_res, &tmp_op);
                                        }
qinsoon's avatar
qinsoon committed
703
                                    } else {
704
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
705
                                    }
706
707
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
qinsoon's avatar
qinsoon committed
708
709
710
                                }
                            },
                            op::ConvOp::SEXT => {
711
712
713
                                if self.match_ireg(op) {
                                    let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
                                    let tmp_res = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
714

715
716
717
                                    // movs op -> result
                                    let from_ty_size = vm.get_backend_type_info(from_ty.id()).size;
                                    let to_ty_size   = vm.get_backend_type_info(to_ty.id()).size;
qinsoon's avatar
qinsoon committed
718

719
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
720
721
                                        self.backend.emit_movs_r_r(&tmp_res, &tmp_op);
                                    } else {
722
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
723
                                    }
724
725
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
qinsoon's avatar
qinsoon committed
726
727
                                }
                            }
qinsoon's avatar
qinsoon committed
728
729
730
731
732
733
                            op::ConvOp::REFCAST | op::ConvOp::PTRCAST => {
                                // just a mov (and hopefully reg alloc will coalesce it)
                                let tmp_res = self.get_result_value(node);

                                if self.match_ireg(op) {
                                    let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
734
                                    self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
735
736
737
738
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
                                }
                            }
qinsoon's avatar
qinsoon committed
739
740
741
                            op::ConvOp::SITOFP => {
                                let tmp_res = self.get_result_value(node);

742
743
744
745
746
747
748
                                assert!(self.match_ireg(op), "unexpected op (expected ireg): {}", op);
                                let tmp_op = self.emit_ireg(op, f_content, f_context, vm);

                                match to_ty.v {
                                    MuType_::Double => self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp_op),
                                    MuType_::Float  => self.backend.emit_cvtsi2ss_f32_r(&tmp_res, &tmp_op),
                                    _ => panic!("expecing fp type as to type in SITOFP, found {}", to_ty)
qinsoon's avatar
qinsoon committed
749
750
751
752
753
                                }
                            }
                            op::ConvOp::FPTOSI => {
                                let tmp_res = self.get_result_value(node);

754
755
756
757
                                assert!(self.match_fpreg(op), "unexpected op (expected fpreg): {}", op);
                                let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);

                                if from_ty.is_double() {
qinsoon's avatar
qinsoon committed
758
                                    self.backend.emit_cvtsd2si_r_f64(&tmp_res, &tmp_op);
759
760
                                } else if from_ty.is_float() {
                                    self.backend.emit_cvtss2si_r_f32(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
761
                                } else {
762
                                    panic!("expected fp type as from type in FPTOSI, found {}", to_ty)
qinsoon's avatar
qinsoon committed
763
764
                                }
                            }
765
766
767
                            op::ConvOp::UITOFP => {
                                let tmp_res = self.get_result_value(node);

768
769
                                assert!(self.match_ireg(op), "unexpected op (expected ireg): {}", op);
                                let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
770

771
                                let op_ty_size = vm.get_backend_type_info(tmp_op.ty.id()).size;
772

qinsoon's avatar
qinsoon committed
773
774
775
776
777
                                if to_ty.is_double() {
                                    match op_ty_size {
                                        8 => {
                                            // movd/movq op -> res
                                            self.backend.emit_mov_fpr_r64(&tmp_res, &tmp_op);
778

qinsoon's avatar
qinsoon committed
779
780
781
782
                                            // punpckldq UITOFP_C0, tmp_res -> tmp_res
                                            // (interleaving low bytes: xmm = xmm[0] mem[0] xmm[1] mem[1]
                                            let mem_c0 = self.get_mem_for_const(UITOFP_C0.clone(), vm);
                                            self.backend.emit_punpckldq_f64_mem128(&tmp_res, &mem_c0);
783

qinsoon's avatar
qinsoon committed
784
785
786
                                            // subpd UITOFP_C1, tmp_res -> tmp_res
                                            let mem_c1 = self.get_mem_for_const(UITOFP_C1.clone(), vm);
                                            self.backend.emit_subpd_f64_mem128(&tmp_res, &mem_c1);
787

qinsoon's avatar
qinsoon committed
788
789
790
791
792
                                            // haddpd tmp_res, tmp_res -> tmp_res
                                            self.backend.emit_haddpd_f64_f64(&tmp_res, &tmp_res);
                                        }
                                        4 => {
                                            let tmp = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
793

qinsoon's avatar
qinsoon committed
794
795
796
                                            // movl op -> tmp(32)
                                            let tmp32 = unsafe { tmp.as_type(UINT32_TYPE.clone()) };
                                            self.backend.emit_mov_r_r(&tmp32, &tmp_op);
797

qinsoon's avatar
qinsoon committed
798
799
800
801
802
803
804
805
                                            // cvtsi2sd %tmp(64) -> %tmp_res
                                            self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp);
                                        }
                                        2 | 1 => {
                                            let tmp_op32 = unsafe { tmp_op.as_type(UINT32_TYPE.clone()) };
                                            self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp_op32);
                                        }
                                        _ => panic!("not implemented int length {}", op_ty_size)
806
                                    }
qinsoon's avatar
qinsoon committed
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
                                } else if to_ty.is_float() {
                                    match op_ty_size {
                                        8 => {
                                            // movl %tmp_op -> %tmp1
                                            let tmp1 = self.make_temporary(f_context, UINT32_TYPE.clone(), vm);
                                            self.backend.emit_mov_r_r(&tmp1, unsafe {&tmp_op.as_type(UINT32_TYPE.clone())});

                                            // andl %tmp1 $1 -> %tmp1
                                            self.backend.emit_and_r_imm(&tmp1, 1);

                                            // testq %tmp_op %tmp_op
                                            self.backend.emit_test_r_r(&tmp_op, &tmp_op);

                                            let blk_if_signed     = format!("{}_{}_uitofp_float_if_signed", self.current_fv_id, node.id());
                                            let blk_if_not_signed = format!("{}_{}_uitofp_float_if_not_signed", self.current_fv_id, node.id());
                                            let blk_done          = format!("{}_{}_uitofp_float_done", self.current_fv_id, node.id());

                                            // js %if_signed
                                            self.backend.emit_js(blk_if_signed.clone());
                                            self.finish_block();

                                            // blk_if_not_signed:
                                            self.start_block(blk_if_not_signed);

                                            // cvtsi2ss %tmp_op -> %tmp_res
                                            self.backend.emit_cvtsi2ss_f32_r(&tmp_res, &tmp_op);

                                            // jmp blk_done
                                            self.backend.emit_jmp(blk_done.clone());
                                            self.finish_block();

                                            // blk_if_signed:
                                            self.start_block(blk_if_signed);

                                            // shr %tmp_op $1 -> %tmp_op
                                            self.backend.emit_shr_r_imm8(&tmp_op, 1);

                                            // or %tmp_op %tmp1 -> %tmp1
                                            self.backend.emit_or_r_r(unsafe {&tmp1.as_type(UINT64_TYPE.clone())}, &tmp_op);

                                            // cvtsi2ss %tmp1 -> %tmp_res
                                            self.backend.emit_cvtsi2ss_f32_r(&tmp_res, &tmp1);

                                            // addss %tmp_res %tmp_res -> %tmp_res
                                            self.backend.emit_addss_f32_f32(&tmp_res, &tmp_res);
                                            self.finish_block();

                                            self.start_block(blk_done);
                                        }
                                        4 => {
                                            // movl %tmp_op -> %tmp1
                                            let tmp1 = self.make_temporary(f_context, UINT32_TYPE.clone(), vm);
                                            self.backend.emit_mov_r_r(&tmp1, &tmp_op);

                                            // cvtsi2ssq %tmp1(64) -> %tmp_res
                                            self.backend.emit_cvtsi2ss_f32_r(&tmp_res, unsafe {&tmp1.as_type(UINT64_TYPE.clone())});
                                        }
                                        2 | 1 => {
                                            let tmp_op32 = unsafe {tmp_op.as_type(UINT32_TYPE.clone())};

                                            // cvtsi2ss %tmp_op32 -> %tmp_res
                                            self.backend.emit_cvtsi2ss_f32_r(&tmp_res, &tmp_op32);
                                        }
                                        _ => panic!("not implemented int length {}", op_ty_size)
871
                                    }
qinsoon's avatar
qinsoon committed
872
873
                                } else {
                                    panic!("expect double or float")
874
875
876
877
878
                                }
                            }
                            op::ConvOp::FPTOUI => {
                                let tmp_res = self.get_result_value(node);

879
                                assert!(self.match_fpreg(op), "unexpected op (expected fpreg): {}", op);
qinsoon's avatar
qinsoon committed
880
                                let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);
881
                                let res_ty_size = vm.get_backend_type_info(tmp_res.ty.id()).size;
882

qinsoon's avatar
qinsoon committed
883
884
885
886
887
                                if from_ty.is_double() {
                                    match res_ty_size {
                                        8 => {
                                            let tmp1 = self.make_temporary(f_context, DOUBLE_TYPE.clone(), vm);
                                            let tmp2 = self.make_temporary(f_context, DOUBLE_TYPE.clone(), vm);
888

qinsoon's avatar
qinsoon committed
889
890
891
                                            // movsd FPTOUI_C_DOUBLE -> %tmp1
                                            let mem_c = self.get_mem_for_const(FPTOUI_C_DOUBLE.clone(), vm);
                                            self.backend.emit_movsd_f64_mem64(&tmp1, &mem_c);
892

qinsoon's avatar
qinsoon committed
893
894
                                            // movapd %tmp_op -> %tmp2
                                            self.backend.emit_movapd_f64_f64(&tmp2, &tmp_op);
895

qinsoon's avatar
qinsoon committed
896
897
                                            // subsd %tmp1, %tmp2 -> %tmp2
                                            self.backend.emit_subsd_f64_f64(&tmp2, &tmp1);
898

qinsoon's avatar
qinsoon committed
899
900
                                            // cvttsd2si %tmp2 -> %tmp_res
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res, &tmp2);
901

qinsoon's avatar
qinsoon committed
902
903
904
                                            let tmp_const = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
                                            // mov 0x8000000000000000 -> %tmp_const
                                            self.backend.emit_mov_r64_imm64(&tmp_const, -9223372036854775808i64);
905

qinsoon's avatar
qinsoon committed
906
907
                                            // xor %tmp_res, %tmp_const -> %tmp_const
                                            self.backend.emit_xor_r_r(&tmp_const, &tmp_res);
qinsoon's avatar
qinsoon committed
908

qinsoon's avatar
qinsoon committed
909
910
                                            // cvttsd2si %tmp_op -> %tmp_res
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res, &tmp_op);
911

qinsoon's avatar
qinsoon committed
912
913
                                            // ucomisd %tmp_op %tmp1
                                            self.backend.emit_ucomisd_f64_f64(&tmp1, &tmp_op);
914

qinsoon's avatar
qinsoon committed
915
916
917
918
919
                                            // cmovaeq %tmp_const -> %tmp_res
                                            self.backend.emit_cmovae_r_r(&tmp_res, &tmp_const);
                                        }
                                        4 => {
                                            let tmp_res64 = unsafe { tmp_res.as_type(UINT64_TYPE.clone()) };
920

qinsoon's avatar
qinsoon committed
921
922
923
924
925
926
927
928
929
930
931
932
933
                                            // cvttsd2si %tmp_op -> %tmp_res(64)
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res64, &tmp_op);
                                        }
                                        2 | 1 => {
                                            let tmp_res32 = unsafe { tmp_res.as_type(UINT32_TYPE.clone()) };

                                            // cvttsd2si %tmp_op -> %tmp_res(32)
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res32, &tmp_op);

                                            // movz %tmp_res -> %tmp_res(32)
                                            self.backend.emit_movz_r_r(&tmp_res32, &tmp_res);
                                        }
                                        _ => panic!("not implemented int length {}", res_ty_size)
934
                                    }
qinsoon's avatar
qinsoon committed
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
                                } else if from_ty.is_float() {
                                    match res_ty_size {
                                        8 => {
                                            let tmp1 = self.make_temporary(f_context, FLOAT_TYPE.clone(), vm);
                                            let tmp2 = self.make_temporary(f_context, FLOAT_TYPE.clone(), vm);

                                            // movss FPTOUI_C_FLOAT -> %tmp1
                                            let mem_c = self.get_mem_for_const(FPTOUI_C_FLOAT.clone(), vm);
                                            self.backend.emit_movss_f32_mem32(&tmp1, &mem_c);

                                            // movaps %tmp_op -> %tmp2
                                            self.backend.emit_movaps_f32_f32(&tmp2, &tmp_op);

                                            // subss %tmp1, %tmp2 -> %tmp2
                                            self.backend.emit_subss_f32_f32(&tmp2, &tmp1);

                                            // cvttss2si %tmp2 -> %tmp_res
                                            self.backend.emit_cvttss2si_r_f32(&tmp_res, &tmp2);

                                            let tmp_const = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
                                            // mov 0x8000000000000000 -> %tmp_const
                                            self.backend.emit_mov_r64_imm64(&tmp_const, -9223372036854775808i64);

                                            // xor %tmp_res, %tmp_const -> %tmp_const
                                            self.backend.emit_xor_r_r(&tmp_const, &tmp_res);
960

qinsoon's avatar
qinsoon committed
961
962
                                            // cvttss2si %tmp_op -> %tmp_res
                                            self.backend.emit_cvttss2si_r_f32(&tmp_res, &tmp_op);
963

qinsoon's avatar
qinsoon committed
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
                                            // ucomiss %tmp_op %tmp1
                                            self.backend.emit_ucomiss_f32_f32(&tmp1, &tmp_op);

                                            // cmovaeq %tmp_const -> %tmp_res
                                            self.backend.emit_cmovae_r_r(&tmp_res, &tmp_const);
                                        }
                                        4 => {
                                            let tmp_res64 = unsafe { tmp_res.as_type(UINT64_TYPE.clone())};

                                            // cvttss2si %tmp_op -> %tmp_res(64)
                                            self.backend.emit_cvttss2si_r_f32(&tmp_res64, &tmp_op);
                                        }
                                        2 | 1 => {
                                            let tmp_res32 = unsafe {tmp_res.as_type(UINT32_TYPE.clone())};

                                            // cvttss2si %tmp_op -> %tmp_res(32)
                                            self.backend.emit_cvttss2si_r_f32(&tmp_res32, &tmp_op);

                                            // movz %tmp_res(32) -> %tmp_res
                                            self.backend.emit_movz_r_r(&tmp_res32, &tmp_res);
                                        }
                                        _ => panic!("not implemented int length {}", res_ty_size)
986
                                    }
qinsoon's avatar
qinsoon committed
987
988
                                } else {
                                    panic!("expect double or float")
989
990
                                }
                            }
qinsoon's avatar
qinsoon committed
991
992
993
                            _ => unimplemented!()
                        }
                    }
994
                    
995
996
                    // load on x64 generates mov inst (no matter what order is specified)
                    // https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
997
                    Instruction_::Load{is_ptr, order, mem_loc} => {
qinsoon's avatar
qinsoon committed
998
999
                        trace!("instsel on LOAD");

qinsoon's avatar
qinsoon committed
1000
                        let ops = inst.ops.read().unwrap();
1001
                        let ref loc_op = ops[mem_loc];
1002
1003
1004
1005
1006
1007
                        
                        // check order
                        match order {
                            MemoryOrder::Relaxed 
                            | MemoryOrder::Consume 
                            | MemoryOrder::Acquire
1008
1009
                            | MemoryOrder::SeqCst
                            | MemoryOrder::NotAtomic => {},
1010
1011
                            _ => panic!("didnt expect order {:?} with store inst", order)
                        }                        
1012

1013
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
1014
                        let res_temp = self.get_result_value(node);
1015

qinsoon's avatar
qinsoon committed
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
                        if self.match_ireg(node) {
                            self.backend.emit_mov_r_mem(&res_temp, &resolved_loc);
                        } else if self.match_fpreg(node) {
                            match res_temp.ty.v {
                                MuType_::Double => self.backend.emit_movsd_f64_mem64(&res_temp, &resolved_loc),
                                MuType_::Float  => self.backend.emit_movss_f32_mem32(&res_temp, &resolved_loc),
                                _ => panic!("expect double or float")
                            }
                        } else {
                            unimplemented!()
                        }
1027
1028
1029
                    }
                    
                    Instruction_::Store{is_ptr, order, mem_loc, value} => {
qinsoon's avatar
qinsoon committed
1030
1031
                        trace!("instsel on STORE");

qinsoon's avatar
qinsoon committed
1032
                        let ops = inst.ops.read().unwrap();
1033
1034
1035
1036
1037
                        let ref loc_op = ops[mem_loc];
                        let ref val_op = ops[value];
                        
                        let generate_plain_mov : bool = {
                            match order {
1038
1039
1040
                                MemoryOrder::Relaxed
                                | MemoryOrder::Release
                                | MemoryOrder::NotAtomic => true,
1041
1042
1043
1044
1045
                                MemoryOrder::SeqCst => false,
                                _ => panic!("didnt expect order {:?} with store inst", order)
                            }
                        };
                        
1046
1047
1048
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);

                        if self.match_iimm(val_op) {
1049
                            let (val, len) = self.node_iimm_to_i32_with_len(val_op);
1050
                            if generate_plain_mov {
1051
                                self.backend.emit_mov_mem_imm(&resolved_loc, val, len);
1052
1053
1054
                            } else {
                                unimplemented!()
                            }
1055
1056
                        } else if self.match_ireg(val_op) {
                            let val = self.emit_ireg(val_op, f_content, f_context, vm);
1057
                            if generate_plain_mov {
qinsoon's avatar
qinsoon committed
1058
                                self.backend.emit_mov_mem_r(&resolved_loc, &val);
1059
1060
1061
                            } else {
                                unimplemented!()
                            }
1062
                        } else if self.match_fpreg(val_op) {
qinsoon's avatar
qinsoon committed
1063
1064
                            let val = self.emit_fpreg(val_op, f_content, f_context, vm);

1065
1066
1067
1068
1069
1070
1071
                            match val.ty.v {
                                MuType_::Double => self.backend.emit_movsd_mem64_f64(&resolved_loc, &val),
                                MuType_::Float  => self.backend.emit_movss_mem32_f32(&resolved_loc, &val),
                                _ => panic!("unexpected fp type: {}", val.ty)
                            }
                        } else {
                            unimplemented!()
1072
1073
                        }
                    }
qinsoon's avatar
qinsoon committed
1074

1075
1076
1077
1078
                    // memory insts: calculate the address, then lea
                    Instruction_::GetIRef(_)
                    | Instruction_::GetFieldIRef{..}
                    | Instruction_::GetVarPartIRef{..}
1079
1080
1081
                    | Instruction_::ShiftIRef{..}
                    | Instruction_::GetElementIRef{..} => {
                        trace!("instsel on GET/FIELD/VARPART/SHIFT/ELEM IREF");
qinsoon's avatar
qinsoon committed
1082

1083
1084
                        let mem_addr = self.emit_get_mem_from_inst(node, f_content, f_context, vm);
                        let tmp_res  = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
1085

1086
                        self.backend.emit_lea_r64(&tmp_res, &mem_addr);
qinsoon's avatar
qinsoon committed
1087
                    }
1088
                    
1089
                    Instruction_::ThreadExit => {
qinsoon's avatar
qinsoon committed
1090
                        trace!("instsel on THREADEXIT");
1091
                        // emit a call to swap_back_to_native_stack(sp_loc: Address)
1092
1093
                        
                        // get thread local and add offset to get sp_loc
qinsoon's avatar
qinsoon committed
1094
                        let tl = self.emit_get_threadlocal(Some(node), f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
1095
                        self.backend.emit_add_r_imm(&tl, *thread::NATIVE_SP_LOC_OFFSET as i32);
1096
                        
qinsoon's avatar
qinsoon committed
1097
                        self.emit_runtime_entry(&entrypoints::SWAP_BACK_TO_NATIVE_STACK, vec![tl.clone()], None, Some(node), f_content, f_context, vm);
1098
                    }
1099
1100

                    Instruction_::CommonInst_GetThreadLocal => {
qinsoon's avatar
qinsoon committed
1101
                        trace!("instsel on GETTHREADLOCAL");
1102
1103
1104
1105
1106
1107
1108
1109
1110
                        // get thread local
                        let tl = self.emit_get_threadlocal(Some(node), f_content, f_context, vm);

                        let tmp_res = self.get_result_value(node);

                        // load [tl + USER_TLS_OFFSET] -> tmp_res
                        self.emit_load_base_offset(&tmp_res, &tl, *thread::USER_TLS_OFFSET as i32, vm);
                    }
                    Instruction_::CommonInst_SetThreadLocal(op) => {
qinsoon's avatar
qinsoon committed
1111
1112
                        trace!("instsel on SETTHREADLOCAL");

1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
                        let ops = inst.ops.read().unwrap();
                        let ref op = ops[op];

                        debug_assert!(self.match_ireg(op));

                        let tmp_op = self.emit_ireg(op, f_content, f_context, vm);

                        // get thread local
                        let tl = self.emit_get_threadlocal(Some(node), f_content, f_context, vm);

                        // store tmp_op -> [tl + USER_TLS_OFFSTE]
                        self.emit_store_base_offset(&tl, *thread::USER_TLS_OFFSET as i32, &tmp_op, vm);
                    }
1126

qinsoon's avatar
qinsoon committed
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
                    Instruction_::CommonInst_Pin(op) => {
                        trace!("instsel on PIN");

                        if !mm::GC_MOVES_OBJECT {
                            // non-moving GC: pin is a nop (move from op to result)
                            let ops = inst.ops.read().unwrap();
                            let ref op = ops[op];

                            let tmp_res = self.get_result_value(node);

                            self.emit_move_node_to_value(&tmp_res, op, f_content, f_context, vm);
                        } else {
                            unimplemented!()
                        }
                    }
                    Instruction_::CommonInst_Unpin(_) => {
                        trace!("instsel on UNPIN");

                        if !mm::GC_MOVES_OBJECT {
                            // do nothing
                        } else {
                            unimplemented!()
                        }
                    }


1153
                    Instruction_::Move(op) => {
qinsoon's avatar
qinsoon committed
1154
1155
                        trace!("instsel on MOVE (internal IR)");

1156
1157
1158
1159
1160
1161
1162
                        let ops = inst.ops.read().unwrap();
                        let ref op = ops[op];

                        let tmp_res = self.get_result_value(node);

                        self.emit_move_node_to_value(&tmp_res, op, f_content, f_context, vm);
                    }
qinsoon's avatar
qinsoon committed
1163
1164
                    
                    Instruction_::New(ref ty) => {
qinsoon's avatar
qinsoon committed
1165
1166
                        trace!("instsel on NEW");

qinsoon's avatar
qinsoon committed
1167
1168
1169
1170
1171
1172
1173
                        if cfg!(debug_assertions) {
                            match ty.v {
                                MuType_::Hybrid(_) => panic!("cannot use NEW for hybrid, use NEWHYBRID instead"),
                                _ => {}
                            }
                        }

qinsoon's avatar
qinsoon committed
1174
                        let ty_info = vm.get_backend_type_info(ty.id());
qinsoon's avatar
qinsoon committed
1175
                        let size = ty_info.size;
1176
                        let ty_align= ty_info.alignment;
qinsoon's avatar
qinsoon committed
1177