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

3
use compiler::backend;
4 5
use compiler::backend::AOT_EMIT_CONTEXT_FILE;
use compiler::backend::AOT_EMIT_DIR;
qinsoon's avatar
qinsoon committed
6
use utils::ByteSize;
7
use compiler::backend::x86_64;
8
use compiler::backend::x86_64::CodeGenerator;
qinsoon's avatar
qinsoon committed
9
use vm::MachineCode;
qinsoon's avatar
qinsoon committed
10
use vm::VM;
11

12 13
use utils::string_utils;

14 15 16
use ast::ptr::P;
use ast::ir::*;

17 18
use std::collections::HashMap;
use std::str;
19
use std::usize;
20
use std::slice::Iter;
21
use std::ops;
22 23

struct ASMCode {
qinsoon's avatar
qinsoon committed
24
    name: MuName, 
25 26
    code: Vec<ASM>,
    reg_defines: HashMap<MuID, Vec<ASMLocation>>,
27 28
    reg_uses: HashMap<MuID, Vec<ASMLocation>>,
    
qinsoon's avatar
qinsoon committed
29 30
    mem_op_used: HashMap<usize, bool>,
    
31 32 33
    preds: Vec<Vec<usize>>,
    succs: Vec<Vec<usize>>,
    
qinsoon's avatar
qinsoon committed
34 35 36 37
    idx_to_blk: HashMap<usize, MuName>,
    blk_to_idx: HashMap<MuName, usize>,
    cond_branches: HashMap<usize, MuName>,
    branches: HashMap<usize, MuName>,
38
    
qinsoon's avatar
qinsoon committed
39 40 41
    blocks: Vec<MuName>,
    block_start: HashMap<MuName, usize>,
    block_range: HashMap<MuName, ops::Range<usize>>,
42
    
qinsoon's avatar
qinsoon committed
43 44
    block_livein: HashMap<MuName, Vec<MuID>>,
    block_liveout: HashMap<MuName, Vec<MuID>>
45 46
}

qinsoon's avatar
qinsoon committed
47 48 49
unsafe impl Send for ASMCode {} 
unsafe impl Sync for ASMCode {}

50 51 52 53
impl MachineCode for ASMCode {
    fn number_of_insts(&self) -> usize {
        self.code.len()
    }
54
    
55 56 57 58 59 60 61 62
    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
63 64 65 66
    fn is_using_mem_op(&self, index: usize) -> bool {
        *self.mem_op_used.get(&index).unwrap()
    }
    
qinsoon's avatar
qinsoon committed
67 68 69 70 71 72 73 74
    fn get_succs(&self, index: usize) -> &Vec<usize> {
        &self.succs[index]
    }
    
    fn get_preds(&self, index: usize) -> &Vec<usize> {
        &self.preds[index]
    }
    
75
    fn get_inst_reg_uses(&self, index: usize) -> &Vec<MuID> {
qinsoon's avatar
qinsoon committed
76
        &self.code[index].uses
77 78
    }
    
79
    fn get_inst_reg_defines(&self, index: usize) -> &Vec<MuID> {
qinsoon's avatar
qinsoon committed
80
        &self.code[index].defines
81
    }
82
    
83
    fn replace_reg(&mut self, from: MuID, to: MuID) {
84
        let to_reg_tag : MuName = backend::all_regs().get(&to).unwrap().name().unwrap();
85
        let to_reg_string = "%".to_string() + &to_reg_tag;
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
        
        match self.reg_defines.get(&from) {
            Some(defines) => {
                for loc in defines {
                    let ref mut inst_to_patch = self.code[loc.line];
                    for i in 0..loc.len {
                        string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
                    }
                }
            },
            None => {}
        }
        
        match self.reg_uses.get(&from) {
            Some(uses) => {
                for loc in uses {
                    let ref mut inst_to_patch = self.code[loc.line];
                    for i in 0..loc.len {
                        string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
                    }   
                }
            },
            None => {}
        }
    }
    
112 113 114 115 116
    fn set_inst_nop(&mut self, index: usize) {
        self.code.remove(index);
        self.code.insert(index, ASM::nop());
    }
    
117 118 119 120 121 122 123 124 125 126 127
    fn emit(&self) -> Vec<u8> {
        let mut ret = vec![];
        
        for inst in self.code.iter() {
            ret.append(&mut inst.code.clone().into_bytes());
            ret.append(&mut "\n".to_string().into_bytes());
        }
        
        ret
    }
    
128 129
    fn trace_mc(&self) {
        trace!("");
130

131 132
        trace!("code for {}: \n", self.name);
        
133 134
        let n_insts = self.code.len();
        for i in 0..n_insts {
135
            self.trace_inst(i);
136 137
        }
        
138 139 140 141 142 143 144
        trace!("")      
    }
    
    fn trace_inst(&self, i: usize) {
        trace!("#{}\t{:30}\t\tdefine: {:?}\tuses: {:?}\tpred: {:?}\tsucc: {:?}", 
            i, self.code[i].code, self.get_inst_reg_defines(i), self.get_inst_reg_uses(i),
            self.preds[i], self.succs[i]);
145
    }
146
    
147 148
    fn get_ir_block_livein(&self, block: &str) -> Option<&Vec<MuID>> {
        self.block_livein.get(&block.to_string())
149 150
    }
    
151 152
    fn get_ir_block_liveout(&self, block: &str) -> Option<&Vec<MuID>> {
        self.block_liveout.get(&block.to_string())
153 154
    }
    
qinsoon's avatar
qinsoon committed
155
    fn get_all_blocks(&self) -> &Vec<MuName> {
156 157 158
        &self.blocks
    }
    
159 160
    fn get_block_range(&self, block: &str) -> Option<ops::Range<usize>> {
        match self.block_range.get(&block.to_string()) {
161 162 163 164
            Some(r) => Some(r.clone()),
            None => None
        }
    }
165 166 167 168 169 170
}

struct ASM {
    code: String,
    defines: Vec<MuID>,
    uses: Vec<MuID>
171 172
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
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![]
        }
    }
197 198 199 200 201 202 203 204
    
    fn nop() -> ASM {
        ASM {
            code: "".to_string(),
            defines: vec![],
            uses: vec![]
        }
    }
205 206
}

207
#[derive(Clone, Debug)]
208 209 210 211 212 213 214
struct ASMLocation {
    line: usize,
    index: usize,
    len: usize
}

impl ASMLocation {
215 216
    /// the 'line' field will be updated later
    fn new(index: usize, len: usize) -> ASMLocation {
217
        ASMLocation{
218
            line: usize::MAX,
219 220 221 222 223 224
            index: index,
            len: len
        }
    }
}

225
pub struct ASMCodeGen {
226
    cur: Option<Box<ASMCode>>
227 228
}

229
const REG_PLACEHOLDER_LEN : usize = 5;
230 231 232 233 234 235
lazy_static! {
    pub static ref REG_PLACEHOLDER : String = {
        let blank_spaces = [' ' as u8; REG_PLACEHOLDER_LEN];
        
        format!("%{}", str::from_utf8(&blank_spaces).unwrap())
    };
236 237 238 239
}

impl ASMCodeGen {
    pub fn new() -> ASMCodeGen {
240
        ASMCodeGen {
241
            cur: None
242 243 244 245 246 247 248 249 250 251 252
        }
    }
    
    fn cur(&self) -> &ASMCode {
        self.cur.as_ref().unwrap()
    }
    
    fn cur_mut(&mut self) -> &mut ASMCode {
        self.cur.as_mut().unwrap()
    }
    
253 254 255 256
    fn line(&self) -> usize {
        self.cur().code.len()
    }
    
257
    fn add_asm_block_label(&mut self, code: String, block_name: MuName) {
258 259 260
        let l = self.line();
        self.cur_mut().code.push(ASM::symbolic(code));
        
261
        self.cur_mut().idx_to_blk.insert(l, block_name.clone());
262 263 264
        self.cur_mut().blk_to_idx.insert(block_name, l);
    }
    
265 266 267 268
    fn add_asm_symbolic(&mut self, code: String){
        self.cur_mut().code.push(ASM::symbolic(code));
    }
    
269 270 271 272
    fn prepare_machine_regs(&self, regs: Iter<P<Value>>) -> Vec<MuID> {
        regs.map(|x| self.prepare_machine_reg(x)).collect()
    } 
    
273
    fn add_asm_call(&mut self, code: String) {
274 275 276 277 278 279
        let mut uses : Vec<MuID> = self.prepare_machine_regs(x86_64::ARGUMENT_GPRs.iter());
        uses.append(&mut self.prepare_machine_regs(x86_64::ARGUMENT_FPRs.iter()));
        
        let mut defines : Vec<MuID> = self.prepare_machine_regs(x86_64::RETURN_GPRs.iter());
        defines.append(&mut self.prepare_machine_regs(x86_64::RETURN_FPRs.iter()));
          
qinsoon's avatar
qinsoon committed
280
        self.add_asm_inst(code, defines, vec![], uses, vec![], false);
281 282 283
    }
    
    fn add_asm_ret(&mut self, code: String) {
284 285 286
        let mut uses : Vec<MuID> = self.prepare_machine_regs(x86_64::RETURN_GPRs.iter());
        uses.append(&mut self.prepare_machine_regs(x86_64::RETURN_FPRs.iter()));
        
qinsoon's avatar
qinsoon committed
287
        self.add_asm_inst(code, vec![], vec![], uses, vec![], false);
288 289
    }
    
290
    fn add_asm_branch(&mut self, code: String, target: MuName) {
291 292
        let l = self.line();
        self.cur_mut().branches.insert(l, target);
qinsoon's avatar
qinsoon committed
293 294
        
        self.add_asm_inst(code, vec![], vec![], vec![], vec![], false);
295 296
    }
    
297
    fn add_asm_branch2(&mut self, code: String, target: MuName) {
298 299
        let l = self.line();
        self.cur_mut().cond_branches.insert(l, target);
qinsoon's avatar
qinsoon committed
300 301
        
        self.add_asm_inst(code, vec![], vec![], vec![], vec![], false);
302 303 304 305 306 307
    }
    
    fn add_asm_inst(
        &mut self, 
        code: String, 
        defines: Vec<MuID>,
308
        mut define_locs: Vec<ASMLocation>, 
309
        uses: Vec<MuID>,
qinsoon's avatar
qinsoon committed
310 311
        mut use_locs: Vec<ASMLocation>,
        is_using_mem_op: bool) 
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
        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) {
343
                mc.reg_uses.get_mut(&id).unwrap().push(loc.clone());
344
            } else {
345
                mc.reg_uses.insert(id, vec![loc.clone()]);
346 347
            }
        }
348
       
349 350
        // put the instruction
        mc.code.push(ASM::inst(code, defines, uses));
qinsoon's avatar
qinsoon committed
351
        mc.mem_op_used.insert(line, is_using_mem_op);
352 353 354 355
    }
    
    fn define_reg(&mut self, reg: &P<Value>, loc: ASMLocation) {
        let id = reg.extract_ssa_id().unwrap();
356
        
357 358 359 360 361 362 363
        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]);
        } 
364 365 366 367 368 369
    }
    
    fn use_reg(&mut self, reg: &P<Value>, loc: ASMLocation) {
        let id = reg.extract_ssa_id().unwrap();
        
        let code = self.cur_mut();
370 371 372
        if code.reg_uses.contains_key(&id) {
            let reg_uses = code.reg_uses.get_mut(&id).unwrap();
            reg_uses.push(loc);
373
        } else {
374
            code.reg_uses.insert(id, vec![loc]);
375 376 377
        } 
    }
    
378
    fn prepare_reg(&self, op: &P<Value>, loc: usize) -> (String, MuID, ASMLocation) {
379 380 381 382 383 384 385
        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()
386
    }
387
    
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 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
    #[allow(unused_assignments)]
    fn prepare_mem(&self, op: &P<Value>, loc: usize) -> (String, Vec<MuID>, Vec<ASMLocation>) {
        let mut ids : Vec<MuID> = vec![];
        let mut locs : Vec<ASMLocation> = vec![];
        let mut result_str : String = "".to_string();
        
        let mut loc_cursor : usize = 0;
        
        match op.v {
            // offset(base,index,scale)
            Value_::Memory(MemoryLocation::Address{ref base, ref offset, ref index, scale}) => {
                // deal with offset
                if offset.is_some() {
                    let offset = offset.as_ref().unwrap();
                    
                    match offset.v {
                        Value_::SSAVar(id) => {
                            // temp as offset
                            let (str, id, loc) = self.prepare_reg(offset, 0);
                            
                            result_str.push_str(&str);
                            ids.push(id);
                            locs.push(loc);
                            
                            loc_cursor += str.len();
                        },
                        Value_::Constant(Constant::Int(val)) => {
                            let str = val.to_string();
                            
                            result_str.push_str(&str);
                            loc_cursor += str.len();
                        },
                        _ => panic!("unexpected offset type: {:?}", offset)
                    }
                }
                
                result_str.push('(');
                loc_cursor += 1; 
                
                // deal with base, base is ssa
                let (str, id, loc) = self.prepare_reg(base, loc_cursor);
                result_str.push_str(&str);
                ids.push(id);
                locs.push(loc);
                loc_cursor += str.len();
                
                // deal with index (ssa or constant)
                if index.is_some() {
                    result_str.push(',');
                    loc_cursor += 1; // plus 1 for ,                    
                    
                    let index = index.as_ref().unwrap();
                    
                    match index.v {
                        Value_::SSAVar(id) => {
                            // temp as offset
                            let (str, id, loc) = self.prepare_reg(index, loc_cursor);
                            
                            result_str.push_str(&str);
                            ids.push(id);
                            locs.push(loc);
                            
                            loc_cursor += str.len();
                        },
                        Value_::Constant(Constant::Int(val)) => {
                            let str = val.to_string();
                            
                            result_str.push_str(&str);
                            loc_cursor += str.len();
                        },
                        _ => panic!("unexpected index type: {:?}", index)
                    }
                    
                    // scale
                    if scale.is_some() {
                        result_str.push(',');
                        loc_cursor += 1;
                        
                        let scale = scale.unwrap();
                        let str = scale.to_string();
                        
                        result_str.push_str(&str);
                        loc_cursor += str.len();
                    }
                }
                
                result_str.push(')');
                loc_cursor += 1;
            },
477 478
            Value_::Memory(MemoryLocation::Symbolic{ref base, ref label}) => {
                result_str.push_str(&symbol(label.clone()));
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
                loc_cursor += label.len();
                
                if base.is_some() {
                    result_str.push('(');
                    loc_cursor += 1;
                    
                    let (str, id, loc) = self.prepare_reg(base.as_ref().unwrap(), loc_cursor);
                    result_str.push_str(&str);
                    ids.push(id);
                    locs.push(loc);
                    loc_cursor += str.len();
                    
                    result_str.push(')');
                    loc_cursor += 1;                    
                }
            },
            _ => panic!("expect mem location as value")
        }
        
        (result_str, ids, locs)
    }
    
501 502
    fn asm_reg_op(&self, op: &P<Value>) -> String {
        let id = op.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
503
        if id < MACHINE_ID_END {
504
            // machine reg
505
            format!("%{}", op.name().unwrap())
506 507 508 509 510 511
        } else {
            // virtual register, use place holder
            REG_PLACEHOLDER.clone()
        }
    }
    
qinsoon's avatar
qinsoon committed
512
    fn asm_block_label(&self, label: MuName) -> String {
513
        symbol(format!("{}_{}", self.cur().name, label))
514
    }
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 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 577 578
    
    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);
            }
        }        
    }
579 580 581
}

impl CodeGenerator for ASMCodeGen {
qinsoon's avatar
qinsoon committed
582
    fn start_code(&mut self, func_name: MuName) {
583
        self.cur = Some(Box::new(ASMCode {
584
                name: func_name.clone(),
585
                code: vec![],
586
                reg_defines: HashMap::new(),
587 588
                reg_uses: HashMap::new(),
                
qinsoon's avatar
qinsoon committed
589 590
                mem_op_used: HashMap::new(),
                
591 592 593 594 595 596
                preds: vec![],
                succs: vec![],
                
                idx_to_blk: HashMap::new(),
                blk_to_idx: HashMap::new(),
                cond_branches: HashMap::new(),
597 598
                branches: HashMap::new(),
                
599 600 601 602
                blocks: vec![],
                block_start: HashMap::new(),
                block_range: HashMap::new(),
                
603 604
                block_livein: HashMap::new(),
                block_liveout: HashMap::new()
605
            }));
606
        
qinsoon's avatar
qinsoon committed
607
        // to link with C sources via gcc
608 609
        self.add_asm_symbolic(directive_globl(symbol(func_name.clone())));
        self.add_asm_symbolic(format!("{}:", symbol(func_name.clone())));
610 611
    }
    
612 613 614
    fn finish_code(&mut self) -> Box<MachineCode> {
        self.control_flow_analysis();
        self.cur.take().unwrap()
615 616 617 618 619 620 621 622 623
    }
    
    fn print_cur_code(&self) {
        println!("");
        
        if self.cur.is_some() {
            let code = self.cur.as_ref().unwrap();
            
            println!("code for {}: ", code.name);
624 625 626 627
            let n_insts = code.code.len();
            for i in 0..n_insts {
                let ref line = code.code[i];
                println!("#{}\t{}", i, line.code);
628 629 630 631 632 633 634 635
            }
        } else {
            println!("no current code");
        }
        
        println!("");
    }
    
qinsoon's avatar
qinsoon committed
636
    fn start_block(&mut self, block_name: MuName) {
637 638 639
        let label = format!("{}:", self.asm_block_label(block_name.clone()));        
        self.add_asm_block_label(label, block_name.clone());
        self.cur_mut().blocks.push(block_name.clone());
640 641 642 643 644
        
        let start = self.line();
        self.cur_mut().block_start.insert(block_name, start);
    }
    
qinsoon's avatar
qinsoon committed
645
    fn end_block(&mut self, block_name: MuName) {
646 647 648 649
        let start : usize = *self.cur().block_start.get(&block_name).unwrap();
        let end : usize = self.line();
        
        self.cur_mut().block_range.insert(block_name, (start..end));
650 651
    }
    
qinsoon's avatar
qinsoon committed
652
    fn set_block_livein(&mut self, block_name: MuName, live_in: &Vec<P<Value>>) {
653 654 655 656
        let cur = self.cur_mut();
        
        let mut res = {
            if !cur.block_livein.contains_key(&block_name) {
657
                cur.block_livein.insert(block_name.clone(), vec![]);
658 659 660 661 662 663 664 665 666 667 668 669
            } else {
                panic!("seems we are inserting livein to block {} twice", block_name);
            }
            
            cur.block_livein.get_mut(&block_name).unwrap()
        };
        
        for value in live_in {
            res.push(value.extract_ssa_id().unwrap());
        }
    }
    
qinsoon's avatar
qinsoon committed
670
    fn set_block_liveout(&mut self, block_name: MuName, live_out: &Vec<P<Value>>) {
671 672 673 674
        let cur = self.cur_mut();
        
        let mut res = {
            if !cur.block_liveout.contains_key(&block_name) {
675
                cur.block_liveout.insert(block_name.clone(), vec![]);
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
            } else {
                panic!("seems we are inserting livein to block {} twice", block_name);
            }
            
            cur.block_liveout.get_mut(&block_name).unwrap()
        };
        
        for value in live_out {
            match value.extract_ssa_id() {
                Some(id) => res.push(id),
                None => {}
            }
        }        
    }
    
691
    fn emit_cmp_r64_r64(&mut self, op1: &P<Value>, op2: &P<Value>) {
qinsoon's avatar
qinsoon committed
692
        trace!("emit: cmp {} {}", op1, op2);
693
        
694 695
        let (reg1, id1, loc1) = self.prepare_reg(op1, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_reg(op2, 4 + 1 + reg1.len() + 1);
696
        
qinsoon's avatar
qinsoon committed
697
        let asm = format!("cmpq {},{}", reg1, reg2);
698
        
699 700 701 702 703
        self.add_asm_inst(
            asm,
            vec![],
            vec![],
            vec![id1, id2],
qinsoon's avatar
qinsoon committed
704 705
            vec![loc1, loc2],
            false
706
        );
707 708
    }
    
qinsoon's avatar
qinsoon committed
709 710
    fn emit_cmp_r64_imm32(&mut self, op1: &P<Value>, op2: u32) {
        trace!("emit: cmp {} {}", op1, op2);
711
        
712
        let (reg1, id1, loc1) = self.prepare_reg(op1, 4 + 1 + 1 + op2.to_string().len() + 1);
713
        
qinsoon's avatar
qinsoon committed
714
        let asm = format!("cmpq ${},{}", op2, reg1);
715
        
716 717 718 719 720
        self.add_asm_inst(
            asm,
            vec![],
            vec![],
            vec![id1],
qinsoon's avatar
qinsoon committed
721 722
            vec![loc1],
            false
723
        )
724 725 726
    }
    
    fn emit_cmp_r64_mem64(&mut self, op1: &P<Value>, op2: &P<Value>) {
qinsoon's avatar
qinsoon committed
727
        trace!("emit: cmp {} {}", op1, op2);
728
        unimplemented!()
729 730
    }
    
qinsoon's avatar
qinsoon committed
731 732
    fn emit_mov_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
        trace!("emit: mov {} -> {}", src, dest);
733
        
734
        let (reg1, id1, loc1) = self.prepare_reg(dest, 4 + 1 + 1 + src.to_string().len() + 1);
735
        
qinsoon's avatar
qinsoon committed
736
        let asm = format!("movq ${},{}", src, reg1);
737
        
738 739 740
        self.add_asm_inst(
            asm,
            vec![id1],
741 742
            vec![loc1],
            vec![],
qinsoon's avatar
qinsoon committed
743 744
            vec![],
            false
745
        )
746 747 748
    }
    
    fn emit_mov_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
qinsoon's avatar
qinsoon committed
749
        trace!("emit: mov {} -> {}", src, dest);
750 751 752 753 754 755 756 757 758 759 760
        
        let (mem, id1, loc1) = self.prepare_mem(src, 4 + 1);
        let (reg, id2, loc2) = self.prepare_reg(dest, 4 + 1 + mem.len() + 1);
        
        let asm = format!("movq {},{}", mem, reg);
        
        self.add_asm_inst(
            asm,
            vec![id2],
            vec![loc2],
            id1,
qinsoon's avatar
qinsoon committed
761 762
            loc1,
            true
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
        )
    }
    
    fn emit_mov_mem64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: mov {} -> {}", src, dest);
        
        let (reg, id1, loc1) = self.prepare_reg(src, 4 + 1);
        let (mem, mut id2, mut loc2) = self.prepare_mem(dest, 4 + 1 + reg.len() + 1);
        
        // the register we used for the memory location is counted as 'use'
        id2.push(id1);
        loc2.push(loc1);
        
        let asm = format!("movq {},{}", reg, mem);
        
        self.add_asm_inst(
            asm,
            vec![], // not defining anything (write to memory)
            vec![],
            id2,
qinsoon's avatar
qinsoon committed
783 784
            loc2,
            true
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
        )
    }
    
    fn emit_mov_mem64_imm32(&mut self, dest: &P<Value>, src: u32) {
        trace!("emit: mov {} -> {}", src, dest);
        
        let (mem, id, loc) = self.prepare_mem(dest, 4 + 1 + 1 + src.to_string().len() + 1);
        
        let asm = format!("movq ${},{}", src, mem);
        
        self.add_asm_inst(
            asm,
            vec![],
            vec![],
            id,
qinsoon's avatar
qinsoon committed
800 801
            loc,
            true
802
        )
qinsoon's avatar
qinsoon committed
803 804 805 806
    }
    
    fn emit_mov_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: mov {} -> {}", src, dest);
807
        
808 809
        let (reg1, id1, loc1) = self.prepare_reg(src, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_reg(dest, 4 + 1 + reg1.len() + 1);
810
        
qinsoon's avatar
qinsoon committed
811
        let asm = format!("movq {},{}", reg1, reg2);
812
        
813 814 815
        self.add_asm_inst(
            asm,
            vec![id2],
816 817
            vec![loc2],
            vec![id1],
qinsoon's avatar
qinsoon committed
818 819
            vec![loc1],
            false
820
        )
qinsoon's avatar
qinsoon committed
821 822 823 824
    }
    
    fn emit_add_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: add {}, {} -> {}", dest, src, dest);
825
        
826 827
        let (reg1, id1, loc1) = self.prepare_reg(src, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_reg(dest, 4 + 1 + reg1.len() + 1);
828
        
qinsoon's avatar
qinsoon committed
829
        let asm = format!("addq {},{}", reg1, reg2);
830
        
831 832
        self.add_asm_inst(
            asm,
833 834
            vec![id2],
            vec![loc2.clone()],
835
            vec![id1, id2],
qinsoon's avatar
qinsoon committed
836 837
            vec![loc1, loc2],
            false
838
        )
qinsoon's avatar
qinsoon committed
839 840 841 842
    }
    
    fn emit_add_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: add {}, {} -> {}", dest, src, dest);
843
        unimplemented!()
qinsoon's avatar
qinsoon committed
844 845 846 847
    }
    
    fn emit_add_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
        trace!("emit: add {}, {} -> {}", dest, src, dest);
848
        
849
        let (reg1, id1, loc1) = self.prepare_reg(dest, 4 + 1 + 1 + src.to_string().len() + 1);
850
        
851
        let asm = format!("addq ${},{}", src, reg1);
852
        
853 854 855 856 857
        self.add_asm_inst(
            asm,
            vec![id1],
            vec![loc1.clone()],
            vec![id1],
qinsoon's avatar
qinsoon committed
858 859
            vec![loc1],
            false
860
        )
qinsoon's avatar
qinsoon committed
861 862 863 864
    }
    
    fn emit_sub_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: sub {}, {} -> {}", dest, src, dest);
865
        
866 867
        let (reg1, id1, loc1) = self.prepare_reg(src, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_reg(dest, 4 + 1 + reg1.len() + 1);
868
        
qinsoon's avatar
qinsoon committed
869
        let asm = format!("subq {},{}", reg1, reg2);
870
        
871 872
        self.add_asm_inst(
            asm,
873 874
            vec![id2],
            vec![loc2.clone()],
875
            vec![id1, id2],
qinsoon's avatar
qinsoon committed
876 877
            vec![loc1, loc2],
            false
878
        )        
qinsoon's avatar
qinsoon committed
879 880 881 882
    }
    
    fn emit_sub_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
        trace!("emit: sub {}, {} -> {}", dest, src, dest);
883
        unimplemented!()
qinsoon's avatar
qinsoon committed
884 885 886 887
    }
    
    fn emit_sub_r64_imm32(&mut self, dest: &P<Value>, src: u32) {
        trace!("emit: sub {}, {} -> {}", dest, src, dest);
888
        
889
        let (reg1, id1, loc1) = self.prepare_reg(dest, 4 + 1 + 1 + src.to_string().len() + 1);
890
        
qinsoon's avatar
qinsoon committed
891
        let asm = format!("subq ${},{}", src, reg1);
892
        
893 894 895 896 897
        self.add_asm_inst(
            asm,
            vec![id1],
            vec![loc1.clone()],
            vec![id1],
qinsoon's avatar
qinsoon committed
898 899
            vec![loc1],
            false
900
        )        
qinsoon's avatar
qinsoon committed
901 902
    }
    
903
    fn emit_mul_r64(&mut self, src: &P<Value>) {
904
        trace!("emit: mul rax, {} -> (rdx, rax)", src);
905
        
906
        let (reg, id, loc) = self.prepare_reg(src, 3 + 1);
907 908
        let rax = self.prepare_machine_reg(&x86_64::RAX);
        let rdx = self.prepare_machine_reg(&x86_64::RDX);
909 910 911
        
        let asm = format!("mul {}", reg);
        
912 913 914 915 916
        self.add_asm_inst(
            asm,
            vec![rax, rdx],
            vec![],
            vec![id, rax],
qinsoon's avatar
qinsoon committed
917 918
            vec![loc],
            false
919
        )
920 921 922 923
    }
    
    fn emit_mul_mem64(&mut self, src: &P<Value>) {
        trace!("emit: mul rax, {} -> rax", src);
924
        unimplemented!()
925 926
    }
    
qinsoon's avatar
qinsoon committed
927
    fn emit_jmp(&mut self, dest: &Block) {
928
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
929
        trace!("emit: jmp {}", dest_name);
930 931
        
        // symbolic label, we dont need to patch it
932
        let asm = format!("jmp {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
933
        self.add_asm_branch(asm, dest_name)
qinsoon's avatar
qinsoon committed
934 935
    }
    
qinsoon's avatar
qinsoon committed
936
    fn emit_je(&mut self, dest: &Block) {
937
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
938
        trace!("emit: je {}", dest_name);
939
        
940
        let asm = format!("je {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
941
        self.add_asm_branch2(asm, dest_name);        
qinsoon's avatar
qinsoon committed
942 943
    }
    
qinsoon's avatar
qinsoon committed
944
    fn emit_jne(&mut self, dest: &Block) {
945
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
946
        trace!("emit: jne {}", dest_name);
947
        
948
        let asm = format!("jne {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
949
        self.add_asm_branch2(asm, dest_name);
qinsoon's avatar
qinsoon committed
950 951
    }
    
qinsoon's avatar
qinsoon committed
952
    fn emit_ja(&mut self, dest: &Block) {
953
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
954
        trace!("emit: ja {}", dest_name);
955
        
956
        let asm = format!("ja {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
957
        self.add_asm_branch2(asm, dest_name);
qinsoon's avatar
qinsoon committed
958 959
    }
    
qinsoon's avatar
qinsoon committed
960
    fn emit_jae(&mut self, dest: &Block) {
961
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
962
        trace!("emit: jae {}", dest_name);
963
        
964
        let asm = format!("jae {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
965
        self.add_asm_branch2(asm, dest_name);        
qinsoon's avatar
qinsoon committed
966 967
    }
    
qinsoon's avatar
qinsoon committed
968
    fn emit_jb(&mut self, dest: &Block) {
969
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
970
        trace!("emit: jb {}", dest_name);
971
        
972
        let asm = format!("jb {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
973
        self.add_asm_branch2(asm, dest_name);
qinsoon's avatar
qinsoon committed
974 975
    }
    
qinsoon's avatar
qinsoon committed
976
    fn emit_jbe(&mut self, dest: &Block) {
977
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
978
        trace!("emit: jbe {}", dest_name);
979
        
980
        let asm = format!("jbe {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
981
        self.add_asm_branch2(asm, dest_name);        
qinsoon's avatar
qinsoon committed
982 983
    }
    
qinsoon's avatar
qinsoon committed
984
    fn emit_jg(&mut self, dest: &Block) {
985
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
986
        trace!("emit: jg {}", dest_name);
987
        
988
        let asm = format!("jg {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
989
        self.add_asm_branch2(asm, dest_name);        
990 991
    }
    
qinsoon's avatar
qinsoon committed
992
    fn emit_jge(&mut self, dest: &Block) {
993
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
994
        trace!("emit: jge {}", dest_name);
995
        
996
        let asm = format!("jge {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
997
        self.add_asm_branch2(asm, dest_name);        
998 999
    }
    
qinsoon's avatar
qinsoon committed
1000
    fn emit_jl(&mut self, dest: &Block) {
1001
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
1002
        trace!("emit: jl {}", dest_name);
1003
        
1004
        let asm = format!("jl {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
1005
        self.add_asm_branch2(asm, dest_name);        
1006 1007
    }
    
qinsoon's avatar
qinsoon committed
1008
    fn emit_jle(&mut self, dest: &Block) {
1009
        let dest_name = dest.name().unwrap();
qinsoon's avatar
qinsoon committed
1010
        trace!("emit: jle {}", dest_name);
1011
        
1012
        let asm = format!("jle {}", self.asm_block_label(dest_name.clone()));
qinsoon's avatar
qinsoon committed
1013
        self.add_asm_branch2(asm, dest_name);        
1014 1015
    }    
    
qinsoon's avatar
qinsoon committed
1016
    fn emit_call_near_rel32(&mut self, func: MuName) {
1017
        trace!("emit: call {}", func);
1018
        
qinsoon's avatar
qinsoon committed
1019
        let asm = format!("call {}", symbol(func));
1020
        self.add_asm_call(asm);
1021 1022
        
        // FIXME: call interferes with machine registers
1023 1024 1025 1026
    }
    
    fn emit_call_near_r64(&mut self, func: &P<Value>) {
        trace!("emit: call {}", func);
1027
        unimplemented!()
1028 1029 1030
    }
    
    fn emit_call_near_mem64(&mut self, func: &P<Value>) {
qinsoon's avatar
qinsoon committed
1031
        trace!("emit: call {}", func);
1032
        unimplemented!()
qinsoon's avatar
qinsoon committed
1033 1034 1035 1036
    }
    
    fn emit_ret(&mut self) {
        trace!("emit: ret");
1037 1038
        
        let asm = format!("ret");
1039
        self.add_asm_ret(asm);
1040
    }
1041
    
1042
    fn emit_push_r64(&mut self, src: &P<Value>) {
1043
        trace!("emit: push {}", src);
1044
        
1045
        let (reg, id, loc) = self.prepare_reg(src, 5 + 1);
1046
        let rsp = self.prepare_machine_reg(&x86_64::RSP);
1047 1048 1049
        
        let asm = format!("pushq {}", reg);
        
1050 1051
        self.add_asm_inst(
            asm,
1052
            vec![rsp],
1053 1054
            vec![],
            vec![id, rsp],
qinsoon's avatar
qinsoon committed
1055 1056
            vec![loc],
            false
1057
        )
1058 1059
    }
    
1060
    fn emit_pop_r64(&mut self, dest: &P<Value>) {
1061
        trace!("emit: pop {}", dest);
1062
        
1063
        let (reg, id, loc) = self.prepare_reg(dest, 4 + 1);
1064
        let rsp = self.prepare_machine_reg(&x86_64::RSP);
1065 1066 1067
        
        let asm = format!("popq {}", reg);
        
1068 1069
        self.add_asm_inst(
            asm,
1070
            vec![id, rsp],
1071
            vec![loc.clone()],
1072
            vec![rsp],
qinsoon's avatar
qinsoon committed
1073 1074
            vec![],
            false
1075
        )        
1076
    }    
1077
}
1078

qinsoon's avatar
qinsoon committed
1079 1080
fn create_emit_directory() {
    use std::fs;    
1081
    match fs::create_dir(AOT_EMIT_DIR) {
qinsoon's avatar
qinsoon committed
1082 1083 1084 1085 1086
        Ok(_) => {},
        Err(_) => {}
    }    
}

qinsoon's avatar
qinsoon committed
1087
pub fn emit_code(fv: &mut MuFunctionVersion, vm: &VM) {
1088 1089
    use std::io::prelude::*;
    use std::fs::File;
qinsoon's avatar
qinsoon committed
1090
    use std::path;
qinsoon's avatar
qinsoon committed
1091 1092
    
    let funcs = vm.funcs().read().unwrap();
qinsoon's avatar
qinsoon committed
1093
    let func = funcs.get(&fv.func_id).unwrap().read().unwrap();
1094 1095

    let compiled_funcs = vm.compiled_funcs().read().unwrap();
qinsoon's avatar
qinsoon committed
1096
    let cf = compiled_funcs.get(&fv.id()).unwrap().read().unwrap();
1097 1098 1099

    let code = cf.mc.emit();

qinsoon's avatar
qinsoon committed
1100 1101
    // create 'emit' directory
    create_emit_directory();
1102

qinsoon's avatar
qinsoon committed
1103
    let mut file_path = path::PathBuf::new();
1104
    file_path.push(AOT_EMIT_DIR);
1105
    file_path.push(func.name().unwrap().to_string() + ".s");
qinsoon's avatar
qinsoon committed
1106 1107
    let mut file = match File::create(file_path.as_path()) {
        Err(why) => panic!("couldn't create emission file {}: {}", file_path.to_str().unwrap(), why),
1108 1109 1110 1111
        Ok(file) => file
    };

    match file.write_all(code.as_slice()) {
qinsoon's avatar
qinsoon committed
1112 1113
        Err(why) => panic!("couldn'd write to file {}: {}", file_path.to_str().unwrap(), why),
        Ok(_) => println!("emit code to {}", file_path.to_str().unwrap())
1114 1115 1116
    }
}

qinsoon's avatar
qinsoon committed
1117
pub fn emit_context(vm: &VM) {
qinsoon's avatar
qinsoon committed
1118 1119 1120
    use std::path;