WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 37e86924 authored by qinsoon's avatar qinsoon
Browse files

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

a function
parent a1db31ea
......@@ -1081,14 +1081,26 @@ 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 {
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)
}
}
}
}
pub trait MuEntity {
......
......@@ -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) {
......@@ -2562,6 +2564,7 @@ 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];
......@@ -2596,11 +2599,14 @@ 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;
......@@ -2608,11 +2614,17 @@ impl <'a> InstructionSelection {
}
} 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,33 +39,20 @@ 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)
};
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.mc_mut().replace_reg(temp, machine_reg);
coloring.cf.temps.insert(temp, machine_reg);
}
}
// find out what callee saved registers are used
// FIXME: current not doing this
......
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
......@@ -22,6 +22,9 @@ 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)
exception_callsites: Vec<(ValueLocation, ValueLocation)>
......@@ -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![]
}
......@@ -60,6 +67,14 @@ impl Frame {
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);
slot.make_memory_op(reg.ty.clone(), 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