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

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
                            },
qinsoon's avatar
qinsoon committed
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);
qinsoon's avatar
qinsoon committed
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];
qinsoon's avatar
qinsoon committed
736

qinsoon's avatar
sdiv    
qinsoon committed
737
                                self.emit_idiv(op1, op2, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
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