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

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

inst_sel.rs 225 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
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;
38
use compiler::backend::make_block_name;
qinsoon's avatar
qinsoon committed
39
40
use compiler::machine_code::CompiledFunction;
use compiler::frame::Frame;
41

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

45
use std::collections::HashMap;
46
47
use std::collections::LinkedList;

qinsoon's avatar
qinsoon committed
48
use std::any::Any;
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
99
100
101
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))
            })
        ]))
    });
102

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

    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))
    });
114
115
}

116
117
const INLINE_FASTPATH : bool = false;

118
pub struct InstructionSelection {
119
    name: &'static str,
120
    backend: Box<CodeGenerator>,
121
122

    current_fv_id: MuID,
123
    current_fv_name: MuName,
qinsoon's avatar
qinsoon committed
124
    current_callsite_id: usize,
qinsoon's avatar
qinsoon committed
125
126
    current_frame: Option<Frame>,
    current_block: Option<MuName>,
127
    current_block_in_ir: Option<MuName>,
qinsoon's avatar
qinsoon committed
128
    current_func_start: Option<ValueLocation>,
129
    // Technically this is a map in that each Key is unique, but we will never try and add duplicate
130
131
132
133
    // keys, or look things up, so a list of tuples is faster than a Map.
    // A list of tuples, the first is the name of a callsite, the next is the callsite destination, the last is the
    // size of arguments pushed on the stack
    current_callsites: LinkedList<(MuName, MuID, usize)>,
qinsoon's avatar
qinsoon committed
134
    // key: block id, val: block location
135
    current_exn_blocks: HashMap<MuID, MuName>,
136
137
138

    current_constants: HashMap<MuID, P<Value>>,
    current_constants_locs: HashMap<MuID, P<Value>>
139
140
}

141
impl <'a> InstructionSelection {
qinsoon's avatar
qinsoon committed
142
    #[cfg(feature = "aot")]
143
    pub fn new() -> InstructionSelection {
144
145
        InstructionSelection{
            name: "Instruction Selection (x64)",
146
            backend: Box::new(ASMCodeGen::new()),
147

148
            current_fv_id: 0,
149
            current_fv_name: String::new(),
qinsoon's avatar
qinsoon committed
150
            current_callsite_id: 0,
qinsoon's avatar
qinsoon committed
151
            current_frame: None,
152
153
154
155
156
157
158
            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
159
            current_func_start: None,
160
            current_callsites: LinkedList::new(),
161
162
163
164
            current_exn_blocks: HashMap::new(),

            current_constants: HashMap::new(),
            current_constants_locs: HashMap::new()
165
166
        }
    }
qinsoon's avatar
qinsoon committed
167
168
169
170
171

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

                            if next_block_in_trace == true_dest.target {
193
194
195
                                (true_dest, false_dest, false)
                            } else {
                                (false_dest, true_dest, true)
196
                            }
197
                        };
198
                        
199
                        let ref ops = inst.ops;
200
                        
201
202
                        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
203
                        
204
                        let branch_target = f_content.get_block(branch_dest.target).name();
205
206
207
    
                        let ref cond = ops[cond];
                        
qinsoon's avatar
qinsoon committed
208
                        if self.match_cmp_res(cond) {
209
                            trace!("emit cmp_res-branch2");
210
                            match self.emit_cmp_res(cond, f_content, f_context, vm) {
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
274
275
276
277
278
279
280
                                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
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
320
321
322
323
324
325
326

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

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

350
                        let fallthrough_temp_block = make_block_name(&self.current_fv_name, node.id(), "branch_fallthrough", );
351
352
                        self.start_block(fallthrough_temp_block);

353
                        let fallthrough_target = f_content.get_block(fallthrough_dest.target).name();
354
                        self.backend.emit_jmp(fallthrough_target);
355
                    },
qinsoon's avatar
qinsoon committed
356
357

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

qinsoon's avatar
qinsoon committed
360
                        trace!("instsel on SELECT");
361
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
362
363
364
365
366

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

367
368
369
370
371
372
373
374
375
376
377
378
379
                        // 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
380
381
382
                        if self.match_ireg(true_val) {
                            // moving integers/pointers
                            let tmp_res   = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
383

384
                            // use cmov for 16/32/64bit integer
qinsoon's avatar
qinsoon committed
385
                            // use jcc  for 8 bit
386
                            // FIXME: could use 32bit register to implement 8bit select
qinsoon's avatar
qinsoon committed
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
413
414
415
416
417
418
419
                            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
                                _ => {
420
421
422
                                    let blk_true  = make_block_name(&self.current_fv_name, node.id(), "select_true");
                                    let blk_false = make_block_name(&self.current_fv_name, node.id(), "select_false");
                                    let blk_end   = make_block_name(&self.current_fv_name, node.id(), "select_end");
qinsoon's avatar
qinsoon committed
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446

                                    // 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!()
                                    }

447
                                    // finishing current block
qinsoon's avatar
qinsoon committed
448
                                    self.finish_block();
449
450

                                    // blk_false:
qinsoon's avatar
qinsoon committed
451
                                    self.start_block(blk_false.clone());
qinsoon's avatar
qinsoon committed
452
453
454
455
456
457
                                    // 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
458
                                    self.finish_block();
qinsoon's avatar
qinsoon committed
459
460

                                    // blk_true:
qinsoon's avatar
qinsoon committed
461
                                    self.start_block(blk_true.clone());
qinsoon's avatar
qinsoon committed
462
463
                                    // mov true value -> result
                                    self.emit_move_node_to_value(&tmp_res, &true_val, f_content, f_context, vm);
464
                                    self.finish_block();
qinsoon's avatar
qinsoon committed
465
466

                                    // blk_end:
467
                                    self.start_block(blk_end.clone());
qinsoon's avatar
qinsoon committed
468
                                }
qinsoon's avatar
qinsoon committed
469
                            }
470
471
472
                        } else if self.match_fpreg(true_val) {
                            let tmp_res = self.get_result_value(node);

473
474
475
                            let blk_true  = make_block_name(&self.current_fv_name, node.id(), "select_true");
                            let blk_false = make_block_name(&self.current_fv_name, node.id(), "select_false");
                            let blk_end   = make_block_name(&self.current_fv_name, node.id(), "select_end");
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500

                            // 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
501
                            self.finish_block();
502
503

                            // blk_false:
qinsoon's avatar
qinsoon committed
504
                            self.start_block(blk_false.clone());
505
506
507
508
509
510
                            // 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
511
                            self.finish_block();
512
513

                            // blk_true:
qinsoon's avatar
qinsoon committed
514
                            self.start_block(blk_true.clone());
515
516
                            // mov true value -> result
                            self.emit_move_node_to_value(&tmp_res, &true_val, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
517
                            self.finish_block();
518
519

                            // blk_end:
qinsoon's avatar
qinsoon committed
520
                            self.start_block(blk_end.clone());
qinsoon's avatar
qinsoon committed
521
522
523
524
525
                        } else {
                            unimplemented!()
                        }
                    },

526
                    Instruction_::CmpOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
527
528
                        use ast::op::CmpOp::*;

qinsoon's avatar
qinsoon committed
529
                        trace!("instsel on CMPOP");
530
                        let ref ops = inst.ops;
531
532
533
                        let ref op1 = ops[op1];
                        let ref op2 = ops[op2];

qinsoon's avatar
qinsoon committed
534
                        let tmp_res = self.get_result_value(node);
535
536
537
                        
                        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
538

539
                        // set byte to result
qinsoon's avatar
qinsoon committed
540
                        match self.emit_cmp_res(node, f_content, f_context, vm) {
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
                            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
558
559

                            _ => unimplemented!()
560
561
562
                        }
                    }

qinsoon's avatar
qinsoon committed
563
                    Instruction_::Branch1(ref dest) => {
qinsoon's avatar
qinsoon committed
564
                        trace!("instsel on BRANCH1");
565
                        let ref ops = inst.ops;
566
                                            
567
                        self.process_dest(&ops, dest, f_content, f_context, vm);
568
                        
569
                        let target = f_content.get_block(dest.target).name();
qinsoon's avatar
qinsoon committed
570
                        
qinsoon's avatar
qinsoon committed
571
                        trace!("emit branch1");
572
                        // jmp
qinsoon's avatar
qinsoon committed
573
                        self.backend.emit_jmp(target);
574
                    },
qinsoon's avatar
qinsoon committed
575
576

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

                        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);

592
                                let target = f_content.get_block(case_dest.target).name();
qinsoon's avatar
qinsoon committed
593
594
595
596
597

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

                                    // cmp case cond
qinsoon's avatar
qinsoon committed
598
                                    self.backend.emit_cmp_imm_r(imm, &tmp_cond);
qinsoon's avatar
qinsoon committed
599
600
601
602
603
604
                                    // 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
605
                                    self.backend.emit_cmp_r_r(&tmp_case_op, &tmp_cond);
qinsoon's avatar
qinsoon committed
606
607
608
609
610
                                    // je dest
                                    self.backend.emit_je(target);
                                } else {
                                    panic!("expecting ireg cond to be either iimm or ireg: {}", cond);
                                }
611
612

                                self.finish_block();
613
614
                                let block_name = make_block_name(&self.current_fv_name, node.id(), format!("switch_not_met_case_{}", case_op_index).as_str());
                                self.start_block(block_name);
qinsoon's avatar
qinsoon committed
615
616
617
618
619
                            }

                            // emit default
                            self.process_dest(&ops, default, f_content, f_context, vm);
                            
620
                            let default_target = f_content.get_block(default.target).name();
qinsoon's avatar
qinsoon committed
621
622
623
624
625
                            self.backend.emit_jmp(default_target);
                        } else {
                            panic!("expecting cond in switch to be ireg: {}", cond);
                        }
                    }
626
                    
qinsoon's avatar
qinsoon committed
627
                    Instruction_::ExprCall{ref data, is_abort} => {
qinsoon's avatar
qinsoon committed
628
629
                        trace!("instsel on EXPRCALL");

qinsoon's avatar
qinsoon committed
630
631
                        if is_abort {
                            unimplemented!()
632
                        }
633
                        
qinsoon's avatar
qinsoon committed
634
635
636
637
638
                        self.emit_mu_call(
                            inst, // inst: &Instruction,
                            data, // calldata: &CallData,
                            None, // resumption: Option<&ResumptionData>,
                            node, // cur_node: &TreeNode, 
639
                            f_content, f_context, vm);
640
641
                    },
                    
qinsoon's avatar
qinsoon committed
642
                    Instruction_::Call{ref data, ref resume} => {
qinsoon's avatar
qinsoon committed
643
644
                        trace!("instsel on CALL");

qinsoon's avatar
qinsoon committed
645
646
647
648
649
650
                        self.emit_mu_call(
                            inst, 
                            data, 
                            Some(resume), 
                            node, 
                            f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
651
652
653
                    },

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

qinsoon's avatar
qinsoon committed
656
657
658
659
660
661
662
663
                        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
664
665
                        trace!("instsel on CCALL");

qinsoon's avatar
qinsoon committed
666
                        self.emit_c_call_ir(inst, data, Some(resume), node, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
667
668
                    }
                    
669
                    Instruction_::Return(_) => {
qinsoon's avatar
qinsoon committed
670
671
                        trace!("instsel on RETURN");

672
                        self.emit_common_epilogue(inst, f_content, f_context, vm);
673
                        
qinsoon's avatar
qinsoon committed
674
                        self.backend.emit_ret();
675
676
                    },
                    
qinsoon's avatar
qinsoon committed
677
                    Instruction_::BinOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
678
679
                        trace!("instsel on BINOP");

qinsoon's avatar
qinsoon committed
680
681
                        self.emit_binop(node, inst, op, op1, op2, f_content, f_context, vm);
                    },
qinsoon's avatar
qinsoon committed
682

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

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

qinsoon's avatar
qinsoon committed
688
689
                        let values = inst.value.as_ref().unwrap();
                        let mut status_value_index = 1;
qinsoon's avatar
qinsoon committed
690

691
                        // status flags only works with int operations
692
                        if RegGroup::get_from_value(&values[0]) == RegGroup::GPR {
693
694
695
696
697
698
699
                            // 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
700

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

706
707
                                self.backend.emit_setz_r8(&tmp_status);
                            }
qinsoon's avatar
qinsoon committed
708

709
710
711
712
                            // unsigned overflow
                            if status.flag_c {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
713

714
715
716
717
718
                                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
719
720
                                }
                            }
qinsoon's avatar
qinsoon committed
721

722
723
724
                            // signed overflow
                            if status.flag_v {
                                let tmp_status = values[status_value_index].clone();
qinsoon's avatar
qinsoon committed
725

726
727
728
729
730
                                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
731
732
                                }
                            }
733
734
                        }
                    }
qinsoon's avatar
qinsoon committed
735
736

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

739
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
740
741
742
743
744

                        let ref op = ops[operand];

                        match operation {
                            op::ConvOp::TRUNC => {
qinsoon's avatar
qinsoon committed
745
746
747
                                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
748
749
                                if self.match_ireg(op) {
                                    let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
750

qinsoon's avatar
qinsoon committed
751
                                    // mov op -> result
qinsoon's avatar
qinsoon committed
752
753
754
755
756
757
758
759
760
761
762
763
764
765
                                    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)
766
                                    }
qinsoon's avatar
qinsoon committed
767
768
769
770
771
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
                                }
                            }
                            op::ConvOp::ZEXT => {
772
773
774
                                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
775

776
777
778
                                    // 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
779

780
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
                                        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
805
                                        }
qinsoon's avatar
qinsoon committed
806
                                    } else {
807
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
808
                                    }
809
810
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
qinsoon's avatar
qinsoon committed
811
812
813
                                }
                            },
                            op::ConvOp::SEXT => {
814
815
816
                                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
817

818
819
820
                                    // 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
821

822
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
                                        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
850
                                    } else {
851
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
852
                                    }
853
854
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
qinsoon's avatar
qinsoon committed
855
856
                                }
                            }
qinsoon's avatar
qinsoon committed
857
858
859
860
861
862
                            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
863
                                    self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
864
865
866
867
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op)
                                }
                            }
qinsoon's avatar
qinsoon committed
868
869
870
                            op::ConvOp::SITOFP => {
                                let tmp_res = self.get_result_value(node);

871
872
873
874
875
876
877
                                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
878
879
880
881
882
                                }
                            }
                            op::ConvOp::FPTOSI => {
                                let tmp_res = self.get_result_value(node);

883
884
885
886
                                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
887
                                    self.backend.emit_cvtsd2si_r_f64(&tmp_res, &tmp_op);
888
889
                                } else if from_ty.is_float() {
                                    self.backend.emit_cvtss2si_r_f32(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
890
                                } else {
891
                                    panic!("expected fp type as from type in FPTOSI, found {}", to_ty)
qinsoon's avatar
qinsoon committed
892
893
                                }
                            }
894
895
896
                            op::ConvOp::UITOFP => {
                                let tmp_res = self.get_result_value(node);

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

900
                                let op_ty_size = vm.get_backend_type_info(tmp_op.ty.id()).size;
901

qinsoon's avatar
qinsoon committed
902
903
904
905
906
                                if to_ty.is_double() {
                                    match op_ty_size {
                                        8 => {
                                            // movd/movq op -> res
                                            self.backend.emit_mov_fpr_r64(&tmp_res, &tmp_op);
907

qinsoon's avatar
qinsoon committed
908
909
910
911
                                            // 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);
912

qinsoon's avatar
qinsoon committed
913
914
915
                                            // 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);
916

qinsoon's avatar
qinsoon committed
917
918
919
920
921
                                            // 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);
922

qinsoon's avatar
qinsoon committed
923
924
925
                                            // movl op -> tmp(32)
                                            let tmp32 = unsafe { tmp.as_type(UINT32_TYPE.clone()) };
                                            self.backend.emit_mov_r_r(&tmp32, &tmp_op);
926

qinsoon's avatar
qinsoon committed
927
928
929
930
931
932
933
934
                                            // 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)
935
                                    }
qinsoon's avatar
qinsoon committed
936
937
938
939
940
941
942
943
944
945
946
947
948
                                } 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);

949
950
951
                                            let blk_if_signed     = make_block_name(&self.current_fv_name, node.id(), "uitofp_float_if_signed",);
                                            let blk_if_not_signed = make_block_name(&self.current_fv_name, node.id(), "uitofp_float_if_not_signed");
                                            let blk_done          = make_block_name(&self.current_fv_name, node.id(), "uitofp_float_done");
qinsoon's avatar
qinsoon committed
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

                                            // 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)
1000
                                    }
qinsoon's avatar
qinsoon committed
1001
1002
                                } else {
                                    panic!("expect double or float")
1003
1004
1005
1006
1007
                                }
                            }
                            op::ConvOp::FPTOUI => {
                                let tmp_res = self.get_result_value(node);

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

qinsoon's avatar
qinsoon committed
1012
1013
1014
1015
1016
                                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);
1017

qinsoon's avatar
qinsoon committed
1018
1019
1020
                                            // 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);
1021

qinsoon's avatar
qinsoon committed
1022
1023
                                            // movapd %tmp_op -> %tmp2
                                            self.backend.emit_movapd_f64_f64(&tmp2, &tmp_op);
1024

qinsoon's avatar
qinsoon committed
1025
1026
                                            // subsd %tmp1, %tmp2 -> %tmp2
                                            self.backend.emit_subsd_f64_f64(&tmp2, &tmp1);
1027

qinsoon's avatar
qinsoon committed
1028
1029
                                            // cvttsd2si %tmp2 -> %tmp_res
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res, &tmp2);
1030

qinsoon's avatar
qinsoon committed
1031
1032
1033
                                            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);
1034

qinsoon's avatar
qinsoon committed
1035
1036
                                            // xor %tmp_res, %tmp_const -> %tmp_const
                                            self.backend.emit_xor_r_r(&tmp_const, &tmp_res);
qinsoon's avatar
qinsoon committed
1037

qinsoon's avatar
qinsoon committed
1038
1039
                                            // cvttsd2si %tmp_op -> %tmp_res
                                            self.backend.emit_cvttsd2si_r_f64(&tmp_res, &tmp_op);
1040

qinsoon's avatar
qinsoon committed
1041
1042
                                            // ucomisd %tmp_op %tmp1
                                            self.backend.emit_ucomisd_f64_f64(&tmp1, &tmp_op);
1043

qinsoon's avatar
qinsoon committed
1044
1045
1046
1047
1048
                                            // 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()) };
1049

qinsoon's avatar
qinsoon committed
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
                                            // 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)
1063
                                    }
qinsoon's avatar
qinsoon committed
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
                                } 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);
1089

qinsoon's avatar
qinsoon committed
1090
1091
                                            // cvttss2si %tmp_op -> %tmp_res
                                            self.backend.emit_cvttss2si_r_f32(&tmp_res, &tmp_op);
1092

qinsoon's avatar
qinsoon committed
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
                                            // 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)
1115
                                    }
qinsoon's avatar
qinsoon committed
1116
1117
                                } else {
                                    panic!("expect double or float")
1118
1119
                                }
                            }
qinsoon's avatar
qinsoon committed
1120
1121
1122
                            _ => unimplemented!()
                        }
                    }
1123
                    
1124
1125
                    // load on x64 generates mov inst (no matter what order is specified)
                    // https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
1126
                    Instruction_::Load{is_ptr, order, mem_loc} => {
qinsoon's avatar
qinsoon committed
1127
1128
                        trace!("instsel on LOAD");

1129
                        let ref ops = inst.ops;
1130
                        let ref loc_op = ops[mem_loc];
1131
1132
1133
1134
1135
1136
                        
                        // check order
                        match order {
                            MemoryOrder::Relaxed 
                            | MemoryOrder::Consume 
                            | MemoryOrder::Acquire
1137
1138
                            | MemoryOrder::SeqCst
                            | MemoryOrder::NotAtomic => {},
1139
1140
                            _ => panic!("didnt expect order {:?} with store inst", order)
                        }                        
1141

1142
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
1143
                        let res_temp = self.get_result_value(node);
1144

qinsoon's avatar
qinsoon committed
1145
1146
                        if self.match_ireg(node) {
                            self.backend.emit_mov_r_mem(&res_temp, &resolved_loc);