GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

Commit db9e7d2f authored by qinsoon's avatar qinsoon

reg alloc works fine

(for callee saved regs, we insert push/pop before reg alloc. and
after allocation, remove unnecessary ones)
parent ed646119
......@@ -444,6 +444,56 @@ impl MachineCode for ASMCode {
self.code.insert(index, ASMInst::nop());
}
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
}
fn emit(&self) -> Vec<u8> {
let mut ret = vec![];
......
......@@ -14,6 +14,7 @@ use runtime::entrypoints::RuntimeEntrypoint;
use compiler::CompilerPass;
use compiler::backend;
use compiler::backend::PROLOGUE_BLOCK_NAME;
use compiler::backend::x86_64;
use compiler::backend::x86_64::CodeGenerator;
use compiler::backend::x86_64::ASMCodeGen;
......@@ -898,7 +899,7 @@ impl <'a> InstructionSelection {
}
fn emit_common_prologue(&mut self, args: &Vec<P<Value>>, vm: &VM) {
let block_name = "prologue".to_string();
let block_name = PROLOGUE_BLOCK_NAME.to_string();
self.backend.start_block(block_name.clone());
// no livein
......@@ -914,10 +915,12 @@ impl <'a> InstructionSelection {
// push all callee-saved registers
{
let frame = self.current_frame.as_mut().unwrap();
let rbp = x86_64::RBP.extract_ssa_id().unwrap();
for i in 0..x86_64::CALLEE_SAVED_GPRs.len() {
let ref reg = x86_64::CALLEE_SAVED_GPRs[i];
// not pushing rbp (as we have done taht)
if reg.extract_ssa_id().unwrap() != x86_64::RBP.extract_ssa_id().unwrap() {
// not pushing rbp (as we have done that)
if reg.extract_ssa_id().unwrap() != rbp {
trace!("allocate frame slot for reg {}", reg);
self.backend.emit_push_r64(&reg);
frame.alloc_slot_for_callee_saved_reg(reg.clone(), vm);
}
......
......@@ -11,6 +11,10 @@ pub const WORD_SIZE : ByteSize = 8;
pub const AOT_EMIT_DIR : &'static str = "emit";
pub const AOT_EMIT_CONTEXT_FILE : &'static str = "context.s";
// this is not full name, but pro/epilogue name is generated from this
pub const PROLOGUE_BLOCK_NAME: &'static str = "prologue";
pub const EPILOGUE_BLOCK_NAME: &'static str = "epilogue";
// X86_64
#[cfg(target_arch = "x86_64")]
......
......@@ -9,6 +9,7 @@ pub use compiler::backend::reg_alloc::graph_coloring::coloring::GraphColoring;
use ast::ir::*;
use vm::VM;
use compiler::CompilerPass;
use compiler::backend::is_callee_saved;
use compiler::backend::init_machine_regs_for_func;
use std::any::Any;
......@@ -58,6 +59,24 @@ impl RegisterAllocation {
}
}
// find out what callee saved registers are used
{
use std::collections::HashSet;
let used_callee_saved: HashSet<MuID> =
coloring.cf.temps.values()
.map(|x| *x)
.filter(|x| is_callee_saved(*x))
.collect();
let used_callee_saved: Vec<MuID> = used_callee_saved.into_iter().collect();
let removed_callee_saved = coloring.cf.mc_mut().remove_unnecessary_callee_saved(used_callee_saved);
for reg in removed_callee_saved {
coloring.cf.frame.remove_record_for_callee_saved_reg(reg);
}
}
coloring.cf.mc().trace_mc();
}
}
......
......@@ -61,6 +61,10 @@ impl Frame {
slot.make_memory_op(reg.ty.clone(), vm)
}
pub fn remove_record_for_callee_saved_reg(&mut self, reg: MuID) {
self.allocated.remove(&reg);
}
pub fn alloc_slot_for_spilling(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
let slot = self.alloc_slot(&reg, vm);
slot.make_memory_op(reg.ty.clone(), vm)
......
......@@ -10,7 +10,9 @@ use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
pub struct CompiledFunction {
pub func_id: MuID,
pub func_ver_id: MuID,
pub temps: HashMap<MuID, MuID>, // assumes one temporary maps to one register
// assumes one temporary maps to one register
pub temps: HashMap<MuID, MuID>,
// not emitting this
pub mc: Option<Box<MachineCode + Send + Sync>>,
......@@ -122,10 +124,15 @@ pub trait MachineCode {
// functions for rewrite
/// replace a temp with a machine register (to_reg must be a machine register)
fn replace_reg(&mut self, from: MuID, to: MuID);
/// replace a temp with another temp
/// replace a temp that is defined in the inst with another temp
fn replace_define_tmp_for_inst(&mut self, from: MuID, to: MuID, inst: usize);
/// replace a temp that is used in the inst with another temp
fn replace_use_tmp_for_inst(&mut self, from: MuID, to: MuID, inst: usize);
/// set an instruction as nop
fn set_inst_nop(&mut self, index: usize);
/// remove unnecessary push/pop if the callee saved register is not used
/// returns what registers push/pop have been deleted
fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> Vec<MuID>;
fn as_any(&self) -> &Any;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment