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 7f5165b0 authored by qinsoon's avatar qinsoon
Browse files

[wip] regalloc check for sequential code (not considering stack slots)

parent 37e86924
#![allow(dead_code)]
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 {
pub struct AliveEntries {
index: EntryID,
inner: LinkedHashMap<EntryID, RegisterEntry>
......@@ -40,7 +16,7 @@ struct AliveEntries {
impl fmt::Display for AliveEntries {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "").unwrap();
writeln!(f, "{} entries", self.inner.len()).unwrap();
writeln!(f, "| {:20} | {:20} | {:20} |", "ssa", "registers", "stack slots").unwrap();
for entry in self.inner.values() {
writeln!(f, "{}", entry).unwrap()
......@@ -51,7 +27,7 @@ impl fmt::Display for AliveEntries {
}
impl AliveEntries {
fn new() -> AliveEntries {
pub fn new() -> AliveEntries {
AliveEntries {
index: 0,
inner: LinkedHashMap::new()
......@@ -65,7 +41,27 @@ impl AliveEntries {
ret
}
fn find_entry_for_reg(&self, reg: MuID) -> Option<&RegisterEntry> {
pub fn find_entry_for_temp(&self, temp: MuID) -> Option<&RegisterEntry> {
for entry in self.inner.values() {
if entry.match_temp(temp) {
return Some(entry);
}
}
None
}
pub fn find_entry_for_temp_mut(&mut self, temp: MuID) -> Option<&mut RegisterEntry> {
for entry in self.inner.values_mut() {
if entry.match_temp(temp) {
return Some(entry)
}
}
None
}
pub fn find_entry_for_reg(&self, reg: MuID) -> Option<&RegisterEntry> {
for entry in self.inner.values() {
if entry.match_reg(reg) {
return Some(entry);
......@@ -75,7 +71,7 @@ impl AliveEntries {
None
}
fn find_entry_for_reg_mut(&mut self, reg: MuID) -> Option<&mut RegisterEntry> {
pub 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);
......@@ -85,7 +81,7 @@ impl AliveEntries {
None
}
fn new_alive_reg(&mut self, reg: MuID) {
pub fn new_alive_reg(&mut self, reg: MuID) {
debug!("adding alive reg: {}", reg);
let id = self.new_index();
......@@ -98,7 +94,7 @@ impl AliveEntries {
self.inner.insert(id, entry);
}
fn new_alive_mem(&mut self, mem: P<Value>) {
pub fn new_alive_mem(&mut self, mem: P<Value>) {
debug!("adding alive mem: {}", mem);
let id = self.new_index();
......@@ -110,18 +106,85 @@ impl AliveEntries {
self.inner.insert(id, entry);
}
pub fn add_temp_in_reg(&mut self, temp: MuID, reg: MuID) {
debug!("adding alive temp in reg: {} in {}", temp, reg);
let entry_exists = self.find_entry_for_temp(temp).is_some();
if entry_exists {
let mut entry = self.find_entry_for_temp_mut(temp).unwrap();
entry.add_real_reg(reg);
} else {
let id = self.new_index();
let entry = RegisterEntry {
temp: Some(temp),
real: vec![reg],
stack: vec![]
};
self.inner.insert(id, entry);
}
}
pub fn remove_reg(&mut self, reg: MuID) {
debug!("removing alive reg: {}", reg);
let mut indices = vec![];
for (index, entry) in self.inner.iter() {
if entry.match_reg(reg) {
indices.push(*index);
}
}
for index in indices {
self.inner.remove(&index);
}
}
pub fn remove_temp(&mut self, reg: MuID) {
debug!("removing alive temp: {}", reg);
let index = {
let mut ret = 0;
for (index, entry) in self.inner.iter() {
if entry.match_temp(reg) {
ret = *index;
}
}
ret
};
self.inner.remove(&index);
}
}
struct RegisterEntry {
pub struct RegisterEntry {
temp : Option<MuID>,
real : Vec<MuID>,
stack : Vec<P<Value>>
}
impl RegisterEntry {
fn match_reg(&self, reg: MuID) -> bool {
pub fn match_temp(&self, temp: MuID) -> bool {
if self.temp.is_some() && self.temp.unwrap() == temp {
true
} else {
false
}
}
pub fn match_reg(&self, reg: MuID) -> bool {
vec_utils::find_value(&self.real, reg).is_some()
}
pub fn add_real_reg(&mut self, reg: MuID) {
if vec_utils::find_value(&mut self.real, reg).is_none() {
self.real.push(reg);
}
}
}
impl fmt::Display for RegisterEntry {
......
use utils::LinkedHashMap;
use utils::LinkedHashSet;
use ast::ir::*;
use compiler::machine_code::CompiledFunction;
pub struct ExactLiveness {
livein : LinkedHashMap<usize, LinkedHashSet<MuID>>,
liveout: LinkedHashMap<usize, LinkedHashSet<MuID>>,
kill : LinkedHashMap<usize, LinkedHashSet<MuID>>
}
impl ExactLiveness {
pub fn new(cf: &CompiledFunction) -> ExactLiveness {
let mut ret = ExactLiveness {
livein: LinkedHashMap::new(),
liveout: LinkedHashMap::new(),
kill: LinkedHashMap::new()
};
ret.liveness_analysis(cf);
ret
}
fn liveness_analysis(&mut self, cf: &CompiledFunction) {
let mc = cf.mc();
for block in mc.get_all_blocks().iter() {
let range = mc.get_block_range(block).unwrap();
let mut liveout : LinkedHashSet<MuID> = LinkedHashSet::from_vec(mc.get_ir_block_liveout(block).unwrap().clone());
for i in range.rev() {
// set liveout
self.liveout.insert(i, liveout.clone());
// compute livein: in[n] <- use[n] + (out[n] - def[n])
for reg_def in mc.get_inst_reg_defines(i) {
liveout.remove(&reg_def);
}
for reg_use in mc.get_inst_reg_uses(i) {
liveout.insert(reg_use);
}
// liveout is livein now
self.livein.insert(i, liveout.clone());
// liveout for prev inst is livein for current inst
}
}
// liveness analysis done
// compute 'kill': if a reg is in livein of an inst, but not liveout, it kills in the inst
for i in self.livein.keys() {
let mut kill : LinkedHashSet<MuID> = LinkedHashSet::new();
let livein = self.livein.get(i).unwrap();
let liveout = self.liveout.get(i).unwrap();
for reg in livein.iter() {
if !liveout.contains(reg) {
kill.insert(*reg);
}
}
self.kill.insert(*i, kill);
}
}
pub fn get_kills(&self, index: usize) -> Option<LinkedHashSet<MuID>> {
match self.kill.get(&index) {
Some(s) => Some(s.clone()),
None => None
}
}
pub fn trace(&self, index: usize) {
if self.livein.contains_key(&index) {
trace!("in : {:?}", self.livein.get(&index).unwrap());
trace!("out : {:?}", self.liveout.get(&index).unwrap());
trace!("kill: {:?}", self.kill.get(&index).unwrap());
}
}
}
\ No newline at end of file
use utils::LinkedHashMap;
use ast::ir::*;
use ast::ptr::*;
use compiler::machine_code::CompiledFunction;
use compiler::backend::get_color_for_precolored as alias;
mod alive_entry;
use compiler::backend::reg_alloc::validate::alive_entry::*;
mod exact_liveness;
use compiler::backend::reg_alloc::validate::exact_liveness::*;
pub fn validate_regalloc(cf: &CompiledFunction,
func: &MuFunctionVersion,
reg_assigned: LinkedHashMap<MuID, MuID>,
reg_spilled: LinkedHashMap<MuID, P<Value>>)
{
debug!("---Validating register allocation results---");
debug!("liveness analysis...");
let liveness = ExactLiveness::new(cf);
for i in 0..cf.mc().number_of_insts() {
cf.mc().trace_inst(i);
liveness.trace(i);
}
let mut alive = AliveEntries::new();
debug!("initializing alive entries for arguments...");
// set up initial states
// machine specific regs, such as program counter, stack pointer, etc
add_machine_specific_regs_at_func_start(&mut alive);
// arguments with real locations
let ref frame = cf.frame;
for (_, reg) in frame.argument_by_reg.iter() {
alive.new_alive_reg(alias(reg.id()));
}
for (_, stack) in frame.argument_by_stack.iter() {
alive.new_alive_mem(stack.clone());
}
debug!("alive entries in the beginning");
debug!("{}", alive);
let mc = cf.mc();
for i in 0..mc.number_of_insts() {
mc.trace_inst(i);
if mc.is_jump(i) {
// we need to flow-sensitive analysis
unimplemented!();
}
for reg_use in mc.get_inst_reg_uses(i) {
validate_use(reg_use, &reg_assigned, &alive);
}
// remove kills in the inst from alive entries
if let Some(kills) = liveness.get_kills(i) {
for reg in kills.iter() {
remove_kill(*reg, &reg_assigned, &mut alive);
}
}
// add defines to alive entries
for reg_def in mc.get_inst_reg_defines(i) {
add_def(reg_def, &reg_assigned, &mut alive);
}
debug!("{}", alive);
trace!("---");
}
}
fn get_machine_reg(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>) -> MuID {
// find machine regs
if reg < MACHINE_ID_END {
reg
} else {
match reg_assigned.get(&reg) {
Some(reg) => *reg,
None => panic!("Temp {} is not assigned to any machine register", reg)
}
}
}
fn validate_use(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>, alive: &AliveEntries) {
if reg < MACHINE_ID_END {
// machine register
// instruction selector choose to use machine registers
// it is not about the correctness of register allocation, we do not verify it here
} else {
let machine_reg = get_machine_reg(reg, reg_assigned);
let temp = reg;
// ensure temp is assigned to the same machine reg in alive entries
if let Some(entry) = alive.find_entry_for_temp(temp) {
if !entry.match_reg(machine_reg) {
error!("Temp{}/MachineReg{} does not match at this point. ", temp, machine_reg);
error!("Temp{} is assigned as {}", temp, entry);
panic!("validation failed: temp-reg pair doesnt match")
}
} else {
error!("Temp{} is not alive at this point. ", temp);
panic!("validation failed: use a temp that is not alive");
}
}
}
fn remove_kill(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>, alive: &mut AliveEntries) {
if reg < MACHINE_ID_END {
if alive.find_entry_for_reg(reg).is_some() {
alive.remove_reg(reg);
}
} else {
let temp = reg;
alive.remove_temp(temp);
}
}
fn add_def(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>, alive: &mut AliveEntries) {
if reg < MACHINE_ID_END {
if alive.find_entry_for_reg(reg).is_none() {
// add new machine register
alive.new_alive_reg(reg);
}
} else {
let machine_reg = get_machine_reg(reg, reg_assigned);
let temp = reg;
alive.add_temp_in_reg(temp, machine_reg);
}
}
#[cfg(target_arch = "x86_64")]
fn add_machine_specific_regs_at_func_start(alive: &mut AliveEntries) {
use compiler::backend::x86_64;
// RIP, RSP, RBP always have valid values
alive.new_alive_reg(x86_64::RIP.id());
alive.new_alive_reg(x86_64::RSP.id());
alive.new_alive_reg(x86_64::RBP.id());
// callee saved regs are alive
alive.new_alive_reg(x86_64::RBX.id());
alive.new_alive_reg(x86_64::R12.id());
alive.new_alive_reg(x86_64::R13.id());
alive.new_alive_reg(x86_64::R14.id());
alive.new_alive_reg(x86_64::R15.id());
}
\ No newline at end of file
......@@ -40,6 +40,24 @@ macro_rules! linked_hashmap {
};
}
#[macro_exprt]
macro_rules! linked_hashset {
(@single $($x:tt)*) => (());
(@count $($rest:expr),*) => (<[()]>::len(&[$(linked_hashset!(@single $rest)),*]));
($($value:expr,)+) => { linked_hashset!($($value),+) };
($($value:expr),*) => {
{
let _cap = linked_hashset!(@count $($key),*);
let mut _map = LinkedHashSet::with_capacity(_cap);
$(
_map.insert($value);
)*
_map
}
};
}
mod address;
pub use address::Address;
pub use address::ObjectReference;
......
......@@ -11,6 +11,12 @@ impl<K: Hash + Eq> LinkedHashSet<K> {
pub fn new() -> Self {
LinkedHashSet(LinkedHashMap::new())
}
pub fn new1(val: K) -> Self {
let mut ret = LinkedHashSet::new();
ret.insert(val);
ret
}
pub fn from_vec(from: Vec<K>) -> Self {
let mut ret = LinkedHashSet::new();
......
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