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

asm_backend.rs 20.6 KB
Newer Older
1
2
#![allow(unused_variables)]

3
use compiler::backend::x86_64;
4
use compiler::backend::x86_64::CodeGenerator;
5
use vm::machine_code::MachineCode;
6
7
8

use ast::ptr::P;
use ast::ir::*;
qinsoon's avatar
qinsoon committed
9
use ast::inst::*;
10

qinsoon's avatar
qinsoon committed
11
12
use std::collections::HashMap;
use std::str;
13
use std::usize;
qinsoon's avatar
qinsoon committed
14
15
16

struct ASMCode {
    name: MuTag, 
17
18
    code: Vec<ASM>,
    reg_defines: HashMap<MuID, Vec<ASMLocation>>,
19
20
21
22
23
24
25
26
27
    reg_uses: HashMap<MuID, Vec<ASMLocation>>,
    
    preds: Vec<Vec<usize>>,
    succs: Vec<Vec<usize>>,
    
    idx_to_blk: HashMap<usize, MuTag>,
    blk_to_idx: HashMap<MuTag, usize>,
    cond_branches: HashMap<usize, MuTag>,
    branches: HashMap<usize, MuTag>
qinsoon's avatar
qinsoon committed
28
29
}

30
31
32
33
impl MachineCode for ASMCode {
    fn number_of_insts(&self) -> usize {
        self.code.len()
    }
qinsoon's avatar
qinsoon committed
34
    
35
36
37
38
39
40
41
42
    fn is_move(&self, index: usize) -> bool {
        let inst = self.code.get(index);
        match inst {
            Some(inst) => inst.code.starts_with("mov"),
            None => false
        }
    }
    
qinsoon's avatar
qinsoon committed
43
44
45
46
47
48
49
50
    fn get_succs(&self, index: usize) -> &Vec<usize> {
        &self.succs[index]
    }
    
    fn get_preds(&self, index: usize) -> &Vec<usize> {
        &self.preds[index]
    }
    
51
    fn get_inst_reg_uses(&self, index: usize) -> &Vec<MuID> {
qinsoon's avatar
qinsoon committed
52
        &self.code[index].uses
53
54
    }
    
55
    fn get_inst_reg_defines(&self, index: usize) -> &Vec<MuID> {
qinsoon's avatar
qinsoon committed
56
        &self.code[index].defines
57
    }
58
59
60
61
62
63
64
65
66
67
68
69
    
    fn print(&self) {
        println!("");

        println!("code for {}: ", self.name);
        let n_insts = self.code.len();
        for i in 0..n_insts {
            let ref line = self.code[i];
            println!("#{}\t{}\t\tpred: {:?}, succ: {:?}", i, line.code, self.preds[i], self.succs[i]);
        }
        
        println!("");        
70
71
72
73
74
75
76
    }
}

struct ASM {
    code: String,
    defines: Vec<MuID>,
    uses: Vec<MuID>
qinsoon's avatar
qinsoon committed
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
impl ASM {
    fn symbolic(line: String) -> ASM {
        ASM {
            code: line,
            defines: vec![],
            uses: vec![]
        }
    }
    
    fn inst(inst: String, defines: Vec<MuID>, uses: Vec<MuID>) -> ASM {
        ASM {
            code: inst,
            defines: defines,
            uses: uses
        }
    }
    
    fn branch(line: String) -> ASM {
        ASM {
            code: line,
            defines: vec![],
            uses: vec![]
        }
    }
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    
    fn call(line: String) -> ASM {
        ASM {
            code: line,
            defines: vec![],
            uses: vec![]
        }
    }
    
    fn ret(line: String) -> ASM {
        ASM {
            code: line,
            defines: vec![],
            uses: vec![]
        }
    }
qinsoon's avatar
qinsoon committed
119
120
}

121
#[derive(Clone, Debug)]
qinsoon's avatar
qinsoon committed
122
123
124
125
126
127
128
struct ASMLocation {
    line: usize,
    index: usize,
    len: usize
}

impl ASMLocation {
129
130
    /// the 'line' field will be updated later
    fn new(index: usize, len: usize) -> ASMLocation {
qinsoon's avatar
qinsoon committed
131
        ASMLocation{
132
            line: usize::MAX,
qinsoon's avatar
qinsoon committed
133
134
135
136
137
138
            index: index,
            len: len
        }
    }
}

139
pub struct ASMCodeGen {
140
    cur: Option<Box<ASMCode>>
141
142
}

qinsoon's avatar
qinsoon committed
143
144
145
146
147
148
149
const REG_PLACEHOLDER_LEN : usize = 3;
lazy_static! {
    pub static ref REG_PLACEHOLDER : String = {
        let blank_spaces = [' ' as u8; REG_PLACEHOLDER_LEN];
        
        format!("%{}", str::from_utf8(&blank_spaces).unwrap())
    };
150
151
152
153
}

impl ASMCodeGen {
    pub fn new() -> ASMCodeGen {
qinsoon's avatar
qinsoon committed
154
        ASMCodeGen {
155
            cur: None
qinsoon's avatar
qinsoon committed
156
157
158
159
160
161
162
163
164
165
166
        }
    }
    
    fn cur(&self) -> &ASMCode {
        self.cur.as_ref().unwrap()
    }
    
    fn cur_mut(&mut self) -> &mut ASMCode {
        self.cur.as_mut().unwrap()
    }
    
167
168
169
170
    fn line(&self) -> usize {
        self.cur().code.len()
    }
    
qinsoon's avatar
qinsoon committed
171
172
173
174
175
176
177
178
179
180
181
182
    fn replace(s: &mut String, index: usize, replace: &str, replace_len: usize) {
        let vec = unsafe {s.as_mut_vec()};
        
        for i in 0..replace_len {
            if i < replace.len() {
                vec[index + i] = replace.as_bytes()[i] as u8;
            } else {
                vec[index + i] = ' ' as u8;
            }
        }
    }
    
183
184
185
186
187
188
189
190
    fn add_asm_block_label(&mut self, code: String, block_name: &'static str) {
        let l = self.line();
        self.cur_mut().code.push(ASM::symbolic(code));
        
        self.cur_mut().idx_to_blk.insert(l, block_name);
        self.cur_mut().blk_to_idx.insert(block_name, l);
    }
    
191
192
193
194
    fn add_asm_symbolic(&mut self, code: String){
        self.cur_mut().code.push(ASM::symbolic(code));
    }
    
195
196
197
198
199
200
201
202
203
204
    fn add_asm_call(&mut self, code: String) {
        self.cur_mut().code.push(ASM::call(code));
    }
    
    fn add_asm_ret(&mut self, code: String) {
        self.cur_mut().code.push(ASM::ret(code));
    }
    
    fn add_asm_branch(&mut self, code: String, target: &'static str) {
        let l = self.line();
205
        self.cur_mut().code.push(ASM::branch(code));
206
207
208
209
210
211
212
213
214
        
        self.cur_mut().branches.insert(l, target);
    }
    
    fn add_asm_branch2(&mut self, code: String, target: &'static str) {
        let l = self.line();
        self.cur_mut().code.push(ASM::branch(code));
        
        self.cur_mut().cond_branches.insert(l, target);
215
216
217
218
219
220
    }
    
    fn add_asm_inst(
        &mut self, 
        code: String, 
        defines: Vec<MuID>,
221
        mut define_locs: Vec<ASMLocation>, 
222
        uses: Vec<MuID>,
223
        mut use_locs: Vec<ASMLocation>) 
224
    {
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
        let line = self.line();
        
        trace!("asm: {}", code);
        trace!("     defines: {:?}, def_locs: {:?}", defines, define_locs);
        trace!("     uses: {:?}, use_locs: {:?}", uses, use_locs);
        let mc = self.cur_mut();
       
        // add locations of defined registers
        for i in 0..define_locs.len() {
            let id = defines[i];
            
            // update line in location
            let ref mut loc = define_locs[i];
            loc.line = line;
            
            if mc.reg_defines.contains_key(&id) {
                mc.reg_defines.get_mut(&id).unwrap().push(loc.clone());
            } else {
                mc.reg_defines.insert(id, vec![loc.clone()]);
            }
        }
       
        for i in 0..use_locs.len() {
            let id = uses[i];
            
            // update line in location
            let ref mut loc = use_locs[i];
            loc.line = line;
            
            if mc.reg_uses.contains_key(&id) {
                mc.reg_defines.get_mut(&id).unwrap().push(loc.clone());
            } else {
                mc.reg_defines.insert(id, vec![loc.clone()]);
            }
        }
260
       
261
262
        // put the instruction
        mc.code.push(ASM::inst(code, defines, uses));
263
264
265
266
    }
    
    fn define_reg(&mut self, reg: &P<Value>, loc: ASMLocation) {
        let id = reg.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
267
        
268
269
270
271
272
273
274
        let code = self.cur_mut();
        if code.reg_defines.contains_key(&id) {
            let regs = code.reg_defines.get_mut(&id).unwrap();
            regs.push(loc);
        } else {
            code.reg_defines.insert(id, vec![loc]);
        } 
qinsoon's avatar
qinsoon committed
275
276
277
278
279
280
    }
    
    fn use_reg(&mut self, reg: &P<Value>, loc: ASMLocation) {
        let id = reg.extract_ssa_id().unwrap();
        
        let code = self.cur_mut();
281
282
283
        if code.reg_uses.contains_key(&id) {
            let reg_uses = code.reg_uses.get_mut(&id).unwrap();
            reg_uses.push(loc);
qinsoon's avatar
qinsoon committed
284
        } else {
285
            code.reg_uses.insert(id, vec![loc]);
qinsoon's avatar
qinsoon committed
286
287
288
        } 
    }
    
289
290
291
292
293
294
295
296
    fn prepare_op(&self, op: &P<Value>, loc: usize) -> (String, MuID, ASMLocation) {
        let str = self.asm_reg_op(op);
        let len = str.len();
        (str, op.extract_ssa_id().unwrap(), ASMLocation::new(loc, len)) 
    }
    
    fn prepare_machine_reg(&self, op: &P<Value>) -> MuID {
        op.extract_ssa_id().unwrap()
297
    }
298
    
qinsoon's avatar
qinsoon committed
299
300
301
302
303
304
305
306
307
308
309
310
311
    fn asm_reg_op(&self, op: &P<Value>) -> String {
        let id = op.extract_ssa_id().unwrap();
        if id < RESERVED_NODE_IDS_FOR_MACHINE {
            // machine reg
            format!("%{}", op.tag)
        } else {
            // virtual register, use place holder
            REG_PLACEHOLDER.clone()
        }
    }
    
    fn asm_block_label(&self, label: MuTag) -> String {
        format!("{}_{}", self.cur().name, label)
312
    }
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
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
368
369
370
371
372
373
374
375
376
    
    fn control_flow_analysis(&mut self) {
        // control flow analysis
        let n_insts = self.line();
        
        let code = self.cur_mut();
        code.preds = vec![vec![]; n_insts];
        code.succs = vec![vec![]; n_insts];
        
        for i in 0..n_insts {
            // determine predecessor - if cur is not block start, its predecessor is previous insts
            let is_block_start = code.idx_to_blk.get(&i);
            if is_block_start.is_none() {
                if i > 0 {
                    code.preds[i].push(i - 1);
                }
            } else {
                // if cur is a branch target, we already set its predecessor
                // if cur is a fall-through block, we set it in a sanity check pass
            }
            
            // determine successor
            let is_branch = code.branches.get(&i);
            if is_branch.is_some() {
                // branch to target
                let target = is_branch.unwrap();
                let target_n = code.blk_to_idx.get(target).unwrap();
                
                // cur inst's succ is target
                code.succs[i].push(*target_n);
                
                // target's pred is cur
                code.preds[*target_n].push(i);
            } else {
                let is_cond_branch = code.cond_branches.get(&i);
                if is_cond_branch.is_some() {
                    // branch to target
                    let target = is_cond_branch.unwrap();
                    let target_n = code.blk_to_idx.get(target).unwrap();
                    
                    // cur insts' succ is target and next inst
                    code.succs[i].push(*target_n);
                    if i < n_insts - 1 {
                        code.succs[i].push(i + 1);
                    }
                    
                    // target's pred is cur
                    code.preds[*target_n].push(i);
                } else {
                    // not branch nor cond branch, succ is next inst
                    if i < n_insts - 1 {
                        code.succs[i].push(i + 1);
                    }
                }
            } 
        }
        
        // a sanity check for fallthrough blocks
        for i in 0..n_insts {
            if i != 0 && code.preds[i].len() == 0 {
                code.preds[i].push(i - 1);
            }
        }        
    }
377
378
379
}

impl CodeGenerator for ASMCodeGen {
qinsoon's avatar
qinsoon committed
380
    fn start_code(&mut self, func_name: MuTag) {
381
        self.cur = Some(Box::new(ASMCode {
qinsoon's avatar
qinsoon committed
382
383
                name: func_name,
                code: vec![],
384
                reg_defines: HashMap::new(),
385
386
387
388
389
390
391
392
393
394
                reg_uses: HashMap::new(),
                
                preds: vec![],
                succs: vec![],
                
                idx_to_blk: HashMap::new(),
                blk_to_idx: HashMap::new(),
                cond_branches: HashMap::new(),
                branches: HashMap::new()
            }));
qinsoon's avatar
qinsoon committed
395
        
396
        self.add_asm_symbolic(format!(".globl {}", func_name));
qinsoon's avatar
qinsoon committed
397
398
    }
    
399
400
401
    fn finish_code(&mut self) -> Box<MachineCode> {
        self.control_flow_analysis();
        self.cur.take().unwrap()
qinsoon's avatar
qinsoon committed
402
403
404
405
406
407
408
409
410
    }
    
    fn print_cur_code(&self) {
        println!("");
        
        if self.cur.is_some() {
            let code = self.cur.as_ref().unwrap();
            
            println!("code for {}: ", code.name);
411
412
413
414
            let n_insts = code.code.len();
            for i in 0..n_insts {
                let ref line = code.code[i];
                println!("#{}\t{}", i, line.code);
qinsoon's avatar
qinsoon committed
415
416
417
418
419
420
421
422
423
            }
        } else {
            println!("no current code");
        }
        
        println!("");
    }
    
    fn start_block(&mut self, block_name: MuTag) {
424
425
        let label = format!("{}:", self.asm_block_label(block_name));        
        self.add_asm_block_label(label, block_name);
qinsoon's avatar
qinsoon committed
426
427
    }
    
428
    fn emit_cmp_r64_r64(&mut self, op1: &P<Value>, op2: &P<Value>) {
qinsoon's avatar
qinsoon committed
429
        trace!("emit: cmp {} {}", op1, op2);
qinsoon's avatar
qinsoon committed
430
        
431
432
        let (reg1, id1, loc1) = self.prepare_op(op1, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_op(op2, 4 + 1 + reg1.len() + 1);
qinsoon's avatar
qinsoon committed
433
434
435
        
        let asm = format!("cmpq {} {}", reg1, reg2);
        
436
437
438
439
440
441
442
        self.add_asm_inst(
            asm,
            vec![],
            vec![],
            vec![id1, id2],
            vec![loc1, loc2]
        );
443
444
    }
    
qinsoon's avatar
qinsoon committed
445
446
    fn emit_cmp_r64_imm32(&mut self, op1: &P<Value>, op2: u32) {
        trace!("emit: cmp {} {}", op1, op2);
qinsoon's avatar
qinsoon committed
447
        
448
        let (reg1, id1, loc1) = self.prepare_op(op1, 4 + 1);
qinsoon's avatar
qinsoon committed
449
450
451
        
        let asm = format!("cmpq {} ${}", reg1, op2);
        
452
453
454
455
456
457
458
        self.add_asm_inst(
            asm,
            vec![],
            vec![],
            vec![id1],
            vec![loc1]
        )
459
460
461
    }
    
    fn emit_cmp_r64_mem64(&mut self, op1: &P<Value>, op2: &P<Value>) {
qinsoon's avatar
qinsoon committed
462
        trace!("emit: cmp {} {}", op1, op2);
qinsoon's avatar
qinsoon committed
463
        unimplemented!()
464
465
    }
    
qinsoon's avatar
qinsoon committed
466
467
    fn emit_mov_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
        trace!("emit: mov {} -> {}", src, dest);
qinsoon's avatar
qinsoon committed
468
        
469
        let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1);
qinsoon's avatar
qinsoon committed
470
471
472
        
        let asm = format!("movq {} ${}", src, reg1);
        
473
474
475
476
477
478
479
        self.add_asm_inst(
            asm,
            vec![],
            vec![],
            vec![id1],
            vec![loc1]
        )
480
481
482
    }
    
    fn emit_mov_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
qinsoon's avatar
qinsoon committed
483
        trace!("emit: mov {} -> {}", src, dest);
qinsoon's avatar
qinsoon committed
484
        unimplemented!()
qinsoon's avatar
qinsoon committed
485
486
487
488
    }
    
    fn emit_mov_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: mov {} -> {}", src, dest);
qinsoon's avatar
qinsoon committed
489
        
490
491
        let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_op(src, 4 + 1 + reg1.len() + 1);
qinsoon's avatar
qinsoon committed
492
493
494
        
        let asm = format!("movq {} {}", reg2, reg1);
        
495
496
497
498
499
500
501
        self.add_asm_inst(
            asm,
            vec![id1],
            vec![loc1],
            vec![id2],
            vec![loc2]
        )
qinsoon's avatar
qinsoon committed
502
503
504
505
    }
    
    fn emit_add_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: add {}, {} -> {}", dest, src, dest);
qinsoon's avatar
qinsoon committed
506
        
507
508
        let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_op(src, 4 + 1 + reg1.len() + 1);
qinsoon's avatar
qinsoon committed
509
510
511
        
        let asm = format!("addq {} {}", reg2, reg1);
        
512
513
514
515
516
517
518
        self.add_asm_inst(
            asm,
            vec![id1],
            vec![loc1.clone()],
            vec![id1, id2],
            vec![loc1, loc2]
        )
qinsoon's avatar
qinsoon committed
519
520
521
522
    }
    
    fn emit_add_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: add {}, {} -> {}", dest, src, dest);
qinsoon's avatar
qinsoon committed
523
        unimplemented!()
qinsoon's avatar
qinsoon committed
524
525
526
527
    }
    
    fn emit_add_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
        trace!("emit: add {}, {} -> {}", dest, src, dest);
qinsoon's avatar
qinsoon committed
528
        
529
        let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1);
qinsoon's avatar
qinsoon committed
530
531
532
        
        let asm = format!("addq {} ${}", src, reg1);
        
533
534
535
536
537
538
539
        self.add_asm_inst(
            asm,
            vec![id1],
            vec![loc1.clone()],
            vec![id1],
            vec![loc1]
        )
qinsoon's avatar
qinsoon committed
540
541
542
543
    }
    
    fn emit_sub_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: sub {}, {} -> {}", dest, src, dest);
qinsoon's avatar
qinsoon committed
544
        
545
546
        let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_op(src, 4 + 1 + reg1.len() + 1);
qinsoon's avatar
qinsoon committed
547
548
549
        
        let asm = format!("subq {} {}", reg2, reg1);
        
550
551
552
553
554
555
556
        self.add_asm_inst(
            asm,
            vec![id1],
            vec![loc1.clone()],
            vec![id1, id2],
            vec![loc1, loc2]
        )        
qinsoon's avatar
qinsoon committed
557
558
559
560
    }
    
    fn emit_sub_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: sub {}, {} -> {}", dest, src, dest);
qinsoon's avatar
qinsoon committed
561
        unimplemented!()
qinsoon's avatar
qinsoon committed
562
563
564
565
    }
    
    fn emit_sub_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
        trace!("emit: sub {}, {} -> {}", dest, src, dest);
qinsoon's avatar
qinsoon committed
566
        
567
        let (reg1, id1, loc1) = self.prepare_op(dest, 4 + 1);
qinsoon's avatar
qinsoon committed
568
569
570
        
        let asm = format!("subq {} ${}", src, reg1);
        
571
572
573
574
575
576
577
        self.add_asm_inst(
            asm,
            vec![id1],
            vec![loc1.clone()],
            vec![id1],
            vec![loc1]
        )        
qinsoon's avatar
qinsoon committed
578
579
    }
    
580
    fn emit_mul_r64(&mut self, src: &P<Value>) {
581
        trace!("emit: mul rax, {} -> (rdx, rax)", src);
qinsoon's avatar
qinsoon committed
582
        
583
584
585
        let (reg, id, loc) = self.prepare_op(src, 3 + 1);
        let rax = self.prepare_machine_reg(&x86_64::RAX);
        let rdx = self.prepare_machine_reg(&x86_64::RDX);
qinsoon's avatar
qinsoon committed
586
587
588
        
        let asm = format!("mul {}", reg);
        
589
590
591
592
593
594
595
        self.add_asm_inst(
            asm,
            vec![rax, rdx],
            vec![],
            vec![id, rax],
            vec![loc]
        )
596
597
598
599
    }
    
    fn emit_mul_mem64(&mut self, src: &P<Value>) {
        trace!("emit: mul rax, {} -> rax", src);
qinsoon's avatar
qinsoon committed
600
        unimplemented!()
601
602
    }
    
qinsoon's avatar
qinsoon committed
603
604
    fn emit_jmp(&mut self, dest: &Destination) {
        trace!("emit: jmp {}", dest.target);
qinsoon's avatar
qinsoon committed
605
606
607
        
        // symbolic label, we dont need to patch it
        let asm = format!("jmp {}", self.asm_block_label(dest.target));
608
        self.add_asm_branch(asm, dest.target)
qinsoon's avatar
qinsoon committed
609
610
611
612
    }
    
    fn emit_je(&mut self, dest: &Destination) {
        trace!("emit: je {}", dest.target);
qinsoon's avatar
qinsoon committed
613
614
        
        let asm = format!("je {}", self.asm_block_label(dest.target));
615
        self.add_asm_branch2(asm, dest.target);        
qinsoon's avatar
qinsoon committed
616
617
618
619
    }
    
    fn emit_jne(&mut self, dest: &Destination) {
        trace!("emit: jne {}", dest.target);
qinsoon's avatar
qinsoon committed
620
621
        
        let asm = format!("jne {}", self.asm_block_label(dest.target));
622
        self.add_asm_branch2(asm, dest.target);
qinsoon's avatar
qinsoon committed
623
624
625
626
    }
    
    fn emit_ja(&mut self, dest: &Destination) {
        trace!("emit: ja {}", dest.target);
qinsoon's avatar
qinsoon committed
627
628
        
        let asm = format!("ja {}", self.asm_block_label(dest.target));
629
        self.add_asm_branch2(asm, dest.target);
qinsoon's avatar
qinsoon committed
630
631
632
633
    }
    
    fn emit_jae(&mut self, dest: &Destination) {
        trace!("emit: jae {}", dest.target);
qinsoon's avatar
qinsoon committed
634
635
        
        let asm = format!("jae {}", self.asm_block_label(dest.target));
636
        self.add_asm_branch2(asm, dest.target);        
qinsoon's avatar
qinsoon committed
637
638
639
640
    }
    
    fn emit_jb(&mut self, dest: &Destination) {
        trace!("emit: jb {}", dest.target);
qinsoon's avatar
qinsoon committed
641
642
        
        let asm = format!("jb {}", self.asm_block_label(dest.target));
643
        self.add_asm_branch2(asm, dest.target);
qinsoon's avatar
qinsoon committed
644
645
646
647
    }
    
    fn emit_jbe(&mut self, dest: &Destination) {
        trace!("emit: jbe {}", dest.target);
qinsoon's avatar
qinsoon committed
648
649
        
        let asm = format!("jbe {}", self.asm_block_label(dest.target));
650
        self.add_asm_branch2(asm, dest.target);        
qinsoon's avatar
qinsoon committed
651
652
    }
    
qinsoon's avatar
qinsoon committed
653
654
    fn emit_jg(&mut self, dest: &Destination) {
        trace!("emit: jg {}", dest.target);
qinsoon's avatar
qinsoon committed
655
656
        
        let asm = format!("jg {}", self.asm_block_label(dest.target));
657
        self.add_asm_branch2(asm, dest.target);        
qinsoon's avatar
qinsoon committed
658
659
660
661
    }
    
    fn emit_jge(&mut self, dest: &Destination) {
        trace!("emit: jge {}", dest.target);
qinsoon's avatar
qinsoon committed
662
663
        
        let asm = format!("jge {}", self.asm_block_label(dest.target));
664
        self.add_asm_branch2(asm, dest.target);        
qinsoon's avatar
qinsoon committed
665
666
667
668
    }
    
    fn emit_jl(&mut self, dest: &Destination) {
        trace!("emit: jl {}", dest.target);
qinsoon's avatar
qinsoon committed
669
670
        
        let asm = format!("jl {}", self.asm_block_label(dest.target));
671
        self.add_asm_branch2(asm, dest.target);        
qinsoon's avatar
qinsoon committed
672
673
674
675
    }
    
    fn emit_jle(&mut self, dest: &Destination) {
        trace!("emit: jle {}", dest.target);
qinsoon's avatar
qinsoon committed
676
677
        
        let asm = format!("jle {}", self.asm_block_label(dest.target));
678
        self.add_asm_branch2(asm, dest.target);        
qinsoon's avatar
qinsoon committed
679
680
    }    
    
681
682
    fn emit_call_near_rel32(&mut self, func: MuTag) {
        trace!("emit: call {}", func);
qinsoon's avatar
qinsoon committed
683
684
        
        let asm = format!("call {}", func);
685
        self.add_asm_call(asm);
686
687
        
        // FIXME: call interferes with machine registers
688
689
690
691
    }
    
    fn emit_call_near_r64(&mut self, func: &P<Value>) {
        trace!("emit: call {}", func);
qinsoon's avatar
qinsoon committed
692
        unimplemented!()
693
694
695
    }
    
    fn emit_call_near_mem64(&mut self, func: &P<Value>) {
qinsoon's avatar
qinsoon committed
696
        trace!("emit: call {}", func);
qinsoon's avatar
qinsoon committed
697
        unimplemented!()
qinsoon's avatar
qinsoon committed
698
699
700
701
    }
    
    fn emit_ret(&mut self) {
        trace!("emit: ret");
qinsoon's avatar
qinsoon committed
702
703
        
        let asm = format!("ret");
704
        self.add_asm_ret(asm);
705
    }
706
    
qinsoon's avatar
qinsoon committed
707
    fn emit_push_r64(&mut self, src: &P<Value>) {
708
        trace!("emit: push {}", src);
qinsoon's avatar
qinsoon committed
709
        
710
        let (reg, id, loc) = self.prepare_op(src, 5 + 1);
qinsoon's avatar
qinsoon committed
711
712
713
        
        let asm = format!("pushq {}", reg);
        
714
715
716
717
718
719
720
        self.add_asm_inst(
            asm,
            vec![],
            vec![],
            vec![id],
            vec![loc]
        )
721
722
    }
    
qinsoon's avatar
qinsoon committed
723
    fn emit_pop_r64(&mut self, dest: &P<Value>) {
724
        trace!("emit: pop {}", dest);
qinsoon's avatar
qinsoon committed
725
        
726
        let (reg, id, loc) = self.prepare_op(dest, 4 + 1);
qinsoon's avatar
qinsoon committed
727
728
729
        
        let asm = format!("popq {}", reg);
        
730
731
732
733
734
735
736
        self.add_asm_inst(
            asm,
            vec![id],
            vec![loc.clone()],
            vec![id],
            vec![loc]
        )        
737
    }    
738
}