GitLab will be upgraded on 31 Jan 2023 from 2.00 pm (AEDT) to 3.00 pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

inst_sel.rs 224 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright 2017 The Australian National University
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15
use ast::ir::*;
16
use ast::ptr::*;
qinsoon's avatar
qinsoon committed
17
use ast::inst::*;
18
use ast::op;
qinsoon's avatar
qinsoon committed
19
use ast::op::*;
qinsoon's avatar
qinsoon committed
20
use ast::types;
qinsoon's avatar
qinsoon committed
21
use ast::types::*;
qinsoon's avatar
qinsoon committed
22
use vm::VM;
qinsoon's avatar
qinsoon committed
23
use runtime::mm;
24
25
use runtime::mm::objectmodel::OBJECT_HEADER_SIZE;
use runtime::mm::objectmodel::OBJECT_HEADER_OFFSET;
26
27
28
29
use runtime::ValueLocation;
use runtime::thread;
use runtime::entrypoints;
use runtime::entrypoints::RuntimeEntrypoint;
30
31

use compiler::CompilerPass;
32
use compiler::backend;
33
use compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
34
use compiler::backend::PROLOGUE_BLOCK_NAME;
qinsoon's avatar
qinsoon committed
35
36
37
use compiler::backend::x86_64;
use compiler::backend::x86_64::CodeGenerator;
use compiler::backend::x86_64::ASMCodeGen;
qinsoon's avatar
qinsoon committed
38
39
use compiler::machine_code::CompiledFunction;
use compiler::frame::Frame;
40

41
use utils::math;
qinsoon's avatar
qinsoon committed
42
use utils::POINTER_SIZE;
43

44
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
45
use std::any::Any;
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
lazy_static! {
    pub static ref LONG_4_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::mustruct(Mu("long_4"), vec![UINT32_TYPE.clone(); 4]))
    );

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

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

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

qinsoon's avatar
qinsoon committed
100
101
    pub static ref FPTOUI_C_DOUBLE : P<Value> = P(Value{
        hdr: MuEntityHeader::named(new_internal_id(), Mu("FPTOUI_C_DOUBLE")),
102
103
104
        ty : UINT64_TYPE.clone(),
        v  : Value_::Constant(Constant::Int(4890909195324358656u64))
    });
qinsoon's avatar
qinsoon committed
105
106
107
108
109
110

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

113
114
const INLINE_FASTPATH : bool = false;

115
pub struct InstructionSelection {
116
    name: &'static str,
117
    backend: Box<CodeGenerator>,
118
119

    current_fv_id: MuID,
qinsoon's avatar
qinsoon committed
120
    current_callsite_id: usize,
qinsoon's avatar
qinsoon committed
121
122
    current_frame: Option<Frame>,
    current_block: Option<MuName>,
123
    current_block_in_ir: Option<MuName>,
qinsoon's avatar
qinsoon committed
124
125
126
127
    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
128
129
130
131
    current_exn_blocks: HashMap<MuID, ValueLocation>,

    current_constants: HashMap<MuID, P<Value>>,
    current_constants_locs: HashMap<MuID, P<Value>>
132
133
}

134
impl <'a> InstructionSelection {
qinsoon's avatar
qinsoon committed
135
    #[cfg(feature = "aot")]
136
    pub fn new() -> InstructionSelection {
137
138
        InstructionSelection{
            name: "Instruction Selection (x64)",
139
            backend: Box::new(ASMCodeGen::new()),
140

141
            current_fv_id: 0,
qinsoon's avatar
qinsoon committed
142
            current_callsite_id: 0,
qinsoon's avatar
qinsoon committed
143
            current_frame: None,
144
145
146
147
148
149
150
            current_block: None,        // which block we are generating code for
            current_block_in_ir: None,  // it is possible the block is newly created in instruction selection
                                        // but sometimes we want to know its control flow
                                        // so we need to track what block it is from the IR

                                        // FIXME: ideally we should not create new blocks in instruction selection
                                        // see Issue #6
qinsoon's avatar
qinsoon committed
151
            current_func_start: None,
qinsoon's avatar
qinsoon committed
152
153
            // key: block id, val: callsite that names the block as exception block
            current_exn_callsites: HashMap::new(), 
154
155
156
157
            current_exn_blocks: HashMap::new(),

            current_constants: HashMap::new(),
            current_constants_locs: HashMap::new()
158
159
        }
    }
qinsoon's avatar
qinsoon committed
160
161
162
163
164

    #[cfg(feature = "jit")]
    pub fn new() -> InstructionSelection {
        unimplemented!()
    }
165
166
    
    // in this pass, we assume that
qinsoon's avatar
qinsoon committed
167
    // * we do not need to backup/restore caller-saved registers
168
169
    // if any of these assumption breaks, we will need to re-emit the code
    #[allow(unused_variables)]
170
    fn instruction_select(&mut self, node: &'a TreeNode, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) {
171
        trace!("instsel on node#{} {}", node.id(), node);
qinsoon's avatar
qinsoon committed
172
173
        
        match node.v {
174
175
            TreeNode_::Instruction(ref inst) => {
                match inst.v {
qinsoon's avatar
qinsoon committed
176
                    Instruction_::Branch2{cond, ref true_dest, ref false_dest, true_prob} => {
qinsoon's avatar
qinsoon committed
177
                        trace!("instsel on BRANCH2");
178
179
                        // '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)
180
                        let (fallthrough_dest, branch_dest, branch_if_true) = {
181
                            // get current block and next block in trace (fallthrough block)
182
                            let cur_block = f_content.get_block_by_name(self.current_block_in_ir.as_ref().unwrap().clone());
183
184
185
                            let next_block_in_trace = cur_block.control_flow.get_hottest_succ().unwrap();

                            if next_block_in_trace == true_dest.target {
186
187
188
                                (true_dest, false_dest, false)
                            } else {
                                (false_dest, true_dest, true)
189
                            }
190
                        };
191
                        
192
                        let ref ops = inst.ops;
193
                        
194
195
                        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
196
                        
197
                        let branch_target = f_content.get_block(branch_dest.target).name().unwrap();
198
199
200
    
                        let ref cond = ops[cond];
                        
qinsoon's avatar
qinsoon committed
201
                        if self.match_cmp_res(cond) {
202
                            trace!("emit cmp_res-branch2");
203
                            match self.emit_cmp_res(cond, f_content, f_context, vm) {
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
                                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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319

                                // 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
320
321
322
323
                                _ => unimplemented!()
                            }
                        } else if self.match_ireg(cond) {
                            trace!("emit ireg-branch2");
324
                            
325
                            let cond_reg = self.emit_ireg(cond, f_content, f_context, vm);
326
                            
qinsoon's avatar
qinsoon committed
327
                            // emit: cmp cond_reg 1
qinsoon's avatar
qinsoon committed
328
                            self.backend.emit_cmp_imm_r(1, &cond_reg);
qinsoon's avatar
qinsoon committed
329
                            // emit: je #branch_dest
330
331
332
333
334
                            if branch_if_true {
                                self.backend.emit_je(branch_target);
                            } else {
                                self.backend.emit_jne(branch_target);
                            }
qinsoon's avatar
qinsoon committed
335
336
                        } else {
                            unimplemented!();
337
                        }
338
339
340
341
342
343
344
345
346
347

                        // it is possible that the fallthrough block is scheduled somewhere else
                        // we need to explicitly jump to it
                        self.finish_block();

                        let fallthrough_temp_block = format!("{}_{}_branch_fallthrough", self.current_fv_id, node.id());
                        self.start_block(fallthrough_temp_block);

                        let fallthrough_target = f_content.get_block(fallthrough_dest.target).name().unwrap();
                        self.backend.emit_jmp(fallthrough_target);
348
                    },
qinsoon's avatar
qinsoon committed
349
350

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

qinsoon's avatar
qinsoon committed
353
                        trace!("instsel on SELECT");
354
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
355
356
357
358
359

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

360
361
362
363
364
365
366
367
368
369
370
371
372
                        // generate compare
                        let cmpop = if self.match_cmp_res(cond) {
                            self.emit_cmp_res(cond, f_content, f_context, vm)
                        } else if self.match_ireg(cond) {
                            let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);
                            // emit: cmp cond_reg 1
                            self.backend.emit_cmp_imm_r(1, &tmp_cond);

                            EQ
                        } else {
                            panic!("expected cond to be ireg, found {}", cond)
                        };

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

377
                            // use cmov for 16/32/64bit integer
qinsoon's avatar
qinsoon committed
378
                            // use jcc  for 8 bit
379
                            // FIXME: could use 32bit register to implement 8bit select
qinsoon's avatar
qinsoon committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
                            match tmp_res.ty.get_int_length() {
                                // cmov
                                Some(len) if len > 8 => {
                                    let tmp_true  = self.emit_ireg(true_val, f_content, f_context, vm);
                                    let tmp_false = self.emit_ireg(false_val, f_content, f_context, vm);

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

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

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

                                        _ => unimplemented!()
                                    }
                                }
                                // jcc
                                _ => {
413
414
415
                                    let blk_true  = format!("{}_{}_select_true",  self.current_fv_id, node.id());
                                    let blk_false = format!("{}_{}_select_false", self.current_fv_id, node.id());
                                    let blk_end   = format!("{}_{}_select_end",   self.current_fv_id, node.id());
qinsoon's avatar
qinsoon committed
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439

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

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

                                        _ => unimplemented!()
                                    }

440
                                    // finishing current block
qinsoon's avatar
qinsoon committed
441
                                    self.finish_block();
442
443

                                    // blk_false:
qinsoon's avatar
qinsoon committed
444
                                    self.start_block(blk_false.clone());
qinsoon's avatar
qinsoon committed
445
446
447
448
449
450
                                    // mov false result here
                                    self.emit_move_node_to_value(&tmp_res, &false_val, f_content, f_context, vm);
                                    // jmp to end
                                    self.backend.emit_jmp(blk_end.clone());

                                    // finishing current block
qinsoon's avatar
qinsoon committed
451
                                    self.finish_block();
qinsoon's avatar
qinsoon committed
452
453

                                    // blk_true:
qinsoon's avatar
qinsoon committed
454
                                    self.start_block(blk_true.clone());
qinsoon's avatar
qinsoon committed
455
456
                                    // mov true value -> result
                                    self.emit_move_node_to_value(&tmp_res, &true_val, f_content, f_context, vm);
457
                                    self.finish_block();
qinsoon's avatar
qinsoon committed
458
459

                                    // blk_end:
460
                                    self.start_block(blk_end.clone());
qinsoon's avatar
qinsoon committed
461
                                }
qinsoon's avatar
qinsoon committed
462
                            }
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
                        } else if self.match_fpreg(true_val) {
                            let tmp_res = self.get_result_value(node);

                            let blk_true  = format!("{}_{}_select_true",  self.current_fv_id, node.id());
                            let blk_false = format!("{}_{}_select_false", self.current_fv_id, node.id());
                            let blk_end   = format!("{}_{}_select_end",   self.current_fv_id, node.id());

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

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

                                _ => unimplemented!()
                            }

                            // finishing current block
qinsoon's avatar
qinsoon committed
494
                            self.finish_block();
495
496

                            // blk_false:
qinsoon's avatar
qinsoon committed
497
                            self.start_block(blk_false.clone());
498
499
500
501
502
503
                            // mov false result here
                            self.emit_move_node_to_value(&tmp_res, &false_val, f_content, f_context, vm);
                            // jmp to end
                            self.backend.emit_jmp(blk_end.clone());

                            // finishing current block
qinsoon's avatar
qinsoon committed
504
                            self.finish_block();
505
506

                            // blk_true:
qinsoon's avatar
qinsoon committed
507
                            self.start_block(blk_true.clone());
508
509
                            // mov true value -> result
                            self.emit_move_node_to_value(&tmp_res, &true_val, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
510
                            self.finish_block();
511
512

                            // blk_end:
qinsoon's avatar
qinsoon committed
513
                            self.start_block(blk_end.clone());
qinsoon's avatar
qinsoon committed
514
515
516
517
518
                        } else {
                            unimplemented!()
                        }
                    },

519
                    Instruction_::CmpOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
520
521
                        use ast::op::CmpOp::*;

qinsoon's avatar
qinsoon committed
522
                        trace!("instsel on CMPOP");
523
                        let ref ops = inst.ops;
524
525
526
                        let ref op1 = ops[op1];
                        let ref op2 = ops[op2];

qinsoon's avatar
qinsoon committed
527
                        let tmp_res = self.get_result_value(node);
528
529
530
                        
                        debug_assert!(tmp_res.ty.get_int_length().is_some());
                        debug_assert!(tmp_res.ty.get_int_length().unwrap() == 1);
qinsoon's avatar
qinsoon committed
531

532
                        // set byte to result
qinsoon's avatar
qinsoon committed
533
                        match self.emit_cmp_res(node, f_content, f_context, vm) {
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
                            EQ  => self.backend.emit_sete_r (&tmp_res),
                            NE  => self.backend.emit_setne_r(&tmp_res),
                            SGE => self.backend.emit_setge_r(&tmp_res),
                            SGT => self.backend.emit_setg_r (&tmp_res),
                            SLE => self.backend.emit_setle_r(&tmp_res),
                            SLT => self.backend.emit_setl_r (&tmp_res),
                            UGE => self.backend.emit_setae_r(&tmp_res),
                            UGT => self.backend.emit_seta_r (&tmp_res),
                            ULE => self.backend.emit_setbe_r(&tmp_res),
                            ULT => self.backend.emit_setb_r (&tmp_res),

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

                            _ => unimplemented!()
553
554
555
                        }
                    }

qinsoon's avatar
qinsoon committed
556
                    Instruction_::Branch1(ref dest) => {
qinsoon's avatar
qinsoon committed
557
                        trace!("instsel on BRANCH1");
558
                        let ref ops = inst.ops;
559
                                            
560
                        self.process_dest(&ops, dest, f_content, f_context, vm);
561
                        
562
                        let target = f_content.get_block(dest.target).name().unwrap();
qinsoon's avatar
qinsoon committed
563
                        
qinsoon's avatar
qinsoon committed
564
                        trace!("emit branch1");
565
                        // jmp
qinsoon's avatar
qinsoon committed
566
                        self.backend.emit_jmp(target);
567
                    },
qinsoon's avatar
qinsoon committed
568
569

                    Instruction_::Switch{cond, ref default, ref branches} => {
qinsoon's avatar
qinsoon committed
570
                        trace!("instsel on SWITCH");
571
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590

                        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
591
                                    self.backend.emit_cmp_imm_r(imm, &tmp_cond);
qinsoon's avatar
qinsoon committed
592
593
594
595
596
597
                                    // 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
598
                                    self.backend.emit_cmp_r_r(&tmp_case_op, &tmp_cond);
qinsoon's avatar
qinsoon committed
599
600
601
602
603
                                    // je dest
                                    self.backend.emit_je(target);
                                } else {
                                    panic!("expecting ireg cond to be either iimm or ireg: {}", cond);
                                }
604
605
606

                                self.finish_block();
                                self.start_block(format!("{}_switch_not_met_case_{}", node.id(), case_op_index));
qinsoon's avatar
qinsoon committed
607
608
609
610
611
612
613
614
615
616
617
                            }

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

qinsoon's avatar
qinsoon committed
622
623
                        if is_abort {
                            unimplemented!()
624
                        }
625
                        
qinsoon's avatar
qinsoon committed
626
627
628
629
630
                        self.emit_mu_call(
                            inst, // inst: &Instruction,
                            data, // calldata: &CallData,
                            None, // resumption: Option<&ResumptionData>,
                            node, // cur_node: &TreeNode, 
631
                            f_content, f_context, vm);
632
633
                    },
                    
qinsoon's avatar
qinsoon committed
634
                    Instruction_::Call{ref data, ref resume} => {
qinsoon's avatar
qinsoon committed
635
636
                        trace!("instsel on CALL");

qinsoon's avatar
qinsoon committed
637
638
639
640
641
642
                        self.emit_mu_call(
                            inst, 
                            data, 
                            Some(resume), 
                            node, 
                            f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
643
644
645
                    },

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

qinsoon's avatar
qinsoon committed
648
649
650
651
652
653
654
655
                        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
656
657
                        trace!("instsel on CCALL");

qinsoon's avatar
qinsoon committed
658
                        self.emit_c_call_ir(inst, data, Some(resume), node, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
659
660
                    }
                    
661
                    Instruction_::Return(_) => {
qinsoon's avatar
qinsoon committed
662
663
                        trace!("instsel on RETURN");

664
                        self.emit_common_epilogue(inst, f_content, f_context, vm);
665
                        
qinsoon's avatar
qinsoon committed
666
                        self.backend.emit_ret();
667
668
                    },
                    
qinsoon's avatar
qinsoon committed
669
                    Instruction_::BinOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
670
671
                        trace!("instsel on BINOP");

qinsoon's avatar
qinsoon committed
672
673
                        self.emit_binop(node, inst, op, op1, op2, f_content, f_context, vm);
                    },
qinsoon's avatar
qinsoon committed
674

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

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

qinsoon's avatar
qinsoon committed
680
681
                        let values = inst.value.as_ref().unwrap();
                        let mut status_value_index = 1;
qinsoon's avatar
qinsoon committed
682

683
                        // status flags only works with int operations
684
                        if RegGroup::get_from_value(&values[0]) == RegGroup::GPR {
685
686
687
688
689
690
691
                            // negative flag
                            if status.flag_n {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;

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

693
694
695
696
                            // zero flag
                            if status.flag_z {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
697

698
699
                                self.backend.emit_setz_r8(&tmp_status);
                            }
qinsoon's avatar
qinsoon committed
700

701
702
703
704
                            // unsigned overflow
                            if status.flag_c {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
705

706
707
708
709
710
                                match op {
                                    BinOp::Add | BinOp::Sub | BinOp::Mul => {
                                        self.backend.emit_setb_r8(&tmp_status);
                                    }
                                    _ => panic!("Only Add/Sub/Mul has #C flag")
qinsoon's avatar
qinsoon committed
711
712
                                }
                            }
qinsoon's avatar
qinsoon committed
713

714
715
716
                            // signed overflow
                            if status.flag_v {
                                let tmp_status = values[status_value_index].clone();
qinsoon's avatar
qinsoon committed
717

718
719
720
721
722
                                match op {
                                    BinOp::Add | BinOp::Sub | BinOp::Mul => {
                                        self.backend.emit_seto_r8(&tmp_status);
                                    }
                                    _ => panic!("Only Add/Sub/Mul has #V flag")
qinsoon's avatar
qinsoon committed
723
724
                                }
                            }
725
726
                        }
                    }
qinsoon's avatar
qinsoon committed
727
728

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

731
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
732
733
734
735
736

                        let ref op = ops[operand];

                        match operation {
                            op::ConvOp::TRUNC => {
qinsoon's avatar
qinsoon committed
737
738
739
                                let tmp_res = self.get_result_value(node);
                                let to_ty_size = vm.get_backend_type_info(tmp_res.ty.id()).size;

qinsoon's avatar
qinsoon committed
740
741
                                if self.match_ireg(op) {
                                    let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
742

qinsoon's avatar
qinsoon committed
743
                                    // mov op -> result
qinsoon's avatar
qinsoon committed
744
745
746
747
748
749
750
751
752
753
754
755
756
757
                                    match to_ty_size {
                                        1 => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT8_TYPE.clone())}),
                                        2 => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT16_TYPE.clone())}),
                                        4 => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT32_TYPE.clone())}),
                                        8 => self.backend.emit_mov_r_r(&tmp_res, unsafe {&tmp_op.as_type(UINT64_TYPE.clone())}),
                                        _  => panic!("unsupported int size: {}", to_ty_size)
                                    }
                                } else if self.match_ireg_ex(op) {
                                    let (op_l, op_h) = self.emit_ireg_ex(op, f_content, f_context, vm);

                                    match to_ty_size {
                                        1 | 2 => self.backend.emit_movz_r_r(unsafe {&tmp_res.as_type(UINT32_TYPE.clone())}, &op_l),
                                        4 | 8 => self.backend.emit_mov_r_r(&tmp_res, &op_l),
                                        _ => panic!("unsupported int size: {}", to_ty_size)
758
                                    }
qinsoon's avatar
qinsoon committed
759
760
761
762
763
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
                                }
                            }
                            op::ConvOp::ZEXT => {
764
765
766
                                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
767

768
769
770
                                    // 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
771

772
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
                                        match (from_ty_size, to_ty_size) {
                                            // int32 to int64
                                            (4, 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);
                                            }
                                            // any int to int128
                                            (_, 16) => {
                                                let (res_l, res_h) = self.split_int128(&tmp_res, f_context, vm);

                                                self.backend.emit_mov_r_r(&res_l, unsafe {&tmp_op.as_type(UINT64_TYPE.clone())});
                                                self.backend.emit_mov_r_imm(&res_h, 0);
                                            }
                                            // else
                                            _ => {
                                                self.backend.emit_movz_r_r(&tmp_res, &tmp_op);
                                            }
qinsoon's avatar
qinsoon committed
797
                                        }
qinsoon's avatar
qinsoon committed
798
                                    } else {
799
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
800
                                    }
801
802
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
qinsoon's avatar
qinsoon committed
803
804
805
                                }
                            },
                            op::ConvOp::SEXT => {
806
807
808
                                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
809

810
811
812
                                    // 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
813

814
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
                                        match (from_ty_size, to_ty_size) {
                                            // int64 to int128
                                            (8, 16) => {
                                                let (res_l, res_h) = self.split_int128(&tmp_res, f_context, vm);

                                                // mov tmp_op -> res_h
                                                // sar res_h 63
                                                self.backend.emit_mov_r_r(&res_h, &tmp_op);
                                                self.backend.emit_sar_r_imm8(&res_h, 63i8);

                                                // mov tmp_op -> res_l
                                                self.backend.emit_mov_r_r(&res_l, &tmp_op);
                                            }
                                            // int32 to int128
                                            (_, 16) => {
                                                let (res_l, res_h) = self.split_int128(&tmp_res, f_context, vm);

                                                // movs tmp_op -> res_l
                                                self.backend.emit_movs_r_r(&res_l, &tmp_op);

                                                // mov res_l -> res_h
                                                // sar res_h 63
                                                self.backend.emit_mov_r_r(&res_h, unsafe {&res_l.as_type(UINT32_TYPE.clone())});
                                                self.backend.emit_sar_r_imm8(&res_h, 63i8);
                                            }
                                            _ => self.backend.emit_movs_r_r(&tmp_res, &tmp_op)
                                        }
qinsoon's avatar
qinsoon committed
842
                                    } else {
843
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
844
                                    }
845
846
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
qinsoon's avatar
qinsoon committed
847
848
                                }
                            }
qinsoon's avatar
qinsoon committed
849
850
851
852
853
854
                            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
855
                                    self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
856
857
858
859
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
                                }
                            }
qinsoon's avatar
qinsoon committed
860
861
862
                            op::ConvOp::SITOFP => {
                                let tmp_res = self.get_result_value(node);

863
864
865
866
867
868
869
                                assert!(self.match_ireg(op), "unexpected op (expected ireg): {}", op);
                                let tmp_op = self.emit_ireg(op, f_content, f_context, vm);

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

875
876
877
878
                                assert!(self.match_fpreg(op), "unexpected op (expected fpreg): {}", op);
                                let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);

                                if from_ty.is_double() {
qinsoon's avatar
qinsoon committed
879
                                    self.backend.emit_cvtsd2si_r_f64(&tmp_res, &tmp_op);
880
881
                                } else if from_ty.is_float() {
                                    self.backend.emit_cvtss2si_r_f32(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
882
                                } else {
883
                                    panic!("expected fp type as from type in FPTOSI, found {}", to_ty)
qinsoon's avatar
qinsoon committed
884
885
                                }
                            }
886
887
888
                            op::ConvOp::UITOFP => {
                                let tmp_res = self.get_result_value(node);

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

892
                                let op_ty_size = vm.get_backend_type_info(tmp_op.ty.id()).size;
893

qinsoon's avatar
qinsoon committed
894
895
896
897
898
                                if to_ty.is_double() {
                                    match op_ty_size {
                                        8 => {
                                            // movd/movq op -> res
                                            self.backend.emit_mov_fpr_r64(&tmp_res, &tmp_op);
899

qinsoon's avatar
qinsoon committed
900
901
902
903
                                            // punpckldq UITOFP_C0, tmp_res -> tmp_res
                                            // (interleaving low bytes: xmm = xmm[0] mem[0] xmm[1] mem[1]
                                            let mem_c0 = self.get_mem_for_const(UITOFP_C0.clone(), vm);
                                            self.backend.emit_punpckldq_f64_mem128(&tmp_res, &mem_c0);
904

qinsoon's avatar
qinsoon committed
905
906
907
                                            // subpd UITOFP_C1, tmp_res -> tmp_res
                                            let mem_c1 = self.get_mem_for_const(UITOFP_C1.clone(), vm);
                                            self.backend.emit_subpd_f64_mem128(&tmp_res, &mem_c1);
908

qinsoon's avatar
qinsoon committed
909
910
911
912
913
                                            // haddpd tmp_res, tmp_res -> tmp_res
                                            self.backend.emit_haddpd_f64_f64(&tmp_res, &tmp_res);
                                        }
                                        4 => {
                                            let tmp = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
914

qinsoon's avatar
qinsoon committed
915
916
917
                                            // movl op -> tmp(32)
                                            let tmp32 = unsafe { tmp.as_type(UINT32_TYPE.clone()) };
                                            self.backend.emit_mov_r_r(&tmp32, &tmp_op);
918

qinsoon's avatar
qinsoon committed
919
920
921
922
923
924
925
926
                                            // cvtsi2sd %tmp(64) -> %tmp_res
                                            self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp);
                                        }
                                        2 | 1 => {
                                            let tmp_op32 = unsafe { tmp_op.as_type(UINT32_TYPE.clone()) };
                                            self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp_op32);
                                        }
                                        _ => panic!("not implemented int length {}", op_ty_size)
927
                                    }
qinsoon's avatar
qinsoon committed
928
929
930
931
932
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
                                } else if to_ty.is_float() {
                                    match op_ty_size {
                                        8 => {
                                            // movl %tmp_op -> %tmp1
                                            let tmp1 = self.make_temporary(f_context, UINT32_TYPE.clone(), vm);
                                            self.backend.emit_mov_r_r(&tmp1, unsafe {&tmp_op.as_type(UINT32_TYPE.clone())});

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

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

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

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

                                            // blk_if_not_signed:
                                            self.start_block(blk_if_not_signed);

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

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

                                            // blk_if_signed:
                                            self.start_block(blk_if_signed);

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

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

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

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

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

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

                                            // cvtsi2ss %tmp_op32 -> %tmp_res
                                            self.backend.emit_cvtsi2ss_f32_r(&tmp_res, &tmp_op32);
                                        }
                                        _ => panic!("not implemented int length {}", op_ty_size)
992
                                    }
qinsoon's avatar
qinsoon committed
993
994
                                } else {
                                    panic!("expect double or float")
995
996
997
998
999
                                }
                            }
                            op::ConvOp::FPTOUI => {
                                let tmp_res = self.get_result_value(node);

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

qinsoon's avatar
qinsoon committed
1004
1005
1006
1007
1008
                                if from_ty.is_double() {
                                    match res_ty_size {
                                        8 => {
                                            let tmp1 = self.make_temporary(f_context, DOUBLE_TYPE.clone(), vm);
                                            let tmp2 = self.make_temporary(f_context, DOUBLE_TYPE.clone(), vm);
1009

qinsoon's avatar
qinsoon committed
1010
1011
1012
                                            // movsd FPTOUI_C_DOUBLE -> %tmp1
                                            let mem_c = self.get_mem_for_const(FPTOUI_C_DOUBLE.clone(), vm);
                                            self.backend.emit_movsd_f64_mem64(&tmp1, &mem_c);
1013

qinsoon's avatar
qinsoon committed
1014
1015
                                            // movapd %tmp_op -> %tmp2
                                            self.backend.emit_movapd_f64_f64(&tmp2, &tmp_op);
1016

qinsoon's avatar
qinsoon committed
1017
1018
                                            // subsd %tmp1, %tmp2 -> %tmp2
                                            self.backend.emit_subsd_f64_f64(&tmp2, &tmp1);
1019

qinsoon's avatar
qinsoon committed
1020
1021
                                            // cvttsd2si %tmp2 -> %tmp_res
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res, &tmp2);
1022

qinsoon's avatar
qinsoon committed
1023
1024
1025
                                            let tmp_const = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
                                            // mov 0x8000000000000000 -> %tmp_const
                                            self.backend.emit_mov_r64_imm64(&tmp_const, -9223372036854775808i64);
1026

qinsoon's avatar
qinsoon committed
1027
1028
                                            // xor %tmp_res, %tmp_const -> %tmp_const
                                            self.backend.emit_xor_r_r(&tmp_const, &tmp_res);
qinsoon's avatar
qinsoon committed
1029

qinsoon's avatar
qinsoon committed
1030
1031
                                            // cvttsd2si %tmp_op -> %tmp_res
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res, &tmp_op);
1032

qinsoon's avatar
qinsoon committed
1033
1034
                                            // ucomisd %tmp_op %tmp1
                                            self.backend.emit_ucomisd_f64_f64(&tmp1, &tmp_op);
1035

qinsoon's avatar
qinsoon committed
1036
1037
1038
1039
1040
                                            // cmovaeq %tmp_const -> %tmp_res
                                            self.backend.emit_cmovae_r_r(&tmp_res, &tmp_const);
                                        }
                                        4 => {
                                            let tmp_res64 = unsafe { tmp_res.as_type(UINT64_TYPE.clone()) };
1041

qinsoon's avatar
qinsoon committed
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
                                            // cvttsd2si %tmp_op -> %tmp_res(64)
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res64, &tmp_op);
                                        }
                                        2 | 1 => {
                                            let tmp_res32 = unsafe { tmp_res.as_type(UINT32_TYPE.clone()) };

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

                                            // movz %tmp_res -> %tmp_res(32)
                                            self.backend.emit_movz_r_r(&tmp_res32, &tmp_res);
                                        }
                                        _ => panic!("not implemented int length {}", res_ty_size)
1055
                                    }
qinsoon's avatar
qinsoon committed
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
                                } else if from_ty.is_float() {
                                    match res_ty_size {
                                        8 => {
                                            let tmp1 = self.make_temporary(f_context, FLOAT_TYPE.clone(), vm);
                                            let tmp2 = self.make_temporary(f_context, FLOAT_TYPE.clone(), vm);

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

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

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

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

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

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

qinsoon's avatar
qinsoon committed
1082
1083
                                            // cvttss2si %tmp_op -> %tmp_res
                                            self.backend.emit_cvttss2si_r_f32(&tmp_res, &tmp_op);
1084

qinsoon's avatar
qinsoon committed
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
                                            // ucomiss %tmp_op %tmp1
                                            self.backend.emit_ucomiss_f32_f32(&tmp1, &tmp_op);

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

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

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

                                            // movz %tmp_res(32) -> %tmp_res
                                            self.backend.emit_movz_r_r(&tmp_res32, &tmp_res);
                                        }
                                        _ => panic!("not implemented int length {}", res_ty_size)
1107
                                    }
qinsoon's avatar
qinsoon committed
1108
1109
                                } else {
                                    panic!("expect double or float")
1110
1111
                                }
                            }
qinsoon's avatar
qinsoon committed
1112
1113
1114
                            _ => unimplemented!()
                        }
                    }
1115
                    
1116
1117
                    // load on x64 generates mov inst (no matter what order is specified)
                    // https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
1118
                    Instruction_::Load{is_ptr, order, mem_loc} => {
qinsoon's avatar
qinsoon committed
1119
1120
                        trace!("instsel on LOAD");

1121
                        let ref ops = inst.ops;
1122
                        let ref loc_op = ops[mem_loc];
1123
1124
1125
1126
1127
1128
                        
                        // check order
                        match order {
                            MemoryOrder::Relaxed 
                            | MemoryOrder::Consume 
                            | MemoryOrder::Acquire
1129
1130
                            | MemoryOrder::SeqCst
                            | MemoryOrder::NotAtomic => {},
1131
1132
                            _ => panic!("didnt expect order {:?} with store inst", order)
                        }                        
1133

1134
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
1135
                        let res_temp = self.get_result_value(node);
1136

qinsoon's avatar
qinsoon committed
1137
1138
                        if self.match_ireg(node) {
                            self.backend.emit_mov_r_mem(&res_temp, &resolved_loc);
qinsoon's avatar
qinsoon committed
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
                        } else if self.match_ireg_ex(node) {
                            let (res_l, res_h) = self.split_int128(&res_temp, f_context, vm);

                            // load lower half
                            self.backend.emit_mov_r_mem(&res_l, &resolved_loc);

                            // shift ptr, and load higher half
                            let loc = self.addr_const_offset_adjust(resolved_loc.extract_memory_location().unwrap(), POINTER_SIZE as u64, vm);
                            let val_loc = self.make_value_memory_location(loc, vm);
                            self.backend.emit_mov_r_mem(&res_h, &val_loc);
qinsoon's avatar
qinsoon committed
1149
1150
1151
1152
1153
1154
1155
1156
1157
                        } else if self.match_fpreg(node) {
                            match res_temp.ty.v {
                                MuType_::Double => self.backend.emit_movsd_f64_mem64(&res_temp, &resolved_loc),
                                MuType_::Float  => self.backend.emit_movss_f32_mem32(&res_temp, &resolved_loc),
                                _ => panic!("expect double or float")
                            }
                        } else {
                            unimplemented!()
                        }
1158
1159
1160
                    }
                    
                    Instruction_::Store{is_ptr, order, mem_loc, value} => {
qinsoon's avatar
qinsoon committed
1161
1162
                        trace!("instsel on STORE");

1163
                        let ref ops = inst.ops;
1164
1165
1166
1167
1168
                        let ref loc_op = ops[mem_loc];
                        let ref val_op = ops[value];
                        
                        let generate_plain_mov : bool = {
                            match order {
1169
1170
1171
                                MemoryOrder::Relaxed
                                | MemoryOrder::Release
                                | MemoryOrder::NotAtomic => true,
1172
1173
1174
1175
1176
                                MemoryOrder::SeqCst => false,
                                _ => panic!("didnt expect order {:?} with store inst", order)
                            }
                        };
                        
1177
1178
1179
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);

                        if self.match_iimm(val_op) {
1180
                            let (val, len) = self.node_iimm_to_i32_with_len(val_op);
1181
                            if generate_plain_mov {
1182
                                self.backend.emit_mov_mem_imm(&resolved_loc, val, len);