asm_backend.rs 58.2 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 compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
7
use utils::ByteSize;
8
use compiler::backend::x86_64;
9
use compiler::backend::x86_64::CodeGenerator;
qinsoon's avatar
qinsoon committed
10
use compiler::machine_code::MachineCode;
qinsoon's avatar
qinsoon committed
11
use vm::VM;
qinsoon's avatar
qinsoon committed
12
use runtime::ValueLocation;
13

qinsoon's avatar
qinsoon committed
14
use utils::vec_utils;
15
use utils::string_utils;
16 17 18
use ast::ptr::P;
use ast::ir::*;

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

struct ASMCode {
qinsoon's avatar
qinsoon committed
26
    name: MuName, 
qinsoon's avatar
qinsoon committed
27
    code: Vec<ASMInst>,
qinsoon's avatar
qinsoon committed
28 29

    blocks: HashMap<MuName, ASMBlock>
30 31
}

qinsoon's avatar
qinsoon committed
32 33 34
unsafe impl Send for ASMCode {} 
unsafe impl Sync for ASMCode {}

35
impl ASMCode {
qinsoon's avatar
qinsoon committed
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
    fn get_use_locations(&self, reg: MuID) -> Vec<ASMLocation> {
        let mut ret = vec![];

        for inst in self.code.iter() {
            match inst.uses.get(&reg) {
                Some(ref locs) => {
                    ret.append(&mut locs.to_vec());
                },
                None => {}
            }
        }

        ret
    }

    fn get_define_locations(&self, reg: MuID) -> Vec<ASMLocation> {
        let mut ret = vec![];

        for inst in self.code.iter() {
            match inst.defines.get(&reg) {
                Some(ref locs) => {
                    ret.append(&mut locs.to_vec());
                },
                None => {}
            }
        }

        ret
    }

qinsoon's avatar
qinsoon committed
66 67 68 69 70 71 72 73 74
    fn is_block_start(&self, inst: usize) -> bool {
        for block in self.blocks.values() {
            if block.start_inst == inst {
                return true;
            }
        }
        false
    }

qinsoon's avatar
qinsoon committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
    fn is_block_end(&self, inst: usize) -> bool {
        for block in self.blocks.values() {
            if block.end_inst == inst + 1 {
                return true;
            }
        }
        false
    }

    fn get_block_by_inst(&self, inst: usize) -> (&String, &ASMBlock) {
        for (name, block) in self.blocks.iter() {
            if inst >= block.start_inst && inst < block.end_inst {
                return (name, block);
            }
        }

        panic!("didnt find any block for inst {}", inst)
    }

qinsoon's avatar
qinsoon committed
94 95 96 97 98 99 100 101 102 103
    fn get_block_by_start_inst(&self, inst: usize) -> Option<&ASMBlock> {
        for block in self.blocks.values() {
            if block.start_inst == inst {
                return Some(block);
            }
        }

        None
    }

104 105 106 107 108 109 110 111
    fn rewrite_insert(
        &self,
        insert_before: HashMap<usize, Vec<Box<ASMCode>>>,
        insert_after: HashMap<usize, Vec<Box<ASMCode>>>) -> Box<ASMCode>
    {
        let mut ret = ASMCode {
            name: self.name.clone(),
            code: vec![],
qinsoon's avatar
qinsoon committed
112
            blocks: hashmap!{},
113 114 115 116
        };

        // iterate through old machine code
        let mut inst_offset = 0;    // how many instructions has been inserted
qinsoon's avatar
qinsoon committed
117
        let mut cur_block_start = usize::MAX;
118 119

        for i in 0..self.number_of_insts() {
qinsoon's avatar
qinsoon committed
120 121 122 123
            if self.is_block_start(i) {
                cur_block_start = i + inst_offset;
            }

124 125 126 127 128 129 130 131 132
            // insert code before this instruction
            if insert_before.contains_key(&i) {
                for insert in insert_before.get(&i).unwrap() {
                    ret.append_code_sequence_all(insert);
                    inst_offset += insert.number_of_insts();
                }
            }

            // copy this instruction
qinsoon's avatar
qinsoon committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
            let mut inst = self.code[i].clone();

            // this instruction has been offset by several instructions('inst_offset')
            // update its info
            // 1. fix defines and uses
            for locs in inst.defines.values_mut() {
                for loc in locs {
                    debug_assert!(loc.line == i);
                    loc.line += inst_offset;
                }
            }
            for locs in inst.uses.values_mut() {
                for loc in locs {
                    debug_assert!(loc.line == i);
                    loc.line += inst_offset;
                }
            }
qinsoon's avatar
qinsoon committed
150 151 152
            // 2. we need to delete existing preds/succs - CFA is required later
            inst.preds.clear();
            inst.succs.clear();
qinsoon's avatar
qinsoon committed
153 154
            // 3. add the inst
            ret.code.push(inst);
155 156 157 158


            // insert code after this instruction
            if insert_after.contains_key(&i) {
qinsoon's avatar
qinsoon committed
159 160 161 162 163 164 165 166
                for insert in insert_after.get(&i).unwrap() {
                    ret.append_code_sequence_all(insert);
                    inst_offset += insert.number_of_insts();
                }
            }

            if self.is_block_end(i) {
                let cur_block_end = i + inst_offset;
167

qinsoon's avatar
qinsoon committed
168 169 170 171 172 173 174 175 176 177
                // copy the block
                let (name, block) = self.get_block_by_inst(i);

                let mut new_block = block.clone();
                new_block.start_inst = cur_block_start;
                cur_block_start = usize::MAX;
                new_block.end_inst = cur_block_end;

                // add to the new code
                ret.blocks.insert(name.clone(), new_block);
178 179 180
            }
        }

qinsoon's avatar
qinsoon committed
181 182 183
        ret.control_flow_analysis();

        Box::new(ret)
184 185 186 187 188 189 190 191
    }

    fn append_code_sequence(
        &mut self,
        another: &Box<ASMCode>,
        start_inst: usize,
        n_insts: usize)
    {
qinsoon's avatar
qinsoon committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
        let base_line = self.number_of_insts();

        for i in 0..n_insts {
            let cur_line_in_self = base_line + i;
            let cur_line_from_copy = start_inst + i;

            let mut inst = another.code[cur_line_from_copy].clone();

            // fix info
            for locs in inst.defines.values_mut() {
                for loc in locs {
                    debug_assert!(loc.line == i);
                    loc.line = cur_line_in_self;
                }
            }
            for locs in inst.uses.values_mut() {
                for loc in locs {
                    debug_assert!(loc.line == i);
                    loc.line = cur_line_in_self;
                }
            }
            // ignore preds/succs

            // add to self
            self.code.push(inst);
        }
218 219 220 221 222 223
    }

    fn append_code_sequence_all(&mut self, another: &Box<ASMCode>) {
        let n_insts = another.number_of_insts();
        self.append_code_sequence(another, 0, n_insts)
    }
qinsoon's avatar
qinsoon committed
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325

    fn control_flow_analysis(&mut self) {
        const TRACE_CFA : bool = false;

        // control flow analysis
        let n_insts = self.number_of_insts();

        let ref blocks = self.blocks;
        let ref mut asm = self.code;

        let block_start = {
            let mut ret = vec![];
            for block in blocks.values() {
                ret.push(block.start_inst);
            }
            ret
        };

        for i in 0..n_insts {
            // determine predecessor - if cur is not block start, its predecessor is previous insts
            let is_block_start = block_start.contains(&i);
            if !is_block_start {
                if i > 0 {
                    if TRACE_CFA {
                        trace!("inst {}: not a block start", i);
                        trace!("inst {}: set PREDS as previous inst {}", i, i - 1);
                    }
                    asm[i].preds.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 branch = asm[i].branch.clone();
            match branch {
                ASMBranchTarget::Unconditional(ref target) => {
                    // branch to target
                    let target_n = self.blocks.get(target).unwrap().start_inst;

                    // cur inst's succ is target
                    asm[i].succs.push(target_n);

                    // target's pred is cur
                    asm[target_n].preds.push(i);

                    if TRACE_CFA {
                        trace!("inst {}: is a branch to {}", i, target);
                        trace!("inst {}: branch target index is {}", i, target_n);
                        trace!("inst {}: set SUCCS as branch target {}", i, target_n);
                        trace!("inst {}: set PREDS as branch source {}", target_n, i);
                    }
                },
                ASMBranchTarget::Conditional(ref target) => {
                    // branch to target
                    let target_n = self.blocks.get(target).unwrap().start_inst;

                    // cur insts' succ is target and next inst
                    asm[i].succs.push(target_n);

                    if TRACE_CFA {
                        trace!("inst {}: is a cond branch to {}", i, target);
                        trace!("inst {}: branch target index is {}", i, target_n);
                        trace!("inst {}: set SUCCS as branch target {}", i, target_n);
                    }

                    if i < n_insts - 1 {
                        if TRACE_CFA {
                            trace!("inst {}: set SUCCS as next inst", i + 1);
                        }
                        asm[i].succs.push(i + 1);
                    }

                    // target's pred is cur
                    asm[target_n].preds.push(i);
                    if TRACE_CFA {
                        trace!("inst {}: set PREDS as {}", target_n, i);
                    }
                },
                ASMBranchTarget::None => {
                    // not branch nor cond branch, succ is next inst
                    if TRACE_CFA {
                        trace!("inst {}: not a branch inst", i);
                    }
                    if i < n_insts - 1 {
                        if TRACE_CFA {
                            trace!("inst {}: set SUCCS as next inst {}", i, i + 1);
                        }
                        asm[i].succs.push(i + 1);
                    }
                }
            }
        }

        // a sanity check for fallthrough blocks
        for i in 0..n_insts {
            if i != 0 && asm[i].preds.len() == 0 {
                asm[i].preds.push(i - 1);
            }
        }
    }
326 327 328 329
}

use std::any::Any;

330
impl MachineCode for ASMCode {
331 332 333
    fn as_any(&self) -> &Any {
        self
    }
334 335 336
    fn number_of_insts(&self) -> usize {
        self.code.len()
    }
337
    
338 339 340 341 342 343 344 345
    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
346
    fn is_using_mem_op(&self, index: usize) -> bool {
qinsoon's avatar
qinsoon committed
347
        self.code[index].is_mem_op_used
qinsoon's avatar
qinsoon committed
348 349
    }
    
qinsoon's avatar
qinsoon committed
350
    fn get_succs(&self, index: usize) -> &Vec<usize> {
qinsoon's avatar
qinsoon committed
351
        &self.code[index].succs
qinsoon's avatar
qinsoon committed
352 353 354
    }
    
    fn get_preds(&self, index: usize) -> &Vec<usize> {
qinsoon's avatar
qinsoon committed
355
        &self.code[index].preds
qinsoon's avatar
qinsoon committed
356 357
    }
    
qinsoon's avatar
qinsoon committed
358 359
    fn get_inst_reg_uses(&self, index: usize) -> Vec<MuID> {
        self.code[index].uses.keys().map(|x| *x).collect()
360 361
    }
    
qinsoon's avatar
qinsoon committed
362 363
    fn get_inst_reg_defines(&self, index: usize) -> Vec<MuID> {
        self.code[index].defines.keys().map(|x| *x).collect()
364
    }
365
    
366
    fn replace_reg(&mut self, from: MuID, to: MuID) {
367 368 369 370
        let to_reg_tag : MuName = match backend::all_regs().get(&to) {
            Some(reg) => reg.name().unwrap(),
            None => panic!("expecting a machine register, but we are required to replace to {}", to)
        };
371
        let to_reg_string = "%".to_string() + &to_reg_tag;
qinsoon's avatar
qinsoon committed
372 373 374 375 376 377 378

        for loc in self.get_define_locations(from) {
            let ref mut inst_to_patch = self.code[loc.line];
            for i in 0..loc.len {
                // FIXME: why loop here?
                string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
            }
379
        }
380

qinsoon's avatar
qinsoon committed
381 382 383 384 385
        for loc in self.get_use_locations(from) {
            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());
            }
386 387
        }
    }
388

389
    fn replace_tmp_for_inst(&mut self, from: MuID, to: MuID, inst: usize) {
390 391 392 393 394 395 396 397
        let to_reg_string : MuName = match backend::all_regs().get(&to) {
            Some(ref machine_reg) => {
                let name = machine_reg.name().unwrap();
                "%".to_string() + &name
            },
            None => REG_PLACEHOLDER.clone()
        };

qinsoon's avatar
qinsoon committed
398 399 400 401 402 403 404 405 406
        let asm = &mut self.code[inst];
        // if this reg is defined, replace the define
        if asm.defines.contains_key(&from) {
            let define_locs = asm.defines.get(&from).unwrap().to_vec();
            // replace temps
            for loc in define_locs.iter() {
                for i in 0..loc.len {
                    string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
                }
407 408
            }

qinsoon's avatar
qinsoon committed
409 410 411
            // remove old key, insert new one
            asm.defines.remove(&from);
            asm.defines.insert(from, define_locs);
412
        }
qinsoon's avatar
qinsoon committed
413 414 415 416 417 418 419 420

        // if this reg is used, replace the use
        if asm.uses.contains_key(&from) {
            let use_locs = asm.uses.get(&from).unwrap().to_vec();
            // replace temps
            for loc in use_locs.iter() {
                for i in 0..loc.len {
                    string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
421 422 423
                }
            }

qinsoon's avatar
qinsoon committed
424 425 426
            // remove old key, insert new one
            asm.uses.remove(&from);
            asm.uses.insert(from, use_locs);
427 428
        }
    }
429
    
430 431
    fn set_inst_nop(&mut self, index: usize) {
        self.code.remove(index);
qinsoon's avatar
qinsoon committed
432
        self.code.insert(index, ASMInst::nop());
433 434
    }
    
435 436 437 438 439 440 441 442 443 444 445
    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
    }
    
446 447
    fn trace_mc(&self) {
        trace!("");
448

449 450
        trace!("code for {}: \n", self.name);
        
451 452
        let n_insts = self.code.len();
        for i in 0..n_insts {
453
            self.trace_inst(i);
454 455
        }
        
456 457 458 459 460 461
        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),
qinsoon's avatar
qinsoon committed
462
            self.code[i].preds, self.code[i].succs);
463
    }
464
    
465
    fn get_ir_block_livein(&self, block: &str) -> Option<&Vec<MuID>> {
qinsoon's avatar
qinsoon committed
466 467 468 469
        match self.blocks.get(block) {
            Some(ref block) => Some(&block.livein),
            None => None
        }
470 471
    }
    
472
    fn get_ir_block_liveout(&self, block: &str) -> Option<&Vec<MuID>> {
qinsoon's avatar
qinsoon committed
473 474 475 476
        match self.blocks.get(block) {
            Some(ref block) => Some(&block.liveout),
            None => None
        }
477 478
    }
    
479
    fn set_ir_block_livein(&mut self, block: &str, set: Vec<MuID>) {
qinsoon's avatar
qinsoon committed
480 481
        let block = self.blocks.get_mut(block).unwrap();
        block.livein = set;
482 483 484
    }
    
    fn set_ir_block_liveout(&mut self, block: &str, set: Vec<MuID>) {
qinsoon's avatar
qinsoon committed
485 486
        let block = self.blocks.get_mut(block).unwrap();
        block.liveout = set;
487 488
    }
    
qinsoon's avatar
qinsoon committed
489 490
    fn get_all_blocks(&self) -> Vec<MuName> {
        self.blocks.keys().map(|x| x.clone()).collect()
491 492
    }
    
493
    fn get_block_range(&self, block: &str) -> Option<ops::Range<usize>> {
qinsoon's avatar
qinsoon committed
494 495
        match self.blocks.get(block) {
            Some(ref block) => Some(block.start_inst..block.end_inst),
496 497 498
            None => None
        }
    }
499 500
}

qinsoon's avatar
qinsoon committed
501 502 503 504 505 506 507
#[derive(Clone, Debug)]
enum ASMBranchTarget {
    None,
    Conditional(MuName),
    Unconditional(MuName)
}

qinsoon's avatar
qinsoon committed
508
#[derive(Clone, Debug)]
qinsoon's avatar
qinsoon committed
509
struct ASMInst {
510
    code: String,
qinsoon's avatar
qinsoon committed
511 512 513 514 515 516 517 518

    defines: HashMap<MuID, Vec<ASMLocation>>,
    uses: HashMap<MuID, Vec<ASMLocation>>,

    is_mem_op_used: bool,
    preds: Vec<usize>,
    succs: Vec<usize>,
    branch: ASMBranchTarget
519 520
}

qinsoon's avatar
qinsoon committed
521 522 523
impl ASMInst {
    fn symbolic(line: String) -> ASMInst {
        ASMInst {
524
            code: line,
qinsoon's avatar
qinsoon committed
525 526 527 528 529 530
            defines: HashMap::new(),
            uses: HashMap::new(),
            is_mem_op_used: false,
            preds: vec![],
            succs: vec![],
            branch: ASMBranchTarget::None
531 532 533
        }
    }
    
qinsoon's avatar
qinsoon committed
534 535 536 537 538 539 540 541 542
    fn inst(
        inst: String,
        defines: HashMap<MuID, Vec<ASMLocation>>,
        uses: HashMap<MuID, Vec<ASMLocation>>,
        is_mem_op_used: bool,
        target: ASMBranchTarget
    ) -> ASMInst
    {
        ASMInst {
543 544
            code: inst,
            defines: defines,
qinsoon's avatar
qinsoon committed
545 546 547 548 549
            uses: uses,
            is_mem_op_used: is_mem_op_used,
            preds: vec![],
            succs: vec![],
            branch: target
550 551
        }
    }
552
    
qinsoon's avatar
qinsoon committed
553 554
    fn nop() -> ASMInst {
        ASMInst {
555
            code: "".to_string(),
qinsoon's avatar
qinsoon committed
556 557 558 559 560 561
            defines: HashMap::new(),
            uses: HashMap::new(),
            is_mem_op_used: false,
            preds: vec![],
            succs: vec![],
            branch: ASMBranchTarget::None
562 563
        }
    }
564 565
}

566
#[derive(Clone, Debug)]
567 568 569 570 571 572 573
struct ASMLocation {
    line: usize,
    index: usize,
    len: usize
}

impl ASMLocation {
qinsoon's avatar
qinsoon committed
574
    fn new(line: usize, index: usize, len: usize) -> ASMLocation {
575
        ASMLocation{
qinsoon's avatar
qinsoon committed
576
            line: line,
577 578 579 580 581 582
            index: index,
            len: len
        }
    }
}

qinsoon's avatar
qinsoon committed
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
#[derive(Clone, Debug)]
/// [start_inst, end_inst)
struct ASMBlock {
    start_inst: usize,
    end_inst: usize,

    livein: Vec<MuID>,
    liveout: Vec<MuID>
}

impl ASMBlock {
    fn new() -> ASMBlock {
        ASMBlock {
            start_inst: usize::MAX,
            end_inst: usize::MAX,
            livein: vec![],
            liveout: vec![]
        }
    }
}

604
pub struct ASMCodeGen {
605
    cur: Option<Box<ASMCode>>
606 607
}

608
const REG_PLACEHOLDER_LEN : usize = 5;
609 610 611 612 613 614
lazy_static! {
    pub static ref REG_PLACEHOLDER : String = {
        let blank_spaces = [' ' as u8; REG_PLACEHOLDER_LEN];
        
        format!("%{}", str::from_utf8(&blank_spaces).unwrap())
    };
615 616 617 618
}

impl ASMCodeGen {
    pub fn new() -> ASMCodeGen {
619
        ASMCodeGen {
620
            cur: None
621 622 623 624 625 626 627 628 629 630 631
        }
    }
    
    fn cur(&self) -> &ASMCode {
        self.cur.as_ref().unwrap()
    }
    
    fn cur_mut(&mut self) -> &mut ASMCode {
        self.cur.as_mut().unwrap()
    }
    
632 633 634 635
    fn line(&self) -> usize {
        self.cur().code.len()
    }
    
636 637
    fn add_asm_label(&mut self, code: String) {
        let l = self.line();
qinsoon's avatar
qinsoon committed
638
        self.cur_mut().code.push(ASMInst::symbolic(code));
639 640
    }
    
641
    fn add_asm_block_label(&mut self, code: String, block_name: MuName) {
642
        let l = self.line();
qinsoon's avatar
qinsoon committed
643
        self.cur_mut().code.push(ASMInst::symbolic(code));
644 645
    }
    
646
    fn add_asm_symbolic(&mut self, code: String){
qinsoon's avatar
qinsoon committed
647
        self.cur_mut().code.push(ASMInst::symbolic(code));
648 649
    }
    
650 651
    fn prepare_machine_regs(&self, regs: Iter<P<Value>>) -> Vec<MuID> {
        regs.map(|x| self.prepare_machine_reg(x)).collect()
qinsoon's avatar
qinsoon committed
652
    }
653
    
654
    fn add_asm_call(&mut self, code: String) {
qinsoon's avatar
qinsoon committed
655
        // a call instruction will use all the argument registers
qinsoon's avatar
qinsoon committed
656 657 658 659 660 661 662
        let mut uses : HashMap<MuID, Vec<ASMLocation>> = HashMap::new();
        for reg in x86_64::ARGUMENT_GPRs.iter() {
            uses.insert(reg.id(), vec![]);
        }
        for reg in x86_64::ARGUMENT_FPRs.iter() {
            uses.insert(reg.id(), vec![]);
        }
qinsoon's avatar
qinsoon committed
663 664

        // defines: return registers
qinsoon's avatar
qinsoon committed
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
        let mut defines : HashMap<MuID, Vec<ASMLocation>> = HashMap::new();
        for reg in x86_64::RETURN_GPRs.iter() {
            defines.insert(reg.id(), vec![]);
        }
        for reg in x86_64::RETURN_FPRs.iter() {
            defines.insert(reg.id(), vec![]);
        }
        for reg in x86_64::CALLER_SAVED_GPRs.iter() {
            if !defines.contains_key(&reg.id()) {
                defines.insert(reg.id(), vec![]);
            }
        }
        for reg in x86_64::CALLER_SAVED_FPRs.iter() {
            if !defines.contains_key(&reg.id()) {
                defines.insert(reg.id(), vec![]);
            }
        }
682
          
qinsoon's avatar
qinsoon committed
683
        self.add_asm_inst(code, defines, uses, false);
684 685 686
    }
    
    fn add_asm_ret(&mut self, code: String) {
qinsoon's avatar
qinsoon committed
687
        let uses : HashMap<MuID, Vec<ASMLocation>> = {
qinsoon's avatar
qinsoon committed
688 689 690 691 692 693 694 695 696
            let mut ret = HashMap::new();
            for reg in x86_64::RETURN_GPRs.iter() {
                ret.insert(reg.id(), vec![]);
            }
            for reg in x86_64::RETURN_FPRs.iter() {
                ret.insert(reg.id(), vec![]);
            }
            ret
        };
697
        
qinsoon's avatar
qinsoon committed
698
        self.add_asm_inst(code, hashmap!{}, uses, false);
699 700
    }
    
701
    fn add_asm_branch(&mut self, code: String, target: MuName) {
qinsoon's avatar
qinsoon committed
702
        self.add_asm_inst_internal(code, hashmap!{}, hashmap!{}, false, ASMBranchTarget::Unconditional(target));
703 704
    }
    
705
    fn add_asm_branch2(&mut self, code: String, target: MuName) {
qinsoon's avatar
qinsoon committed
706
        self.add_asm_inst_internal(code, hashmap!{}, hashmap!{}, false, ASMBranchTarget::Conditional(target));
707 708 709 710 711
    }
    
    fn add_asm_inst(
        &mut self, 
        code: String, 
qinsoon's avatar
qinsoon committed
712 713 714 715 716 717 718 719 720 721 722 723 724 725
        defines: HashMap<MuID, Vec<ASMLocation>>,
        uses: HashMap<MuID, Vec<ASMLocation>>,
        is_using_mem_op: bool)
    {
        self.add_asm_inst_internal(code, defines, uses, is_using_mem_op, ASMBranchTarget::None)
    }

    fn add_asm_inst_internal(
        &mut self,
        code: String,
        defines: HashMap<MuID, Vec<ASMLocation>>,
        uses: HashMap<MuID, Vec<ASMLocation>>,
        is_using_mem_op: bool,
        target: ASMBranchTarget)
726
    {
727 728
        let line = self.line();
        trace!("asm: {}", code);
qinsoon's avatar
qinsoon committed
729 730
        trace!("     defines: {:?}", defines);
        trace!("     uses: {:?}", uses);
731
        let mc = self.cur_mut();
qinsoon's avatar
qinsoon committed
732

733
        // put the instruction
qinsoon's avatar
qinsoon committed
734
        mc.code.push(ASMInst::inst(code, defines, uses, is_using_mem_op, target));
735 736
    }
    
737
    fn prepare_reg(&self, op: &P<Value>, loc: usize) -> (String, MuID, ASMLocation) {
738 739 740 741 742 743 744
        if cfg!(debug_assertions) {
            match op.v {
                Value_::SSAVar(_) => {},
                _ => panic!("expecting register op")
            }
        }
        
745 746
        let str = self.asm_reg_op(op);
        let len = str.len();
qinsoon's avatar
qinsoon committed
747
        (str, op.extract_ssa_id().unwrap(), ASMLocation::new(self.line(), loc, len))
748 749 750
    }
    
    fn prepare_machine_reg(&self, op: &P<Value>) -> MuID {
751 752 753 754 755 756 757
        if cfg!(debug_assertions) {
            match op.v {
                Value_::SSAVar(_) => {},
                _ => panic!("expecting machine register op")
            }
        }        
        
758
        op.extract_ssa_id().unwrap()
759
    }
760
    
761
    #[allow(unused_assignments)]
qinsoon's avatar
qinsoon committed
762
    fn prepare_mem(&self, op: &P<Value>, loc: usize) -> (String, HashMap<MuID, Vec<ASMLocation>>) {
763 764 765 766 767 768
        if cfg!(debug_assertions) {
            match op.v {
                Value_::Memory(_) => {},
                _ => panic!("expecting register op")
            }
        }        
qinsoon's avatar
qinsoon committed
769

770 771 772 773
        let mut ids : Vec<MuID> = vec![];
        let mut locs : Vec<ASMLocation> = vec![];
        let mut result_str : String = "".to_string();
        
774
        let mut loc_cursor : usize = loc;
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
        
        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)) => {
qinsoon's avatar
qinsoon committed
795
                            let str = (val as i32).to_string();
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
                            
                            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)) => {
qinsoon's avatar
qinsoon committed
833
                            let str = (val as i32).to_string();
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
                            
                            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;
            },
857 858
            Value_::Memory(MemoryLocation::Symbolic{ref base, ref label}) => {
                result_str.push_str(&symbol(label.clone()));
859 860 861 862 863 864 865 866 867 868 869
                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();
qinsoon's avatar
qinsoon committed
870

871
                    result_str.push(')');
qinsoon's avatar
qinsoon committed
872
                    loc_cursor += 1;
873 874 875 876
                }
            },
            _ => panic!("expect mem location as value")
        }
qinsoon's avatar
qinsoon committed
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894

        let uses : HashMap<MuID, Vec<ASMLocation>> = {
            let mut map : HashMap<MuID, Vec<ASMLocation>> = hashmap!{};
            for i in 0..ids.len() {
                let id = ids[i];
                let loc = locs[i].clone();

                if map.contains_key(&id) {
                    map.get_mut(&id).unwrap().push(loc);
                } else {
                    map.insert(id, vec![loc]);
                }
            }
            map
        };


        (result_str, uses)
895 896
    }
    
897 898
    fn asm_reg_op(&self, op: &P<Value>) -> String {
        let id = op.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
899
        if id < MACHINE_ID_END {
900
            // machine reg
901
            format!("%{}", op.name().unwrap())
902 903 904 905 906 907
        } else {
            // virtual register, use place holder
            REG_PLACEHOLDER.clone()
        }
    }
    
qinsoon's avatar
qinsoon committed
908
    fn asm_block_label(&self, label: MuName) -> String {
909
        symbol(format!("{}_{}", self.cur().name, label))
910
    }
911 912 913 914
    
    fn control_flow_analysis(&mut self) {
        // control flow analysis
        let n_insts = self.line();
qinsoon's avatar
qinsoon committed
915

916
        let code = self.cur_mut();
qinsoon's avatar
qinsoon committed
917
        let ref blocks = code.blocks;
qinsoon's avatar
qinsoon committed
918
        let ref mut asm = code.code;
qinsoon's avatar
qinsoon committed
919 920 921 922 923 924 925 926

        let block_start = {
            let mut ret = vec![];
            for block in blocks.values() {
                ret.push(block.start_inst);
            }
            ret
        };
927 928 929
        
        for i in 0..n_insts {
            // determine predecessor - if cur is not block start, its predecessor is previous insts
qinsoon's avatar
qinsoon committed
930 931
            let is_block_start = block_start.contains(&i);
            if !is_block_start {
932
                if i > 0 {
933 934
                    trace!("inst {}: not a block start", i);
                    trace!("inst {}: set PREDS as previous inst {}", i, i-1);
qinsoon's avatar
qinsoon committed
935
                    asm[i].preds.push(i - 1);
936 937 938 939 940 941 942
                }
            } 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
qinsoon's avatar
qinsoon committed
943 944 945 946 947 948
            let branch = asm[i].branch.clone();
            match branch {
                ASMBranchTarget::Unconditional(ref target) => {
                    // branch to target
                    trace!("inst {}: is a branch to {}", i, target);

qinsoon's avatar
qinsoon committed
949
                    let target_n = code.blocks.get(target).unwrap().start_inst;
qinsoon's avatar
qinsoon committed
950 951 952 953
                    trace!("inst {}: branch target index is {}", i, target_n);

                    // cur inst's succ is target
                    trace!("inst {}: set SUCCS as branch target {}", i, target_n);
qinsoon's avatar
qinsoon committed
954
                    asm[i].succs.push(target_n);
qinsoon's avatar
qinsoon committed
955 956 957

                    // target's pred is cur
                    trace!("inst {}: set PREDS as branch source {}", target_n, i);
qinsoon's avatar
qinsoon committed
958
                    asm[target_n].preds.push(i);
qinsoon's avatar
qinsoon committed
959 960
                },
                ASMBranchTarget::Conditional(ref target) => {
961
                    // branch to target
962
                    trace!("inst {}: is a cond branch to {}", i, target);
qinsoon's avatar
qinsoon committed
963

qinsoon's avatar
qinsoon committed
964
                    let target_n = code.blocks.get(target).unwrap().start_inst;
965
                    trace!("inst {}: branch target index is {}", i, target_n);
qinsoon's avatar
qinsoon committed
966

967
                    // cur insts' succ is target and next inst
qinsoon's avatar
qinsoon committed
968
                    asm[i].succs.push(target_n);
969
                    trace!("inst {}: set SUCCS as branch target {}", i, target_n);
970
                    if i < n_insts - 1 {
qinsoon's avatar
qinsoon committed
971 972
                        trace!("inst {}: set SUCCS as next inst", i + 1);
                        asm[i].succs.push(i + 1);
973
                    }
qinsoon's avatar
qinsoon committed
974

975
                    // target's pred is cur
qinsoon's avatar
qinsoon committed
976 977
                    asm[target_n].preds.push(i);
                    trace!("inst {}: set PREDS as {}", target_n, i);
qinsoon's avatar
qinsoon committed
978 979
                },
                ASMBranchTarget::None => {
980
                    // not branch nor cond branch, succ is next inst
981
                    trace!("inst {}: not a branch inst", i);
982
                    if i < n_insts - 1 {
983
                        trace!("inst {}: set SUCCS as next inst {}", i, i + 1);
qinsoon's avatar
qinsoon committed
984
                        asm[i].succs.push(i + 1);
985 986
                    }
                }
qinsoon's avatar
qinsoon committed
987
            }
988 989 990 991
        }
        
        // a sanity check for fallthrough blocks
        for i in 0..n_insts {
qinsoon's avatar
qinsoon committed
992 993
            if i != 0 && asm[i].preds.len() == 0 {
                asm[i].preds.push(i - 1);
994 995 996
            }
        }        
    }
997 998 999 1000

    fn finish_code_sequence_asm(&mut self) -> Box<ASMCode> {
        self.cur.take().unwrap()
    }
1001 1002 1003
}

impl CodeGenerator for ASMCodeGen {
qinsoon's avatar
qinsoon committed
1004
    fn start_code(&mut self, func_name: MuName) -> ValueLocation {
1005
        self.cur = Some(Box::new(ASMCode {
1006
                name: func_name.clone(),
1007
                code: vec![],
qinsoon's avatar
qinsoon committed
1008
                blocks: hashmap!{},
1009
            }));
1010
        
qinsoon's avatar
qinsoon committed
1011
        // to link with C sources via gcc
qinsoon's avatar
qinsoon committed
1012 1013 1014 1015
        let func_symbol = symbol(func_name.clone());
        self.add_asm_symbolic(directive_globl(func_symbol.clone()));
        self.add_asm_symbolic(format!("{}:", func_symbol.clone()));
        
1016
        ValueLocation::Relocatable(RegGroup::GPR, func_name)
1017 1018
    }
    
1019
    fn finish_code(&mut self, func_name: MuName) -> (Box<MachineCode + Sync + Send>, ValueLocation) {
1020 1021
        let func_end = {
            let mut symbol = func_name.clone();
qinsoon's avatar
qinsoon committed
1022 1023 1024
            symbol.push_str("_end");
            symbol
        };
1025 1026
        self.add_asm_symbolic(directive_globl(symbol(func_end.clone())));
        self.add_asm_symbolic(format!("{}:", symbol(func_end.clone())));
qinsoon's avatar
qinsoon committed
1027
        
1028
        self.control_flow_analysis();
qinsoon's avatar
qinsoon committed
1029 1030 1031
        
        (
            self.cur.take().unwrap(),
1032
            ValueLocation::Relocatable(RegGroup::GPR, func_end)
qinsoon's avatar
qinsoon committed
1033
        )
1034
    }
1035 1036 1037 1038 1039

    fn start_code_sequence(&mut self) {
        self.cur = Some(Box::new(ASMCode {
            name: "snippet".to_string(),
            code: vec![],
qinsoon's avatar
qinsoon committed
1040
            blocks: hashmap!{}
1041 1042 1043 1044
        }));
    }

    fn finish_code_sequence(&mut self) -> Box<MachineCode + Sync + Send> {
1045
        self.finish_code_sequence_asm()
1046 1047
    }

1048 1049 1050 1051 1052 1053 1054
    fn print_cur_code(&self) {
        println!("");
        
        if self.cur.is_some() {
            let code = self.cur.as_ref().unwrap();
            
            println!("code for {}: ", code.name);
1055 1056 1057 1058
            let n_insts = code.code.len();
            for i in 0..n_insts {
                let ref line = code.code[i];
                println!("#{}\t{}", i, line.code);
1059 1060 1061 1062 1063 1064 1065 1066
            }
        } else {
            println!("no current code");
        }
        
        println!("");
    }
    
qinsoon's avatar
qinsoon committed
1067
    fn start_block(&mut self, block_name: MuName) {
1068 1069
        let label = format!("{}:", self.asm_block_label(block_name.clone()));        
        self.add_asm_block_label(label, block_name.clone());
qinsoon's avatar
qinsoon committed
1070 1071

        self.cur_mut().blocks.insert(block_name.clone(), ASMBlock::new());
1072
        let start = self.line();
qinsoon's avatar
qinsoon committed
1073
        self.cur_mut().blocks.get_mut(&block_name).unwrap().start_inst = start;
1074 1075
    }
    
qinsoon's avatar
qinsoon committed
1076
    fn start_exception_block(&mut self, block_name: MuName) -> ValueLocation {
1077 1078 1079
        let block = self.asm_block_label(block_name.clone());
        self.add_asm_symbolic(directive_globl(symbol(block.clone())));
        self.add_asm_symbolic(format!("{}:", symbol(block.clone())));
qinsoon's avatar
qinsoon committed
1080 1081 1082
        
        self.start_block(block_name);
        
1083
        ValueLocation::Relocatable(RegGroup::GPR, block)
qinsoon's avatar
qinsoon committed
1084 1085
    }
    
qinsoon's avatar
qinsoon committed
1086
    fn end_block(&mut self, block_name: MuName) {
qinsoon's avatar
qinsoon committed
1087 1088 1089 1090 1091 1092 1093
        let line = self.line();
        match self.cur_mut().blocks.get_mut(&block_name) {
            Some(ref mut block) => {
                block.end_inst = line;
            }
            None => panic!("trying to end block {} which hasnt been started", block_name)
        }
1094 1095
    }
    
qinsoon's avatar
qinsoon committed
1096
    fn set_block_livein(&mut self, block_name: MuName, live_in: &Vec<P<Value>>) {
1097
        let cur = self.cur_mut();
qinsoon's avatar
qinsoon committed
1098 1099 1100 1101 1102 1103 1104 1105 1106

        match cur.blocks.get_mut(&block_name) {
            Some(ref mut block) => {
                if block.livein.is_empty() {
                    let mut live_in = {
                        let mut ret = vec![];
                        for p in live_in {
                            match p.extract_ssa_id() {
                                Some(id) => ret.push(id),
qinsoon's avatar
qinsoon committed
1107 1108
                                // this should not happen
                                None => error!("{} as live-in of block {} is not SSA", p, block_name)
qinsoon's avatar
qinsoon committed
1109 1110 1111 1112 1113 1114 1115 1116
                            }
                        }
                        ret
                    };
                    block.livein.append(&mut live_in);
                } else {
                    panic!("seems we are inserting livein to block {} twice", block_name);
                }
1117
            }
qinsoon's avatar
qinsoon committed
1118
            None => panic!("haven't created ASMBlock for {}", block_name)
1119 1120 1121
        }
    }
    
qinsoon's avatar
qinsoon committed
1122
    fn set_block_liveout(&mut self, block_name: MuName, live_out: &Vec<P<Value>>) {
1123
        let cur = self.cur_mut();
qinsoon's avatar
qinsoon committed
1124 1125 1126 1127 1128 1129 1130 1131 1132

        match cur.blocks.get_mut(&block_name) {
            Some(ref mut block) => {
                if block.liveout.is_empty() {
                    let mut live_out = {
                        let mut ret = vec![];
                        for p in live_out {
                            match p.extract_ssa_id() {
                                Some(id) => ret.push(id),
qinsoon's avatar
qinsoon committed
1133 1134 1135
                                // the liveout are actually args out of this block
                                // (they can be constants)
                                None => trace!("{} as live-out of block {} is not SSA", p, block_name)
qinsoon's avatar
qinsoon committed
1136 1137 1138 1139 1140 1141 1142 1143
                            }
                        }
                        ret
                    };
                    block.liveout.append(&mut live_out);
                } else {
                    panic!("seems we are inserting liveout to block {} twice", block_name);
                }
1144
            }
qinsoon's avatar
qinsoon committed
1145 1146
            None => panic!("haven't created ASMBlock for {}", block_name)
        }
1147 1148
    }
    
1149 1150 1151 1152 1153 1154 1155
    fn emit_nop(&mut self, bytes: usize) {
        trace!("emit: nop ({} bytes)", bytes);
        
        let asm = String::from("nop");
        
        self.add_asm_inst(
            asm,
qinsoon's avatar
qinsoon committed
1156 1157
            hashmap!{},
            hashmap!{},
1158 1159 1160 1161
            false
        );
    }
    
1162
    fn emit_cmp_r64_r64(&mut self, op1: &P<Value>, op2: &P<Value>) {
qinsoon's avatar
qinsoon committed
1163
        trace!("emit: cmp {} {}", op1, op2);
1164
        
1165 1166
        let (reg1, id1, loc1) = self.prepare_reg(op1, 4 + 1);
        let (reg2, id2, loc2) = self.prepare_reg(op2, 4 + 1 + reg1.len() + 1);
1167
        
qinsoon's avatar
qinsoon committed
1168
        let asm = format!("cmpq {},{}", reg1, reg2);
1169
        
1170 1171
        self.add_asm_inst(
            asm,
qinsoon's avatar
qinsoon committed
1172 1173 1174 1175 1176
            hashmap!{},
            hashmap!{
                id1 => vec![loc1],
                id2 => vec![loc2]
            },
qinsoon's avatar
qinsoon committed
1177
            false
1178
        );
1179 1180
    }
    
1181
    fn emit_cmp_r64_imm32(&mut self, op1: &P<Value>, op2: i32) {
qinsoon's avatar
qinsoon committed
1182
        trace!("emit: cmp {} {}", op1, op2);
1183
        
1184
        let (reg1, id1, loc1) = self.prepare_reg(op1, 4 + 1 + 1 + op2.to_string().len() + 1);
1185
        
qinsoon's avatar
qinsoon committed
1186
        let asm = format!("cmpq ${},{}", op2, reg1);
1187
        
1188 1189
        self.add_asm_inst(
            asm,
qinsoon's avatar
qinsoon committed
1190 1191 1192 1193
            hashmap!{},
            hashmap!{
                id1 => vec![loc1]
            },
qinsoon's avatar
qinsoon committed
1194
            false
1195
        )
1196 1197 1198
    }
    
    fn emit_cmp_r64_mem64(&mut self, op1: &P<Value>, op2: &P<Value>) {
qinsoon's avatar
qinsoon committed
1199
        trace!("emit: cmp {} {}", op1, op2);
1200 1201
        
        let (reg, id1, loc1) = self.prepare_reg(op1, 4 + 1);
qinsoon's avatar
qinsoon committed
1202
        let (mem, mut uses) = self.prepare_mem(op2, 4 + 1 + reg.len() + 1);
1203 1204 1205 1206
        
        let asm = format!("cmpq {},{}", reg, mem);
        
        // merge use vec
qinsoon's avatar
qinsoon committed
1207 1208 1209 1210 1211
        if uses.contains_key(&id1) {
            uses.get_mut(&id1).unwrap().push(loc1);
        } else {
            uses.insert(id1, vec![loc1]);
        }
1212 1213 1214
        
        self.add_asm_inst(
            asm,
qinsoon's avatar
qinsoon committed
1215 1216
            hashmap!{},
            uses,
1217 1218
            true
        )
1219 1220
    }
    
1221
    fn emit_mov_r64_imm32(&mut self, dest: &P<Value>, src: i32) {
qinsoon's avatar
qinsoon committed
1222
        trace!("emit: mov {} -> {}", src, dest);
1223
        
1224
        let (reg1, id1, loc1) = self.prepare_reg(dest, 4 + 1 + 1 + src.to_string().len() + 1);
1225
        
qinsoon's avatar
qinsoon committed
1226
        let asm = format!("movq ${},{}", src, reg1);
1227
        
1228 1229
        self.add_asm_inst(
            asm,
qinsoon's avatar
qinsoon committed
1230 1231 1232 1233
            hashmap!{
                id1 => vec![loc1]
            },
            hashmap!{},
qinsoon's avatar
qinsoon committed
1234
            false
1235
        )
1236 1237
    }
    
1238
    // load
1239
    fn emit_mov_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
qinsoon's avatar
qinsoon committed
1240
        trace!("emit: mov {} -> {}", src, dest);
1241
        
qinsoon's avatar
qinsoon committed
1242
        let (mem, uses) = self.prepare_mem(src, 4 + 1);
1243 1244 1245 1246 1247 1248
        let (reg, id2, loc2) = self.prepare_reg(dest, 4 + 1 + mem.len() + 1);
        
        let asm = format!("movq {},{}", mem, reg);
        
        self.add_asm_inst(
            asm,
qinsoon's avatar
qinsoon committed
1249 1250 1251 1252
            hashmap!{
                id2 => vec![loc2]
            },
            uses,
qinsoon's avatar
qinsoon committed
1253
            true
1254 1255 1256
        )
    }
    
1257
    // store
1258 1259 1260 1261
    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);
qinsoon's avatar
qinsoon committed
1262
        let (mem, mut uses) = self.prepare_mem(dest, 4 + 1 + reg.len() + 1);
1263 1264
        
        // the register we used for the memory location is counted as 'use'
1265
        // use the vec from mem as 'use' (push use reg from src to it)
qinsoon's avatar
qinsoon committed
1266 1267 1268 1269 1270
        if uses.contains_key(&id1) {
            uses.get_mut(&id1).unwrap().push(loc1);
        } else {