Commit 37e86924 authored by qinsoon's avatar qinsoon

[wip] set up initial status for reg alloc validation at the beginning of

a function
parent a1db31ea
......@@ -1081,12 +1081,24 @@ impl PartialEq for MuEntityHeader {
}
}
const PRINT_ABBREVIATE_NAME: bool = false;
impl fmt::Display for MuEntityHeader {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.name().is_none() {
write!(f, "UNNAMED #{}", self.id)
} else {
write!(f, "{} #{}", self.name().unwrap(), self.id)
if PRINT_ABBREVIATE_NAME {
let name = self.name().unwrap().clone();
let abbr_name = name.split('.').map(
|x| match x.chars().next() {
Some(c) => c,
None => '_'
}).fold("".to_string(), |mut acc, x| {acc.push(x); acc});
write!(f, "{} #{}", abbr_name, self.id)
} else {
write!(f, "{} #{}", self.name().unwrap(), self.id)
}
}
}
}
......
......@@ -1957,7 +1957,7 @@ impl <'a> InstructionSelection {
tmp_res
}
fn emit_load_base_offset (&mut self, dest: &P<Value>, base: &P<Value>, offset: i32, vm: &VM) {
fn emit_load_base_offset (&mut self, dest: &P<Value>, base: &P<Value>, offset: i32, vm: &VM) -> P<Value> {
let mem = self.make_memory_op_base_offset(base, offset, dest.ty.clone(), vm);
if dest.is_int_reg() {
......@@ -1967,6 +1967,8 @@ impl <'a> InstructionSelection {
} else {
unimplemented!();
}
mem
}
fn emit_store_base_offset (&mut self, base: &P<Value>, offset: i32, src: &P<Value>, vm: &VM) {
......@@ -2558,10 +2560,11 @@ impl <'a> InstructionSelection {
self.backend.emit_push_r64(&x86_64::RBP);
// mov rsp -> rbp
self.backend.emit_mov_r_r(&x86_64::RBP, &x86_64::RSP);
// 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];
......@@ -2596,23 +2599,32 @@ impl <'a> InstructionSelection {
};
self.backend.emit_mov_r_r(&arg, &arg_gpr);
self.current_frame.as_mut().unwrap().add_argument_by_reg(arg.id(), arg_gpr.clone());
gpr_arg_count += 1;
} else {
// unload from stack
self.emit_load_base_offset(&arg, &x86_64::RBP.clone(), stack_arg_offset, vm);
let stack_slot = self.emit_load_base_offset(&arg, &x86_64::RBP.clone(), stack_arg_offset, vm);
self.current_frame.as_mut().unwrap().add_argument_by_stack(arg.id(), stack_slot);
// move stack_arg_offset by the size of 'arg'
let arg_size = vm.get_backend_type_info(arg.ty.id()).size;
stack_arg_offset += arg_size as i32;
}
} else if arg.is_fp_reg() {
if fpr_arg_count < x86_64::ARGUMENT_FPRs.len() {
self.backend.emit_movsd_f64_f64(&arg, &x86_64::ARGUMENT_FPRs[fpr_arg_count]);
let arg_fpr = x86_64::ARGUMENT_FPRs[fpr_arg_count].clone();
self.backend.emit_movsd_f64_f64(&arg, &arg_fpr);
self.current_frame.as_mut().unwrap().add_argument_by_reg(arg.id(), arg_fpr);
fpr_arg_count += 1;
} else {
// unload from stack
self.emit_load_base_offset(&arg, &x86_64::RBP.clone(), stack_arg_offset, vm);
let stack_slot = self.emit_load_base_offset(&arg, &x86_64::RBP.clone(), stack_arg_offset, vm);
self.current_frame.as_mut().unwrap().add_argument_by_stack(arg.id(), stack_slot);
// move stack_arg_offset by the size of 'arg'
let arg_size = vm.get_backend_type_info(arg.ty.id()).size;
......
......@@ -691,4 +691,33 @@ impl <'a> GraphColoring<'a> {
spills
}
pub fn get_assignments(&self) -> LinkedHashMap<MuID, MuID> {
let mut ret = LinkedHashMap::new();
for node in self.ig.nodes() {
let temp = self.ig.get_temp_of(node);
if temp < MACHINE_ID_END {
continue;
} else {
let alias = self.get_alias(node);
let machine_reg = match self.ig.get_color_of(alias) {
Some(reg) => reg,
None => panic!(
"Reg{}/{:?} (aliased as Reg{}/{:?}) is not assigned with a color",
self.ig.get_temp_of(node), node,
self.ig.get_temp_of(alias), alias)
};
ret.insert(temp, machine_reg);
}
}
ret
}
pub fn get_spill_history(&self) -> LinkedHashMap<MuID, P<Value>> {
self.spill_history.clone()
}
}
......@@ -13,6 +13,7 @@ use vm::VM;
use compiler::CompilerPass;
use compiler::backend::is_callee_saved;
use compiler::backend::init_machine_regs_for_func;
use compiler::backend::reg_alloc::validate;
use utils::POINTER_SIZE;
use std::any::Any;
......@@ -38,32 +39,19 @@ impl RegisterAllocation {
let coloring = GraphColoring::start(func, &mut cf, vm);
if !vm.vm_options.flag_disable_regalloc_validate {
let reg_assignment = coloring.get_assignments();
let reg_spilled = coloring.get_spill_history();
validate::validate_regalloc(&coloring.cf, &coloring.func, reg_assignment, reg_spilled)
}
// replace regs
trace!("Replacing Registers...");
for node in coloring.ig.nodes() {
let temp = coloring.ig.get_temp_of(node);
// skip machine registers
if temp < MACHINE_ID_END {
continue;
} else {
let alias = coloring.get_alias(node);
let machine_reg = match coloring.ig.get_color_of(alias) {
Some(reg) => reg,
None => panic!(
"Reg{}/{:?} (aliased as Reg{}/{:?}) is not assigned with a color",
coloring.ig.get_temp_of(node), node,
coloring.ig.get_temp_of(alias), alias)
};
trace!("replacing {} with {}", temp, machine_reg);
coloring.cf.mc_mut().replace_reg(temp, machine_reg);
coloring.cf.temps.insert(temp, machine_reg);
}
for (temp, machine_reg) in coloring.get_assignments() {
trace!("replacing {} with {}", temp, machine_reg);
coloring.cf.mc_mut().replace_reg(temp, machine_reg);
coloring.cf.temps.insert(temp, machine_reg);
}
// find out what callee saved registers are used
......
pub mod graph_coloring;
//mod regalloc_validate;
mod validate;
pub use compiler::backend::reg_alloc::graph_coloring::RegisterAllocation;
pub fn validate_regalloc(spilled: LinkedHashMap<MuID, P<Value>>, ) {
}
\ No newline at end of file
use utils::LinkedHashMap;
use utils::vec_utils;
use ast::ir::*;
use ast::ptr::*;
use compiler::machine_code::CompiledFunction;
use std::fmt;
pub fn validate_regalloc(cf: &CompiledFunction,
func: &MuFunctionVersion,
reg_assigned: LinkedHashMap<MuID, MuID>,
reg_spilled: LinkedHashMap<MuID, P<Value>>)
{
debug!("---Validating register allocation results---");
let mut alive = AliveEntries::new();
debug!("initializing alive entries for arguments...");
// start with arguments with real locations
let ref frame = cf.frame;
for (temp, reg) in frame.argument_by_reg.iter() {
alive.new_alive_reg(reg.id());
}
for (temp, stack) in frame.argument_by_stack.iter() {
alive.new_alive_mem(stack.clone());
}
debug!("alive entries in the beginning");
debug!("{}", alive);
}
type EntryID = usize;
struct AliveEntries {
index: EntryID,
inner: LinkedHashMap<EntryID, RegisterEntry>
}
impl fmt::Display for AliveEntries {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "").unwrap();
writeln!(f, "| {:20} | {:20} | {:20} |", "ssa", "registers", "stack slots").unwrap();
for entry in self.inner.values() {
writeln!(f, "{}", entry).unwrap()
}
Ok(())
}
}
impl AliveEntries {
fn new() -> AliveEntries {
AliveEntries {
index: 0,
inner: LinkedHashMap::new()
}
}
fn new_index(&mut self) -> EntryID {
let ret = self.index;
self.index += 1;
ret
}
fn find_entry_for_reg(&self, reg: MuID) -> Option<&RegisterEntry> {
for entry in self.inner.values() {
if entry.match_reg(reg) {
return Some(entry);
}
}
None
}
fn find_entry_for_reg_mut(&mut self, reg: MuID) -> Option<&mut RegisterEntry> {
for entry in self.inner.values_mut() {
if entry.match_reg(reg) {
return Some(entry);
}
}
None
}
fn new_alive_reg(&mut self, reg: MuID) {
debug!("adding alive reg: {}", reg);
let id = self.new_index();
let entry = RegisterEntry {
temp : None,
real : vec![reg],
stack: vec![]
};
self.inner.insert(id, entry);
}
fn new_alive_mem(&mut self, mem: P<Value>) {
debug!("adding alive mem: {}", mem);
let id = self.new_index();
let entry = RegisterEntry {
temp : None,
real : vec![],
stack: vec![mem]
};
self.inner.insert(id, entry);
}
}
struct RegisterEntry {
temp : Option<MuID>,
real : Vec<MuID>,
stack : Vec<P<Value>>
}
impl RegisterEntry {
fn match_reg(&self, reg: MuID) -> bool {
vec_utils::find_value(&self.real, reg).is_some()
}
}
impl fmt::Display for RegisterEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let temp = match self.temp {
Some(id) => format!("{}", id),
None => "_".to_string()
};
let real = format!("{:?}", self.real);
let stack = format!("{:?}", self.stack);
write!(f, "| {:20} | {:20} | {:20} |", temp, real, stack)
}
}
\ No newline at end of file
......@@ -21,6 +21,9 @@ use vm::VM;
pub struct Frame {
func_ver_id: MuID,
cur_offset: isize, // offset to rbp
pub argument_by_reg: HashMap<MuID, P<Value>>,
pub argument_by_stack: HashMap<MuID, P<Value>>,
pub allocated: HashMap<MuID, FrameSlot>,
// (callsite, destination address)
......@@ -47,6 +50,10 @@ impl Frame {
Frame {
func_ver_id: func_ver_id,
cur_offset: - (POINTER_SIZE as isize * 1), // reserve for old RBP
argument_by_reg: HashMap::new(),
argument_by_stack: HashMap::new(),
allocated: HashMap::new(),
exception_callsites: vec![]
}
......@@ -59,6 +66,14 @@ impl Frame {
pub fn cur_size(&self) -> usize {
self.cur_offset.abs() as usize
}
pub fn add_argument_by_reg(&mut self, temp: MuID, reg: P<Value>) {
self.argument_by_reg.insert(temp, reg);
}
pub fn add_argument_by_stack(&mut self, temp: MuID, stack_slot: P<Value>) {
self.argument_by_stack.insert(temp, stack_slot);
}
pub fn alloc_slot_for_callee_saved_reg(&mut self, reg: P<Value>, vm: &VM) -> P<Value> {
let slot = self.alloc_slot(&reg, vm);
......
......@@ -54,7 +54,7 @@ impl VMOptions {
pub fn init(str: &str) -> VMOptions {
info!("init vm options with: {:?}", str);
let mut ret : VMOptions = Docopt::new(USAGE)
let ret : VMOptions = Docopt::new(USAGE)
.and_then(|d| d.argv(str.split_whitespace().into_iter()).parse())
.unwrap_or_else(|e| e.exit()).decode().unwrap();
......
......@@ -354,6 +354,51 @@ fn lshr() -> VM {
vm
}
#[test]
fn test_add_simple() {
let lib = testutil::compile_fnc("add", &add);
unsafe {
let add : libloading::Symbol<unsafe extern fn(u64, u64) -> u64> = lib.get(b"add").unwrap();
let res = add(1, 1);
println!("add(1, 1) = {}", res);
assert!(res == 2);
}
}
fn add() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
funcsig! ((vm) sig = (int64, int64) -> (int64));
funcdecl! ((vm) <sig> add);
funcdef! ((vm) <sig> add VERSION add_v1);
block! ((vm, add_v1) blk_entry);
ssa! ((vm, add_v1) <int64> a);
ssa! ((vm, add_v1) <int64> b);
// sum = Add %a %b
ssa! ((vm, add_v1) <int64> sum);
inst! ((vm, add_v1) blk_entry_add:
sum = BINOP (BinOp::Add) a b
);
inst! ((vm, add_v1) blk_entry_ret:
RET (sum)
);
define_block! ((vm, add_v1) blk_entry(a, b) {
blk_entry_add, blk_entry_ret
});
define_func_ver!((vm) add_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_add_int64_n() {
let lib = testutil::compile_fnc("add_int64_n", &add_int64_n);
......
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