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

3
use compiler::backend::AOT_EMIT_CONTEXT_FILE;
qinsoon's avatar
qinsoon committed
4
use compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
5
use utils::ByteSize;
6
use compiler::backend::x86_64;
7
use compiler::backend::x86_64::CodeGenerator;
qinsoon's avatar
qinsoon committed
8
use compiler::backend::{Reg, Mem};
qinsoon's avatar
qinsoon committed
9
use compiler::backend::x86_64::check_op_len;
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

qinsoon's avatar
qinsoon committed
29 30 31
    blocks: HashMap<MuName, ASMBlock>,

    frame_size_patchpoints: Vec<ASMLocation>
32 33
}

qinsoon's avatar
qinsoon committed
34 35 36
unsafe impl Send for ASMCode {} 
unsafe impl Sync for ASMCode {}

37
impl ASMCode {
qinsoon's avatar
qinsoon committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
    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
68 69 70 71 72 73 74 75 76
    fn is_block_start(&self, inst: usize) -> bool {
        for block in self.blocks.values() {
            if block.start_inst == inst {
                return true;
            }
        }
        false
    }

77
    fn is_last_inst_in_block(&self, inst: usize) -> bool {
qinsoon's avatar
qinsoon committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
        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
96 97 98 99 100 101 102 103 104 105
    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
    }

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

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

qinsoon's avatar
qinsoon committed
123 124 125 126
        // inst N in old machine code is N' in new machine code
        // this map stores the relationship
        let mut location_map : HashMap<usize, usize> = HashMap::new();

127
        for i in 0..self.number_of_insts() {
128 129
            trace!("Inst{}", i);

qinsoon's avatar
qinsoon committed
130 131
            if self.is_block_start(i) {
                cur_block_start = i + inst_offset;
132
                trace!("  block start is shifted to {}", cur_block_start);
qinsoon's avatar
qinsoon committed
133 134
            }

135 136 137 138 139
            // 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();
140
                    trace!("  inserted {} insts before", insert.number_of_insts());
141 142 143 144
                }
            }

            // copy this instruction
qinsoon's avatar
qinsoon committed
145 146
            let mut inst = self.code[i].clone();

qinsoon's avatar
qinsoon committed
147 148
            // old ith inst is now the (i + inst_offset)th instruction
            location_map.insert(i, i + inst_offset);
149
            trace!("  Inst{} is now Inst{}", i, i + inst_offset);
qinsoon's avatar
qinsoon committed
150

qinsoon's avatar
qinsoon committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
            // 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
166 167 168
            // 2. we need to delete existing preds/succs - CFA is required later
            inst.preds.clear();
            inst.succs.clear();
qinsoon's avatar
qinsoon committed
169 170
            // 3. add the inst
            ret.code.push(inst);
171 172 173 174


            // insert code after this instruction
            if insert_after.contains_key(&i) {
qinsoon's avatar
qinsoon committed
175 176 177
                for insert in insert_after.get(&i).unwrap() {
                    ret.append_code_sequence_all(insert);
                    inst_offset += insert.number_of_insts();
178
                    trace!("  inserted {} insts after", insert.number_of_insts());
qinsoon's avatar
qinsoon committed
179 180 181
                }
            }

182 183
            if self.is_last_inst_in_block(i) {
                let cur_block_end = i + 1 + inst_offset;
184

qinsoon's avatar
qinsoon committed
185 186 187
                // copy the block
                let (name, block) = self.get_block_by_inst(i);

qinsoon's avatar
qinsoon committed
188
                let new_block = ASMBlock{
189 190 191 192 193 194 195 196 197 198
                    start_inst: cur_block_start,
                    end_inst: cur_block_end,

                    livein: vec![],
                    liveout: vec![]
                };

                trace!("  old block: {:?}", block);
                trace!("  new block: {:?}", new_block);

qinsoon's avatar
qinsoon committed
199 200 201 202
                cur_block_start = usize::MAX;

                // add to the new code
                ret.blocks.insert(name.clone(), new_block);
203 204 205
            }
        }

qinsoon's avatar
qinsoon committed
206 207 208 209 210
        // fix patchpoint
        for patchpoint in self.frame_size_patchpoints.iter() {
            let new_patchpoint = ASMLocation {
                line: *location_map.get(&patchpoint.line).unwrap(),
                index: patchpoint.index,
qinsoon's avatar
qinsoon committed
211 212
                len: patchpoint.len,
                oplen: patchpoint.oplen
qinsoon's avatar
qinsoon committed
213 214 215 216 217
            };

            ret.frame_size_patchpoints.push(new_patchpoint);
        }

qinsoon's avatar
qinsoon committed
218 219 220
        ret.control_flow_analysis();

        Box::new(ret)
221 222 223 224 225 226 227 228
    }

    fn append_code_sequence(
        &mut self,
        another: &Box<ASMCode>,
        start_inst: usize,
        n_insts: usize)
    {
qinsoon's avatar
qinsoon committed
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
        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);
        }
255 256 257 258 259 260
    }

    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
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 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362

    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);
            }
        }
    }
qinsoon's avatar
qinsoon committed
363 364 365 366

    fn add_frame_size_patchpoint(&mut self, patchpoint: ASMLocation) {
        self.frame_size_patchpoints.push(patchpoint);
    }
367 368 369 370
}

use std::any::Any;

371
impl MachineCode for ASMCode {
372 373 374
    fn as_any(&self) -> &Any {
        self
    }
375 376 377
    fn number_of_insts(&self) -> usize {
        self.code.len()
    }
378
    
379 380 381
    fn is_move(&self, index: usize) -> bool {
        let inst = self.code.get(index);
        match inst {
qinsoon's avatar
qinsoon committed
382 383
            Some(inst) => inst.code.starts_with("mov")
                && !(inst.code.starts_with("movs") || inst.code.starts_with("movz")),
384 385 386 387
            None => false
        }
    }
    
qinsoon's avatar
qinsoon committed
388
    fn is_using_mem_op(&self, index: usize) -> bool {
qinsoon's avatar
qinsoon committed
389
        self.code[index].is_mem_op_used
qinsoon's avatar
qinsoon committed
390 391
    }
    
qinsoon's avatar
qinsoon committed
392
    fn get_succs(&self, index: usize) -> &Vec<usize> {
qinsoon's avatar
qinsoon committed
393
        &self.code[index].succs
qinsoon's avatar
qinsoon committed
394 395 396
    }
    
    fn get_preds(&self, index: usize) -> &Vec<usize> {
qinsoon's avatar
qinsoon committed
397
        &self.code[index].preds
qinsoon's avatar
qinsoon committed
398 399
    }
    
qinsoon's avatar
qinsoon committed
400 401
    fn get_inst_reg_uses(&self, index: usize) -> Vec<MuID> {
        self.code[index].uses.keys().map(|x| *x).collect()
402 403
    }
    
qinsoon's avatar
qinsoon committed
404 405
    fn get_inst_reg_defines(&self, index: usize) -> Vec<MuID> {
        self.code[index].defines.keys().map(|x| *x).collect()
406
    }
407
    
408
    fn replace_reg(&mut self, from: MuID, to: MuID) {
qinsoon's avatar
qinsoon committed
409 410
        for loc in self.get_define_locations(from) {
            let ref mut inst_to_patch = self.code[loc.line];
qinsoon's avatar
qinsoon committed
411 412 413 414 415 416 417

            // pick the right reg based on length
            let to_reg = x86_64::get_alias_for_length(to, loc.oplen);
            let to_reg_tag = to_reg.name().unwrap();
            let to_reg_string = "%".to_string() + &to_reg_tag;

            string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
418
        }
419

qinsoon's avatar
qinsoon committed
420 421
        for loc in self.get_use_locations(from) {
            let ref mut inst_to_patch = self.code[loc.line];
qinsoon's avatar
qinsoon committed
422 423 424 425 426 427 428

            // pick the right reg based on length
            let to_reg = x86_64::get_alias_for_length(to, loc.oplen);
            let to_reg_tag = to_reg.name().unwrap();
            let to_reg_string = "%".to_string() + &to_reg_tag;

            string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
429 430
        }
    }
431

432
    fn replace_define_tmp_for_inst(&mut self, from: MuID, to: MuID, inst: usize) {
qinsoon's avatar
qinsoon committed
433
        let to_reg_string : MuName = REG_PLACEHOLDER.clone();
434

qinsoon's avatar
qinsoon committed
435 436 437 438 439 440
        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() {
qinsoon's avatar
qinsoon committed
441
                string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
442 443
            }

qinsoon's avatar
qinsoon committed
444 445
            // remove old key, insert new one
            asm.defines.remove(&from);
446
            asm.defines.insert(to, define_locs);
447
        }
448 449 450
    }

    fn replace_use_tmp_for_inst(&mut self, from: MuID, to: MuID, inst: usize) {
qinsoon's avatar
qinsoon committed
451
        let to_reg_string : MuName = REG_PLACEHOLDER.clone();
452 453

        let asm = &mut self.code[inst];
qinsoon's avatar
qinsoon committed
454 455 456 457 458 459

        // 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() {
qinsoon's avatar
qinsoon committed
460
                string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
461 462
            }

qinsoon's avatar
qinsoon committed
463 464
            // remove old key, insert new one
            asm.uses.remove(&from);
465
            asm.uses.insert(to, use_locs);
466 467
        }
    }
468
    
469 470
    fn set_inst_nop(&mut self, index: usize) {
        self.code.remove(index);
qinsoon's avatar
qinsoon committed
471
        self.code.insert(index, ASMInst::nop());
472
    }
qinsoon's avatar
qinsoon committed
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522

    fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> Vec<MuID> {
        // we always save rbp
        let rbp = x86_64::RBP.extract_ssa_id().unwrap();
        // every push/pop will use/define rsp
        let rsp = x86_64::RSP.extract_ssa_id().unwrap();

        let find_op_other_than_rsp = |inst: &ASMInst| -> Option<MuID> {
            for id in inst.defines.keys() {
                if *id != rsp && *id != rbp {
                    return Some(*id);
                }
            }
            for id in inst.uses.keys() {
                if *id != rsp && *id != rbp {
                    return Some(*id);
                }
            }

            None
        };

        let mut inst_to_remove = vec![];
        let mut regs_to_remove = vec![];

        for i in 0..self.number_of_insts() {
            let ref inst = self.code[i];

            if inst.code.contains("push") || inst.code.contains("pop") {
                match find_op_other_than_rsp(inst) {
                    Some(op) => {
                        // if this push/pop instruction is about a callee saved register
                        // and the register is not used, we set the instruction as nop
                        if x86_64::is_callee_saved(op) && !used_callee_saved.contains(&op) {
                            trace!("removing instruction {:?} for save/restore unnecessary callee saved regs", inst);
                            regs_to_remove.push(op);
                            inst_to_remove.push(i);
                        }
                    }
                    None => {}
                }
            }
        }

        for i in inst_to_remove {
            self.set_inst_nop(i);
        }

        regs_to_remove
    }
qinsoon's avatar
qinsoon committed
523 524 525 526 527 528 529 530 531 532 533 534

    fn patch_frame_size(&mut self, size: usize) {
        let size = size.to_string();

        debug_assert!(size.len() <= FRAME_SIZE_PLACEHOLDER_LEN);

        for loc in self.frame_size_patchpoints.iter() {
            let ref mut inst = self.code[loc.line];

            string_utils::replace(&mut inst.code, loc.index, &size, size.len());
        }
    }
535
    
536 537 538 539 540 541 542 543 544 545 546
    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
    }
    
547 548
    fn trace_mc(&self) {
        trace!("");
549

550 551
        trace!("code for {}: \n", self.name);
        
552 553
        let n_insts = self.code.len();
        for i in 0..n_insts {
554
            self.trace_inst(i);
555 556
        }
        
557 558 559 560 561 562
        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
563
            self.code[i].preds, self.code[i].succs);
564
    }
565
    
566
    fn get_ir_block_livein(&self, block: &str) -> Option<&Vec<MuID>> {
qinsoon's avatar
qinsoon committed
567 568 569 570
        match self.blocks.get(block) {
            Some(ref block) => Some(&block.livein),
            None => None
        }
571 572
    }
    
573
    fn get_ir_block_liveout(&self, block: &str) -> Option<&Vec<MuID>> {
qinsoon's avatar
qinsoon committed
574 575 576 577
        match self.blocks.get(block) {
            Some(ref block) => Some(&block.liveout),
            None => None
        }
578 579
    }
    
580
    fn set_ir_block_livein(&mut self, block: &str, set: Vec<MuID>) {
qinsoon's avatar
qinsoon committed
581 582
        let block = self.blocks.get_mut(block).unwrap();
        block.livein = set;
583 584 585
    }
    
    fn set_ir_block_liveout(&mut self, block: &str, set: Vec<MuID>) {
qinsoon's avatar
qinsoon committed
586 587
        let block = self.blocks.get_mut(block).unwrap();
        block.liveout = set;
588 589
    }
    
qinsoon's avatar
qinsoon committed
590 591
    fn get_all_blocks(&self) -> Vec<MuName> {
        self.blocks.keys().map(|x| x.clone()).collect()
592 593
    }
    
594
    fn get_block_range(&self, block: &str) -> Option<ops::Range<usize>> {
qinsoon's avatar
qinsoon committed
595 596
        match self.blocks.get(block) {
            Some(ref block) => Some(block.start_inst..block.end_inst),
597 598 599
            None => None
        }
    }
600 601
}

qinsoon's avatar
qinsoon committed
602 603 604 605 606 607 608
#[derive(Clone, Debug)]
enum ASMBranchTarget {
    None,
    Conditional(MuName),
    Unconditional(MuName)
}

qinsoon's avatar
qinsoon committed
609
#[derive(Clone, Debug)]
qinsoon's avatar
qinsoon committed
610
struct ASMInst {
611
    code: String,
qinsoon's avatar
qinsoon committed
612 613 614 615 616 617 618 619

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

    is_mem_op_used: bool,
    preds: Vec<usize>,
    succs: Vec<usize>,
    branch: ASMBranchTarget
620 621
}

qinsoon's avatar
qinsoon committed
622 623 624
impl ASMInst {
    fn symbolic(line: String) -> ASMInst {
        ASMInst {
625
            code: line,
qinsoon's avatar
qinsoon committed
626 627 628 629 630 631
            defines: HashMap::new(),
            uses: HashMap::new(),
            is_mem_op_used: false,
            preds: vec![],
            succs: vec![],
            branch: ASMBranchTarget::None
632 633 634
        }
    }
    
qinsoon's avatar
qinsoon committed
635 636 637 638 639 640 641 642 643
    fn inst(
        inst: String,
        defines: HashMap<MuID, Vec<ASMLocation>>,
        uses: HashMap<MuID, Vec<ASMLocation>>,
        is_mem_op_used: bool,
        target: ASMBranchTarget
    ) -> ASMInst
    {
        ASMInst {
644 645
            code: inst,
            defines: defines,
qinsoon's avatar
qinsoon committed
646 647 648 649 650
            uses: uses,
            is_mem_op_used: is_mem_op_used,
            preds: vec![],
            succs: vec![],
            branch: target
651 652
        }
    }
653
    
qinsoon's avatar
qinsoon committed
654 655
    fn nop() -> ASMInst {
        ASMInst {
656
            code: "".to_string(),
qinsoon's avatar
qinsoon committed
657 658 659 660 661 662
            defines: HashMap::new(),
            uses: HashMap::new(),
            is_mem_op_used: false,
            preds: vec![],
            succs: vec![],
            branch: ASMBranchTarget::None
663 664
        }
    }
665 666
}

667
#[derive(Clone, Debug, PartialEq, Eq)]
668 669 670
struct ASMLocation {
    line: usize,
    index: usize,
qinsoon's avatar
qinsoon committed
671 672
    len: usize,
    oplen: usize,
673 674 675
}

impl ASMLocation {
qinsoon's avatar
qinsoon committed
676
    fn new(line: usize, index: usize, len: usize, oplen: usize) -> ASMLocation {
677
        ASMLocation{
qinsoon's avatar
qinsoon committed
678
            line: line,
679
            index: index,
qinsoon's avatar
qinsoon committed
680 681
            len: len,
            oplen: oplen
682 683 684 685
        }
    }
}

qinsoon's avatar
qinsoon committed
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
#[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![]
        }
    }
}

707
pub struct ASMCodeGen {
708
    cur: Option<Box<ASMCode>>
709 710
}

711
const REG_PLACEHOLDER_LEN : usize = 5;
712 713 714 715 716 717
lazy_static! {
    pub static ref REG_PLACEHOLDER : String = {
        let blank_spaces = [' ' as u8; REG_PLACEHOLDER_LEN];
        
        format!("%{}", str::from_utf8(&blank_spaces).unwrap())
    };
718 719
}

qinsoon's avatar
qinsoon committed
720 721 722 723 724 725 726 727
const FRAME_SIZE_PLACEHOLDER_LEN : usize = 10; // a frame is smaller than 1 << 10
lazy_static! {
    pub static ref FRAME_SIZE_PLACEHOLDER : String = {
        let blank_spaces = [' ' as u8; FRAME_SIZE_PLACEHOLDER_LEN];
        format!("{}", str::from_utf8(&blank_spaces).unwrap())
    };
}

728 729
impl ASMCodeGen {
    pub fn new() -> ASMCodeGen {
730
        ASMCodeGen {
731
            cur: None
732 733 734 735 736 737 738 739 740 741 742
        }
    }
    
    fn cur(&self) -> &ASMCode {
        self.cur.as_ref().unwrap()
    }
    
    fn cur_mut(&mut self) -> &mut ASMCode {
        self.cur.as_mut().unwrap()
    }
    
743 744 745 746
    fn line(&self) -> usize {
        self.cur().code.len()
    }
    
747 748
    fn add_asm_label(&mut self, code: String) {
        let l = self.line();
qinsoon's avatar
qinsoon committed
749
        self.cur_mut().code.push(ASMInst::symbolic(code));
750 751
    }
    
752
    fn add_asm_block_label(&mut self, code: String, block_name: MuName) {
753
        let l = self.line();
qinsoon's avatar
qinsoon committed
754
        self.cur_mut().code.push(ASMInst::symbolic(code));
755 756
    }
    
757
    fn add_asm_symbolic(&mut self, code: String){
qinsoon's avatar
qinsoon committed
758
        self.cur_mut().code.push(ASMInst::symbolic(code));
759 760
    }
    
761 762
    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
763
    }
764
    
765
    fn add_asm_call(&mut self, code: String) {
qinsoon's avatar
qinsoon committed
766
        // a call instruction will use all the argument registers
qinsoon's avatar
qinsoon committed
767 768 769 770 771 772 773
        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
774 775

        // defines: return registers
qinsoon's avatar
qinsoon committed
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
        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![]);
            }
        }
793
          
qinsoon's avatar
qinsoon committed
794
        self.add_asm_inst(code, defines, uses, false);
795 796 797
    }
    
    fn add_asm_ret(&mut self, code: String) {
798 799 800 801 802
        // return instruction does not use anything (not RETURN REGS)
        // otherwise it will keep RETURN REGS alive
        // and if there is no actual move into RETURN REGS, it will keep RETURN REGS for alive for very long
        // and prevents anything using those regsiters
        self.add_asm_inst(code, hashmap!{}, hashmap!{}, false);
803 804
    }
    
805
    fn add_asm_branch(&mut self, code: String, target: MuName) {
qinsoon's avatar
qinsoon committed
806
        self.add_asm_inst_internal(code, hashmap!{}, hashmap!{}, false, ASMBranchTarget::Unconditional(target));
807 808
    }
    
809
    fn add_asm_branch2(&mut self, code: String, target: MuName) {
qinsoon's avatar
qinsoon committed
810
        self.add_asm_inst_internal(code, hashmap!{}, hashmap!{}, false, ASMBranchTarget::Conditional(target));
811 812 813 814 815
    }
    
    fn add_asm_inst(
        &mut self, 
        code: String, 
qinsoon's avatar
qinsoon committed
816 817 818 819 820 821 822 823 824 825 826 827 828 829
        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)
830
    {
831 832
        let line = self.line();
        trace!("asm: {}", code);
qinsoon's avatar
qinsoon committed
833 834
        trace!("     defines: {:?}", defines);
        trace!("     uses: {:?}", uses);
835
        let mc = self.cur_mut();
qinsoon's avatar
qinsoon committed
836

837
        // put the instruction
qinsoon's avatar
qinsoon committed
838
        mc.code.push(ASMInst::inst(code, defines, uses, is_using_mem_op, target));
839 840
    }
    
841
    fn prepare_reg(&self, op: &P<Value>, loc: usize) -> (String, MuID, ASMLocation) {
842 843 844 845 846 847 848
        if cfg!(debug_assertions) {
            match op.v {
                Value_::SSAVar(_) => {},
                _ => panic!("expecting register op")
            }
        }
        
849 850
        let str = self.asm_reg_op(op);
        let len = str.len();
qinsoon's avatar
qinsoon committed
851 852 853 854 855 856 857 858 859 860 861 862 863 864
        (str, op.extract_ssa_id().unwrap(), ASMLocation::new(self.line(), loc, len, check_op_len(op)))
    }

    fn prepare_fpreg(&self, op: &P<Value>, loc: usize) -> (String, MuID, ASMLocation) {
        if cfg!(debug_assertions) {
            match op.v {
                Value_::SSAVar(_) => {},
                _ => panic!("expecting register op")
            }
        }

        let str = self.asm_reg_op(op);
        let len = str.len();
        (str, op.extract_ssa_id().unwrap(), ASMLocation::new(self.line(), loc, len, 64))
865 866 867
    }
    
    fn prepare_machine_reg(&self, op: &P<Value>) -> MuID {
868 869 870 871 872 873 874
        if cfg!(debug_assertions) {
            match op.v {
                Value_::SSAVar(_) => {},
                _ => panic!("expecting machine register op")
            }
        }        
        
875
        op.extract_ssa_id().unwrap()
876
    }
877
    
878
    #[allow(unused_assignments)]
qinsoon's avatar
qinsoon committed
879
    fn prepare_mem(&self, op: &P<Value>, loc: usize) -> (String, HashMap<MuID, Vec<ASMLocation>>) {
880 881 882
        if cfg!(debug_assertions) {
            match op.v {
                Value_::Memory(_) => {},
qinsoon's avatar
qinsoon committed
883
                _ => panic!("expecting memory op")
884 885
            }
        }        
qinsoon's avatar
qinsoon committed
886

887 888 889 890
        let mut ids : Vec<MuID> = vec![];
        let mut locs : Vec<ASMLocation> = vec![];
        let mut result_str : String = "".to_string();
        
891
        let mut loc_cursor : usize = loc;
892 893 894 895 896 897 898 899 900 901 902
        
        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
qinsoon's avatar
qinsoon committed
903
                            let (str, id, loc) = self.prepare_reg(offset, loc_cursor);
904 905 906 907 908 909 910 911
                            
                            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
912
                            let str = (val as i32).to_string();
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
                            
                            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
950
                            let str = (val as i32).to_string();
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
                            
                            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;
            },
974 975
            Value_::Memory(MemoryLocation::Symbolic{ref base, ref label}) => {
                result_str.push_str(&symbol(label.clone()));
976 977 978 979 980 981 982 983 984 985 986
                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
987

988
                    result_str.push(')');
qinsoon's avatar
qinsoon committed
989
                    loc_cursor += 1;
990 991 992 993
                }
            },
            _ => panic!("expect mem location as value")
        }
qinsoon's avatar
qinsoon committed
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011

        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)
1012
    }
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022

    fn prepare_imm(&self, op: i32, len: usize) -> i32 {
        match len {
            64 => op,
            32 => op,
            16 => op as i16 as i32,
            8  => op as i8  as i32,
            _ => unimplemented!()
        }
    }
1023
    
1024 1025
    fn asm_reg_op(&self, op: &P<Value>) -> String {
        let id = op.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
1026
        if id < MACHINE_ID_END {
1027
            // machine reg
1028
            format!("%{}", op.name().unwrap())
1029 1030 1031 1032 1033 1034
        } else {
            // virtual register, use place holder
            REG_PLACEHOLDER.clone()
        }
    }
    
qinsoon's avatar
qinsoon committed
1035 1036
    fn mangle_block_label(&self, label: MuName) -> String {
        format!("{}_{}", self.cur().name, label)
1037
    }
1038 1039 1040 1041
    
    fn control_flow_analysis(&mut self) {
        // control flow analysis
        let n_insts = self.line();
qinsoon's avatar
qinsoon committed
1042

1043
        let code = self.cur_mut();
qinsoon's avatar
qinsoon committed
1044
        let ref blocks = code.blocks;
qinsoon's avatar
qinsoon committed
1045
        let ref mut asm = code.code;
qinsoon's avatar
qinsoon committed
1046 1047 1048 1049 1050 1051 1052 1053

        let block_start = {
            let mut ret = vec![];
            for block in blocks.values() {
                ret.push(block.start_inst);
            }
            ret
        };
1054 1055 1056
        
        for i in 0..n_insts {
            // determine predecessor - if cur is not block start, its predecessor is previous insts
qinsoon's avatar
qinsoon committed
1057 1058
            let is_block_start = block_start.contains(&i);
            if !is_block_start {
1059
                if i > 0 {
1060 1061
                    trace!("inst {}: not a block start", i);
                    trace!("inst {}: set PREDS as previous inst {}", i, i-1);
qinsoon's avatar
qinsoon committed
1062
                    asm[i].preds.push(i - 1);
1063 1064 1065 1066 1067 1068 1069
                }
            } 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
1070 1071 1072 1073 1074 1075
            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
1076
                    let target_n = code.blocks.get(target).unwrap().start_inst;
qinsoon's avatar
qinsoon committed
1077 1078 1079 1080
                    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
1081
                    asm[i].succs.push(target_n);
qinsoon's avatar
qinsoon committed
1082 1083 1084

                    // target's pred is cur
                    trace!("inst {}: set PREDS as branch source {}", target_n, i);
qinsoon's avatar
qinsoon committed
1085
                    asm[target_n].preds.push(i);
qinsoon's avatar
qinsoon committed
1086 1087
                },
                ASMBranchTarget::Conditional(ref target) => {
1088
                    // branch to target
1089
                    trace!("inst {}: is a cond branch to {}", i, target);
qinsoon's avatar
qinsoon committed
1090

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

1094
                    // cur insts' succ is target and next inst
qinsoon's avatar
qinsoon committed
1095
                    asm[i].succs.push(target_n);
1096
                    trace!("inst {}: set SUCCS as branch target {}", i, target_n);
1097
                    if i < n_insts - 1 {
qinsoon's avatar
qinsoon committed
1098 1099
                        trace!("inst {}: set SUCCS as next inst", i + 1);
                        asm[i].succs.push(i + 1);
1100
                    }
qinsoon's avatar
qinsoon committed
1101

1102
                    // target's pred is cur
qinsoon's avatar
qinsoon committed
1103 1104
                    asm[target_n].preds.push(i);
                    trace!("inst {}: set PREDS as {}", target_n, i);
qinsoon's avatar
qinsoon committed
1105 1106
                },
                ASMBranchTarget::None => {
1107
                    // not branch nor cond branch, succ is next inst
1108
                    trace!("inst {}: not a branch inst", i);
1109
                    if i < n_insts - 1 {
1110
                        trace!("inst {}: set SUCCS as next inst {}", i, i + 1);
qinsoon's avatar
qinsoon committed
1111
                        asm[i].succs.push(i + 1);
1112 1113
                    }
                }
qinsoon's avatar
qinsoon committed
1114
            }
1115 1116 1117 1118
        }
        
        // a sanity check for fallthrough blocks
        for i in 0..n_insts {
qinsoon's avatar
qinsoon committed
1119 1120
            if i != 0 && asm[i].preds.len() == 0 {
                asm[i].preds.push(i - 1);
1121 1122 1123
            }
        }        
    }
1124 1125 1126 1127

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

qinsoon's avatar
qinsoon committed
1129 1130
    fn internal_binop_no_def_r_r(&mut self, inst: &str, op1: &P<Value>, op2: &P<Value>) {
        let len = check_op_len(op1);
1131

qinsoon's avatar
qinsoon committed
1132 1133 1134
        // with postfix
        let inst = inst.to_string() + &op_postfix(len);
        trace!("emit: {} {} {}", inst, op1, op2);
1135

qinsoon's avatar
qinsoon committed
1136 1137
        let (reg1, id1, loc1) = self.prepare_reg(op1, inst.len() + 1);
        let (reg2, id2, loc2) = self.prepare_reg(op2, inst.len() + 1 + reg1.len() + 1);
1138

qinsoon's avatar
qinsoon committed
1139
        let asm = format!("{} {},{}", inst, reg1, reg2);
1140

qinsoon's avatar
qinsoon committed
1141 1142 1143 1144 1145 1146 1147
        self.add_asm_inst(
            asm,
            hashmap!{},
            {
                if id1 == id2 {
                    hashmap!{
                        id1 => vec![loc1, loc2]
1148
                    }
qinsoon's avatar
qinsoon committed
1149 1150 1151 1152 1153 1154 1155 1156 1157
                } else {
                    hashmap!{
                        id1 => vec![loc1],
                        id2 => vec![loc2]
                    }
                }
            },
            false
        )
1158 1159
    }

qinsoon's avatar
qinsoon committed
1160 1161
    fn internal_binop_no_def_imm_r(&mut self, inst: &str, op1: i32, op2: &P<Value>) {
        let len = check_op_len(op2);
1162

qinsoon's avatar
qinsoon committed
1163 1164
        let inst = inst.to_string() + &op_postfix(len);
        trace!("emit: {} {} {}", inst, op1, op2);
1165

1166 1167
        let imm = self.prepare_imm(op1, len);
        let (reg2, id2, loc2) = self.prepare_reg(op2, inst.len() + 1 + 1 + imm.to_string().len() + 1);
1168

1169
        let asm = format!("{} ${},{}", inst, imm, reg2);
1170

qinsoon's avatar
qinsoon committed
1171 1172 1173 1174 1175 1176 1177 1178
        self.add_asm_inst(
            asm,
            hashmap!{},
            hashmap!{
                id2 => vec![loc2]
            },
            false
        )
1179 1180
    }

qinsoon's avatar
qinsoon committed
1181 1182
    fn internal_binop_no_def_mem_r(&mut self, inst: &str, op1: &P<Value>, op2: &P<Value>) {
        let len = check_op_len(op2);
1183

qinsoon's avatar
qinsoon committed
1184 1185
        let inst = inst.to_string() + &op_postfix(len);
        trace!("emit: {} {} {}", inst, op1, op2);
1186

qinsoon's avatar
qinsoon committed
1187 1188
        let (mem, mut uses)  = self.prepare_mem(op1, inst.len() + 1);
        let (reg, id1, loc1) = self.prepare_reg(op2, inst.len() + 1 + mem.len() + 1);
1189

qinsoon's avatar
qinsoon committed
1190
        let asm = format!("{} {},{}", inst, mem, reg);
1191

qinsoon's avatar
qinsoon committed
1192 1193 1194 1195 1196 1197
        // merge use vec
        if uses.contains_key(&id1) {
            let mut locs = uses.get_mut(&id1).unwrap();
            vec_utils::add_unique(locs, loc1.clone());
        } else {
            uses.insert(id1, vec![loc1]);
1198
        }
qinsoon's avatar
qinsoon committed
1199 1200 1201 1202 1203 1204 1205

        self.add_asm_inst(
            asm,
            hashmap!{},
            uses,
            true
        )
1206 1207
    }

qinsoon's avatar
qinsoon committed
1208 1209
    fn internal_binop_no_def_r_mem(&mut self, inst: &str, op1: &P<Value>, op2: &P<Value>) {
        let len = check_op_len(op1);
1210

qinsoon's avatar
qinsoon committed
1211 1212
        let inst = inst.to_string() + &op_postfix(len);
        trace!("emit: {} {} {}", inst, op1, op2);
1213

qinsoon's avatar
qinsoon committed
1214 1215
        let (mem, mut uses) = self.prepare_mem(op2, inst.len() + 1);
        let (reg, id1, loc1) = self.prepare_reg(op1, inst.len() + 1 + mem.len() + 1);
1216

qinsoon's avatar
qinsoon committed
1217 1218 1219 1220 1221
        if uses.contains_key(&id1) {
            let mut locs = uses.get_mut(&id1).unwrap();
            vec_utils::add_unique(locs, loc1.clone());
        } else {
            uses.insert(id1, vec![loc1.clone()]);
1222 1223
        }

qinsoon's avatar
qinsoon committed
1224
        let asm = format!("{} {},{}", inst, mem, reg);
1225

qinsoon's avatar
qinsoon committed
1226 1227 1228 1229 1230 1231
        self.add_asm_inst(
            asm,
            hashmap!{},
            uses,
            true
        )
1232 1233
    }

qinsoon's avatar
qinsoon committed
1234 1235
    fn internal_binop_def_r_r(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
        let len = check_op_len(src);
1236

qinsoon's avatar
qinsoon committed
1237 1238
        let inst = inst.to_string() + &op_postfix(len);
        trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
1239

qinsoon's avatar
qinsoon committed
1240 1241
        let (reg1, id1, loc1) = self.prepare_reg(src, inst.len() + 1);
        let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + reg1.len() + 1);
1242

qinsoon's avatar
qinsoon committed
1243
        let asm = format!("{} {},{}", inst, reg1, reg2);
1244

qinsoon's avatar
qinsoon committed
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
        self.add_asm_inst(
            asm,
            hashmap!{
                id2 => vec![loc2.clone()]
            },
            {
                if id1 == id2 {
                    hashmap!{
                        id1 => vec![loc1, loc2]
                    }
                } else {
                    hashmap!{
                        id1 => vec![loc1],
                        id2 => vec![loc2]
                    }
                }
            },
            false
        )
1264 1265
    }

qinsoon's avatar
qinsoon committed
1266 1267
    fn internal_binop_def_r_mr(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
        let len = check_op_len(dest);
1268

qinsoon's avatar
qinsoon committed
1269 1270
        let inst = inst.to_string() + &op_postfix(len);
        trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
1271

qinsoon's avatar
qinsoon committed
1272 1273 1274
        let mreg = self.prepare_machine_reg(src);
        let mreg_name = src.name().unwrap();
        let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + 1 + mreg_name.len() + 1);
1275

qinsoon's avatar
qinsoon committed
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
        let asm = format!("{} %{},{}", inst, mreg_name, reg2);

        self.add_asm_inst(
            asm,
            hashmap!{
                id2 => vec![loc2.clone()]
            },
            hashmap!{
                id2 => vec![loc2],
                mreg => vec![]
            },
            false
        )
1289 1290
    }

qinsoon's avatar
qinsoon committed
1291 1292
    fn internal_binop_def_r_imm(&mut self, inst: &str, dest: &P<Value>, src: i32) {
        let len = check_op_len(dest);
1293

qinsoon's avatar