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

inst_sel.rs 192 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#![allow(unused_variables)]
#![warn(unused_imports)]
#![warn(unreachable_code)]
#![warn(dead_code)]
use ast::ir::*;
use ast::ptr::*;
use ast::inst::*;
use ast::op;
use ast::op::*;
use ast::types;
use ast::types::*;
use vm::VM;
use runtime::mm;
use runtime::mm::objectmodel::OBJECT_HEADER_SIZE;

use runtime::ValueLocation;
use runtime::thread;
use runtime::entrypoints;
use runtime::entrypoints::RuntimeEntrypoint;

use compiler::CompilerPass;

use compiler::backend::PROLOGUE_BLOCK_NAME;

use compiler::backend::aarch64::*;
use compiler::machine_code::CompiledFunction;
use compiler::frame::Frame;

use std::collections::HashMap;
use std::any::Any;

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

    pub static ref FPTOUI_C : P<Value> = P(Value{
        hdr: MuEntityHeader::named(new_internal_id(), Mu("FPTOUI_C")),
        ty : UINT64_TYPE.clone(),
        v  : Value_::Constant(Constant::Int(4890909195324358656u64))
    });
}

const INLINE_FASTPATH : bool = false;

pub struct InstructionSelection {
    name: &'static str,
    backend: Box<CodeGenerator>,

    current_fv_id: MuID,
    current_callsite_id: usize,
    current_frame: Option<Frame>,
    current_block: Option<MuName>,
    current_func_start: Option<ValueLocation>,
    // key: block id, val: callsite that names the block as exception block
    current_exn_callsites: HashMap<MuID, Vec<ValueLocation>>,
    // key: block id, val: block location
    current_exn_blocks: HashMap<MuID, ValueLocation>,

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

impl <'a> InstructionSelection {
    #[cfg(feature = "aot")]
    pub fn new() -> InstructionSelection {
        InstructionSelection {
            name: "Instruction Selection (x64)",
            backend: Box::new(ASMCodeGen::new()),

            current_fv_id: 0,
            current_callsite_id: 0,
            current_frame: None,
            current_block: None,
            current_func_start: None,
            // key: block id, val: callsite that names the block as exception block
            current_exn_callsites: HashMap::new(),
            current_exn_blocks: HashMap::new(),

            current_constants: HashMap::new(),
            current_constants_locs: HashMap::new()
        }
    }

    #[cfg(feature = "jit")]
    pub fn new() -> InstructionSelection {
        unimplemented!()
    }

    // in this pass, we assume that
    // * we do not need to backup/restore caller-saved registers
    // if any of these assumption breaks, we will need to re-emit the code
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
141
    fn instruction_select(&mut self, node: &'a TreeNode, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) {
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
        trace!("instsel on node#{} {}", node.id(), node);

        match node.v {
            TreeNode_::Instruction(ref inst) => {
                match inst.v {
                    // aarch64
                    Instruction_::Branch2 { cond, ref true_dest, ref false_dest, true_prob } => {
                        // TODO: How does control flow pass to fallthrough_dest ???
                        trace!("instsel on BRANCH2");
                        // '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)
                        let (fallthrough_dest, branch_dest, branch_if_true) = {
                            if true_prob > 0.5f32 {
                                (true_dest, false_dest, false)
                            } else {
                                (false_dest, true_dest, true)
                            }
                        };

                        let ops = inst.ops.read().unwrap();

                        self.process_dest(&ops, fallthrough_dest, f_content, f_context, vm);
                        self.process_dest(&ops, branch_dest, f_content, f_context, vm);

                        let branch_target = f_content.get_block(branch_dest.target).name().unwrap();

                        let ref cond = ops[cond];

                        let mut cmpop = if self.match_cmp_res(cond) {
                            trace!("emit cmp_res-branch2");
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
172
                            self.emit_cmp_res(cond, f_content, f_context, vm)
173
                        } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
174
                            let cond_reg = self.emit_ireg(cond, f_content, f_context, vm);
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
                            self.backend.emit_cmp_imm(&cond_reg, 0, false);
                            op::CmpOp::NE
                        };

                        if !branch_if_true {
                            cmpop = cmpop.invert();
                        }

                        let cond = get_condition_codes(cmpop);

                        if cmpop == op::CmpOp::FFALSE {
                            ; // Do nothing
                        } else if cmpop == op::CmpOp::FTRUE {
                            self.backend.emit_b(branch_target);
                        } else {
                            self.backend.emit_b_cond(cond[0], branch_target.clone());

                            if cond.len() == 2 {
                                self.backend.emit_b_cond(cond[1], branch_target);
                            }
                        }
                    },

                    // aarch64
                    Instruction_::Select { cond, true_val, false_val } => {
                        use ast::op::CmpOp::*;

                        trace!("instsel on SELECT");
                        let ops = inst.ops.read().unwrap();

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

                        let tmp_res = self.get_result_value(node);

                        // moving integers/pointers
                        // generate compare
                        let cmpop = if self.match_cmp_res(cond) {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
214
                            self.emit_cmp_res(cond, f_content, f_context, vm)
215
                        } else if self.match_ireg(cond) {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
216
                            let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);
217
218
219
220
221
222
                            self.backend.emit_cmp_imm(&tmp_cond, 0, false);
                            NE
                        } else {
                            panic!("expected ireg, found {}", cond)
                        };

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
223
224
                        let tmp_true = self.emit_reg(true_val, f_content, f_context, vm);
                        let tmp_false = self.emit_reg(false_val, f_content, f_context, vm);
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

                        let cond = get_condition_codes(cmpop);

                        if self.match_ireg(true_val) {
                            if cmpop == FFALSE {
                                self.backend.emit_mov(&tmp_res, &tmp_false);
                            } else if cmpop == FTRUE {
                                self.backend.emit_mov(&tmp_res, &tmp_true);
                            } else {
                                self.backend.emit_csel(&tmp_res, &tmp_true, &tmp_false, cond[0]);

                                if cond.len() == 2 {
                                    self.backend.emit_csel(&tmp_res, &tmp_true, &tmp_res, cond[1]);
                                }
                            }
                        } else if self.match_fpreg(true_val) {
                            if cmpop == FFALSE {
                                self.backend.emit_fmov(&tmp_res, &tmp_false);
                            } else if cmpop == FTRUE {
                                self.backend.emit_fmov(&tmp_res, &tmp_true);
                            } else {
                                self.backend.emit_fcsel(&tmp_res, &tmp_true, &tmp_false, cond[0]);

                                if cond.len() == 2 {
                                    self.backend.emit_fcsel(&tmp_res, &tmp_true, &tmp_res, cond[1]);
                                }
                            }
                        } else {
                            // moving vectors, floatingpoints
                            unimplemented!()
                        }
                    },

                    // aarch64
                    Instruction_::CmpOp(op, op1, op2) => {
                        use ast::op::CmpOp::*;

                        trace!("instsel on CMPOP");
                        let ops = inst.ops.read().unwrap();
                        let ref op1 = ops[op1];
                        let ref op2 = ops[op2];

                        let tmp_res = self.get_result_value(node);

                        debug_assert!(tmp_res.ty.get_int_length().is_some());
                        debug_assert!(tmp_res.ty.get_int_length().unwrap() == 1);

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
272
                        let cmpop = self.emit_cmp_res_op(op, &op1, &op2, f_content, f_context, vm);
273
274
275
                        let cond = get_condition_codes(cmpop);

                        if cmpop == FFALSE {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
276
                            self.emit_mov_u64(&tmp_res, 0);
277
                        } else if cmpop == FTRUE {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
278
                            self.emit_mov_u64(&tmp_res, 1);
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
                        } else {
                            self.backend.emit_cset(&tmp_res, cond[0]);

                            // Note: some compariosns can't be computed based on a single aarch64 flag
                            // insted they are computed as a condition OR NOT another condition.
                            if cond.len() == 2 {
                                self.backend.emit_csinc(&tmp_res, &tmp_res, &WZR, invert_condition_code(cond[1]));
                            }
                        }
                    }

                    // aarch64
                    Instruction_::Branch1(ref dest) => {
                        trace!("instsel on BRANCH1");
                        let ops = inst.ops.read().unwrap();

                        self.process_dest(&ops, dest, f_content, f_context, vm);

                        let target = f_content.get_block(dest.target).name().unwrap();

                        trace!("emit branch1");
                        // jmp
                        self.backend.emit_b(target);
                    },

                    // aarch64
                    Instruction_::Switch { cond, ref default, ref branches } => {
                        trace!("instsel on SWITCH");
                        let ops = inst.ops.read().unwrap();

                        let ref cond = ops[cond];

                        if self.match_ireg(cond) {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
312
313
                            let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);
                            self.emit_zext(&tmp_cond);
314
315
316
317
318
319
320
321
322
323
324
325

                            // emit each branch
                            for &(case_op_index, ref case_dest) in branches {
                                let ref case_op = ops[case_op_index];

                                // process dest
                                self.process_dest(&ops, case_dest, f_content, f_context, vm);

                                let target = f_content.get_block(case_dest.target).name().unwrap();

                                let mut imm_val = 0 as u64;
                                // Is one of the arguments a valid immediate?
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
326
327
                                let emit_imm = if self.match_node_iimm(&case_op) {
                                    imm_val = self.node_iimm_to_u64(&case_op);
328
329
330
331
332
333
334
335
336
337
338
                                    is_valid_arithmetic_imm(imm_val)
                                } else {
                                    false
                                };

                                if emit_imm {
                                    let imm_shift = imm_val > 4096;
                                    let imm_op2 = if imm_shift { imm_val >> 12 } else { imm_val };

                                    self.backend.emit_cmp_imm(&tmp_cond, imm_op2 as u16, imm_shift);
                                } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
339
340
                                    let tmp_case_op = self.emit_ireg(case_op, f_content, f_context, vm);
                                    self.emit_zext(&tmp_case_op);
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
                                    self.backend.emit_cmp(&tmp_cond, &tmp_case_op);
                                }

                                self.backend.emit_b_cond("EQ", target);

                                self.finish_block();
                                self.start_block(format!("{}_switch_not_met_case_{}", node.id(), case_op_index));
                            }

                            // emit default
                            self.process_dest(&ops, default, f_content, f_context, vm);

                            let default_target = f_content.get_block(default.target).name().unwrap();
                            self.backend.emit_b(default_target);
                        } else {
                            panic!("expecting cond in switch to be ireg: {}", cond);
                        }
                    }

                    // aarch64
                    Instruction_::ExprCall { ref data, is_abort } => {
                        trace!("instsel on EXPRCALL");

                        if is_abort {
                            unimplemented!()
                        }

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
368
                        self.emit_mu_call(
369
370
371
372
373
374
375
376
377
378
379
                            inst, // inst: &Instruction,
                            data, // calldata: &CallData,
                            None, // resumption: Option<&ResumptionData>,
                            node, // cur_node: &TreeNode, 
                            f_content, f_context, vm);
                    },

                    // aarch64
                    Instruction_::Call { ref data, ref resume } => {
                        trace!("instsel on CALL");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
380
                        self.emit_mu_call(
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
                            inst,
                            data,
                            Some(resume),
                            node,
                            f_content, f_context, vm);
                    },

                    // aarch64
                    Instruction_::ExprCCall { ref data, is_abort } => {
                        trace!("instsel on EXPRCCALL");

                        if is_abort {
                            unimplemented!()
                        }

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
396
                        self.emit_c_call_ir(inst, data, None, node, f_content, f_context, vm);
397
398
399
400
401
402
                    }

                    // aarch64
                    Instruction_::CCall { ref data, ref resume } => {
                        trace!("instsel on CCALL");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
403
                        self.emit_c_call_ir(inst, data, Some(resume), node, f_content, f_context, vm);
404
405
406
407
408
409
                    }

                    // aarch64
                    Instruction_::Return(_) => {
                        trace!("instsel on RETURN");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
410
                        self.emit_common_epilogue(inst, f_content, f_context, vm);
411
412
413
414
415
416
417

                        self.backend.emit_ret(&LR); // return to the Link Register
                    },

                    // aarch64
                    Instruction_::BinOp(op, op1, op2) => {
                        trace!("instsel on BINOP");
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
418
                        self.emit_binop(node, inst, op, BinOpStatus { flag_n: false, flag_z: false, flag_c: false, flag_v: false }, op1, op2, f_content, f_context, vm);
419
420
421
422
423
                    },

                    // aarch64
                    Instruction_::BinOpWithStatus(op, status, op1, op2) => {
                        trace!("instsel on BINOP_STATUS");
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
424
                        self.emit_binop(node, inst, op, status, op1, op2, f_content, f_context, vm);
425
426
427
428
429
430
431
432
433
434
435
                    }

                    // aarch64
                    Instruction_::ConvOp { operation, ref from_ty, ref to_ty, operand } => {
                        trace!("instsel on CONVOP");

                        let ops = inst.ops.read().unwrap();

                        let ref op = ops[operand];

                        let tmp_res = self.get_result_value(node);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
436
                        let tmp_op = self.emit_reg(op, f_content, f_context, vm);
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501

                        let from_ty_size = get_bit_size(&from_ty, vm);
                        let to_ty_size = get_bit_size(&to_ty, vm);

                        match operation {
                            op::ConvOp::TRUNC => {
                                self.backend.emit_mov(&tmp_res, unsafe { &tmp_op.as_type(tmp_res.ty.clone()) });
                            },
                            op::ConvOp::ZEXT => {
                                if from_ty_size != to_ty_size {
                                    self.backend.emit_ubfx(&tmp_res, unsafe { &tmp_op.as_type(tmp_res.ty.clone()) }, 0, from_ty_size as u8);
                                } else {
                                    self.backend.emit_mov(&tmp_res, &tmp_op);
                                }
                            },
                            op::ConvOp::SEXT => {
                                if from_ty_size != to_ty_size {
                                    self.backend.emit_sbfx(&tmp_res, unsafe { &tmp_op.as_type(tmp_res.ty.clone()) }, 0, from_ty_size as u8);
                                } else {
                                    self.backend.emit_mov(&tmp_res, &tmp_op);
                                }
                            },
                            op::ConvOp::REFCAST | op::ConvOp::PTRCAST => {
                                // just a mov (and hopefully reg alloc will coalesce it)
                                self.backend.emit_mov(&tmp_res, &tmp_op);
                            },

                            op::ConvOp::UITOFP => {
                                self.backend.emit_ucvtf(&tmp_res, &tmp_op);
                            },

                            op::ConvOp::SITOFP => {
                                self.backend.emit_scvtf(&tmp_res, &tmp_op);
                            },

                            op::ConvOp::FPTOUI => {
                                self.backend.emit_fcvtzu(&tmp_res, &tmp_op);
                            },

                            op::ConvOp::FPTOSI => {
                                self.backend.emit_fcvtzs(&tmp_res, &tmp_op);
                            },

                            op::ConvOp::BITCAST => {
                                self.backend.emit_fmov(&tmp_res, &tmp_op);
                            },
                            op::ConvOp::FPTRUNC | op::ConvOp::FPEXT => {
                                self.backend.emit_fcvt(&tmp_res, &tmp_op);
                            },
                        }
                    }

                    // aarch64
                    Instruction_::Load { is_ptr, order, mem_loc } => {
                        trace!("instsel on LOAD");
                        let ops = inst.ops.read().unwrap();
                        let ref loc_op = ops[mem_loc];

                        // Whether to use a load acquire
                        let use_acquire = match order {
                            MemoryOrder::Relaxed | MemoryOrder::NotAtomic => false,
                            MemoryOrder::Consume | MemoryOrder::Acquire | MemoryOrder::SeqCst => true,
                            _ => panic!("didnt expect order {:?} with load inst", order)
                        };

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
502
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);
503
504
505
506
                        let res_temp = self.get_result_value(node);

                        if use_acquire {
                            // Can only have a base for a LDAR
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
507
                            let temp_loc = self.emit_mem_base(&resolved_loc, f_context, vm);
508
509
                            self.backend.emit_ldar(&res_temp, &temp_loc);
                        } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
510
                            let temp_loc = self.emit_mem(&resolved_loc, f_context, vm);
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
                            self.backend.emit_ldr(&res_temp, &temp_loc, false);
                        }
                    }

                    // aarch64
                    Instruction_::Store { is_ptr, order, mem_loc, value } => {
                        trace!("instsel on STORE");
                        let ops = inst.ops.read().unwrap();
                        let ref loc_op = ops[mem_loc];
                        let ref val_op = ops[value];

                        // Whether to use a store release or not
                        let use_release = match order {
                            MemoryOrder::Relaxed | MemoryOrder::NotAtomic => false,
                            MemoryOrder::Release | MemoryOrder::SeqCst => true,
                            _ => panic!("didnt expect order {:?} with load inst", order)
                        };

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
529
530
                        let resolved_loc = self.emit_node_addr_to_value(loc_op, f_content, f_context, vm);
                        let val = self.emit_reg(val_op, f_content, f_context, vm);
531
532
533

                        if use_release {
                            // Can only have a base for a STLR
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
534
                            let temp_loc = self.emit_mem_base(&resolved_loc, f_context, vm);
535
536
                            self.backend.emit_stlr(&temp_loc, &val);
                        } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
537
                            let temp_loc = self.emit_mem(&resolved_loc, f_context, vm);
538
539
540
541
542
                            self.backend.emit_str(&temp_loc, &val);
                        }
                    }

                    // aarch64
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576


                /*    (RESULT, SUCESS) = CMPXCHG WEAK ordSucc ordFail <T> LOC EXPECTED DESIRED excClause
                        LDaxR   RESULT <- *LOC
                CMP     RESULT, EXPECTED
                B.NE    compare_failed  // RESULT != EXPECTED
                STlxR   SUCCESS, DESIRED -> *LOC    // if sucess = 0, than the operation succeded
                B       compare_succeded
                compare_failed:
                    CLREX   // comparison failed (only execute CLREX if the store was not attempted)
                MOV SUCCESS, 1  // fail
                compare_succeded:
                    EOR SUCESS, SUCESS, #1 // value will only be 1 if sucess = 0 (only posrsible if the Store suceeded)
                    // (if the above store failed, than we don't realy care...)


                    //The result v is the result of the initial load operation and s is whether the comparison is successful or not.

                    (RESULT, SUCESS) = CMPXCHG ordSucc ordFail <T> LOC EXPECTED DESIRED excClause
                store_failed:
                    LDaxR   RESULT <- *LOC                           // Sucess  ordering (relaxed and release are Xr others are AXr)
                CMP     RESULT, EXPECTED
                B.NE    compare_failed
                STLXR   SUCCESS, DESIRED -> *LOC               // Sucess ordering  (relaxed and acquire ar Xr, all others are LXr)
                CBNZ    SUCCESS, store_failed // try again
                B       compare_succeded
                compare_failed:
                    CLREX
                MOV SUCCESS, 1
                compare_succeded:
                    MVM SUCCESS, SUCCESS // STLXR returns sucess as '0', but we want suces to be a '1', so inver it
                */

                // aarch64
577
578
579
580
581
582
                    Instruction_::GetIRef(_)
                    | Instruction_::GetFieldIRef { .. }
                    | Instruction_::GetElementIRef{..}
                    | Instruction_::GetVarPartIRef { .. }
                    | Instruction_::ShiftIRef { .. } => {
                        trace!("instsel on GET/FIELD/VARPARTIREF, SHIFTIREF");
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
583
                        let mem_addr = self.emit_get_mem_from_inst(node, f_content, f_context, vm);
584
                        let tmp_res = self.get_result_value(node);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
585
                        self.emit_calculate_address(&tmp_res, &mem_addr, f_context, vm);
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
                    }

                    // aarch64
                    Instruction_::Fence(order) => {
                        trace!("instsel on FENCE");

                        // Whether to emit a load fence or a normal one
                        let use_load = match order {
                            MemoryOrder::Release | MemoryOrder::SeqCst | MemoryOrder::AcqRel => false,
                            MemoryOrder::Acquire => true,
                            _ => panic!("didnt expect order {:?} with load inst", order)
                        };

                        if use_load {
                            // Data Memory Barrirer for Inner Shariable Domain (for Load accesses only)
                            self.backend.emit_dmb("ISHLD");
                        } else {
                            // Data Memory Barrirer for Inner Shariable Domain
                            self.backend.emit_dmb("ISH");
                        }
                    }
                    // aarch64
                    Instruction_::ThreadExit => {
                        trace!("instsel on THREADEXIT");
                        // emit a call to swap_back_to_native_stack(sp_loc: Address)

                        // get thread local and add offset to get sp_loc
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
613
                        let tl = self.emit_get_threadlocal(Some(node), f_content, f_context, vm);
614
615
                        self.backend.emit_add_imm(&tl, &tl, *thread::NATIVE_SP_LOC_OFFSET as u16, false);

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
616
                        self.emit_runtime_entry(&entrypoints::SWAP_BACK_TO_NATIVE_STACK, vec![tl.clone()], None, Some(node), f_content, f_context, vm);
617
618
619
620
621
622
                    }

                    // aarch64
                    Instruction_::CommonInst_GetThreadLocal => {
                        trace!("instsel on GETTHREADLOCAL");
                        // get thread local
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
623
                        let tl = self.emit_get_threadlocal(Some(node), f_content, f_context, vm);
624
625
626
627

                        let tmp_res = self.get_result_value(node);

                        // load [tl + USER_TLS_OFFSET] -> tmp_res
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
628
                        self.emit_load_base_offset(&tmp_res, &tl, *thread::USER_TLS_OFFSET as i64, f_context, vm);
629
630
631
632
633
634
635
636
637
638
                    }

                    // aarch64
                    Instruction_::CommonInst_SetThreadLocal(op) => {
                        trace!("instsel on SETTHREADLOCAL");
                        let ops = inst.ops.read().unwrap();
                        let ref op = ops[op];

                        debug_assert!(self.match_ireg(op));

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
639
                        let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
640
641

                        // get thread local
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
642
                        let tl = self.emit_get_threadlocal(Some(node), f_content, f_context, vm);
643
644

                        // store tmp_op -> [tl + USER_TLS_OFFSTE]
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
645
                        self.emit_store_base_offset(&tl, *thread::USER_TLS_OFFSET as i64, &tmp_op, f_context, vm);
646
647
648
649
650
651
652
653
654
655
656
657
                    }

                    // aarch64
                    Instruction_::CommonInst_Pin(op) => {
                        trace!("instsel on PIN");
                        if !mm::GC_MOVES_OBJECT {
                            // non-moving GC: pin is a nop (move from op to result)
                            let ops = inst.ops.read().unwrap();
                            let ref op = ops[op];

                            let tmp_res = self.get_result_value(node);

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
658
                            self.emit_move_node_to_value(&tmp_res, op, f_content, f_context, vm);
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
                        } else {
                            unimplemented!()
                        }
                    }

                    // aarch64
                    Instruction_::CommonInst_Unpin(_) => {
                        trace!("instsel on UNPIN");
                        if !mm::GC_MOVES_OBJECT {
                            // do nothing
                        } else {
                            unimplemented!()
                        }
                    }

                    // aarch64
                    Instruction_::Move(op) => {
                        trace!("instsel on MOVE (internal IR)");
                        let ops = inst.ops.read().unwrap();
                        let ref op = ops[op];

                        let tmp_res = self.get_result_value(node);

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
682
                        self.emit_move_node_to_value(&tmp_res, op, f_content, f_context, vm);
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
                    }

                    // AARCH64
                    Instruction_::New(ref ty) => {
                        trace!("instsel on NEW");
                        if cfg!(debug_assertions) {
                            match ty.v {
                                MuType_::Hybrid(_) => panic!("cannot use NEW for hybrid, use NEWHYBRID instead"),
                                _ => {}
                            }
                        }

                        let ty_info = vm.get_backend_type_info(ty.id());
                        let size = ty_info.size;
                        let ty_align = ty_info.alignment;

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
699
                        let const_size = self.make_value_int_const(size as u64, vm);
700

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
701
702
                        let tmp_allocator = self.emit_get_allocator(node, f_content, f_context, vm);
                        let tmp_res = self.emit_alloc_sequence(tmp_allocator.clone(), const_size, ty_align, node, f_content, f_context, vm);
703
704

                        // ASM: call muentry_init_object(%allocator, %tmp_res, %encode)
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
705
706
                        let encode = self.make_value_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
                        self.emit_runtime_entry(
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
                            &entrypoints::INIT_OBJ,
                            vec![tmp_allocator.clone(), tmp_res.clone(), encode],
                            None,
                            Some(node), f_content, f_context, vm
                        );
                    }

                    // aarch64
                    Instruction_::NewHybrid(ref ty, var_len) => {
                        trace!("instsel on NEWHYBRID");
                        if cfg!(debug_assertions) {
                            match ty.v {
                                MuType_::Hybrid(_) => {},
                                _ => panic!("NEWHYBRID is only for allocating hybrid types, use NEW for others")
                            }
                        }

                        let ty_info = vm.get_backend_type_info(ty.id());
                        let ty_align = ty_info.alignment;
                        let fix_part_size = ty_info.size;
                        let var_ty_size = match ty.v {
                            MuType_::Hybrid(ref name) => {
                                let map_lock = HYBRID_TAG_MAP.read().unwrap();
                                let hybrid_ty_ = map_lock.get(name).unwrap();
                                let var_ty = hybrid_ty_.get_var_ty();

                                vm.get_backend_type_info(var_ty.id()).size
                            },
                            _ => panic!("only expect HYBRID type here")
                        };

                        // actual size = fix_part_size + var_ty_size * len
                        let (actual_size, length) = {
                            let ops = inst.ops.read().unwrap();
                            let ref var_len = ops[var_len];

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
743
744
                            if self.match_node_iimm(var_len) {
                                let var_len = self.node_iimm_to_u64(var_len);
745
746
                                let actual_size = fix_part_size + var_ty_size * (var_len as usize);
                                (
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
747
748
                                    self.make_value_int_const(actual_size as u64, vm),
                                    self.make_value_int_const(var_len as u64, vm)
749
750
751
                                )
                            } else {
                                let tmp_actual_size = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
752
                                let tmp_var_len = self.emit_ireg(var_len, f_content, f_context, vm);
753
754
755
756
757
758

                                // tmp_actual_size = tmp_var_len*var_ty_size
                                if var_ty_size.is_power_of_two() {
                                    self.backend.emit_lsl_imm(&tmp_actual_size, &tmp_var_len, log2(var_ty_size as u64) as u8);
                                } else {
                                    let temp_mul = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
759
                                    self.emit_mov_u64(&tmp_actual_size, var_ty_size as u64);
760
761
762
                                    self.backend.emit_mul(&tmp_actual_size, &tmp_var_len, &temp_mul);
                                }
                                // tmp_actual_size = tmp_var_len*var_ty_size + fix_part_size
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
763
                                self.emit_add_u64(&tmp_actual_size, &tmp_actual_size, f_context, vm, fix_part_size as u64);
764
765
766
767
                                (tmp_actual_size, tmp_var_len)
                            }
                        };

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
768
769
                        let tmp_allocator = self.emit_get_allocator(node, f_content, f_context, vm);
                        let tmp_res = self.emit_alloc_sequence(tmp_allocator.clone(), actual_size, ty_align, node, f_content, f_context, vm);
770
771

                        // ASM: call muentry_init_object(%allocator, %tmp_res, %encode)
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
772
773
                        let encode = self.make_value_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
                        self.emit_runtime_entry(
774
775
776
777
778
779
780
781
782
783
784
785
786
                            &entrypoints::INIT_HYBRID,
                            vec![tmp_allocator.clone(), tmp_res.clone(), encode, length],
                            None,
                            Some(node), f_content, f_context, vm
                        );
                    }

                    // Runtime Entry
                    Instruction_::Throw(op_index) => {
                        trace!("instsel on THROW");
                        let ops = inst.ops.read().unwrap();
                        let ref exception_obj = ops[op_index];

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
787
                        self.emit_runtime_entry(
788
789
790
791
792
793
794
795
796
797
798
799
                            &entrypoints::THROW_EXCEPTION,
                            vec![exception_obj.clone_value()],
                            None,
                            Some(node), f_content, f_context, vm);
                    }

                    // Runtime Entry
                    Instruction_::PrintHex(index) => {
                        trace!("instsel on PRINTHEX");
                        let ops = inst.ops.read().unwrap();
                        let ref op = ops[index];

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
800
                        self.emit_runtime_entry(
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
                            &entrypoints::PRINT_HEX,
                            vec![op.clone_value()],
                            None,
                            Some(node), f_content, f_context, vm
                        );
                    }

                    _ => unimplemented!()
                } // main switch
            },

            TreeNode_::Value(_) => {}
        }
    }

    fn make_temporary(&mut self, f_context: &mut FunctionContext, ty: P<MuType>, vm: &VM) -> P<Value> {
        f_context.make_temporary(vm.next_id(), ty).clone_value()
    }


Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
821
    fn make_value_int_const(&mut self, val: u64, vm: &VM) -> P<Value> {
822
823
824
825
826
827
828
829
        P(Value {
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: UINT64_TYPE.clone(),
            v: Value_::Constant(Constant::Int(val))
        })
    }

    // TODO: Deleted f_context
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
830
831
832
    fn make_value_base_offset(&mut self, base: &P<Value>, offset: i64, ty: &P<MuType>, vm: &VM) -> P<Value> {
        let mem = self.make_memory_location_base_offset(base, offset, vm);
        self.make_value_from_memory(mem, ty, vm)
833
834
    }

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
835
    fn make_value_from_memory(&mut self, mem: MemoryLocation, ty: &P<MuType>, vm: &VM) -> P<Value> {
836
837
838
839
840
841
842
        P(Value {
            hdr: MuEntityHeader::unnamed(vm.next_id()),
            ty: ty.clone(),
            v: Value_::Memory(mem)
        })
    }

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
843
    fn make_memory_location_base_offset(&mut self, base: &P<Value>, offset: i64, vm: &VM) -> MemoryLocation {
844
845
846
847
848
849
850
851
852
853
        if offset == 0 {
            MemoryLocation::VirtualAddress{
                base: base.clone(),
                offset: None,
                scale: 1,
                signed: true,
            }
        } else {
            MemoryLocation::VirtualAddress{
                base: base.clone(),
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
854
                offset: Some(self.make_value_int_const(offset as u64, vm)),
855
856
857
858
859
860
                scale: 1,
                signed: true,
            }
        }
    }

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
861
    fn emit_mem(&mut self, pv: &P<Value>, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
862
863
864
865
866
867
868
869
870
        let n = vm.get_backend_type_info(pv.ty.id()).alignment;
        match pv.v {
            Value_::Memory(ref mem) => {
                match mem {
                    &MemoryLocation::VirtualAddress{ref base, ref offset, scale, signed} => {
                        let mut shift = 0 as u8;
                        let offset =
                            if offset.is_some() {
                                let offset = offset.as_ref().unwrap();
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
871
872
                                if self.match_value_iimm(offset) {
                                    let mut offset_val = self.value_iimm_to_i64(offset);
873
874
                                    offset_val *= scale as i64;
                                    if is_valid_immediate_offset(offset_val, n) {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
875
                                        Some(self.make_value_int_const(offset_val as u64, vm))
876
877
                                    } else {
                                        let offset = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
878
                                        self.emit_mov_u64(&offset, offset_val as u64);
879
880
881
                                        Some(offset)
                                    }
                                } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
882
                                    let offset = self.emit_ireg_value(offset, f_context, vm);
883
884
885
886
887
888
889
890
891
892

                                    // TODO: If scale == n*m (for some m), set shift = n, and multiply index by m
                                    if !is_valid_immediate_scale(scale, n) {
                                        let temp = self.make_temporary(f_context, offset.ty.clone(), vm);

                                        // TODO: Will this be correct if offset is treated as signed (i think so...)
                                        if scale.is_power_of_two() {
                                            self.backend.emit_lsl_imm(&temp, &offset, log2(scale as u64) as u8);
                                        } else {
                                            let temp_mul = self.make_temporary(f_context, offset.ty.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
893
                                            self.emit_mov_u64(&temp_mul, scale as u64);
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
                                            self.backend.emit_mul(&temp, &offset, &temp_mul);
                                        }

                                        Some(temp)
                                    } else {
                                        shift = log2(scale) as u8;
                                        Some(offset)
                                    }
                                }
                            }
                            else {
                                None
                            };

                        P(Value {
                            hdr: MuEntityHeader::unnamed(vm.next_id()),
                            ty: pv.ty.clone(),
                            v: Value_::Memory(MemoryLocation::Address {
                                base: base.clone(),
                                offset: offset,
                                shift: shift,
                                signed: signed
                            })
                        })
                    }
                    _ => pv.clone()
                }
            }
            _ => panic!("expected memory")
        }
    }

    #[warn(unused_variables)] // Same as emit_mem except returns a memory location with only a base
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
927
928
    // NOTE: This code duplicates allot of code in emit_mem and emit_calculate_address
    fn emit_mem_base(&mut self, pv: &P<Value>, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
929
930
931
932
933
934
        match pv.v {
            Value_::Memory(ref mem) => {
                let base = match mem {
                    &MemoryLocation::VirtualAddress{ref base, ref offset, scale, signed} => {
                        if offset.is_some() {
                            let offset = offset.as_ref().unwrap();
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
935
936
                            if self.match_value_iimm(offset) {
                                let offset_val = self.value_iimm_to_i64(offset);
937
938
939
940
                                if offset_val == 0 {
                                    base.clone() // trivial
                                } else {
                                    let temp = self.make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
941
                                    self.emit_add_u64(&temp, &base, f_context, vm, (offset_val * scale as i64) as u64);
942
943
944
                                    temp
                                }
                            } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
945
                                let offset = self.emit_ireg_value(offset, f_context, vm);
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960

                                // TODO: If scale == r*m (for some 0 <= m <= 4), multiply offset by r
                                // then use and add_ext(,...,m)
                                if scale.is_power_of_two() && is_valid_immediate_extension(log2(scale)) {
                                    let temp = self.make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
                                    self.backend.emit_add_ext(&temp, &base, &offset, signed, log2(scale) as u8);
                                    temp
                                } else {
                                    let temp_offset = self.make_temporary(f_context, offset.ty.clone(), vm);

                                    // TODO: Will this be correct if offset is treated as signed (i think so...)
                                    if scale.is_power_of_two() {
                                        self.backend.emit_lsl_imm(&temp_offset, &offset, log2(scale as u64) as u8);
                                    } else {
                                        let temp_mul = self.make_temporary(f_context, offset.ty.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
961
                                        self.emit_mov_u64(&temp_mul, scale as u64);
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
                                        self.backend.emit_mul(&temp_offset, &offset, &temp_mul);
                                    }

                                    // Don't need to create a new register, just overwrite temp_offset
                                    let temp = unsafe { temp_offset.as_type(ADDRESS_TYPE.clone()) };
                                    // Need to use add_ext, in case offset is 32-bits
                                    self.backend.emit_add_ext(&temp, &base, &temp_offset, signed, 0);
                                    temp
                                }
                            }
                        }
                        else {
                            base.clone() // trivial
                        }
                    }
                    &MemoryLocation::Address{ref base, ref offset, shift, signed} => {
                        if offset.is_some() {
                            let ref offset = offset.as_ref().unwrap();

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
981
982
                            if self.match_value_iimm(&offset) {
                                let offset = self.value_iimm_to_u64(&offset);
983
984
985
986
987
                                if offset == 0 {
                                    // Offset is 0, it can be ignored
                                    base.clone()
                                } else {
                                    let temp = self.make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
988
                                    self.emit_add_u64(&temp, &base, f_context, vm, offset as u64);
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
                                    temp
                                }
                            } else if offset.is_int_reg() {
                                let temp = self.make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
                                self.backend.emit_add_ext(&temp, &base, &offset, signed, shift);
                                temp
                            } else {
                                panic!("Offset should be an integer register or a constant")
                            }
                        } else {
                            // Simple base address
                            base.clone()
                        }
                    }
                    &MemoryLocation::Symbolic{..} => {
                        let temp = self.make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
                        self.backend.emit_adr(&temp, &pv);
                        temp
                    },
                };

                P(Value {
                    hdr: MuEntityHeader::unnamed(vm.next_id()),
                    ty: pv.ty.clone(),
                    v: Value_::Memory(MemoryLocation::Address {
                        base: base.clone(),
                        offset: None,
                        shift: 0,
                        signed: false
                    })
                })
            }
            _ => panic!("expected memory")
        }
    }

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1025
    fn make_memory_location_base_offset_scale(&mut self, base: &P<Value>, offset: &P<Value>, scale: u64, signed: bool) -> MemoryLocation {
1026
1027
1028
1029
1030
1031
1032
1033
1034
        MemoryLocation::VirtualAddress{
            base: base.clone(),
            offset: Some(offset.clone()),
            scale: scale,
            signed: signed
        }
    }

    // Returns a memory location pointing to 'base + (offset+more_offset)*scale'
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1035
    /*fn memory_location_adjust_offset(&mut self, mem: MemoryLocation, more_offset: i64, f_context: &mut FunctionContext, vm: &VM) -> MemoryLocation {
1036
1037
1038
1039
1040
        match mem {
            MemoryLocation::VirtualAddress { base, offset, scale, signed } => {
                let offset =
                    if offset.is_some() {
                        let offset = offset.unwrap();
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1041
                        if self.match_value_iimm(&offset) {
1042
                            let offset = offset.extract_int_const() + (more_offset as u64);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1043
                            self.make_value_int_const(offset as u64, vm)
1044
1045
                        } else {
                            let temp = self.make_temporary(f_context, offset.ty.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1046
1047
                            let offset = self.emit_ireg_value(&offset, f_context, vm);
                            self.emit_add_u64(&temp, &offset, f_context, vm, more_offset as u64);
1048
1049
1050
1051
                            temp
                        }
                    }
                    else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1052
                        self.make_value_int_const(more_offset as u64, vm)
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
                    };
                MemoryLocation::VirtualAddress {
                    base: base.clone(),
                    offset: Some(offset),
                    scale: scale,
                    signed: signed,
                }

            },
            _ => panic!("expected a VirtualAddress memory location")
        }
    }*/
    // Returns a memory location that points to 'Base + offset*scale + more_offset'
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1066
    fn memory_location_shift(&mut self, mem: MemoryLocation, more_offset: i64, f_context: &mut FunctionContext, vm: &VM) -> MemoryLocation {
1067
1068
1069
1070
1071
        match mem {
            MemoryLocation::VirtualAddress { base, offset, scale, signed } => {
                let offset =
                    if offset.is_some() {
                        let offset = offset.unwrap();
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1072
                        if self.match_value_iimm(&offset) {
1073
                            let offset = offset.extract_int_const()*scale + (more_offset as u64);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1074
                            self.make_value_int_const(offset as u64, vm)
1075
                        } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1076
                            let offset = self.emit_ireg_value(&offset, f_context, vm);
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
                            let temp = self.make_temporary(f_context, offset.ty.clone(), vm);

                            if scale == 1 {
                                // do nothing, temp = offset*scale
                                self.backend.emit_mov(&temp, &offset);
                            } else if scale.is_power_of_two() {
                                // temp = offset << log2(scale)
                                self.backend.emit_lsl_imm(&temp, &offset, log2(scale as u64) as u8);
                            } else {
                                // temp = offset * scale
                                let temp_mul = self.make_temporary(f_context, offset.ty.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1088
                                self.emit_mov_u64(&temp_mul, scale as u64);
1089
1090
1091
                                self.backend.emit_mul(&temp, &offset, &temp_mul);
                            }

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1092
                            self.emit_add_u64(&temp, &temp, f_context, vm, more_offset as u64);
1093
1094
1095
1096
                            temp
                        }
                    }
                    else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1097
                        self.make_value_int_const(more_offset as u64, vm)
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
                    };
                MemoryLocation::VirtualAddress {
                    base: base.clone(),
                    offset: Some(offset),
                    scale: 1,
                    signed: signed,
                }

            },
            _ => panic!("expected a VirtualAddress memory location")
        }
    }

    // Returns a memory location that points to 'Base + offset*scale + more_offset*new_scale'
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1112
1113
1114
1115
1116
    fn memory_location_shift_scale(&mut self, mem: MemoryLocation, more_offset:  &P<Value>, new_scale: u64, f_context: &mut FunctionContext, vm: &VM) -> MemoryLocation {
        if self.match_value_iimm(&more_offset) {
            let more_offset = self.value_iimm_to_i64(&more_offset);
            let mem = self.memory_location_shift(mem, more_offset, f_context, vm);
            self.memory_location_append_scale(mem, new_scale)
1117
1118
1119
1120
1121
1122
        } else {
            match mem {
                MemoryLocation::VirtualAddress { base, offset, scale, signed } => {
                    let offset =
                        if offset.is_some() {
                            let offset = offset.unwrap();
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1123
                            if self.match_value_iimm(&offset) {
1124
                                let temp = self.make_temporary(f_context, offset.ty.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1125
                                self.emit_add_u64(&temp, &more_offset, f_context, vm, offset.extract_int_const() * scale);
1126
1127
                                temp
                            } else {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1128
                                let offset = self.emit_ireg_value(&offset, f_context, vm);
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
                                let temp = self.make_temporary(f_context, offset.ty.clone(), vm);

                                if scale == 1 {
                                    // do nothing, temp = offset*scale
                                    self.backend.emit_mov(&temp, &offset);
                                } else if scale.is_power_of_two() {
                                    // temp = offset << log2(scale)
                                    self.backend.emit_lsl_imm(&temp, &offset, log2(scale as u64) as u8);
                                } else {
                                    // temp = offset * scale
                                    let temp_mul = self.make_temporary(f_context, offset.ty.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1140
                                    self.emit_mov_u64(&temp_mul, scale as u64);
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
                                    self.backend.emit_mul(&temp, &offset, &temp_mul);
                                }

                                let temp_more = self.make_temporary(f_context, offset.ty.clone(), vm);

                                if new_scale.is_power_of_two() {
                                    // temp_more = more_offset << log2(new_scale)
                                    self.backend.emit_lsl_imm(&temp_more, &more_offset, log2(scale as u64) as u8);
                                } else {
                                    // temp_more = more_offset * new_scale
                                    let temp_mul = self.make_temporary(f_context, more_offset.ty.clone(), vm);
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1152
                                    self.emit_mov_u64(&temp_mul, new_scale as u64);
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
                                    self.backend.emit_mul(&temp_more, &more_offset, &temp_mul);
                                }

                                // TODO: If scale is a valid ext_shift then use it here (and don't pre multiple offset)
                                self.backend.emit_add_ext(&temp, &temp_more, &temp, signed, 0);
                                temp
                            }
                        } else {
                            more_offset.clone()
                        };
                    MemoryLocation::VirtualAddress {
                        base: base.clone(),
                        offset: Some(offset),
                        scale: new_scale,
                        signed: signed,
                    }
                },
                _ => panic!("expected a VirtualAddress memory location")
            }
        }
    }


    // UNUSED
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1177
    fn memory_location_append_offset(&mut self, mem: MemoryLocation, new_offset: &P<Value>, new_signed: bool) -> MemoryLocation {
1178
1179
        match mem {
            MemoryLocation::VirtualAddress { base, offset, scale, signed } => {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1180
                self.make_memory_location_base_offset_scale(&base, &new_offset, scale, new_signed)
1181
1182
1183
1184
1185
1186
            },
            _ => panic!("expected an address memory location")
        }
    }

    // UNUSED
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1187
    fn memory_location_append_offset_scale(&mut self, mem: MemoryLocation, new_offset: &P<Value>, new_scale: u64, new_signed: bool) -> MemoryLocation {
1188
1189
        match mem {
            MemoryLocation::VirtualAddress { ref base, ref offset, scale, signed } => {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1190
                self.make_memory_location_base_offset_scale(&base, &new_offset, new_scale, new_signed)
1191
1192
1193
1194
1195
1196
            },
            _ => panic!("expected an address memory location")
        }
    }

    // UNUSED
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1197
    fn memory_location_append_scale(&mut self, mem: MemoryLocation, new_scale: u64) -> MemoryLocation {
1198
1199
1200
        match mem {
            MemoryLocation::VirtualAddress { ref base, ref offset, scale, signed } => {
                match offset.as_ref() {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1201
                    Some(ref offset) => self.make_memory_location_base_offset_scale(&base, &offset, new_scale, signed),
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
                    _ => panic!("A scale requires an offset")
                }

            },
            _ => panic!("expected an address memory location")
        }
    }

    // Returns the size of the operation
    // TODO: If the RHS of an ADD is negative change it to a SUB (and vice versa)
    // TODO: Treat SUB 0, Op2  and EOR 0, Op2 specially
    // Note: Assume that trivial operations will be optimised away by the Mu IR compiler
    // TODO: Use a shift when dividing or multiplying by a power of two
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1215
    fn emit_binop(&mut self, node: &TreeNode, inst: &Instruction, op: BinOp, status: BinOpStatus, op1: OpIndex, op2: OpIndex, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) {
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
        use std;
        let mut op1 = op1;
        let mut op2 = op2;
        let ops = inst.ops.read().unwrap();
        let res = self.get_result_value(node);

        // Get the size (in bits) of the type the operation is on
        let n = get_bit_size(&res.ty, vm);
        let output_status = status.flag_n || status.flag_z || status.flag_c || status.flag_v;
        let values = inst.value.as_ref().unwrap();
        let mut status_value_index = 0;
        // NOTE: XZR is just a dummy value here (it will not be used)
        let tmp_status_n = if status.flag_n {
            status_value_index += 1;
            values[status_value_index].clone()
        } else { XZR.clone() };
        let tmp_status_z = if status.flag_z {
            status_value_index += 1;
            values[status_value_index].clone()
        } else { XZR.clone() };
        let tmp_status_c = if status.flag_c {
            status_value_index += 1;
            values[status_value_index].clone()
        } else { XZR.clone() };
        let tmp_status_v = if status.flag_v {
            status_value_index += 1;
            values[status_value_index].clone()
        } else { XZR.clone() };

        // TODO: Division by zero exception (note: must explicitly check for this, arm dosn't do it)
        // TODO: (Unneccesary??) Check that flags aren't output for instructions that don't support them
        match op {
            // The lower n bits of the result will be correct, and will not depend
            // on the > n bits of op1 or op2
            op::BinOp::Add => {
                let mut imm_val = 0 as u64;
                // Is one of the arguments a valid immediate?
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1253
1254
                let emit_imm = if self.match_node_iimm(&ops[op2]) {
                    imm_val = self.node_iimm_to_u64(&ops[op2]);
1255
                    is_valid_arithmetic_imm(imm_val)
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1256
1257
                } else if self.match_node_iimm(&ops[op1]) {
                    imm_val = self.node_iimm_to_u64(&ops[op1]);
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
                    // if op1 is a valid immediate, swap it with op2
                    if is_valid_arithmetic_imm(imm_val) {
                        std::mem::swap(&mut op1, &mut op2);
                        true
                    } else {
                        false
                    }
                } else {
                    false
                };

                if emit_imm {
                    trace!("emit add-ireg-imm");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1272
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
1273
1274
1275
1276
                    let imm_shift = imm_val > 4096;
                    let imm_op2 = if imm_shift { imm_val >> 12 } else { imm_val };

                    if output_status {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1277
                        self.emit_zext(&reg_op1);
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
                        self.backend.emit_adds_imm(&res, &reg_op1, imm_op2 as u16, imm_shift);

                        if status.flag_v {
                            if n < 32 {
                                // tmp_status[n-1] = 1 iff res and op1 have different signs
                                self.backend.emit_eor(&tmp_status_v, &res, &reg_op1);
                                // tmp[n-1] = 1 iff op1 and op2 have different signs

                                // Sign bit of op2 is 0
                                if !get_bit(imm_val, n - 1) {
                                    // tmp_status[n-1] = 1 iff res and op1 have different signs
                                    //      and op1 has the same sign as op2 (which is 0)
                                    self.backend.emit_bic(&tmp_status_v, &tmp_status_v, &reg_op1);
                                } else {
                                    // tmp_status[n-1] = 1 iff res and op1 have different signs
                                    //      and op1 has the same sign as op2 (which is 1)
                                    self.backend.emit_and(&tmp_status_v, &tmp_status_v, &reg_op1);
                                }

                                // Check the sign bit of tmp_status (i.e. tmp_status[n-1])
                                self.backend.emit_tst_imm(&tmp_status_v, 1 << (n - 1));
                                self.backend.emit_cset(&tmp_status_v, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_v, "VS");
                            }
                        }
                        if status.flag_c {
                            if n < 32 {
                                // Test the carry bit of res
                                self.backend.emit_tst_imm(&res, 1 << n);
                                self.backend.emit_cset(&tmp_status_c, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_c, "CS");
                            }
                        }
                    } else {
                        self.backend.emit_add_imm(&res, &reg_op1, imm_op2 as u16, imm_shift);
                    }
                } else {
                    trace!("emit add-ireg-ireg");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1319
1320
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                    let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
1321
1322

                    if output_status {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1323
                        self.emit_zext(&reg_op1);
1324
1325
                        if n == 1 {
                            // adds_ext dosn't support extending 1 bit numbers
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1326
                            self.emit_zext(&reg_op2);
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
                            self.backend.emit_adds(&res, &reg_op1, &reg_op2);
                        } else {
                            // Emit an adds that zero extends op2
                            self.backend.emit_adds_ext(&res, &reg_op1, &reg_op2, false, 0);
                        }

                        if status.flag_v {
                            if n < 32 {
                                let tmp = self.make_temporary(f_context, UINT32_TYPE.clone(), vm);

                                // tmp_status[n-1] = 1 iff res and op1 have different signs
                                self.backend.emit_eor(&tmp_status_v, &res, &reg_op1);
                                // tmp[n-1] = 1 iff op1 and op2 have different signs
                                self.backend.emit_eor(&tmp, &reg_op1, &reg_op2);

                                // tmp_status[n-1] = 1 iff res and op1 have different signs
                                //      and op1 and op2 have the same sign
                                self.backend.emit_bic(&tmp_status_v, &tmp_status_v, &tmp);

                                // Check tmp_status[n-1]
                                self.backend.emit_tst_imm(&tmp_status_v, 1 << (n - 1));
                                self.backend.emit_cset(&tmp_status_v, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_v, "VS");
                            }
                        }

                        if status.flag_c {
                            if n < 32 {
                                // Test the carry bit of res
                                self.backend.emit_tst_imm(&res, 1 << n);
                                self.backend.emit_cset(&tmp_status_c, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_c, "CS");
                            }
                        }
                    } else {
                        self.backend.emit_add(&res, &reg_op1, &reg_op2);
                    }
                }
            },
            op::BinOp::Sub => {
                // TODO: Case when the immediate needs to be 1' or sign-extended...
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1370
1371
                if self.match_node_iimm(&ops[op2]) &&
                    is_valid_arithmetic_imm(self.node_iimm_to_u64(&ops[op2])) &&
1372
1373
1374
1375
                    !(status.flag_c && n < 32) {
                    // Can't compute the carry but using a subs_imm instruction
                    trace!("emit sub-ireg-imm");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1376
1377
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                    let imm_val = self.node_iimm_to_u64(&ops[op2]);
1378
1379
1380
1381
                    let imm_shift = imm_val > 4096;
                    let imm_op2 = if imm_shift { imm_val >> 12 } else { imm_val };

                    if output_status {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1382
                        self.emit_zext(&reg_op1);
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
                        self.backend.emit_subs_imm(&res, &reg_op1, imm_op2 as u16, imm_shift);

                        if status.flag_v {
                            if n < 32 {
                                // tmp_status[n-1] = 1 iff res and op1 have different signs
                                self.backend.emit_eor(&tmp_status_v, &res, &reg_op1);
                                // tmp[n-1] = 1 iff op1 and op2 have different signs

                                // Sign bit of op2 is 0
                                if imm_val & (1 << (n - 1)) == 0 {
                                    // tmp_status[n-1] = 1 iff res and op1 have different signs
                                    //      and op1 has the same sign as -op2 (which is 1)
                                    self.backend.emit_and(&tmp_status_v, &tmp_status_v, &reg_op1);
                                } else {
                                    // tmp_status[n-1] = 1 iff res and op1 have different signs
                                    //      and op1 has the same sign as op2 (which is 0)
                                    self.backend.emit_bic(&tmp_status_v, &tmp_status_v, &reg_op1);
                                }

                                // Check the sign bit of tmp_status (i.e. tmp_status[n-1])
                                self.backend.emit_tst_imm(&tmp_status_v, 1 << (n - 1));
                                self.backend.emit_cset(&tmp_status_v, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_v, "VS");
                            }
                        }

                        if status.flag_c {
                            if n < 32 {
                                // Test the carry bit of res
                                self.backend.emit_tst_imm(&res, 1 << n);
                                self.backend.emit_cset(&tmp_status_c, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_c, "CS");
                            }
                        }
                    } else {
                        self.backend.emit_sub_imm(&res, &reg_op1, imm_op2 as u16, imm_shift);
                    }
                } else {
                    trace!("emit sub-ireg-ireg");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1425
1426
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                    let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
1427
1428

                    if output_status {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1429
                        self.emit_zext(&reg_op1);
1430
1431
1432
1433
1434
1435

                        if status.flag_c {
                            // Note: reg_op2 is 'one'-extended so that SUB res, zext(reg_op1), oext(reg_op2)
                            // Is equivelent to: ADD res, zext(reg_op1), zext(~reg_op2), +1
                            // (this allows the carry flag to be computed as the 'n'th bit of res

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1436
                            self.emit_oext(&reg_op2);
1437
1438
1439
                            self.backend.emit_subs(&res, &reg_op1, &reg_op2);
                        } else if n == 1 {
                            // if the carry flag isn't been computed, just zero extend op2
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1440
                            self.emit_zext(&reg_op2);
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
                            self.backend.emit_subs(&res, &reg_op1, &reg_op2);
                        } else {
                            // Emit an subs that zero extends op2
                            self.backend.emit_subs_ext(&res, &reg_op1, &reg_op2, false, 0);
                        }


                        if status.flag_v {
                            if n < 32 {
                                let tmp = self.make_temporary(f_context, UINT32_TYPE.clone(), vm);

                                // tmp_status[n-1] = 1 iff res and op1 have different signs
                                self.backend.emit_eor(&tmp_status_v, &res, &reg_op1);
                                // tmp[n-1] = 1 iff op1 and -op2 have different signs
                                self.backend.emit_eon(&tmp, &reg_op1, &reg_op2);

                                // tmp_status[n-1] = 1 iff res and op1 have different signs
                                //      and op1 and op2 have the same sign
                                self.backend.emit_bic(&tmp_status_v, &tmp_status_v, &tmp);

                                // Check tmp_status[n-1]
                                self.backend.emit_tst_imm(&tmp_status_v, 1 << (n - 1));
                                self.backend.emit_cset(&tmp_status_v, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_v, "VS");
                            }
                        }

                        if status.flag_c {
                            if n < 32 {
                                // Test the carry bit of res
                                self.backend.emit_tst_imm(&res, 1 << n);
                                self.backend.emit_cset(&tmp_status_c, "NE");
                            } else {
                                self.backend.emit_cset(&tmp_status_c, "CS");
                            }
                        }
                    } else {
                        self.backend.emit_sub(&res, &reg_op1, &reg_op2);
                    }
                }
            },

            op::BinOp::And => {
                let mut imm_val = 0 as u64;
                // Is one of the arguments a valid immediate?
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1487
1488
                let emit_imm = if self.match_node_iimm(&ops[op2]) {
                    imm_val = self.node_iimm_to_u64(&ops[op2]);
1489
                    is_valid_logical_imm(imm_val, n)
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1490
1491
                } else if self.match_node_iimm(&ops[op1]) {
                    imm_val = self.node_iimm_to_u64(&ops[op1]);
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
                    // if op1 is a valid immediate, swap it with op2
                    if is_valid_logical_imm(imm_val, n) {
                        std::mem::swap(&mut op1, &mut op2);
                        true
                    } else {
                        false
                    }
                } else {
                    false
                };

                if emit_imm {
                    trace!("emit and-ireg-imm");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1506
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
1507
1508
1509
1510
1511
1512
1513
1514
1515

                    if output_status {
                        self.backend.emit_ands_imm(&res, &reg_op1, replicate_logical_imm(imm_val, n));
                    } else {
                        self.backend.emit_and_imm(&res, &reg_op1, replicate_logical_imm(imm_val, n));
                    }
                } else {
                    trace!("emit and-ireg-ireg");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1516
1517
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                    let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528

                    if output_status {
                        self.backend.emit_ands(&res, &reg_op1, &reg_op2);
                    } else {
                        self.backend.emit_and(&res, &reg_op1, &reg_op2);
                    }
                }
            },
            op::BinOp::Or => {
                let mut imm_val = 0 as u64;
                // Is one of the arguments a valid immediate?
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1529
1530
                let emit_imm = if self.match_node_iimm(&ops[op2]) {
                    imm_val = self.node_iimm_to_u64(&ops[op2]);
1531
                    is_valid_logical_imm(imm_val, n)
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1532
1533
                } else if self.match_node_iimm(&ops[op1]) {
                    imm_val = self.node_iimm_to_u64(&ops[op1]);
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
                    // if op1 is a valid immediate, swap it with op2
                    if is_valid_logical_imm(imm_val, n) {
                        std::mem::swap(&mut op1, &mut op2);
                        true
                    } else {
                        false
                    }
                } else {
                    false
                };

                if emit_imm {
                    trace!("emit or-ireg-imm");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1548
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
1549
1550
1551
1552
1553

                    self.backend.emit_orr_imm(&res, &reg_op1, replicate_logical_imm(imm_val, n));
                } else {
                    trace!("emit or-ireg-ireg");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1554
1555
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                    let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
1556
1557
1558
1559
1560
1561
1562

                    self.backend.emit_orr(&res, &reg_op1, &reg_op2);
                }
            },
            op::BinOp::Xor => {
                let mut imm_val = 0 as u64;
                // Is one of the arguments a valid immediate?
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1563
1564
                let emit_imm = if self.match_node_iimm(&ops[op2]) {
                    imm_val = self.node_iimm_to_u64(&ops[op2]);
1565
                    is_valid_logical_imm(imm_val, n)
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1566
1567
                } else if self.match_node_iimm(&ops[op1]) {
                    imm_val = self.node_iimm_to_u64(&ops[op1]);
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
                    // if op1 is a valid immediate, swap it with op2
                    if is_valid_logical_imm(imm_val, n) {
                        std::mem::swap(&mut op1, &mut op2);
                        true
                    } else {
                        false
                    }
                } else {
                    false
                };

                if emit_imm {
                    trace!("emit xor-ireg-imm");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1582
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
1583
1584
1585
1586
1587

                    self.backend.emit_eor_imm(&res, &reg_op1, replicate_logical_imm(imm_val, n));
                } else {
                    trace!("emit xor-ireg-ireg");

Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1588
1589
                    let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
                    let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
1590
1591
1592
1593
1594
1595
1596
1597

                    self.backend.emit_eor(&res, &reg_op1, &reg_op2);
                }
            },

            op::BinOp::Mul => {
                trace!("emit mul-ireg-ireg");