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 256 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
2
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
3
4
5
// 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
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
9
10
11
12
13
14
// 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 vm::VM;
qinsoon's avatar
qinsoon committed
22
use runtime::mm;
qinsoon's avatar
qinsoon committed
23
24
use runtime::mm::OBJECT_HEADER_SIZE;
use runtime::mm::OBJECT_HEADER_OFFSET;
25
26
27
28
use runtime::ValueLocation;
use runtime::thread;
use runtime::entrypoints;
use runtime::entrypoints::RuntimeEntrypoint;
29
30

use compiler::CompilerPass;
qinsoon's avatar
qinsoon committed
31
use compiler::backend::BackendType;
32
use compiler::backend::RegGroup;
33
use compiler::PROLOGUE_BLOCK_NAME;
qinsoon's avatar
qinsoon committed
34
35
36
use compiler::backend::x86_64;
use compiler::backend::x86_64::CodeGenerator;
use compiler::backend::x86_64::ASMCodeGen;
37
use compiler::backend::make_block_name;
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;
45
46
use std::collections::LinkedList;

qinsoon's avatar
qinsoon committed
47
use std::any::Any;
48

49
lazy_static! {
qinsoon's avatar
qinsoon committed
50
51
    /// struct<int32, int32, int32, int32>
    static ref LONG_4_TYPE : P<MuType> = P(
qinsoon's avatar
qinsoon committed
52
53
        MuType::new(new_internal_id(), MuType_::mustruct(Mu("long_4"),
        vec![UINT32_TYPE.clone(); 4]))
54
55
    );

qinsoon's avatar
qinsoon committed
56
57
    /// constant for converting unsigned integer to floating point
    static ref UITOFP_C0 : P<Value> = P(Value{
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
        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))
            })
        ]))
    });

qinsoon's avatar
qinsoon committed
84
85
    /// struct<int64, int64>
    static ref QUAD_2_TYPE : P<MuType> = P(
qinsoon's avatar
qinsoon committed
86
87
        MuType::new(new_internal_id(), MuType_::mustruct(Mu("quad_2"),
        vec![UINT64_TYPE.clone(); 2]))
88
89
    );

qinsoon's avatar
qinsoon committed
90
91
    /// constant for converting unsigned integer to floating point
    static ref UITOFP_C1 : P<Value> = P(Value{
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
        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))
            })
        ]))
    });
107

qinsoon's avatar
qinsoon committed
108
109
    /// constant for converting double to unsigned integer
    static ref FPTOUI_C_DOUBLE : P<Value> = P(Value{
qinsoon's avatar
qinsoon committed
110
        hdr: MuEntityHeader::named(new_internal_id(), Mu("FPTOUI_C_DOUBLE")),
111
112
113
        ty : UINT64_TYPE.clone(),
        v  : Value_::Constant(Constant::Int(4890909195324358656u64))
    });
qinsoon's avatar
qinsoon committed
114

qinsoon's avatar
qinsoon committed
115
    /// constant for converting float to unsigned integer
qinsoon's avatar
qinsoon committed
116
117
118
119
120
    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))
    });
121
122
}

qinsoon's avatar
qinsoon committed
123
124
125
126
/// for some IR instructions, we need a call into runtime
/// for efficiency, we may emit runtime fastpath directly in assembly
//  FIXME: we should have a separate pass to rewrite the instruction into a fastpath (in IR),
//         and a call to slowpath, then instruction selection (see Issue#6)
qinsoon's avatar
qinsoon committed
127
const INLINE_FASTPATH: bool = false;
128

129
pub struct InstructionSelection {
130
    name: &'static str,
qinsoon's avatar
qinsoon committed
131
    /// backend code generator
132
    backend: Box<CodeGenerator>,
133

qinsoon's avatar
qinsoon committed
134
135
    // information about the function being compiled
    /// ID of current function version being compiled
136
    current_fv_id: MuID,
137
    /// name of current function version being compiled
138
    current_fv_name: MuName,
qinsoon's avatar
qinsoon committed
139
    /// used to create a unique callsite ID for current function
qinsoon's avatar
qinsoon committed
140
    current_callsite_id: usize,
qinsoon's avatar
qinsoon committed
141
    /// frame for current function
qinsoon's avatar
qinsoon committed
142
    current_frame: Option<Frame>,
qinsoon's avatar
qinsoon committed
143
144
    /// block that is currently being compiled
    /// the block may be created during instruction selection
qinsoon's avatar
qinsoon committed
145
    current_block: Option<MuName>,
qinsoon's avatar
qinsoon committed
146
147
    /// IR block that is currently being compiled
    /// use this block name to trace some information at IR level
148
    current_block_in_ir: Option<MuName>,
qinsoon's avatar
qinsoon committed
149
    /// start location of current function
qinsoon's avatar
qinsoon committed
150
    current_func_start: Option<ValueLocation>,
qinsoon's avatar
qinsoon committed
151
152
153
154
    /// technically this is a map in that each Key is unique, but we will never try and
    /// add duplicate 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
155
    current_callsites: LinkedList<(MuName, MuID, usize)>,
qinsoon's avatar
qinsoon committed
156
    // key: block id, val: block location
157
    current_exn_blocks: HashMap<MuID, MuName>,
qinsoon's avatar
qinsoon committed
158
159
    /// constants used in this function that are put to memory
    /// key: value id, val: constant value
160
    current_constants: HashMap<MuID, P<Value>>,
qinsoon's avatar
qinsoon committed
161
162
    /// constants used in this function that are put to memory
    /// key: value id, val: memory location
qinsoon's avatar
qinsoon committed
163
    current_constants_locs: HashMap<MuID, P<Value>>,
164
165
}

qinsoon's avatar
qinsoon committed
166
impl<'a> InstructionSelection {
qinsoon's avatar
qinsoon committed
167
    #[cfg(feature = "aot")]
168
    pub fn new() -> InstructionSelection {
qinsoon's avatar
qinsoon committed
169
        InstructionSelection {
170
            name: "Instruction Selection (x64)",
171
            backend: Box::new(ASMCodeGen::new()),
172

173
            current_fv_id: 0,
174
            current_fv_name: String::new(),
qinsoon's avatar
qinsoon committed
175
            current_callsite_id: 0,
qinsoon's avatar
qinsoon committed
176
            current_frame: None,
qinsoon's avatar
qinsoon committed
177
178
179
180
181
182
183
184
185
186
            // which block we are generating code for
            current_block: 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
            current_block_in_ir: None,
qinsoon's avatar
qinsoon committed
187
            current_func_start: None,
188
            current_callsites: LinkedList::new(),
189
190
191
            current_exn_blocks: HashMap::new(),

            current_constants: HashMap::new(),
qinsoon's avatar
qinsoon committed
192
            current_constants_locs: HashMap::new(),
193
194
        }
    }
qinsoon's avatar
qinsoon committed
195
196
197
198
199

    #[cfg(feature = "jit")]
    pub fn new() -> InstructionSelection {
        unimplemented!()
    }
qinsoon's avatar
qinsoon committed
200
201
202

    /// we use hand-written pattern matching rules for instruction selection
    /// for a pattern that can match several rules, the first rule met will be executed, and chosen.
qinsoon's avatar
qinsoon committed
203
204
205
206
207
208
209
    fn instruction_select(
        &mut self,
        node: &'a TreeNode,
        f_content: &FunctionContent,
        f_context: &mut FunctionContext,
        vm: &VM,
    ) {
210
        trace!("instsel on node#{} {}", node.id(), node);
qinsoon's avatar
qinsoon committed
211

qinsoon's avatar
qinsoon committed
212
        match node.v {
213
214
            TreeNode_::Instruction(ref inst) => {
                match inst.v {
qinsoon's avatar
qinsoon committed
215
216
217
218
219
220
                    Instruction_::Branch2 {
                        cond,
                        ref true_dest,
                        ref false_dest,
                        ..
                    } => {
qinsoon's avatar
qinsoon committed
221
                        trace!("instsel on BRANCH2");
222
                        let (fallthrough_dest, branch_dest) = (false_dest, true_dest);
qinsoon's avatar
qinsoon committed
223

224
                        let ref ops = inst.ops;
225
226
                        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
227

228
                        let branch_target = f_content.get_block(branch_dest.target).name();
qinsoon's avatar
qinsoon committed
229

230
                        let ref cond = ops[cond];
qinsoon's avatar
qinsoon committed
231
                        if self.match_cmp_res(cond) {
qinsoon's avatar
qinsoon committed
232
                            // this branch2's cond is from a comparison result
233
                            trace!("emit cmp_res-branch2");
234
                            match self.emit_cmp_res(cond, f_content, f_context, vm) {
qinsoon's avatar
qinsoon committed
235
236
                                op::CmpOp::EQ => self.backend.emit_je(branch_target),
                                op::CmpOp::NE => self.backend.emit_jne(branch_target),
237
238
239
240
241
242
243
244
                                op::CmpOp::UGE => self.backend.emit_jae(branch_target),
                                op::CmpOp::UGT => self.backend.emit_ja(branch_target),
                                op::CmpOp::ULE => self.backend.emit_jbe(branch_target),
                                op::CmpOp::ULT => self.backend.emit_jb(branch_target),
                                op::CmpOp::SGE => self.backend.emit_jge(branch_target),
                                op::CmpOp::SGT => self.backend.emit_jg(branch_target),
                                op::CmpOp::SLE => self.backend.emit_jle(branch_target),
                                op::CmpOp::SLT => self.backend.emit_jl(branch_target),
qinsoon's avatar
qinsoon committed
245
246

                                // floating point
qinsoon's avatar
qinsoon committed
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
                                op::CmpOp::FOEQ | op::CmpOp::FUEQ => {
                                    self.backend.emit_je(branch_target)
                                }
                                op::CmpOp::FONE | op::CmpOp::FUNE => {
                                    self.backend.emit_jne(branch_target)
                                }
                                op::CmpOp::FOGT | op::CmpOp::FUGT => {
                                    self.backend.emit_ja(branch_target)
                                }
                                op::CmpOp::FOGE | op::CmpOp::FUGE => {
                                    self.backend.emit_jae(branch_target)
                                }
                                op::CmpOp::FOLT | op::CmpOp::FULT => {
                                    self.backend.emit_jb(branch_target)
                                }
                                op::CmpOp::FOLE | op::CmpOp::FULE => {
                                    self.backend.emit_jbe(branch_target)
                                }
qinsoon's avatar
qinsoon committed
265

qinsoon's avatar
qinsoon committed
266
                                _ => unimplemented!(),
qinsoon's avatar
qinsoon committed
267
268
                            }
                        } else if self.match_ireg(cond) {
qinsoon's avatar
qinsoon committed
269
270
                            // this branch2 cond is a temporary with value, or an instruction that
                            // emits a temporary
qinsoon's avatar
qinsoon committed
271
                            trace!("emit ireg-branch2");
qinsoon's avatar
qinsoon committed
272

273
                            let cond_reg = self.emit_ireg(cond, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
274

qinsoon's avatar
qinsoon committed
275
                            // emit: cmp cond_reg 1
qinsoon's avatar
qinsoon committed
276
                            self.backend.emit_cmp_imm_r(1, &cond_reg);
qinsoon's avatar
qinsoon committed
277
                            // emit: je #branch_dest
278
                            self.backend.emit_je(branch_target);
qinsoon's avatar
qinsoon committed
279
                        } else {
qinsoon's avatar
qinsoon committed
280
                            panic!("unexpected cond in BRANCH2: {}", cond)
281
                        }
qinsoon's avatar
qinsoon committed
282
                    }
qinsoon's avatar
qinsoon committed
283

qinsoon's avatar
qinsoon committed
284
285
286
287
288
                    Instruction_::Select {
                        cond,
                        true_val,
                        false_val,
                    } => {
qinsoon's avatar
qinsoon committed
289
290
                        use ast::op::CmpOp::*;

qinsoon's avatar
qinsoon committed
291
                        trace!("instsel on SELECT");
292
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
293
294
295
296
297

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

qinsoon's avatar
qinsoon committed
298
                        // generate comparison
299
300
301
302
303
304
305
306
307
308
309
310
                        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
311
                        // emit code to move values
qinsoon's avatar
qinsoon committed
312
313
                        if self.match_ireg(true_val) {
                            // moving integers/pointers
qinsoon's avatar
qinsoon committed
314
                            let tmp_res = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
315

316
                            // use cmov for 16/32/64bit integer
qinsoon's avatar
qinsoon committed
317
                            // use jcc  for 8 bit
318
                            // FIXME: could use 32bit register to implement 8bit select
qinsoon's avatar
qinsoon committed
319
320
321
                            match tmp_res.ty.get_int_length() {
                                // cmov
                                Some(len) if len > 8 => {
qinsoon's avatar
qinsoon committed
322
323
324
325
                                    let tmp_true =
                                        self.emit_ireg(true_val, f_content, f_context, vm);
                                    let tmp_false =
                                        self.emit_ireg(false_val, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
326
327
328
329
330

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

                                    match cmpop {
qinsoon's avatar
qinsoon committed
331
332
                                        EQ => self.backend.emit_cmove_r_r(&tmp_res, &tmp_true),
                                        NE => self.backend.emit_cmovne_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
333
                                        SGE => self.backend.emit_cmovge_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
334
                                        SGT => self.backend.emit_cmovg_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
335
                                        SLE => self.backend.emit_cmovle_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
336
                                        SLT => self.backend.emit_cmovl_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
337
                                        UGE => self.backend.emit_cmovae_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
338
                                        UGT => self.backend.emit_cmova_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
339
                                        ULE => self.backend.emit_cmovbe_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
340
                                        ULT => self.backend.emit_cmovb_r_r(&tmp_res, &tmp_true),
qinsoon's avatar
qinsoon committed
341

qinsoon's avatar
qinsoon committed
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
                                        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)
                                        }
qinsoon's avatar
qinsoon committed
360

qinsoon's avatar
qinsoon committed
361
                                        // FFALSE/FTRUE unimplemented
qinsoon's avatar
qinsoon committed
362
                                        _ => unimplemented!(),
qinsoon's avatar
qinsoon committed
363
364
                                    }
                                }
qinsoon's avatar
qinsoon committed
365
                                // jcc - for 8-bits integer
qinsoon's avatar
qinsoon committed
366
                                _ => {
qinsoon's avatar
qinsoon committed
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
                                    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
382
383
384

                                    // jump to blk_true if true
                                    match cmpop {
qinsoon's avatar
qinsoon committed
385
386
                                        EQ => self.backend.emit_je(blk_true.clone()),
                                        NE => self.backend.emit_jne(blk_true.clone()),
qinsoon's avatar
qinsoon committed
387
                                        SGE => self.backend.emit_jge(blk_true.clone()),
qinsoon's avatar
qinsoon committed
388
                                        SGT => self.backend.emit_jg(blk_true.clone()),
qinsoon's avatar
qinsoon committed
389
                                        SLE => self.backend.emit_jle(blk_true.clone()),
qinsoon's avatar
qinsoon committed
390
                                        SLT => self.backend.emit_jl(blk_true.clone()),
qinsoon's avatar
qinsoon committed
391
                                        UGE => self.backend.emit_jae(blk_true.clone()),
qinsoon's avatar
qinsoon committed
392
                                        UGT => self.backend.emit_ja(blk_true.clone()),
qinsoon's avatar
qinsoon committed
393
                                        ULE => self.backend.emit_jbe(blk_true.clone()),
qinsoon's avatar
qinsoon committed
394
                                        ULT => self.backend.emit_jb(blk_true.clone()),
qinsoon's avatar
qinsoon committed
395

qinsoon's avatar
qinsoon committed
396
                                        FOEQ | FUEQ => self.backend.emit_je(blk_true.clone()),
qinsoon's avatar
qinsoon committed
397
                                        FONE | FUNE => self.backend.emit_jne(blk_true.clone()),
qinsoon's avatar
qinsoon committed
398
                                        FOGT | FUGT => self.backend.emit_ja(blk_true.clone()),
qinsoon's avatar
qinsoon committed
399
                                        FOGE | FUGE => self.backend.emit_jae(blk_true.clone()),
qinsoon's avatar
qinsoon committed
400
                                        FOLT | FULT => self.backend.emit_jb(blk_true.clone()),
qinsoon's avatar
qinsoon committed
401
402
                                        FOLE | FULE => self.backend.emit_jbe(blk_true.clone()),

qinsoon's avatar
qinsoon committed
403
                                        // FFALSE/FTRUE unimplemented
qinsoon's avatar
qinsoon committed
404
                                        _ => unimplemented!(),
qinsoon's avatar
qinsoon committed
405
406
                                    }

407
                                    // finishing current block
qinsoon's avatar
qinsoon committed
408
                                    self.finish_block();
409
410

                                    // blk_false:
qinsoon's avatar
qinsoon committed
411
                                    self.start_block(blk_false.clone());
qinsoon's avatar
qinsoon committed
412
                                    // mov false result here
qinsoon's avatar
qinsoon committed
413
414
415
416
417
418
419
                                    self.emit_move_node_to_value(
                                        &tmp_res,
                                        &false_val,
                                        f_content,
                                        f_context,
                                        vm,
                                    );
qinsoon's avatar
qinsoon committed
420
421
422
                                    // jmp to end
                                    self.backend.emit_jmp(blk_end.clone());
                                    // finishing current block
qinsoon's avatar
qinsoon committed
423
                                    self.finish_block();
qinsoon's avatar
qinsoon committed
424
425

                                    // blk_true:
qinsoon's avatar
qinsoon committed
426
                                    self.start_block(blk_true.clone());
qinsoon's avatar
qinsoon committed
427
                                    // mov true value -> result
qinsoon's avatar
qinsoon committed
428
429
430
431
432
433
434
                                    self.emit_move_node_to_value(
                                        &tmp_res,
                                        &true_val,
                                        f_content,
                                        f_context,
                                        vm,
                                    );
435
                                    self.finish_block();
qinsoon's avatar
qinsoon committed
436
437

                                    // blk_end:
438
                                    self.start_block(blk_end.clone());
qinsoon's avatar
qinsoon committed
439
                                }
qinsoon's avatar
qinsoon committed
440
                            }
441
442
443
                        } else if self.match_fpreg(true_val) {
                            let tmp_res = self.get_result_value(node);

qinsoon's avatar
qinsoon committed
444
445
446
447
448
449
                            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");
450
451
452

                            // jump to blk_true if true
                            match cmpop {
qinsoon's avatar
qinsoon committed
453
454
                                EQ => self.backend.emit_je(blk_true.clone()),
                                NE => self.backend.emit_jne(blk_true.clone()),
455
                                SGE => self.backend.emit_jge(blk_true.clone()),
qinsoon's avatar
qinsoon committed
456
                                SGT => self.backend.emit_jg(blk_true.clone()),
457
                                SLE => self.backend.emit_jle(blk_true.clone()),
qinsoon's avatar
qinsoon committed
458
                                SLT => self.backend.emit_jl(blk_true.clone()),
459
                                UGE => self.backend.emit_jae(blk_true.clone()),
qinsoon's avatar
qinsoon committed
460
                                UGT => self.backend.emit_ja(blk_true.clone()),
461
                                ULE => self.backend.emit_jbe(blk_true.clone()),
qinsoon's avatar
qinsoon committed
462
                                ULT => self.backend.emit_jb(blk_true.clone()),
463

qinsoon's avatar
qinsoon committed
464
                                FOEQ | FUEQ => self.backend.emit_je(blk_true.clone()),
465
                                FONE | FUNE => self.backend.emit_jne(blk_true.clone()),
qinsoon's avatar
qinsoon committed
466
                                FOGT | FUGT => self.backend.emit_ja(blk_true.clone()),
467
                                FOGE | FUGE => self.backend.emit_jae(blk_true.clone()),
qinsoon's avatar
qinsoon committed
468
                                FOLT | FULT => self.backend.emit_jb(blk_true.clone()),
469
470
                                FOLE | FULE => self.backend.emit_jbe(blk_true.clone()),

qinsoon's avatar
qinsoon committed
471
                                _ => unimplemented!(),
472
473
474
                            }

                            // finishing current block
qinsoon's avatar
qinsoon committed
475
                            self.finish_block();
476
477

                            // blk_false:
qinsoon's avatar
qinsoon committed
478
                            self.start_block(blk_false.clone());
479
                            // mov false result here
qinsoon's avatar
qinsoon committed
480
481
482
483
484
485
486
                            self.emit_move_node_to_value(
                                &tmp_res,
                                &false_val,
                                f_content,
                                f_context,
                                vm,
                            );
487
488
489
490
                            // jmp to end
                            self.backend.emit_jmp(blk_end.clone());

                            // finishing current block
qinsoon's avatar
qinsoon committed
491
                            self.finish_block();
492
493

                            // blk_true:
qinsoon's avatar
qinsoon committed
494
                            self.start_block(blk_true.clone());
495
                            // mov true value -> result
qinsoon's avatar
qinsoon committed
496
497
498
499
500
501
502
                            self.emit_move_node_to_value(
                                &tmp_res,
                                &true_val,
                                f_content,
                                f_context,
                                vm,
                            );
qinsoon's avatar
qinsoon committed
503
                            self.finish_block();
504
505

                            // blk_end:
qinsoon's avatar
qinsoon committed
506
                            self.start_block(blk_end.clone());
qinsoon's avatar
qinsoon committed
507
508
509
                        } else {
                            unimplemented!()
                        }
qinsoon's avatar
qinsoon committed
510
                    }
qinsoon's avatar
qinsoon committed
511

qinsoon's avatar
qinsoon committed
512
                    Instruction_::CmpOp(_, _, _) => {
qinsoon's avatar
qinsoon committed
513
                        use ast::op::CmpOp::*;
qinsoon's avatar
qinsoon committed
514
                        trace!("instsel on CMPOP");
515

qinsoon's avatar
qinsoon committed
516
                        let tmp_res = self.get_result_value(node);
qinsoon's avatar
qinsoon committed
517
518
                        assert!(tmp_res.ty.get_int_length().is_some());
                        assert!(tmp_res.ty.get_int_length().unwrap() == 1);
qinsoon's avatar
qinsoon committed
519

520
                        // set byte to result
qinsoon's avatar
qinsoon committed
521
                        match self.emit_cmp_res(node, f_content, f_context, vm) {
qinsoon's avatar
qinsoon committed
522
523
                            EQ => self.backend.emit_sete_r(&tmp_res),
                            NE => self.backend.emit_setne_r(&tmp_res),
524
                            SGE => self.backend.emit_setge_r(&tmp_res),
qinsoon's avatar
qinsoon committed
525
                            SGT => self.backend.emit_setg_r(&tmp_res),
526
                            SLE => self.backend.emit_setle_r(&tmp_res),
qinsoon's avatar
qinsoon committed
527
                            SLT => self.backend.emit_setl_r(&tmp_res),
528
                            UGE => self.backend.emit_setae_r(&tmp_res),
qinsoon's avatar
qinsoon committed
529
                            UGT => self.backend.emit_seta_r(&tmp_res),
530
                            ULE => self.backend.emit_setbe_r(&tmp_res),
qinsoon's avatar
qinsoon committed
531
                            ULT => self.backend.emit_setb_r(&tmp_res),
532

qinsoon's avatar
qinsoon committed
533
                            FOEQ | FUEQ => self.backend.emit_sete_r(&tmp_res),
534
                            FONE | FUNE => self.backend.emit_setne_r(&tmp_res),
qinsoon's avatar
qinsoon committed
535
                            FOGT | FUGT => self.backend.emit_seta_r(&tmp_res),
536
                            FOGE | FUGE => self.backend.emit_setae_r(&tmp_res),
qinsoon's avatar
qinsoon committed
537
                            FOLT | FULT => self.backend.emit_setb_r(&tmp_res),
538
                            FOLE | FULE => self.backend.emit_setbe_r(&tmp_res),
qinsoon's avatar
qinsoon committed
539

qinsoon's avatar
qinsoon committed
540
                            // FFALSE/FTRUE
qinsoon's avatar
qinsoon committed
541
                            _ => unimplemented!(),
542
543
544
                        }
                    }

qinsoon's avatar
qinsoon committed
545
                    Instruction_::Branch1(ref dest) => {
qinsoon's avatar
qinsoon committed
546
                        trace!("instsel on BRANCH1");
547
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
548

549
                        self.process_dest(&ops, dest, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
550

551
                        let target = f_content.get_block(dest.target).name();
552
                        // jmp
qinsoon's avatar
qinsoon committed
553
                        self.backend.emit_jmp(target);
qinsoon's avatar
qinsoon committed
554
                    }
qinsoon's avatar
qinsoon committed
555

qinsoon's avatar
qinsoon committed
556
557
558
559
560
                    Instruction_::Switch {
                        cond,
                        ref default,
                        ref branches,
                    } => {
qinsoon's avatar
qinsoon committed
561
                        trace!("instsel on SWITCH");
562
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
563
564
565
566
567
                        let ref cond = ops[cond];

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

qinsoon's avatar
qinsoon committed
568
569
570
571
                            // currently implementing switch as cascading conditional branch
                            // This is slow if there are many 'case' arms. We should consider
                            // using a switch table

qinsoon's avatar
qinsoon committed
572
573
574
575
576
577
578
                            // 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);

579
                                let target = f_content.get_block(case_dest.target).name();
qinsoon's avatar
qinsoon committed
580
581
582
583
584

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

                                    // cmp case cond
qinsoon's avatar
qinsoon committed
585
                                    self.backend.emit_cmp_imm_r(imm, &tmp_cond);
qinsoon's avatar
qinsoon committed
586
587
588
                                    // je dest
                                    self.backend.emit_je(target);
                                } else if self.match_ireg(case_op) {
qinsoon's avatar
qinsoon committed
589
590
                                    let tmp_case_op =
                                        self.emit_ireg(case_op, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
591
592

                                    // cmp case cond
qinsoon's avatar
qinsoon committed
593
                                    self.backend.emit_cmp_r_r(&tmp_case_op, &tmp_cond);
qinsoon's avatar
qinsoon committed
594
595
596
                                    // je dest
                                    self.backend.emit_je(target);
                                } else {
qinsoon's avatar
qinsoon committed
597
598
599
600
                                    panic!(
                                        "expecting ireg cond to be either iimm or ireg: {}",
                                        cond
                                    );
qinsoon's avatar
qinsoon committed
601
                                }
602
603

                                self.finish_block();
qinsoon's avatar
qinsoon committed
604
605
606
607
608
                                let block_name = make_block_name(
                                    &self.current_fv_name,
                                    node.id(),
                                    format!("switch_not_met_case_{}", case_op_index).as_str(),
                                );
609
                                self.start_block(block_name);
qinsoon's avatar
qinsoon committed
610
611
612
613
                            }

                            // emit default
                            self.process_dest(&ops, default, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
614

615
                            let default_target = f_content.get_block(default.target).name();
qinsoon's avatar
qinsoon committed
616
617
                            self.backend.emit_jmp(default_target);
                        } else {
qinsoon's avatar
qinsoon committed
618
619
                            // other EQ-comparable types, e.g. floating point
                            unimplemented!()
qinsoon's avatar
qinsoon committed
620
621
                        }
                    }
qinsoon's avatar
qinsoon committed
622
623

                    Instruction_::ExprCall { ref data, is_abort } => {
qinsoon's avatar
qinsoon committed
624
625
                        trace!("instsel on EXPRCALL");

qinsoon's avatar
qinsoon committed
626
                        if is_abort {
qinsoon's avatar
qinsoon committed
627
628
629
                            // if any exception throws from the callee,
                            // we should abort execution, otherwise rethrow the exception
                            // FIXME: implement is_abort
qinsoon's avatar
qinsoon committed
630
                            unimplemented!()
631
                        }
qinsoon's avatar
qinsoon committed
632

qinsoon's avatar
qinsoon committed
633
634
635
636
                        self.emit_mu_call(
                            inst, // inst: &Instruction,
                            data, // calldata: &CallData,
                            None, // resumption: Option<&ResumptionData>,
qinsoon's avatar
qinsoon committed
637
638
639
640
641
642
643
644
645
646
647
                            node, // cur_node: &TreeNode,
                            f_content,
                            f_context,
                            vm,
                        );
                    }

                    Instruction_::Call {
                        ref data,
                        ref resume,
                    } => {
qinsoon's avatar
qinsoon committed
648
649
                        trace!("instsel on CALL");

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

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

qinsoon's avatar
qinsoon committed
656
                        if is_abort {
qinsoon's avatar
qinsoon committed
657
658
659
                            // if any exception throws from the callee,
                            // we should abort execution, otherwise rethrow the exception
                            // FIXME: implement is_abort
qinsoon's avatar
qinsoon committed
660
661
662
                            unimplemented!()
                        }

qinsoon's avatar
qinsoon committed
663
                        self.emit_c_call_ir(inst, data, None, node, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
664
665
                    }

qinsoon's avatar
qinsoon committed
666
667
668
669
                    Instruction_::CCall {
                        ref data,
                        ref resume,
                    } => {
qinsoon's avatar
qinsoon committed
670
671
                        trace!("instsel on CCALL");

qinsoon's avatar
qinsoon committed
672
673
674
675
676
                        self.emit_c_call_ir(
                            inst,
                            data,
                            Some(resume),
                            node,
qinsoon's avatar
qinsoon committed
677
678
679
680
                            f_content,
                            f_context,
                            vm,
                        );
qinsoon's avatar
qinsoon committed
681
                    }
qinsoon's avatar
qinsoon committed
682

683
                    Instruction_::Return(_) => {
qinsoon's avatar
qinsoon committed
684
685
                        trace!("instsel on RETURN");

686
                        self.emit_common_epilogue(inst, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
687

qinsoon's avatar
qinsoon committed
688
                        self.backend.emit_ret();
qinsoon's avatar
qinsoon committed
689
690
                    }

qinsoon's avatar
qinsoon committed
691
                    Instruction_::BinOp(op, op1, op2) => {
qinsoon's avatar
qinsoon committed
692
693
                        trace!("instsel on BINOP");

qinsoon's avatar
qinsoon committed
694
                        self.emit_binop(node, inst, op, op1, op2, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
695
                    }
qinsoon's avatar
qinsoon committed
696

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

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

qinsoon's avatar
qinsoon committed
702
703
                        let values = inst.value.as_ref().unwrap();
                        let mut status_value_index = 1;
qinsoon's avatar
qinsoon committed
704

705
                        // status flags only works with int operations
706
                        if RegGroup::get_from_value(&values[0]) == RegGroup::GPR {
qinsoon's avatar
qinsoon committed
707
708
709
710
711
                            // for mul, div, idiv, some of the flags may not generated
                            // from the computation, and we may need extra code
                            // to get the flags
                            // FIXME: See Issue#22

712
713
714
715
                            // negative flag
                            if status.flag_n {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
716

717
718
                                self.backend.emit_sets_r8(&tmp_status);
                            }
qinsoon's avatar
qinsoon committed
719

720
721
722
723
                            // zero flag
                            if status.flag_z {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
724

725
726
                                self.backend.emit_setz_r8(&tmp_status);
                            }
qinsoon's avatar
qinsoon committed
727

728
729
730
731
                            // unsigned overflow
                            if status.flag_c {
                                let tmp_status = values[status_value_index].clone();
                                status_value_index += 1;
qinsoon's avatar
qinsoon committed
732

733
734
735
736
                                match op {
                                    BinOp::Add | BinOp::Sub | BinOp::Mul => {
                                        self.backend.emit_setb_r8(&tmp_status);
                                    }
qinsoon's avatar
qinsoon committed
737
                                    _ => panic!("Only Add/Sub/Mul has #C flag"),
qinsoon's avatar
qinsoon committed
738
739
                                }
                            }
qinsoon's avatar
qinsoon committed
740

741
742
743
                            // signed overflow
                            if status.flag_v {
                                let tmp_status = values[status_value_index].clone();
qinsoon's avatar
qinsoon committed
744

745
746
747
748
                                match op {
                                    BinOp::Add | BinOp::Sub | BinOp::Mul => {
                                        self.backend.emit_seto_r8(&tmp_status);
                                    }
qinsoon's avatar
qinsoon committed
749
                                    _ => panic!("Only Add/Sub/Mul has #V flag"),
qinsoon's avatar
qinsoon committed
750
751
                                }
                            }
752
753
754
                        } else if RegGroup::get_from_value(&values[0]) == RegGroup::GPREX {
                            unimplemented!()
                        } else {
qinsoon's avatar
[wip]    
qinsoon committed
755
                            panic!("only int operations allow binop status flags")
756
757
                        }
                    }
qinsoon's avatar
qinsoon committed
758

qinsoon's avatar
qinsoon committed
759
760
761
762
763
764
                    Instruction_::ConvOp {
                        operation,
                        ref from_ty,
                        ref to_ty,
                        operand,
                    } => {
qinsoon's avatar
qinsoon committed
765
766
                        trace!("instsel on CONVOP");

767
                        let ref ops = inst.ops;
qinsoon's avatar
qinsoon committed
768
769
770
                        let ref op = ops[operand];

                        match operation {
qinsoon's avatar
[wip]    
qinsoon committed
771
                            // Truncate (from int to int)
qinsoon's avatar
qinsoon committed
772
                            op::ConvOp::TRUNC => {
qinsoon's avatar
qinsoon committed
773
                                let tmp_res = self.get_result_value(node);
qinsoon's avatar
vm.rs    
qinsoon committed
774
                                let to_ty_size = vm.get_backend_type_size(tmp_res.ty.id());
qinsoon's avatar
qinsoon committed
775

qinsoon's avatar
qinsoon committed
776
777
                                if self.match_ireg(op) {
                                    let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
778

qinsoon's avatar
qinsoon committed
779
                                    // mov op -> result
qinsoon's avatar
qinsoon committed
780
                                    match 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
                                        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),
qinsoon's avatar
qinsoon committed
802
803
                                    }
                                } else if self.match_ireg_ex(op) {
qinsoon's avatar
qinsoon committed
804
                                    let (op_l, _) = self.emit_ireg_ex(op, f_content, f_context, vm);
qinsoon's avatar
qinsoon committed
805
806

                                    match to_ty_size {
qinsoon's avatar
qinsoon committed
807
808
809
810
811
812
                                        1 | 2 => {
                                            self.backend.emit_movz_r_r(
                                                unsafe { &tmp_res.as_type(UINT32_TYPE.clone()) },
                                                &op_l,
                                            )
                                        }
qinsoon's avatar
qinsoon committed
813
                                        4 | 8 => self.backend.emit_mov_r_r(&tmp_res, &op_l),
qinsoon's avatar
qinsoon committed
814
                                        _ => panic!("unsupported int size: {}", to_ty_size),
815
                                    }
qinsoon's avatar
qinsoon committed
816
817
818
819
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
                                }
                            }
qinsoon's avatar
[wip]    
qinsoon committed
820
                            // Zero extend (from int to int)
qinsoon's avatar
qinsoon committed
821
                            op::ConvOp::ZEXT => {
822
823
824
                                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
825

826
                                    // movz op -> result
qinsoon's avatar
vm.rs    
qinsoon committed
827
                                    let from_ty_size = vm.get_backend_type_size(from_ty.id());
qinsoon's avatar
qinsoon committed
828
                                    let to_ty_size = vm.get_backend_type_size(to_ty.id());
qinsoon's avatar
qinsoon committed
829

qinsoon's avatar
qinsoon committed
830
831
                                    // we treat int1 as int8, so it is possible
                                    // from_ty_size == to_ty_size == 1 byte
qinsoon's avatar
[wip]    
qinsoon committed
832
833
                                    assert!(from_ty_size <= to_ty_size);

834
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
835
836
837
                                        match (from_ty_size, to_ty_size) {
                                            // int32 to int64
                                            (4, 8) => {
qinsoon's avatar
qinsoon committed
838
839
                                                // zero extend from 32 bits to 64 bits is
                                                // a mov instruction
qinsoon's avatar
qinsoon committed
840
841
842
                                                // x86 does not have movzlq (32 to 64)

                                                // tmp_op is int32, but tmp_res is int64
qinsoon's avatar
qinsoon committed
843
844
845
846
                                                // 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()) };
qinsoon's avatar
qinsoon committed
847
848
849
850
851

                                                self.backend.emit_mov_r_r(&tmp_res32, &tmp_op);
                                            }
                                            // any int to int128
                                            (_, 16) => {
qinsoon's avatar
qinsoon committed
852
853
                                                let (res_l, res_h) =
                                                    self.split_int128(&tmp_res, f_context, vm);
qinsoon's avatar
qinsoon committed
854

qinsoon's avatar
qinsoon committed
855
856
857
                                                self.backend.emit_mov_r_r(&res_l, unsafe {
                                                    &tmp_op.as_type(UINT64_TYPE.clone())
                                                });
qinsoon's avatar
qinsoon committed
858
859
                                                self.backend.emit_mov_r_imm(&res_h, 0);
                                            }
qinsoon's avatar
[wip]    
qinsoon committed
860
                                            // other cases
qinsoon's avatar
qinsoon committed
861
862
863
                                            _ => {
                                                self.backend.emit_movz_r_r(&tmp_res, &tmp_op);
                                            }
qinsoon's avatar
qinsoon committed
864
                                        }
qinsoon's avatar
qinsoon committed
865
                                    } else {
866
                                        self.backend.emit_mov_r_r(&tmp_res, &tmp_op);
qinsoon's avatar
qinsoon committed
867
                                    }
868
869
                                } else {
                                    panic!("unexpected op (expect ireg): {}", op);
qinsoon's avatar
qinsoon committed
870
                                }
qinsoon's avatar
qinsoon committed
871
                            }
qinsoon's avatar
[wip]    
qinsoon committed
872
                            // Sign extend (from int to int)
qinsoon's avatar
qinsoon committed
873
                            op::ConvOp::SEXT => {
874
875
876
                                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
877

878
                                    // movs op -> result
qinsoon's avatar
vm.rs    
qinsoon committed
879
                                    let from_ty_size = vm.get_backend_type_size(from_ty.id());
qinsoon's avatar
qinsoon committed
880
                                    let to_ty_size = vm.get_backend_type_size(to_ty.id());
qinsoon's avatar
qinsoon committed
881

qinsoon's avatar
qinsoon committed
882
883
                                    // we treat int1 as int8, so it is possible
                                    // from_ty_size == to_ty_size == 1 byte
qinsoon's avatar
[wip]    
qinsoon committed
884
885
                                    assert!(from_ty_size <= to_ty_size);

886
                                    if from_ty_size != to_ty_size {
qinsoon's avatar
qinsoon committed
887
888
889
                                        match (from_ty_size, to_ty_size) {
                                            // int64 to int128
                                            (8, 16) => {
qinsoon's avatar
qinsoon committed
890
891
                                                let (res_l, res_h) =
                                                    self.split_int128(&tmp_res, f_context, vm);