Commit c313f4d7 authored by Isaac Oscar Gariano's avatar Isaac Oscar Gariano

Fixed all failed testcases on both aarch64 and x86-64.

parent 4e35ae29
Pipeline #439 passed with stage
in 74 minutes and 54 seconds
......@@ -22,6 +22,7 @@ use std::str;
use std::usize;
use std::slice::Iter;
use std::ops;
use std::collections::HashSet;
struct ASMCode {
name: MuName,
......@@ -652,71 +653,52 @@ impl MachineCode for ASMCode {
// self.code.insert(index, ASMInst::nop());
}
fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> (Vec<MuID>, usize) {
fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> HashSet<MuID> {
// every push pair (STP)/and pop pair (LDP) will use/define SP
let sp = SP.extract_ssa_id().unwrap();
let fp = FP.extract_ssa_id().unwrap();
let find_op_other_than_sp = |inst: &ASMInst| -> Vec<MuID> {
let mut ret : Vec<MuID> = vec![];
// Note: this version assumes only 1 callee is pushed or poped
let find_op_other_than_fp = |inst: &ASMInst| -> MuID {
for id in inst.defines.keys() {
if *id != sp {
ret.push(*id);
if *id != fp {
return *id;
}
}
for id in inst.uses.keys() {
if *id != sp {
ret.push(*id);
if *id != fp {
return *id;
}
}
ret
panic!("Expected to find a used register other than the FP");
};
let mut inst_to_remove = vec![];
let mut regs_to_remove = vec![];
let mut number_kept = 0; // Number of callee saved registers kept
let mut regs_to_remove = HashSet::new();
for i in 0..self.number_of_insts() {
let ref inst = self.code[i];
if inst.code.starts_with("STP ") || inst.code.starts_with("LDP ") {
let regs = find_op_other_than_sp(inst);
let mut temp_kept = 0;
let mut remove = true;
for r in &regs {
if is_callee_saved(*r) {
// Keep this callee saved register
// (will still be kept if unused and the instruction isn't to be deleted)
temp_kept += 1;
if used_callee_saved.contains(&r) {
remove = false; // We can't remove the instruction
}
} else {
// Not an (unused) callee saved register, don't remove the instruction
remove = false;
match inst.spill_info {
Some(SpillMemInfo::CalleeSaved) => {
let reg = find_op_other_than_fp(inst);
if !used_callee_saved.contains(&reg) {
inst_to_remove.push(i);
regs_to_remove.insert(reg);
}
}
if remove {
inst_to_remove.push(i);
regs_to_remove.extend(regs);
} else {
// All the callee saved registers are kept (even if some aren't used)
number_kept += temp_kept;
}
_ => {}
}
}
for i in inst_to_remove {
self.set_inst_nop(i);
}
(regs_to_remove, number_kept)
regs_to_remove
}
fn patch_frame_size(&mut self, size: usize, size_used: usize) {
fn patch_frame_size(&mut self, size: usize) {
debug_assert!(size % 16 == 0);
debug_assert!(size_used % 16 == 0);
let size = size.to_string();
......@@ -801,9 +783,7 @@ impl MachineCode for ASMCode {
block.liveout = set;
}
fn get_all_blocks(&self) -> Vec<MuName> {
self.blocks.keys().map(|x| x.clone()).collect()
}
fn get_all_blocks(&self) -> Vec<MuName> { self.blocks.keys().map(|x| x.clone()).collect() }
fn get_entry_block(&self) -> MuName {
self.entry.clone()
......@@ -848,7 +828,8 @@ enum ASMBranchTarget {
#[derive(Clone, Debug)]
enum SpillMemInfo {
Load(P<Value>),
Store(P<Value>)
Store(P<Value>),
CalleeSaved, // Callee saved record
}
#[derive(Clone, Debug)]
......@@ -1094,6 +1075,16 @@ impl ASMCodeGen {
self.add_asm_inst_internal(code, defines, uses, is_using_mem_op, ASMBranchTarget::None, None)
}
fn add_asm_inst_with_callee_saved(
&mut self,
code: String,
defines: LinkedHashMap<MuID, Vec<ASMLocation>>,
uses: LinkedHashMap<MuID, Vec<ASMLocation>>,
is_using_mem_op: bool,
) {
self.add_asm_inst_internal(code, defines, uses, is_using_mem_op, ASMBranchTarget::None, Some(SpillMemInfo::CalleeSaved))
}
fn add_asm_inst_with_spill(
&mut self,
code: String,
......@@ -1220,6 +1211,10 @@ impl ASMCodeGen {
result_str.push('#');
result_str.push_str(&str);
},
Value_::Constant(Constant::ExternSym(ref name)) => {
result_str.push('#');
result_str.push_str(name.as_str());
}
_ => panic!("unexpected offset type: {:?}", offset)
}
}
......@@ -1285,8 +1280,8 @@ impl ASMCodeGen {
self.cur.take().unwrap()
}
fn emit_ldr_spill(&mut self, dest: Reg, src: Mem) { self.internal_load("LDR", dest, src, false, true); }
fn emit_str_spill(&mut self, dest: Mem, src: Reg) { self.internal_store("STR", dest, src, true) }
fn emit_ldr_spill(&mut self, dest: Reg, src: Mem) { self.internal_load("LDR", dest, src, false, true, false); }
fn emit_str_spill(&mut self, dest: Mem, src: Reg) { self.internal_store("STR", dest, src, true, false) }
fn internal_simple(&mut self, inst: &str) {
let inst = inst.to_string();
......@@ -1755,7 +1750,7 @@ impl ASMCodeGen {
)
}
fn internal_load(&mut self, inst: &str, dest: &P<Value>, src: Mem, signed: bool, is_spill_related: bool)
fn internal_load(&mut self, inst: &str, dest: &P<Value>, src: Mem, signed: bool, is_spill_related: bool, is_callee_saved: bool)
{
let op_len = primitive_byte_size(&dest.ty);
let inst = inst.to_string() + if signed {
......@@ -1784,7 +1779,14 @@ impl ASMCodeGen {
let asm = format!("{} {},{}", inst, reg, mem);
if is_spill_related {
if is_callee_saved {
self.add_asm_inst_with_callee_saved(
asm,
ignore_zero_register(id, vec![loc]),
uses,
true,
)
} else if is_spill_related {
self.add_asm_inst_with_spill(
asm,
ignore_zero_register(id, vec![loc]),
......@@ -1823,7 +1825,7 @@ impl ASMCodeGen {
}
fn internal_store(&mut self, inst: &str, dest: Mem, src : &P<Value>, is_spill_related: bool)
fn internal_store(&mut self, inst: &str, dest: Mem, src : &P<Value>, is_spill_related: bool, is_callee_saved: bool)
{
let op_len = primitive_byte_size(&src.ty);
let inst = inst.to_string() + match op_len {
......@@ -1852,7 +1854,14 @@ impl ASMCodeGen {
let asm = format!("{} {},{}", inst, reg, mem);
if is_spill_related {
if is_callee_saved {
self.add_asm_inst_with_callee_saved(
asm,
linked_hashmap!{},
uses,
true,
)
} else if is_spill_related {
self.add_asm_inst_with_spill(
asm,
linked_hashmap!{},
......@@ -2010,6 +2019,7 @@ impl CodeGenerator for ASMCodeGen {
// to link with C sources via gcc
let func_symbol = symbol(func_name.clone());
self.add_asm_symbolic(directive_globl(func_symbol.clone()));
self.add_asm_symbolic(format!(".type {}, @function", func_symbol.clone()));
self.add_asm_symbolic(format!("{}:", func_symbol.clone()));
ValueLocation::Relocatable(RegGroup::GPR, func_name)
......@@ -2023,6 +2033,7 @@ impl CodeGenerator for ASMCodeGen {
};
self.add_asm_symbolic(directive_globl(symbol(func_end.clone())));
self.add_asm_symbolic(format!("{}:", symbol(func_end.clone())));
self.add_asm_symbolic(format!(".size {}, {}-{}", symbol(func_name.clone()), symbol(func_end.clone()), symbol(func_name.clone())));
self.cur.as_mut().unwrap().control_flow_analysis();
......@@ -2093,6 +2104,10 @@ impl CodeGenerator for ASMCodeGen {
}
}
fn block_exists(&self, block_name: MuName) -> bool {
self.cur().blocks.contains_key(&block_name)
}
fn set_block_livein(&mut self, block_name: MuName, live_in: &Vec<P<Value>>) {
let cur = self.cur_mut();
......@@ -2147,22 +2162,22 @@ impl CodeGenerator for ASMCodeGen {
}
fn add_cfi_startproc(&mut self) {
self.add_asm_symbolic(".cfi_startproc".to_string());
self.add_asm_symbolic("\t.cfi_startproc".to_string());
}
fn add_cfi_endproc(&mut self) {
self.add_asm_symbolic(".cfi_endproc".to_string());
self.add_asm_symbolic("\t.cfi_endproc".to_string());
}
fn add_cfi_def_cfa_register(&mut self, reg: Reg) {
let reg = self.asm_reg_op(reg);
self.add_asm_symbolic(format!(".cfi_def_cfa_register {}", reg));
self.add_asm_symbolic(format!("\t.cfi_def_cfa_register {}", reg));
}
fn add_cfi_def_cfa_offset(&mut self, offset: i32) {
self.add_asm_symbolic(format!(".cfi_def_cfa_offset {}", offset));
self.add_asm_symbolic(format!("\t.cfi_def_cfa_offset {}", offset));
}
fn add_cfi_offset(&mut self, reg: Reg, offset: i32) {
let reg = self.asm_reg_op(reg);
self.add_asm_symbolic(format!(".cfi_offset {}, {}", reg, offset));
self.add_asm_symbolic(format!("\t.cfi_offset {}, {}", reg, offset));
}
fn emit_frame_grow(&mut self) {
......@@ -2258,7 +2273,7 @@ impl CodeGenerator for ASMCodeGen {
fn emit_blr(&mut self, callsite: String, func: Reg, pe: Option<MuName>) -> ValueLocation {
trace!("emit: \tBLR {}", func);
let (reg1, id1, loc1) = self.prepare_reg(func, 2 + 1);
let (reg1, id1, loc1) = self.prepare_reg(func, 3 + 1);
let asm = format!("BLR {}", reg1);
self.add_asm_call(asm, pe, Some((id1, loc1)));
......@@ -2333,8 +2348,8 @@ impl CodeGenerator for ASMCodeGen {
// Address calculation
fn emit_adr(&mut self, dest: Reg, src: Mem) { self.internal_load("ADR", dest, src, false, false) }
fn emit_adrp(&mut self, dest: Reg, src: Mem) { self.internal_load("ADRP", dest, src, false, false) }
fn emit_adr(&mut self, dest: Reg, src: Mem) { self.internal_load("ADR", dest, src, false, false, false) }
fn emit_adrp(&mut self, dest: Reg, src: Mem) { self.internal_load("ADRP", dest, src, false, false, false) }
// Unary operators
fn emit_mov(&mut self, dest: Reg, src: Reg) { self.internal_unop("MOV", dest, src) }
......@@ -2407,6 +2422,22 @@ impl CodeGenerator for ASMCodeGen {
)
}
// The 'str' will be patched by the linker (used to access global variables)
fn emit_add_str(&mut self, dest: Reg, src1: Reg, src2: &str) {
trace!("emit: \tADD {}, {} -> {}", src1, src2, dest);
let (reg1, id1, loc1) = self.prepare_reg(dest, 3 + 1);
let (reg2, id2, loc2) = self.prepare_reg(src1, 3 + 1 + reg1.len() + 1);
let asm = format!("ADD {},{},#{}", reg1, reg2, src2);
self.add_asm_inst(
asm,
ignore_zero_register(id1, vec![loc1]),
ignore_zero_register(id2, vec![loc2]),
false
)
}
// Binary operations with immediates
fn emit_add_imm(&mut self, dest: Reg, src1: Reg, src2: u16, shift: bool) {self.internal_binop_imm("ADD", dest, src1, src2 as u64, if shift {12} else {0})}
fn emit_adds_imm(&mut self, dest: Reg, src1: Reg, src2: u16, shift: bool) {self.internal_binop_imm("ADDS", dest, src1, src2 as u64, if shift {12} else {0})}
......@@ -2590,13 +2621,17 @@ impl CodeGenerator for ASMCodeGen {
)
}
fn emit_ldr_callee_saved(&mut self, dest: Reg, src: Mem) { self.internal_load("LDR", dest, src, false, false, true); }
fn emit_str_callee_saved(&mut self, dest: Mem, src: Reg) { self.internal_store("STR", dest, src, false, true) }
// Loads
fn emit_ldr(&mut self, dest: Reg, src: Mem, signed: bool) { self.internal_load("LDR", dest, src, signed, false); }
fn emit_ldtr(&mut self, dest: Reg, src: Mem, signed: bool) { self.internal_load("LDTR", dest, src, signed, false); }
fn emit_ldur(&mut self, dest: Reg, src: Mem, signed: bool) { self.internal_load("LDUR", dest, src, signed, false); }
fn emit_ldxr(&mut self, dest: Reg, src: Mem) { self.internal_load("LDXR", dest, src, false, false); }
fn emit_ldaxr(&mut self, dest: Reg, src: Mem) { self.internal_load("LDAXR", dest, src, false, false); }
fn emit_ldar(&mut self, dest: Reg, src: Mem) { self.internal_load("LDAR", dest, src, false, false); }
fn emit_ldr(&mut self, dest: Reg, src: Mem, signed: bool) { self.internal_load("LDR", dest, src, signed, false, false); }
fn emit_ldtr(&mut self, dest: Reg, src: Mem, signed: bool) { self.internal_load("LDTR", dest, src, signed, false, false); }
fn emit_ldur(&mut self, dest: Reg, src: Mem, signed: bool) { self.internal_load("LDUR", dest, src, signed, false, false); }
fn emit_ldxr(&mut self, dest: Reg, src: Mem) { self.internal_load("LDXR", dest, src, false, false, false); }
fn emit_ldaxr(&mut self, dest: Reg, src: Mem) { self.internal_load("LDAXR", dest, src, false, false, false); }
fn emit_ldar(&mut self, dest: Reg, src: Mem) { self.internal_load("LDAR", dest, src, false, false, false); }
// Load pair
fn emit_ldp(&mut self, dest1: Mem, dest2: Reg, src: Mem) { self.internal_load_pair("LDP", dest1, dest2, src) }
......@@ -2605,12 +2640,12 @@ impl CodeGenerator for ASMCodeGen {
fn emit_ldnp(&mut self, dest1: Mem, dest2: Reg, src: Mem) { self.internal_load_pair("LDNP", dest1, dest2, src) }
// Stores
fn emit_str(&mut self, dest: Mem, src: Reg) { self.internal_store("STR", dest, src, false) }
fn emit_sttr(&mut self, dest: Mem, src: Reg) { self.internal_store("STTR", dest, src, false) }
fn emit_stur(&mut self, dest: Mem, src: Reg) { self.internal_store("STUR", dest, src, false) }
fn emit_str(&mut self, dest: Mem, src: Reg) { self.internal_store("STR", dest, src, false, false) }
fn emit_sttr(&mut self, dest: Mem, src: Reg) { self.internal_store("STTR", dest, src, false, false) }
fn emit_stur(&mut self, dest: Mem, src: Reg) { self.internal_store("STUR", dest, src, false, false) }
fn emit_stxr(&mut self, dest: Mem, status: Reg, src: Reg) { self.internal_store_exclusive("STXR", dest, status, src) }
fn emit_stlxr(&mut self, dest: Mem, status: Reg, src: Reg) { self.internal_store_exclusive("STLXR", dest, status, src) }
fn emit_stlr(&mut self, dest: Mem, src: Reg) { self.internal_store("STLR", dest, src, false) }
fn emit_stlr(&mut self, dest: Mem, src: Reg) { self.internal_store("STLR", dest, src, false, false) }
// Store Pairs
fn emit_stp(&mut self, dest: Mem, src1: Reg, src2: Reg) { self.internal_store_pair("STP", dest, src1, src2) }
......@@ -2713,11 +2748,11 @@ pub fn emit_code(fv: &mut MuFunctionVersion, vm: &VM) {
Ok(file) => file
};
file.write("\t.arch armv8-a\n".as_bytes()).unwrap();
// constants in text section
file.write("\t.text\n".as_bytes()).unwrap();
// FIXME: need a more precise way to determine alignment
// (probably use alignment backend info, which require introducing int128 to zebu)
write_const_min_align(&mut file);
for (id, constant) in cf.consts.iter() {
......@@ -2734,8 +2769,8 @@ pub fn emit_code(fv: &mut MuFunctionVersion, vm: &VM) {
}
}
// min alignment as 16 byte (written as 4 (2^4) on macos)
const MIN_ALIGN : ByteSize = 16;
// min alignment as 4 bytes
const MIN_ALIGN : ByteSize = 4;
fn check_min_align(align: ByteSize) -> ByteSize {
if align > MIN_ALIGN {
......@@ -2752,7 +2787,7 @@ fn write_const_min_align(f: &mut File) {
#[cfg(target_os = "linux")]
fn write_align(f: &mut File, align: ByteSize) {
use std::io::Write;
f.write_fmt(format_args!("\t.align {}\n", check_min_align(align))).unwrap();
f.write_fmt(format_args!("\t.balign {}\n", check_min_align(align))).unwrap();
}
fn write_const(f: &mut File, constant: P<Value>, loc: P<Value>) {
......@@ -2994,7 +3029,7 @@ fn directive_globl(name: String) -> String {
}
fn directive_comm(name: String, size: ByteSize, align: ByteSize) -> String {
format!(".comm {},{},{}", name, size, align)
format!("\t.comm {},{},{}", name, size, align)
}
#[cfg(target_os = "linux")]
......
......@@ -16,6 +16,7 @@ pub trait CodeGenerator {
fn print_cur_code(&self);
fn start_block(&mut self, block_name: MuName);
fn block_exists(&self, block_name: MuName) -> bool;
fn start_exception_block(&mut self, block_name: MuName) -> ValueLocation;
fn set_block_livein(&mut self, block_name: MuName, live_in: &Vec<P<Value>>);
fn set_block_liveout(&mut self, block_name: MuName, live_out: &Vec<P<Value>>);
......@@ -38,6 +39,10 @@ pub trait CodeGenerator {
fn emit_push_pair(&mut self, src1: Reg, src2: Reg, stack: Reg); // Emits a STP
fn emit_pop_pair(&mut self, dest1: Reg, dest2: Reg, stack: Reg); // Emits a LDP
// For callee saved loads and stores (flags them so that only they are removed)
fn emit_ldr_callee_saved(&mut self, dest: Reg, src: Mem);
fn emit_str_callee_saved(&mut self, dest: Mem, src: Reg);
/* DON'T IMPLEMENT
SIMD instructions (unless they operate soley on GPRS or Dn, and Sn registers)
......@@ -266,6 +271,9 @@ TODO:
fn emit_orr_shift(&mut self, dest: Reg, src1: Reg, src2: Reg, shift: &str, amount: u8);
// binary ops with immediates
// The 'str' will be patched by the linker (used to access global variables)
fn emit_add_str(&mut self, dest: Reg, src1: Reg, src2: &str);
fn emit_add_imm(&mut self, dest: Reg, src1: Reg, src2: u16, shift: bool);
fn emit_adds_imm(&mut self, dest: Reg, src1: Reg, src2: u16, shift: bool);
fn emit_sub_imm(&mut self, dest: Reg, src1: Reg, src2: u16, shift: bool);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -335,7 +335,7 @@ lazy_static! {
X27.clone(),
X28.clone(),
// Note: These two are technically CALEE saved but need to be dealt with specially
// Note: These two are technically CALLEE saved but need to be dealt with specially
//X29.clone(), // Frame Pointer
//X30.clone() // Link Register
];
......@@ -608,6 +608,33 @@ lazy_static! {
map
};
pub static ref CALLEE_SAVED_REGs : [P<Value>; 18] = [
X19.clone(),
X20.clone(),
X21.clone(),
X22.clone(),
X23.clone(),
X24.clone(),
X25.clone(),
X26.clone(),
X27.clone(),
X28.clone(),
// Note: These two are technically CALLEE saved but need to be dealt with specially
//X29.clone(), // Frame Pointer
//X30.clone() // Link Register
D8.clone(),
D9.clone(),
D10.clone(),
D11.clone(),
D12.clone(),
D13.clone(),
D14.clone(),
D15.clone()
];
// put caller saved regs first (they imposes no overhead if there is no call instruction)
pub static ref ALL_USABLE_MACHINE_REGs : Vec<P<Value>> = vec![
X19.clone(),
......@@ -789,7 +816,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
// Splits an integer immediate into four 16-bit segments (returns the least significant first)
pub fn split_aarch64_iimm(val: u64) -> (u16, u16, u16, u16) {
pub fn split_aarch64_imm_u64(val: u64) -> (u16, u16, u16, u16) {
(val as u16, (val >> 16) as u16, (val >> 32) as u16, (val >> 48) as u16)
}
......@@ -852,10 +879,10 @@ pub fn get_bit(x: u64, i: usize) -> bool {
(x & ((1 as u64) << i) ) != 0
}
// Returns true if val = A << S, from some A < 4096, and S = 0 or S = 12
// Returns true if val = A << S, from some 0 <= A < 4096, and S = 0 or S = 12
// Note: Even though '0' is a valid arithmetic immediate, the Zero register should be used instead
pub fn is_valid_arithmetic_imm(val : u64) -> bool {
val < 4096 || ((val & 0b111111111111) == 0 && val < (4096 << 12))
val > 0 && val < 4096 || ((val & 0b111111111111) == 0 && val < (4096 << 12))
}
// aarch64 instructions only operate on 32 and 64-bit registers
......@@ -1107,15 +1134,15 @@ pub fn round_up(n: usize, d: usize) -> usize { ((n + d - 1)/d)*d }
// TODO: Implement this more efficiently?
pub fn log2(val: u64) -> u64 {
debug_assert!(val.is_power_of_two());
/*debug_assert!(val != 0);
debug_assert!(val != 0);
let mut ret = 0;
for i in 0..63 {
if val & (1 << i) != 0 {
ret = i;
}
}*/
}
// WARNING: This will only work for val < 2^31
let ret = (val as f64).log2() as u64;
//let ret = (val as f64).log2() as u64;
debug_assert!(val == 1 << ret);
ret
}
......
......@@ -25,6 +25,7 @@ use std::str;
use std::usize;
use std::slice::Iter;
use std::ops;
use std::collections::HashSet;
struct ASMCode {
name: MuName,
......@@ -655,51 +656,41 @@ impl MachineCode for ASMCode {
// self.code.insert(index, ASMInst::nop());
}
fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> (Vec<MuID>, usize) {
fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> HashSet<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> {
let find_op_other_than_rbp = |inst: &ASMInst| -> MuID {
for id in inst.defines.keys() {
if *id != rsp && *id != rbp {
return Some(*id);
if *id != rbp {
return *id;
}
}
for id in inst.uses.keys() {
if *id != rsp && *id != rbp {
return Some(*id);
if *id != rbp {
return *id;
}
}
None
panic!("Expected to find a used register other than the rbp");
};
let mut inst_to_remove = vec![];
let mut regs_to_remove = vec![];
let mut kept_callee_saved = 0;
let mut regs_to_remove = HashSet::new();
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) {
if used_callee_saved.contains(&op) {
kept_callee_saved += 1;
} else {
trace!("removing instruction {:?} for save/restore unnecessary callee saved regs", inst);
regs_to_remove.push(op);
inst_to_remove.push(i);
}
}
match inst.spill_info {
Some(SpillMemInfo::CalleeSaved) => {
let reg = find_op_other_than_rbp(inst);
if !used_callee_saved.contains(&reg) {
trace!("removing instruction {:?} for save/restore unnecessary callee saved regs", inst);
regs_to_remove.insert(reg);
inst_to_remove.push(i);
}
None => {}
}
_ => {}
}
}
......@@ -707,11 +698,10 @@ impl MachineCode for ASMCode {
self.set_inst_nop(i);
}
(regs_to_remove, kept_callee_saved)
regs_to_remove
}
#[allow(unused_variables)]
fn patch_frame_size(&mut self, size: usize, size_used: usize) {
fn patch_frame_size(&mut self, size: usize) {
let size = size.to_string();
debug_assert!(size.len() <= FRAME_SIZE_PLACEHOLDER_LEN);
......@@ -841,7 +831,8 @@ enum ASMBranchTarget {
#[derive(Clone, Debug)]
enum SpillMemInfo {
Load(P<Value>),
Store(P<Value>)
Store(P<Value>),
CalleeSaved, // Callee saved record
}
#[derive(Clone, Debug)]
......@@ -1080,6 +1071,16 @@ impl ASMCodeGen {
self.add_asm_inst_internal(code, defines, uses, is_using_mem_op, ASMBranchTarget::None, None)
}
fn add_asm_inst_with_callee_saved(
&mut self,
code: String,
defines: LinkedHashMap<MuID, Vec<ASMLocation>>,
uses: LinkedHashMap<MuID, Vec<ASMLocation>>,
is_using_mem_op: bool,
) {
self.add_asm_inst_internal(code, defines, uses, is_using_mem_op, ASMBranchTarget::None, Some(SpillMemInfo::CalleeSaved))
}
fn add_asm_inst_with_spill(
&mut self,
code: String,
......@@ -1624,7 +1625,7 @@ impl ASMCodeGen {
}
fn internal_mov_r_mem(&mut self, inst: &str, dest: Reg, src: Mem,
is_spill_related: bool
is_spill_related: bool, is_callee_saved: bool
) {
let len = check_op_len(dest);
......@@ -1636,7 +1637,16 @@ impl ASMCodeGen {
let asm = format!("{} {},{}", inst, mem, reg);
if is_spill_related {
if is_callee_saved {
self.add_asm_inst_with_callee_saved(
asm,
linked_hashmap!{
id2 => vec![loc2]
},
uses,
true,
)
} else if is_spill_related {
self.add_asm_inst_with_spill(
asm,
linked_hashmap!{
......@@ -1659,7 +1669,7 @@ impl ASMCodeGen {
}
fn internal_mov_mem_r(&mut self, inst: &str, dest: Mem, src: Reg,
is_spill_related: bool)
is_spill_related: bool, is_callee_saved: bool)
{
let len = check_op_len(src);
......@@ -1680,7 +1690,14 @@ impl ASMCodeGen {
let asm = format!("{} {},{}", inst, reg, mem);
if is_spill_related {
if is_callee_saved {
self.add_asm_inst_with_callee_saved(
asm,
linked_hashmap! {},
uses,
true,
)
} else if is_spill_related {
self.add_asm_inst_with_spill(
asm,
linked_hashmap!{},
......@@ -1843,11 +1860,11 @@ impl ASMCodeGen {
}
fn emit_spill_store_gpr(&mut self, dest: Mem, src: Reg) {
self.internal_mov_mem_r("mov", dest, src, true)
self.internal_mov_mem_r("mov", dest, src, true, false)
}