inst_sel.rs 139 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::OpCode;
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 12 13
use runtime::ValueLocation;
use runtime::thread;
use runtime::entrypoints;
use runtime::entrypoints::RuntimeEntrypoint;
14 15

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

24
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
25
use std::any::Any;
26

27
pub struct InstructionSelection {
28
    name: &'static str,
29 30
    backend: Box<CodeGenerator>,
    
qinsoon's avatar
qinsoon committed
31
    current_callsite_id: usize,
qinsoon's avatar
qinsoon committed
32 33
    current_frame: Option<Frame>,
    current_block: Option<MuName>,
qinsoon's avatar
qinsoon committed
34 35 36 37 38
    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
    current_exn_blocks: HashMap<MuID, ValueLocation>     
39 40
}

41
impl <'a> InstructionSelection {
qinsoon's avatar
qinsoon committed
42
    #[cfg(feature = "aot")]
43
    pub fn new() -> InstructionSelection {
44 45
        InstructionSelection{
            name: "Instruction Selection (x64)",
46
            backend: Box::new(ASMCodeGen::new()),
qinsoon's avatar
qinsoon committed
47
            
qinsoon's avatar
qinsoon committed
48
            current_callsite_id: 0,
qinsoon's avatar
qinsoon committed
49 50 51
            current_frame: None,
            current_block: None,
            current_func_start: None,
qinsoon's avatar
qinsoon committed
52 53 54
            // key: block id, val: callsite that names the block as exception block
            current_exn_callsites: HashMap::new(), 
            current_exn_blocks: HashMap::new()
55 56
        }
    }
qinsoon's avatar
qinsoon committed
57 58 59 60 61

    #[cfg(feature = "jit")]
    pub fn new() -> InstructionSelection {
        unimplemented!()
    }
62 63 64 65 66 67 68
    
    // in this pass, we assume that
    // 1. all temporaries will use 64bit registers
    // 2. we do not need to backup/restore caller-saved registers
    // 3. we need to backup/restore all the callee-saved registers
    // if any of these assumption breaks, we will need to re-emit the code
    #[allow(unused_variables)]
69
    fn instruction_select(&mut self, node: &'a TreeNode, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) {
qinsoon's avatar
qinsoon committed
70 71 72
        trace!("instsel on node {}", node);
        
        match node.v {
73 74
            TreeNode_::Instruction(ref inst) => {
                match inst.v {
qinsoon's avatar
qinsoon committed
75
                    Instruction_::Branch2{cond, ref true_dest, ref false_dest, true_prob} => {
qinsoon's avatar
qinsoon committed
76
                        trace!("instsel on BRANCH2");
77 78
                        // '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)
79 80 81 82 83
                        let (fallthrough_dest, branch_dest, branch_if_true) = {
                            if true_prob > 0.5f32 {
                                (true_dest, false_dest, false)
                            } else {
                                (false_dest, true_dest, true)
84
                            }
85
                        };
86
                        
qinsoon's avatar
qinsoon committed
87
                        let ops = inst.ops.read().unwrap();
88
                        
89 90
                        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
91
                        
92
                        let branch_target = f_content.get_block(branch_dest.target).name().unwrap();
93 94 95
    
                        let ref cond = ops[cond];
                        
qinsoon's avatar
qinsoon committed
96
                        if self.match_cmp_res(cond) {
97
                            trace!("emit cmp_res-branch2");
98
                            match self.emit_cmp_res(cond, f_content, f_context, vm) {
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 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
                                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
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

                                // 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
215 216 217 218
                                _ => unimplemented!()
                            }
                        } else if self.match_ireg(cond) {
                            trace!("emit ireg-branch2");
219
                            
220
                            let cond_reg = self.emit_ireg(cond, f_content, f_context, vm);
221
                            
qinsoon's avatar
qinsoon committed
222
                            // emit: cmp cond_reg 1
qinsoon's avatar
qinsoon committed
223
                            self.backend.emit_cmp_imm_r(1, &cond_reg);
qinsoon's avatar
qinsoon committed
224
                            // emit: je #branch_dest
225
                            self.backend.emit_je(branch_target);
qinsoon's avatar
qinsoon committed
226 227
                        } else {
                            unimplemented!();
228
                        }
229
                    },
qinsoon's avatar
qinsoon committed
230 231

                    Instruction_::Select{cond, true_val, false_val} => {
qinsoon's avatar
qinsoon committed
232
                        trace!("instsel on SELECT");
qinsoon's avatar
qinsoon committed
233 234 235 236 237 238 239 240 241 242 243 244
                        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);
                            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);

qinsoon's avatar
qinsoon committed
245 246 247
                            // mov tmp_false -> tmp_res
                            self.backend.emit_mov_r_r(&tmp_res, &tmp_false);

qinsoon's avatar
qinsoon committed
248 249 250
                            if self.match_cmp_res(cond) {
                                match self.emit_cmp_res(cond, f_content, f_context, vm) {
                                    op::CmpOp::EQ => {
qinsoon's avatar
qinsoon committed
251
                                        self.backend.emit_cmove_r_r (&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
252 253
                                    }
                                    op::CmpOp::NE => {
qinsoon's avatar
qinsoon committed
254
                                        self.backend.emit_cmovne_r_r(&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
255 256
                                    }
                                    op::CmpOp::SGE => {
qinsoon's avatar
qinsoon committed
257
                                        self.backend.emit_cmovge_r_r(&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
258 259
                                    }
                                    op::CmpOp::SGT => {
qinsoon's avatar
qinsoon committed
260
                                        self.backend.emit_cmovg_r_r (&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
261 262
                                    }
                                    op::CmpOp::SLE => {
qinsoon's avatar
qinsoon committed
263
                                        self.backend.emit_cmovle_r_r(&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
264 265
                                    }
                                    op::CmpOp::SLT => {
qinsoon's avatar
qinsoon committed
266
                                        self.backend.emit_cmovl_r_r (&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
267 268
                                    }
                                    op::CmpOp::UGE => {
qinsoon's avatar
qinsoon committed
269
                                        self.backend.emit_cmovae_r_r(&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
270 271
                                    }
                                    op::CmpOp::UGT => {
qinsoon's avatar
qinsoon committed
272
                                        self.backend.emit_cmova_r_r (&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
273 274
                                    }
                                    op::CmpOp::ULE => {
qinsoon's avatar
qinsoon committed
275
                                        self.backend.emit_cmovbe_r_r(&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
276 277
                                    }
                                    op::CmpOp::ULT => {
qinsoon's avatar
qinsoon committed
278
                                        self.backend.emit_cmovb_r_r (&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
279 280 281 282 283 284
                                    }
                                    _ => panic!("expecting CmpOp for integers")
                                }
                            } else if self.match_ireg(cond) {
                                let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);

qinsoon's avatar
qinsoon committed
285 286 287
                                // emit: mov tmp_false -> tmp_res
                                self.backend.emit_mov_r_r(&tmp_res, &tmp_false);

qinsoon's avatar
qinsoon committed
288
                                // emit: cmp cond_reg 1
qinsoon's avatar
qinsoon committed
289
                                self.backend.emit_cmp_imm_r(1, &tmp_cond);
qinsoon's avatar
qinsoon committed
290 291

                                // emit: cmove tmp_true -> tmp_res
qinsoon's avatar
qinsoon committed
292
                                self.backend.emit_cmove_r_r(&tmp_res, &tmp_true);
qinsoon's avatar
qinsoon committed
293 294 295 296 297 298 299 300 301
                            } else {
                                unimplemented!()
                            }
                        } else {
                            // moving vectors, floatingpoints
                            unimplemented!()
                        }
                    },

302
                    Instruction_::CmpOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
303 304
                        use ast::op::CmpOp::*;

qinsoon's avatar
qinsoon committed
305
                        trace!("instsel on CMPOP");
306 307 308 309
                        let ops = inst.ops.read().unwrap();
                        let ref op1 = ops[op1];
                        let ref op2 = ops[op2];

qinsoon's avatar
qinsoon committed
310
                        let tmp_res = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
311

qinsoon's avatar
qinsoon committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
                        // cmov only take (16/32/64bits registers)
                        // make res64, and set to zero
                        let tmp_res64 = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
                        self.backend.emit_xor_r_r(&tmp_res64, &tmp_res64);

                        // set tmp1 as 1 (cmov doesnt allow immediate or reg8 as operand)
                        let tmp_1 = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
                        self.backend.emit_mov_r_imm(&tmp_1, 1);

                        // cmov 1 to result
                        match self.emit_cmp_res(node, f_content, f_context, vm) {
                            EQ  => self.backend.emit_cmove_r_r (&tmp_res64, &tmp_1),
                            NE  => self.backend.emit_cmovne_r_r(&tmp_res64, &tmp_1),
                            SGE => self.backend.emit_cmovge_r_r(&tmp_res64, &tmp_1),
                            SGT => self.backend.emit_cmovg_r_r (&tmp_res64, &tmp_1),
                            SLE => self.backend.emit_cmovle_r_r(&tmp_res64, &tmp_1),
                            SLT => self.backend.emit_cmovl_r_r (&tmp_res64, &tmp_1),
                            UGE => self.backend.emit_cmovae_r_r(&tmp_res64, &tmp_1),
                            UGT => self.backend.emit_cmova_r_r (&tmp_res64, &tmp_1),
                            ULE => self.backend.emit_cmovbe_r_r(&tmp_res64, &tmp_1),
                            ULT => self.backend.emit_cmovb_r_r (&tmp_res64, &tmp_1),

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

                            _ => unimplemented!()
342
                        }
qinsoon's avatar
qinsoon committed
343 344 345

                        // truncate tmp_res64 to tmp_res (probably u8)
                        self.backend.emit_mov_r_r(&tmp_res, &tmp_res64);
346 347
                    }

qinsoon's avatar
qinsoon committed
348
                    Instruction_::Branch1(ref dest) => {
qinsoon's avatar
qinsoon committed
349
                        trace!("instsel on BRANCH1");
qinsoon's avatar
qinsoon committed
350
                        let ops = inst.ops.read().unwrap();
351
                                            
352
                        self.process_dest(&ops, dest, f_content, f_context, vm);
353
                        
354
                        let target = f_content.get_block(dest.target).name().unwrap();
qinsoon's avatar
qinsoon committed
355
                        
qinsoon's avatar
qinsoon committed
356
                        trace!("emit branch1");
357
                        // jmp
qinsoon's avatar
qinsoon committed
358
                        self.backend.emit_jmp(target);
359
                    },
qinsoon's avatar
qinsoon committed
360 361

                    Instruction_::Switch{cond, ref default, ref branches} => {
qinsoon's avatar
qinsoon committed
362
                        trace!("instsel on SWITCH");
qinsoon's avatar
qinsoon committed
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
                        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
383
                                    self.backend.emit_cmp_imm_r(imm, &tmp_cond);
qinsoon's avatar
qinsoon committed
384 385 386 387 388 389
                                    // 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
390
                                    self.backend.emit_cmp_r_r(&tmp_case_op, &tmp_cond);
qinsoon's avatar
qinsoon committed
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
                                    // je dest
                                    self.backend.emit_je(target);
                                } else {
                                    panic!("expecting ireg cond to be either iimm or ireg: {}", cond);
                                }
                            }

                            // 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);
                        }
                    }
407
                    
qinsoon's avatar
qinsoon committed
408
                    Instruction_::ExprCall{ref data, is_abort} => {
qinsoon's avatar
qinsoon committed
409 410
                        trace!("instsel on EXPRCALL");

qinsoon's avatar
qinsoon committed
411 412
                        if is_abort {
                            unimplemented!()
413
                        }
414
                        
qinsoon's avatar
qinsoon committed
415 416 417 418 419
                        self.emit_mu_call(
                            inst, // inst: &Instruction,
                            data, // calldata: &CallData,
                            None, // resumption: Option<&ResumptionData>,
                            node, // cur_node: &TreeNode, 
420
                            f_content, f_context, vm);
421 422
                    },
                    
qinsoon's avatar
qinsoon committed
423
                    Instruction_::Call{ref data, ref resume} => {
qinsoon's avatar
qinsoon committed
424 425
                        trace!("instsel on CALL");

qinsoon's avatar
qinsoon committed
426 427 428 429 430 431
                        self.emit_mu_call(
                            inst, 
                            data, 
                            Some(resume), 
                            node, 
                            f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
432 433 434
                    },

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

qinsoon's avatar
qinsoon committed
437 438 439 440 441 442 443 444
                        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
445 446
                        trace!("instsel on CCALL");

qinsoon's avatar
qinsoon committed
447
                        self.emit_c_call_ir(inst, data, Some(resume), node, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
448 449
                    }
                    
450
                    Instruction_::Return(_) => {
qinsoon's avatar
qinsoon committed
451 452
                        trace!("instsel on RETURN");

453
                        self.emit_common_epilogue(inst, f_content, f_context, vm);
454
                        
qinsoon's avatar
qinsoon committed
455
                        self.backend.emit_ret();
456 457
                    },
                    
qinsoon's avatar
qinsoon committed
458
                    Instruction_::BinOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
459 460
                        trace!("instsel on BINOP");

qinsoon's avatar
qinsoon committed
461
                        let ops = inst.ops.read().unwrap();
462 463

                        let res_tmp = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
464
                        
465 466
                        match op {
                            op::BinOp::Add => {
qinsoon's avatar
qinsoon committed
467
                                if self.match_ireg(&ops[op1]) && self.match_iimm(&ops[op2]) {
qinsoon's avatar
qinsoon committed
468 469
                                    trace!("emit add-ireg-imm");
                                    
470
                                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
471
                                    let reg_op2 = self.node_iimm_to_i32(&ops[op2]);
qinsoon's avatar
qinsoon committed
472 473
                                    
                                    // mov op1, res
qinsoon's avatar
qinsoon committed
474
                                    self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
qinsoon's avatar
qinsoon committed
475
                                    // add op2, res
qinsoon's avatar
qinsoon committed
476
                                    self.backend.emit_add_r_imm(&res_tmp, reg_op2);
qinsoon's avatar
qinsoon committed
477 478 479
                                } else if self.match_ireg(&ops[op1]) && self.match_mem(&ops[op2]) {
                                    trace!("emit add-ireg-mem");
                                    
480
                                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
qinsoon's avatar
shl  
qinsoon committed
481
                                    let reg_op2 = self.emit_mem(&ops[op2], vm);
qinsoon's avatar
qinsoon committed
482 483
                                    
                                    // mov op1, res
qinsoon's avatar
qinsoon committed
484
                                    self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
qinsoon's avatar
qinsoon committed
485
                                    // add op2 res
qinsoon's avatar
qinsoon committed
486
                                    self.backend.emit_add_r_mem(&res_tmp, &reg_op2);
qinsoon's avatar
qinsoon committed
487 488 489 490 491 492 493
                                } else if self.match_ireg(&ops[op1]) && self.match_ireg(&ops[op2]) {
                                    trace!("emit add-ireg-ireg");

                                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                                    let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);

                                    // mov op1, res
qinsoon's avatar
qinsoon committed
494
                                    self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
qinsoon's avatar
qinsoon committed
495
                                    // add op2 res
qinsoon's avatar
qinsoon committed
496
                                    self.backend.emit_add_r_r(&res_tmp, &reg_op2);
qinsoon's avatar
qinsoon committed
497 498 499
                                } else {
                                    unimplemented!()
                                }
500 501
                            },
                            op::BinOp::Sub => {
502
                                if self.match_ireg(&ops[op1]) && self.match_iimm(&ops[op2]) {
qinsoon's avatar
qinsoon committed
503 504
                                    trace!("emit sub-ireg-imm");

505
                                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
506
                                    let imm_op2 = self.node_iimm_to_i32(&ops[op2]);
qinsoon's avatar
qinsoon committed
507 508
                                    
                                    // mov op1, res
qinsoon's avatar
qinsoon committed
509
                                    self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
qinsoon's avatar
qinsoon committed
510
                                    // add op2, res
qinsoon's avatar
qinsoon committed
511
                                    self.backend.emit_sub_r_imm(&res_tmp, imm_op2);
qinsoon's avatar
qinsoon committed
512 513 514
                                } else if self.match_ireg(&ops[op1]) && self.match_mem(&ops[op2]) {
                                    trace!("emit sub-ireg-mem");
                                    
515
                                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
qinsoon's avatar
shl  
qinsoon committed
516
                                    let mem_op2 = self.emit_mem(&ops[op2], vm);
qinsoon's avatar
qinsoon committed
517 518
                                    
                                    // mov op1, res
qinsoon's avatar
qinsoon committed
519
                                    self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
qinsoon's avatar
qinsoon committed
520
                                    // sub op2 res
qinsoon's avatar
qinsoon committed
521
                                    self.backend.emit_sub_r_mem(&res_tmp, &mem_op2);
522 523
                                } else if self.match_ireg(&ops[op1]) && self.match_ireg(&ops[op2]) {
                                    trace!("emit sub-ireg-ireg");
524

525 526
                                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                                    let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
527

528
                                    // mov op1, res
qinsoon's avatar
qinsoon committed
529
                                    self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
530
                                    // add op2 res
qinsoon's avatar
qinsoon committed
531
                                    self.backend.emit_sub_r_r(&res_tmp, &reg_op2);
qinsoon's avatar
qinsoon committed
532 533 534
                                } else {
                                    unimplemented!()
                                }
535
                            },
536 537 538 539 540 541 542 543 544 545 546
                            op::BinOp::And => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

                                if self.match_ireg(op1) && self.match_iimm(op2) {
                                    trace!("emit and-ireg-iimm");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let imm_op2 = self.node_iimm_to_i32(op2);

                                    // mov op1 -> res
qinsoon's avatar
qinsoon committed
547
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
548
                                    // and op2, res -> res
qinsoon's avatar
qinsoon committed
549
                                    self.backend.emit_and_r_imm(&res_tmp, imm_op2);
550 551 552 553 554 555 556
                                } else if self.match_ireg(op1) && self.match_mem(op2) {
                                    trace!("emit and-ireg-mem");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let mem_op2 = self.emit_mem(op2, vm);

                                    // mov op1, res
qinsoon's avatar
qinsoon committed
557
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
558
                                    // and op2, res -> res
qinsoon's avatar
qinsoon committed
559
                                    self.backend.emit_and_r_mem(&res_tmp, &mem_op2);
560 561 562 563 564 565 566
                                } else if self.match_ireg(op1) && self.match_ireg(op2) {
                                    trace!("emit and-ireg-ireg");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);

                                    // mov op1, res
qinsoon's avatar
qinsoon committed
567
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
568
                                    // and op2, res -> res
qinsoon's avatar
qinsoon committed
569
                                    self.backend.emit_and_r_r(&res_tmp, &tmp_op2);
570 571 572 573
                                } else {
                                    unimplemented!()
                                }
                            },
574 575 576 577 578 579 580 581 582 583 584
                            op::BinOp::Or => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

                                if self.match_ireg(op1) && self.match_iimm(op2) {
                                    trace!("emit or-ireg-iimm");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let imm_op2 = self.node_iimm_to_i32(op2);

                                    // mov op1 -> res
qinsoon's avatar
qinsoon committed
585
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
586
                                    // Or op2, res -> res
qinsoon's avatar
qinsoon committed
587
                                    self.backend.emit_or_r_imm(&res_tmp, imm_op2);
588 589 590 591 592 593 594
                                } else if self.match_ireg(op1) && self.match_mem(op2) {
                                    trace!("emit or-ireg-mem");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let mem_op2 = self.emit_mem(op2, vm);

                                    // mov op1, res
qinsoon's avatar
qinsoon committed
595
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
596
                                    // Or op2, res -> res
qinsoon's avatar
qinsoon committed
597
                                    self.backend.emit_or_r_mem(&res_tmp, &mem_op2);
598 599 600 601 602 603 604
                                } else if self.match_ireg(op1) && self.match_ireg(op2) {
                                    trace!("emit or-ireg-ireg");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);

                                    // mov op1, res
qinsoon's avatar
qinsoon committed
605
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
606
                                    // Or op2, res -> res
qinsoon's avatar
qinsoon committed
607
                                    self.backend.emit_or_r_r(&res_tmp, &tmp_op2);
608 609 610 611
                                } else {
                                    unimplemented!()
                                }
                            },
612 613 614 615 616 617 618 619 620 621 622
                            op::BinOp::Xor => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

                                if self.match_ireg(op1) && self.match_iimm(op2) {
                                    trace!("emit xor-ireg-iimm");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let imm_op2 = self.node_iimm_to_i32(op2);

                                    // mov op1 -> res
qinsoon's avatar
qinsoon committed
623
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
624
                                    // xor op2, res -> res
qinsoon's avatar
qinsoon committed
625
                                    self.backend.emit_xor_r_imm(&res_tmp, imm_op2);
626 627 628 629 630 631 632
                                } else if self.match_ireg(op1) && self.match_mem(op2) {
                                    trace!("emit xor-ireg-mem");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let mem_op2 = self.emit_mem(op2, vm);

                                    // mov op1, res
qinsoon's avatar
qinsoon committed
633
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
634
                                    // xor op2, res -> res
qinsoon's avatar
qinsoon committed
635
                                    self.backend.emit_xor_r_mem(&res_tmp, &mem_op2);
636 637 638 639 640 641 642
                                } else if self.match_ireg(op1) && self.match_ireg(op2) {
                                    trace!("emit xor-ireg-ireg");

                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
                                    let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);

                                    // mov op1, res
qinsoon's avatar
qinsoon committed
643
                                    self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
644
                                    // xor op2, res -> res
qinsoon's avatar
qinsoon committed
645
                                    self.backend.emit_xor_r_r(&res_tmp, &tmp_op2);
646 647 648 649
                                } else {
                                    unimplemented!()
                                }
                            }
650
                            op::BinOp::Mul => {
651 652
                                // mov op1 -> rax
                                let op1 = &ops[op1];
qinsoon's avatar
qinsoon committed
653 654 655 656 657 658 659 660 661

                                let mreg_op1 = match op1.clone_value().ty.get_int_length() {
                                    Some(64) => x86_64::RAX.clone(),
                                    Some(32) => x86_64::EAX.clone(),
                                    Some(16) => x86_64::AX.clone(),
                                    Some(8)  => x86_64::AL.clone(),
                                    _ => unimplemented!()
                                };

662
                                if self.match_iimm(op1) {
663
                                    let imm_op1 = self.node_iimm_to_i32(op1);
664
                                    
qinsoon's avatar
qinsoon committed
665
                                    self.backend.emit_mov_r_imm(&mreg_op1, imm_op1);
666
                                } else if self.match_mem(op1) {
qinsoon's avatar
shl  
qinsoon committed
667
                                    let mem_op1 = self.emit_mem(op1, vm);
668
                                    
qinsoon's avatar
qinsoon committed
669
                                    self.backend.emit_mov_r_mem(&mreg_op1, &mem_op1);
670 671 672
                                } else if self.match_ireg(op1) {
                                    let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);

qinsoon's avatar
qinsoon committed
673
                                    self.backend.emit_mov_r_r(&mreg_op1, &reg_op1);
674 675 676 677
                                } else {
                                    unimplemented!();
                                }
                                
qinsoon's avatar
qinsoon committed
678
                                // mul op2
679
                                let op2 = &ops[op2];
680
                                if self.match_iimm(op2) {
681
                                    let imm_op2 = self.node_iimm_to_i32(op2);
682 683 684
                                    
                                    // put imm in a temporary
                                    // here we use result reg as temporary
qinsoon's avatar
qinsoon committed
685
                                    self.backend.emit_mov_r_imm(&res_tmp, imm_op2);
686
                                    
qinsoon's avatar
qinsoon committed
687
                                    self.backend.emit_mul_r(&res_tmp);
688
                                } else if self.match_mem(op2) {
qinsoon's avatar
shl  
qinsoon committed
689
                                    let mem_op2 = self.emit_mem(op2, vm);
690
                                    
qinsoon's avatar
qinsoon committed
691
                                    self.backend.emit_mul_mem(&mem_op2);
692 693 694
                                } else if self.match_ireg(op2) {
                                    let reg_op2 = self.emit_ireg(op2, f_content, f_context, vm);

qinsoon's avatar
qinsoon committed
695
                                    self.backend.emit_mul_r(&reg_op2);
696 697 698 699 700
                                } else {
                                    unimplemented!();
                                }
                                
                                // mov rax -> result
qinsoon's avatar
qinsoon committed
701 702 703 704 705 706 707 708
                                match res_tmp.ty.get_int_length() {
                                    Some(64) => self.backend.emit_mov_r_r(&res_tmp, &x86_64::RAX),
                                    Some(32) => self.backend.emit_mov_r_r(&res_tmp, &x86_64::EAX),
                                    Some(16) => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AX),
                                    Some(8)  => self.backend.emit_mov_r_r(&res_tmp, &x86_64::AL),
                                    _ => unimplemented!()
                                }

709
                            },
710 711 712 713
                            op::BinOp::Udiv => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

qinsoon's avatar
sdiv  
qinsoon committed
714
                                self.emit_udiv(op1, op2, f_content, f_context, vm);
715

qinsoon's avatar
sdiv  
qinsoon committed
716
                                // mov rax -> result
qinsoon's avatar
qinsoon committed
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
                                match res_tmp.ty.get_int_length() {
                                    Some(64) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::RAX);
                                    }
                                    Some(32) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::EAX);
                                    }
                                    Some(16) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::AX);
                                    }
                                    Some(8)  => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::AL);
                                    }
                                    _ => unimplemented!()
                                }
qinsoon's avatar
sdiv  
qinsoon committed
732 733 734 735
                            },
                            op::BinOp::Sdiv => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];
736

qinsoon's avatar
sdiv  
qinsoon committed
737
                                self.emit_idiv(op1, op2, f_content, f_context, vm);
738 739

                                // mov rax -> result
qinsoon's avatar
qinsoon committed
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
                                match res_tmp.ty.get_int_length() {
                                    Some(64) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::RAX);
                                    }
                                    Some(32) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::EAX);
                                    }
                                    Some(16) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::AX);
                                    }
                                    Some(8)  => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::AL);
                                    }
                                    _ => unimplemented!()
                                }
qinsoon's avatar
sdiv  
qinsoon committed
755
                            },
qinsoon's avatar
qinsoon committed
756 757 758 759 760 761 762
                            op::BinOp::Urem => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

                                self.emit_udiv(op1, op2, f_content, f_context, vm);

                                // mov rdx -> result
qinsoon's avatar
qinsoon committed
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
                                match res_tmp.ty.get_int_length() {
                                    Some(64) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::RDX);
                                    }
                                    Some(32) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::EDX);
                                    }
                                    Some(16) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::DX);
                                    }
                                    Some(8)  => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::AH);
                                    }
                                    _ => unimplemented!()
                                }
qinsoon's avatar
qinsoon committed
778 779 780 781 782 783 784 785
                            },
                            op::BinOp::Srem => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

                                self.emit_idiv(op1, op2, f_content, f_context, vm);

                                // mov rdx -> result
qinsoon's avatar
qinsoon committed
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
                                match res_tmp.ty.get_int_length() {
                                    Some(64) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::RDX);
                                    }
                                    Some(32) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::EDX);
                                    }
                                    Some(16) => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::DX);
                                    }
                                    Some(8)  => {
                                        self.backend.emit_mov_r_r(&res_tmp, &x86_64::AH);
                                    }
                                    _ => unimplemented!()
                                }
qinsoon's avatar
qinsoon committed
801
                            },
qinsoon's avatar
qinsoon committed
802

qinsoon's avatar
shl  
qinsoon committed
803 804 805 806
                            op::BinOp::Shl => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

807 808 809
                                if self.match_mem(op1) {
                                    unimplemented!()
                                } else if self.match_ireg(op1) {
qinsoon's avatar
shl  
qinsoon committed
810 811
                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);

812 813 814 815
                                    if self.match_iimm(op2) {
                                        let imm_op2 = self.node_iimm_to_i32(op2) as i8;

                                        // shl op1, op2 -> op1
qinsoon's avatar
qinsoon committed
816
                                        self.backend.emit_shl_r_imm8(&tmp_op1, imm_op2);
817 818

                                        // mov op1 -> result
qinsoon's avatar
qinsoon committed
819
                                        self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
820
                                    } else if self.match_ireg(op2) {
qinsoon's avatar
shl  
qinsoon committed
821 822
                                        let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);

qinsoon's avatar
qinsoon committed
823 824
                                        // mov op2 -> cl
                                        self.backend.emit_mov_r_r(&x86_64::CL, &tmp_op2);
qinsoon's avatar
shl  
qinsoon committed
825 826

                                        // shl op1, cl -> op1
qinsoon's avatar
qinsoon committed
827
                                        self.backend.emit_shl_r_cl(&tmp_op1);
qinsoon's avatar
shl  
qinsoon committed
828 829

                                        // mov op1 -> result
qinsoon's avatar
qinsoon committed
830
                                        self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
qinsoon's avatar
shl  
qinsoon committed
831 832 833
                                    } else {
                                        panic!("unexpected op2 (not ireg not iimm): {}", op2);
                                    }
834 835
                                } else {
                                    panic!("unexpected op1 (not ireg not mem): {}", op1);
qinsoon's avatar
shl  
qinsoon committed
836
                                }
qinsoon's avatar
qinsoon committed
837 838 839 840 841
                            },
                            op::BinOp::Lshr => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

842 843 844
                                if self.match_mem(op1) {
                                    unimplemented!()
                                } else if self.match_ireg(op1) {
qinsoon's avatar
qinsoon committed
845 846
                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);

847 848 849 850
                                    if self.match_iimm(op2) {
                                        let imm_op2 = self.node_iimm_to_i32(op2) as i8;

                                        // shr op1, op2 -> op1
qinsoon's avatar
qinsoon committed
851
                                        self.backend.emit_shr_r_imm8(&tmp_op1, imm_op2);
852 853

                                        // mov op1 -> result
qinsoon's avatar
qinsoon committed
854
                                        self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
855
                                    } else if self.match_ireg(op2) {
qinsoon's avatar
qinsoon committed
856 857
                                        let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);

qinsoon's avatar
qinsoon committed
858 859
                                        // mov op2 -> cl
                                        self.backend.emit_mov_r_r(&x86_64::CL, &tmp_op2);
qinsoon's avatar
qinsoon committed
860 861

                                        // shr op1, cl -> op1
qinsoon's avatar
qinsoon committed
862
                                        self.backend.emit_shr_r_cl(&tmp_op1);
qinsoon's avatar
qinsoon committed
863 864

                                        // mov op1 -> result
qinsoon's avatar
qinsoon committed
865
                                        self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
qinsoon's avatar
qinsoon committed
866 867 868
                                    } else {
                                        panic!("unexpected op2 (not ireg not iimm): {}", op2);
                                    }
869 870
                                } else {
                                    panic!("unexpected op1 (not ireg not mem): {}", op1);
qinsoon's avatar
qinsoon committed
871 872 873 874 875 876
                                }
                            },
                            op::BinOp::Ashr => {
                                let op1 = &ops[op1];
                                let op2 = &ops[op2];

877 878 879
                                if self.match_mem(op1) {
                                    unimplemented!()
                                } else if self.match_ireg(op1) {
qinsoon's avatar
qinsoon committed
880 881
                                    let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);

882 883 884 885
                                    if self.match_iimm(op2) {
                                        let imm_op2 = self.node_iimm_to_i32(op2) as i8;

                                        // sar op1, op2 -> op1
qinsoon's avatar
qinsoon committed
886
                                        self.backend.emit_sar_r_imm8(&tmp_op1, imm_op2);
887 888

                                        // mov op1 -> result
qinsoon's avatar
qinsoon committed
889
                                        self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
890
                                    } else if self.match_ireg(op2) {
qinsoon's avatar
qinsoon committed
891 892
                                        let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);

qinsoon's avatar
qinsoon committed
893 894
                                        // mov op2 -> cl
                                        self.backend.emit_mov_r_r(&x86_64::CL, &tmp_op2);
qinsoon's avatar
qinsoon committed
895 896

                                        // sar op1, cl -> op1
qinsoon's avatar
qinsoon committed
897
                                        self.backend.emit_sar_r_cl(&tmp_op1);
qinsoon's avatar
qinsoon committed
898 899

                                        // mov op1 -> result
qinsoon's avatar
qinsoon committed
900
                                        self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
901
                                    } else  {
qinsoon's avatar
qinsoon committed
902 903
                                        panic!("unexpected op2 (not ireg not iimm): {}", op2);
                                    }
904 905
                                } else {
                                    panic!("unexpected op1 (not ireg not mem): {}", op1);
qinsoon's avatar
qinsoon committed
906 907 908
                                }
                            },

qinsoon's avatar
shl  
qinsoon committed
909

qinsoon's avatar
qinsoon committed
910 911
                            // floating point
                            op::BinOp::FAdd => {
912
                                if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
qinsoon's avatar
qinsoon committed
913 914 915
                                    trace!("emit add-fpreg-mem");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
qinsoon's avatar
shl  
qinsoon committed
916
                                    let mem_op2 = self.emit_mem(&ops[op2], vm);
qinsoon's avatar
qinsoon committed
917 918 919 920 921

                                    // mov op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // sub op2 res
                                    self.backend.emit_addsd_f64_mem64(&res_tmp, &mem_op2);
922 923 924 925 926 927 928 929 930 931
                                } else if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
                                    trace!("emit add-fpreg-fpreg");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);

                                    // movsd op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // add op2 res
                                    self.backend.emit_addsd_f64_f64(&res_tmp, &reg_op2);
qinsoon's avatar
qinsoon committed
932
                                } else {
qinsoon's avatar
qinsoon committed
933 934 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 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
                                    panic!("unexpected fadd: {}", node)
                                }
                            }

                            op::BinOp::FSub => {
                                if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
                                    trace!("emit sub-fpreg-mem");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let mem_op2 = self.emit_mem(&ops[op2], vm);

                                    // mov op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // sub op2 res
                                    self.backend.emit_subsd_f64_mem64(&res_tmp, &mem_op2);
                                } else if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
                                    trace!("emit sub-fpreg-fpreg");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);

                                    // movsd op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // sub op2 res
                                    self.backend.emit_subsd_f64_f64(&res_tmp, &reg_op2);
                                } else {
                                    panic!("unexpected fsub: {}", node)
                                }
                            }

                            op::BinOp::FMul => {
                                if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
                                    trace!("emit mul-fpreg-mem");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let mem_op2 = self.emit_mem(&ops[op2], vm);

                                    // mov op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // mul op2 res
                                    self.backend.emit_mulsd_f64_mem64(&res_tmp, &mem_op2);
                                } else if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
                                    trace!("emit mul-fpreg-fpreg");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);

                                    // movsd op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // mul op2 res
                                    self.backend.emit_mulsd_f64_f64(&res_tmp, &reg_op2);
                                } else {
                                    panic!("unexpected fmul: {}", node)
                                }
                            }

                            op::BinOp::FDiv => {
                                if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
                                    trace!("emit div-fpreg-mem");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let mem_op2 = self.emit_mem(&ops[op2], vm);

                                    // mov op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // div op2 res
                                    self.backend.emit_divsd_f64_mem64(&res_tmp, &mem_op2);
                                } else if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
                                    trace!("emit div-fpreg-fpreg");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);

                                    // movsd op1, res
                                    self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
                                    // div op2 res
                                    self.backend.emit_divsd_f64_f64(&res_tmp, &reg_op2);
                                } else {
                                    panic!("unexpected fdiv: {}", node)
qinsoon's avatar
qinsoon committed
1012 1013
                                }
                            }
qinsoon's avatar
qinsoon committed
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028

                            op::BinOp::FRem => {
                                if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
                                    trace!("emit frem-fpreg-fpreg");

                                    let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
                                    let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);

                                    let reg_tmp = self.get_result_value(node);

                                    self.emit_runtime_entry(&entrypoints::FREM, vec![reg_op1.clone(), reg_op2.clone()], Some(vec![reg_tmp.clone()]), Some(node), f_content, f_context, vm);
                                } else {
                                    panic!("unexpected fdiv: {}", node)
                                }
                            }
1029 1030
                        }
                    }
qinsoon's avatar
qinsoon committed
1031 1032

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

qinsoon's avatar
qinsoon committed
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
                        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);
                                    let tmp_res = self.get_result_value(node);

                                    // mov op -> result
qinsoon's avatar
qinsoon committed
1046
                                    self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
1047 1048 1049 1050 1051
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
                                }
                            }
                            op::ConvOp::ZEXT => {
1052 1053 1054
                                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
1055

1056 1057 1058
                                    // 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
1059

1060
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
                                        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
1074
                                    } else {
1075
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
1076
                                    }
1077 1078
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
qinsoon's avatar
qinsoon committed
1079 1080 1081
                                }
                            },
                            op::ConvOp::SEXT => {
1082 1083 1084
                                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
1085

1086 1087 1088
                                    // 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
1089

1090
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
1091 1092
                                        self.backend.emit_movs_r_r(&tmp_res, &tmp_op);
                                    } else {
1093
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
1094
                                    }
1095 1096
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
qinsoon's avatar
qinsoon committed
1097 1098
                                }
                            }
1099 1100 1101 1102 1103 1104
                            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
1105
                                    self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
1106 1107 1108 1109
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
                                }
                            }
qinsoon's avatar
qinsoon committed
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
                            op::ConvOp::SITOFP => {
                                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);
                                    self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp_op);
                                } else {
                                    panic!("unexpected op (expected ireg): {}", op)
                                }
                            }
                            op::ConvOp::FPTOSI => {
                                let tmp_res = self.get_result_value(node);

                                if self.match_fpreg(op) {
                                    let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);
                                    self.backend.emit_cvtsd2si_r_f64(&tmp_res, &tmp_op);
                                } else {
                                    panic!("unexpected op (expected fpreg): {}", op)
                                }
                            }
qinsoon's avatar
qinsoon committed
1130 1131 1132 1133

                            _ => unimplemented!()
                        }
                    }
1134
                    
1135 1136
                    // load on x64 generates mov inst (no matter what order is specified)
                    // https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
1137
                    Instruction_::Load{is_ptr, order, mem_loc} => {
qinsoon's avatar
qinsoon committed
1138 1139
                        trace!("instsel on LOAD");

qinsoon's avatar
qinsoon committed
1140
                        let ops = inst.ops.read().unwrap();
1141
                        let ref loc_op = ops[mem_loc];
1142 1143 1144 1145 1146 1147
                        
                        // check order
                        match order {
                            MemoryOrder::Relaxed 
                            | MemoryOrder::Consume 
                            | MemoryOrder::Acquire
1148 1149
                            | MemoryOrder::SeqCst
                            | MemoryOrder::NotAtomic => {},
1150 1151
                            _ => panic!("didnt expect order {:?} with store inst", order)
                        }                        
1152

1153
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
1154
                        let res_temp = self.get_result_value(node);
1155 1156 1157
                        
                        if self.match_ireg(node) {
                            // emit mov(GPR)
qinsoon's avatar
qinsoon committed
1158
                            self.backend.emit_mov_r_mem(&res_temp, &resolved_loc);
1159 1160 1161 1162 1163 1164 1165
                        } else {
                            // emit mov(FPR)
                            unimplemented!()
                        }
                    }
                    
                    Instruction_::Store{is_ptr, order, mem_loc, value}