asm_backend.rs 90.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 384 385 386 387 388 389 390 391 392 393 394 395 396 397
            Some(inst) => {
                let ref inst = inst.code;

                if inst.starts_with("movsd") || inst.starts_with("movss") {
                    // floating point move
                    true
                } else if inst.starts_with("movs") || inst.starts_with("movz") {
                    // sign extend, zero extend
                    false
                } else if inst.starts_with("mov") {
                    // normal mov
                    true
                } else {
                    false
                }
            },
398 399 400 401
            None => false
        }
    }
    
qinsoon's avatar
qinsoon committed
402
    fn is_using_mem_op(&self, index: usize) -> bool {
qinsoon's avatar
qinsoon committed
403
        self.code[index].is_mem_op_used
qinsoon's avatar
qinsoon committed
404 405
    }
    
qinsoon's avatar
qinsoon committed
406
    fn get_succs(&self, index: usize) -> &Vec<usize> {
qinsoon's avatar
qinsoon committed
407
        &self.code[index].succs
qinsoon's avatar
qinsoon committed
408 409 410
    }
    
    fn get_preds(&self, index: usize) -> &Vec<usize> {
qinsoon's avatar
qinsoon committed
411
        &self.code[index].preds
qinsoon's avatar
qinsoon committed
412 413
    }
    
qinsoon's avatar
qinsoon committed
414 415
    fn get_inst_reg_uses(&self, index: usize) -> Vec<MuID> {
        self.code[index].uses.keys().map(|x| *x).collect()
416 417
    }
    
qinsoon's avatar
qinsoon committed
418 419
    fn get_inst_reg_defines(&self, index: usize) -> Vec<MuID> {
        self.code[index].defines.keys().map(|x| *x).collect()
420
    }
421
    
422
    fn replace_reg(&mut self, from: MuID, to: MuID) {
qinsoon's avatar
qinsoon committed
423 424
        for loc in self.get_define_locations(from) {
            let ref mut inst_to_patch = self.code[loc.line];
qinsoon's avatar
qinsoon committed
425 426 427 428 429 430 431

            // 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());
432
        }
433

qinsoon's avatar
qinsoon committed
434 435
        for loc in self.get_use_locations(from) {
            let ref mut inst_to_patch = self.code[loc.line];
qinsoon's avatar
qinsoon committed
436 437 438 439 440 441 442

            // 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());
443 444
        }
    }
445

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

qinsoon's avatar
qinsoon committed
449 450 451 452 453 454
        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
455
                string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
456 457
            }

qinsoon's avatar
qinsoon committed
458 459
            // remove old key, insert new one
            asm.defines.remove(&from);
460
            asm.defines.insert(to, define_locs);
461
        }
462 463 464
    }

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

        let asm = &mut self.code[inst];
qinsoon's avatar
qinsoon committed
468 469 470 471 472 473

        // 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
474
                string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
475 476
            }

qinsoon's avatar
qinsoon committed
477 478
            // remove old key, insert new one
            asm.uses.remove(&from);
479
            asm.uses.insert(to, use_locs);
480 481
        }
    }
482
    
483 484
    fn set_inst_nop(&mut self, index: usize) {
        self.code.remove(index);
qinsoon's avatar
qinsoon committed
485
        self.code.insert(index, ASMInst::nop());
486
    }
qinsoon's avatar
qinsoon committed
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 523 524 525 526 527 528 529 530 531 532 533 534 535 536

    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
537 538 539 540 541 542 543 544 545 546 547 548

    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());
        }
    }
549
    
550 551 552 553 554 555 556 557 558 559 560
    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
    }
    
561 562
    fn trace_mc(&self) {
        trace!("");
563

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

qinsoon's avatar
qinsoon committed
616 617 618 619 620 621 622
#[derive(Clone, Debug)]
enum ASMBranchTarget {
    None,
    Conditional(MuName),
    Unconditional(MuName)
}

qinsoon's avatar
qinsoon committed
623
#[derive(Clone, Debug)]
qinsoon's avatar
qinsoon committed
624
struct ASMInst {
625
    code: String,
qinsoon's avatar
qinsoon committed
626 627 628 629 630 631 632 633

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

    is_mem_op_used: bool,
    preds: Vec<usize>,
    succs: Vec<usize>,
    branch: ASMBranchTarget
634 635
}

qinsoon's avatar
qinsoon committed
636 637 638
impl ASMInst {
    fn symbolic(line: String) -> ASMInst {
        ASMInst {
639
            code: line,
qinsoon's avatar
qinsoon committed
640 641 642 643 644 645
            defines: HashMap::new(),
            uses: HashMap::new(),
            is_mem_op_used: false,
            preds: vec![],
            succs: vec![],
            branch: ASMBranchTarget::None
646 647 648
        }
    }
    
qinsoon's avatar
qinsoon committed
649 650 651 652 653 654 655 656 657
    fn inst(
        inst: String,
        defines: HashMap<MuID, Vec<ASMLocation>>,
        uses: HashMap<MuID, Vec<ASMLocation>>,
        is_mem_op_used: bool,
        target: ASMBranchTarget
    ) -> ASMInst
    {
        ASMInst {
658 659
            code: inst,
            defines: defines,
qinsoon's avatar
qinsoon committed
660 661 662 663 664
            uses: uses,
            is_mem_op_used: is_mem_op_used,
            preds: vec![],
            succs: vec![],
            branch: target
665 666
        }
    }
667
    
qinsoon's avatar
qinsoon committed
668 669
    fn nop() -> ASMInst {
        ASMInst {
670
            code: "".to_string(),
qinsoon's avatar
qinsoon committed
671 672 673 674 675 676
            defines: HashMap::new(),
            uses: HashMap::new(),
            is_mem_op_used: false,
            preds: vec![],
            succs: vec![],
            branch: ASMBranchTarget::None
677 678
        }
    }
679 680
}

681
#[derive(Clone, Debug, PartialEq, Eq)]
682 683 684
struct ASMLocation {
    line: usize,
    index: usize,
qinsoon's avatar
qinsoon committed
685 686
    len: usize,
    oplen: usize,
687 688 689
}

impl ASMLocation {
qinsoon's avatar
qinsoon committed
690
    fn new(line: usize, index: usize, len: usize, oplen: usize) -> ASMLocation {
691
        ASMLocation{
qinsoon's avatar
qinsoon committed
692
            line: line,
693
            index: index,
qinsoon's avatar
qinsoon committed
694 695
            len: len,
            oplen: oplen
696 697 698 699
        }
    }
}

qinsoon's avatar
qinsoon committed
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
#[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![]
        }
    }
}

721
pub struct ASMCodeGen {
722
    cur: Option<Box<ASMCode>>
723 724
}

725
const REG_PLACEHOLDER_LEN : usize = 5;
726 727 728 729 730 731
lazy_static! {
    pub static ref REG_PLACEHOLDER : String = {
        let blank_spaces = [' ' as u8; REG_PLACEHOLDER_LEN];
        
        format!("%{}", str::from_utf8(&blank_spaces).unwrap())
    };
732 733
}

qinsoon's avatar
qinsoon committed
734 735 736 737 738 739 740 741
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())
    };
}

742 743
impl ASMCodeGen {
    pub fn new() -> ASMCodeGen {
744
        ASMCodeGen {
745
            cur: None
746 747 748 749 750 751 752 753 754 755 756
        }
    }
    
    fn cur(&self) -> &ASMCode {
        self.cur.as_ref().unwrap()
    }
    
    fn cur_mut(&mut self) -> &mut ASMCode {
        self.cur.as_mut().unwrap()
    }
    
757 758 759 760
    fn line(&self) -> usize {
        self.cur().code.len()
    }
    
761 762
    fn add_asm_label(&mut self, code: String) {
        let l = self.line();
qinsoon's avatar
qinsoon committed
763
        self.cur_mut().code.push(ASMInst::symbolic(code));
764 765
    }
    
766
    fn add_asm_block_label(&mut self, code: String, block_name: MuName) {
767
        let l = self.line();
qinsoon's avatar
qinsoon committed
768
        self.cur_mut().code.push(ASMInst::symbolic(code));
769 770
    }
    
771
    fn add_asm_symbolic(&mut self, code: String){
qinsoon's avatar
qinsoon committed
772
        self.cur_mut().code.push(ASMInst::symbolic(code));
773 774
    }
    
775 776
    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
777
    }
778
    
779
    fn add_asm_call(&mut self, code: String) {
qinsoon's avatar
qinsoon committed
780
        // a call instruction will use all the argument registers
qinsoon's avatar
qinsoon committed
781 782 783 784 785 786 787
        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
788 789

        // defines: return registers
qinsoon's avatar
qinsoon committed
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
        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![]);
            }
        }
807
          
qinsoon's avatar
qinsoon committed
808
        self.add_asm_inst(code, defines, uses, false);
809 810 811
    }
    
    fn add_asm_ret(&mut self, code: String) {
812 813 814 815 816
        // 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);
817 818
    }
    
819
    fn add_asm_branch(&mut self, code: String, target: MuName) {
qinsoon's avatar
qinsoon committed
820
        self.add_asm_inst_internal(code, hashmap!{}, hashmap!{}, false, ASMBranchTarget::Unconditional(target));
821 822
    }
    
823
    fn add_asm_branch2(&mut self, code: String, target: MuName) {
qinsoon's avatar
qinsoon committed
824
        self.add_asm_inst_internal(code, hashmap!{}, hashmap!{}, false, ASMBranchTarget::Conditional(target));
825 826 827 828 829
    }
    
    fn add_asm_inst(
        &mut self, 
        code: String, 
qinsoon's avatar
qinsoon committed
830 831 832 833 834 835 836 837 838 839 840 841 842 843
        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)
844
    {
845 846
        let line = self.line();
        trace!("asm: {}", code);
qinsoon's avatar
qinsoon committed
847 848
        trace!("     defines: {:?}", defines);
        trace!("     uses: {:?}", uses);
849
        let mc = self.cur_mut();
qinsoon's avatar
qinsoon committed
850

851
        // put the instruction
qinsoon's avatar
qinsoon committed
852
        mc.code.push(ASMInst::inst(code, defines, uses, is_using_mem_op, target));
853 854
    }
    
855
    fn prepare_reg(&self, op: &P<Value>, loc: usize) -> (String, MuID, ASMLocation) {
856 857 858 859 860 861 862
        if cfg!(debug_assertions) {
            match op.v {
                Value_::SSAVar(_) => {},
                _ => panic!("expecting register op")
            }
        }
        
863 864
        let str = self.asm_reg_op(op);
        let len = str.len();
qinsoon's avatar
qinsoon committed
865 866 867 868 869 870 871 872 873 874 875 876 877 878
        (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))
879 880 881
    }
    
    fn prepare_machine_reg(&self, op: &P<Value>) -> MuID {
882 883 884 885 886 887 888
        if cfg!(debug_assertions) {
            match op.v {
                Value_::SSAVar(_) => {},
                _ => panic!("expecting machine register op")
            }
        }        
        
889
        op.extract_ssa_id().unwrap()
890
    }
891
    
892
    #[allow(unused_assignments)]
qinsoon's avatar
qinsoon committed
893
    fn prepare_mem(&self, op: &P<Value>, loc: usize) -> (String, HashMap<MuID, Vec<ASMLocation>>) {
894 895 896
        if cfg!(debug_assertions) {
            match op.v {
                Value_::Memory(_) => {},
qinsoon's avatar
qinsoon committed
897
                _ => panic!("expecting memory op")
898 899
            }
        }        
qinsoon's avatar
qinsoon committed
900

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

1002
                    result_str.push(')');
qinsoon's avatar
qinsoon committed
1003
                    loc_cursor += 1;
1004 1005 1006 1007
                }
            },
            _ => panic!("expect mem location as value")
        }
qinsoon's avatar
qinsoon committed
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025

        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)
1026
    }
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036

    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!()
        }
    }
1037
    
1038 1039
    fn asm_reg_op(&self, op: &P<Value>) -> String {
        let id = op.extract_ssa_id().unwrap();
qinsoon's avatar
qinsoon committed
1040
        if id < MACHINE_ID_END {
1041
            // machine reg
1042
            format!("%{}", op.name().unwrap())
1043 1044 1045 1046 1047 1048
        } else {
            // virtual register, use place holder
            REG_PLACEHOLDER.clone()
        }
    }
    
qinsoon's avatar
qinsoon committed
1049 1050
    fn mangle_block_label(&self, label: MuName) -> String {
        format!("{}_{}", self.cur().name, label)
1051
    }
1052 1053 1054 1055
    
    fn control_flow_analysis(&mut self) {
        // control flow analysis
        let n_insts = self.line();
qinsoon's avatar
qinsoon committed
1056

1057
        let code = self.cur_mut();
qinsoon's avatar
qinsoon committed
1058
        let ref blocks = code.blocks;
qinsoon's avatar
qinsoon committed
1059
        let ref mut asm = code.code;
qinsoon's avatar
qinsoon committed
1060 1061 1062 1063 1064 1065 1066 1067

        let block_start = {
            let mut ret = vec![];
            for block in blocks.values() {
                ret.push(block.start_inst);
            }
            ret
        };
1068 1069 1070
        
        for i in 0..n_insts {
            // determine predecessor - if cur is not block start, its predecessor is previous insts
qinsoon's avatar
qinsoon committed
1071 1072
            let is_block_start = block_start.contains(&i);
            if !is_block_start {
1073
                if i > 0 {
1074 1075
                    trace!("inst {}: not a block start", i);
                    trace!("inst {}: set PREDS as previous inst {}", i, i-1);
qinsoon's avatar
qinsoon committed
1076
                    asm[i].preds.push(i - 1);
1077 1078 1079 1080 1081 1082 1083
                }
            } 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
1084 1085 1086 1087 1088 1089
            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
1090
                    let target_n = code.blocks.get(target).unwrap().start_inst;
qinsoon's avatar
qinsoon committed
1091 1092 1093 1094
                    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
1095
                    asm[i].succs.push(target_n);
qinsoon's avatar
qinsoon committed
1096 1097 1098

                    // target's pred is cur
                    trace!("inst {}: set PREDS as branch source {}", target_n, i);
qinsoon's avatar
qinsoon committed
1099
                    asm[target_n].preds.push(i);
qinsoon's avatar
qinsoon committed
1100 1101
                },
                ASMBranchTarget::Conditional(ref target) => {
1102
                    // branch to target
1103
                    trace!("inst {}: is a cond branch to {}", i, target);
qinsoon's avatar
qinsoon committed
1104

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

1108
                    // cur insts' succ is target and next inst
qinsoon's avatar
qinsoon committed
1109
                    asm[i].succs.push(target_n);
1110
                    trace!("inst {}: set SUCCS as branch target {}", i, target_n);
1111
                    if i < n_insts - 1 {
qinsoon's avatar
qinsoon committed
1112 1113
                        trace!("inst {}: set SUCCS as next inst", i + 1);
                        asm[i].succs.push(i + 1);
1114
                    }
qinsoon's avatar
qinsoon committed
1115

1116
                    // target's pred is cur
qinsoon's avatar
qinsoon committed
1117 1118
                    asm[target_n].preds.push(i);
                    trace!("inst {}: set PREDS as {}", target_n, i);
qinsoon's avatar
qinsoon committed
1119 1120
                },
                ASMBranchTarget::None => {
1121
                    // not branch nor cond branch, succ is next inst
1122
                    trace!("inst {}: not a branch inst", i);
1123
                    if i < n_insts - 1 {
1124
                        trace!("inst {}: set SUCCS as next inst {}", i, i + 1);
qinsoon's avatar
qinsoon committed
1125
                        asm[i].succs.push(i + 1);
1126 1127
                    }
                }
qinsoon's avatar
qinsoon committed
1128
            }
1129 1130 1131 1132
        }
        
        // a sanity check for fallthrough blocks
        for i in 0..n_insts {
qinsoon's avatar
qinsoon committed
1133 1134
            if i != 0 && asm[i].preds.len() == 0 {
                asm[i].preds.push(i - 1);
1135 1136 1137
            }
        }        
    }
1138 1139 1140 1141

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

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

qinsoon's avatar
qinsoon committed
1146 1147 1148
        // with postfix
        let inst = inst.to_string() + &op_postfix(len);
        trace!("emit: {} {} {}", inst, op1, op2);
1149

qinsoon's avatar
qinsoon committed
1150 1151
        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);
1152

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

qinsoon's avatar
qinsoon committed
1155 1156 1157 1158 1159 1160 1161
        self.add_asm_inst(
            asm,
            hashmap!{},
            {
                if id1 == id2 {
                    hashmap!{
                        id1 => vec![loc1, loc2]
1162
                    }
qinsoon's avatar
qinsoon committed
1163 1164 1165 1166 1167 1168 1169 1170 1171
                } else {
                    hashmap!{
                        id1 => vec![loc1],
                        id2 => vec![loc2]
                    }
                }
            },
            false
        )
1172 1173
    }

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

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

1180 1181
        let imm = self.prepare_imm(op1, len);
        let (reg2, id2, loc2) = self.prepare_reg(op2, inst.len() + 1 + 1 + imm.to_string().len() + 1);
1182

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

qinsoon's avatar
qinsoon committed
1185 1186 1187 1188 1189 1190 1191 1192
        self.add_asm_inst(
            asm,
            hashmap!{},
            hashmap!{
                id2 => vec![loc2]
            },
            false
        )
1193 1194
    }

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

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

qinsoon's avatar
qinsoon committed
1201 1202
        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);
1203

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

qinsoon's avatar
qinsoon committed
1206 1207 1208 1209 1210 1211
        // 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]);
1212
        }
qinsoon's avatar
qinsoon committed
1213 1214 1215 1216 1217 1218 1219

        self.add_asm_inst(
            asm,
            hashmap!{},
            uses,
            true
        )
1220 1221
    }

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

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

qinsoon's avatar
qinsoon committed
1228 1229
        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);
1230

qinsoon's avatar
qinsoon committed
1231 1232 1233 1234 1235
        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()]);
1236 1237
        }

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

qinsoon's avatar
qinsoon committed
1240 1241 1242 1243 1244 1245
        self.add_asm_inst(
            asm,
            hashmap!{},
            uses,
            true
        )
1246 1247
    }

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

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

qinsoon's avatar
qinsoon committed
1254 1255
        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);
1256

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

qinsoon's avatar
qinsoon committed
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
        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
        )
1278 1279
    }

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

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

qinsoon's avatar
qinsoon committed
1286 1287 1288
        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);
1289

qinsoon's avatar
qinsoon committed
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
        let asm = format!("{} %{},{}", inst, mreg_name, reg2);

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