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

[wip] also verifying spilling

parent 7c234f21
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Cargo &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Rust &lt;mu&gt;" level="project" /> <orderEntry type="library" name="Rust &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Cargo &lt;mu&gt;" level="project" />
</component> </component>
</module> </module>
\ No newline at end of file
...@@ -500,6 +500,28 @@ impl MachineCode for ASMCode { ...@@ -500,6 +500,28 @@ impl MachineCode for ASMCode {
_ => None _ => None
} }
} }
fn is_spill_load(&self, index: usize) -> Option<P<Value>> {
if let Some(inst) = self.code.get(index) {
match inst.spill_info {
Some(SpillMemInfo::Load(ref p)) => Some(p.clone()),
_ => None
}
} else {
None
}
}
fn is_spill_store(&self, index: usize) -> Option<P<Value>> {
if let Some(inst) = self.code.get(index) {
match inst.spill_info {
Some(SpillMemInfo::Store(ref p)) => Some(p.clone()),
_ => None
}
} else {
None
}
}
fn get_succs(&self, index: usize) -> &Vec<usize> { fn get_succs(&self, index: usize) -> &Vec<usize> {
&self.code[index].succs &self.code[index].succs
...@@ -3373,14 +3395,16 @@ pub fn spill_rewrite( ...@@ -3373,14 +3395,16 @@ pub fn spill_rewrite(
spills: &LinkedHashMap<MuID, P<Value>>, spills: &LinkedHashMap<MuID, P<Value>>,
func: &mut MuFunctionVersion, func: &mut MuFunctionVersion,
cf: &mut CompiledFunction, cf: &mut CompiledFunction,
vm: &VM) -> Vec<P<Value>> vm: &VM) -> LinkedHashMap<MuID, MuID>
{ {
trace!("spill rewrite for x86_64 asm backend"); trace!("spill rewrite for x86_64 asm backend");
trace!("code before spilling"); trace!("code before spilling");
cf.mc().trace_mc(); cf.mc().trace_mc();
let mut new_nodes = vec![]; // if temp a gets spilled, all its uses and defines will become a use/def of a scratch temp
// we maintain this mapping for later use
let mut spilled_scratch_temps = LinkedHashMap::new();
// record code and their insertion point, so we can do the copy/insertion all at once // record code and their insertion point, so we can do the copy/insertion all at once
let mut spill_code_before: LinkedHashMap<usize, Vec<Box<ASMCode>>> = LinkedHashMap::new(); let mut spill_code_before: LinkedHashMap<usize, Vec<Box<ASMCode>>> = LinkedHashMap::new();
...@@ -3407,8 +3431,10 @@ pub fn spill_rewrite( ...@@ -3407,8 +3431,10 @@ pub fn spill_rewrite(
// generate a random new temporary // generate a random new temporary
let temp_ty = val_reg.ty.clone(); let temp_ty = val_reg.ty.clone();
let temp = func.new_ssa(vm.next_id(), temp_ty.clone()).clone_value(); let temp = func.new_ssa(vm.next_id(), temp_ty.clone()).clone_value();
vec_utils::add_unique(&mut new_nodes, temp.clone());
// maintain mapping
trace!("reg {} used in Inst{} is replaced as {}", val_reg, i, temp); trace!("reg {} used in Inst{} is replaced as {}", val_reg, i, temp);
spilled_scratch_temps.insert(temp.id(), reg);
// generate a load // generate a load
let code = { let code = {
...@@ -3453,7 +3479,8 @@ pub fn spill_rewrite( ...@@ -3453,7 +3479,8 @@ pub fn spill_rewrite(
} else { } else {
let temp_ty = val_reg.ty.clone(); let temp_ty = val_reg.ty.clone();
let temp = func.new_ssa(vm.next_id(), temp_ty.clone()).clone_value(); let temp = func.new_ssa(vm.next_id(), temp_ty.clone()).clone_value();
vec_utils::add_unique(&mut new_nodes, temp.clone());
spilled_scratch_temps.insert(temp.id(), reg);
temp temp
}; };
...@@ -3499,5 +3526,5 @@ pub fn spill_rewrite( ...@@ -3499,5 +3526,5 @@ pub fn spill_rewrite(
trace!("code after spilling"); trace!("code after spilling");
cf.mc().trace_mc(); cf.mc().trace_mc();
new_nodes spilled_scratch_temps
} }
...@@ -44,7 +44,10 @@ pub struct GraphColoring<'a> { ...@@ -44,7 +44,10 @@ pub struct GraphColoring<'a> {
worklist_spill: Vec<NodeIndex>, worklist_spill: Vec<NodeIndex>,
spillable: LinkedHashMap<MuID, bool>, spillable: LinkedHashMap<MuID, bool>,
spilled_nodes: Vec<NodeIndex>, spilled_nodes: Vec<NodeIndex>,
spill_history: LinkedHashMap<MuID, P<Value>>, // for validation, we need to log all registers get spilled
// for validation
spill_history: LinkedHashMap<MuID, P<Value>>, // we need to log all registers get spilled with their spill location
spill_scratch_temps: LinkedHashMap<MuID, MuID>, // we need to know the mapping between scratch temp -> original temp
worklist_freeze: LinkedHashSet<NodeIndex>, worklist_freeze: LinkedHashSet<NodeIndex>,
frozen_moves: LinkedHashSet<Move>, frozen_moves: LinkedHashSet<Move>,
...@@ -55,10 +58,13 @@ pub struct GraphColoring<'a> { ...@@ -55,10 +58,13 @@ pub struct GraphColoring<'a> {
impl <'a> GraphColoring<'a> { impl <'a> GraphColoring<'a> {
pub fn start (func: &'a mut MuFunctionVersion, cf: &'a mut CompiledFunction, vm: &'a VM) -> GraphColoring<'a> { pub fn start (func: &'a mut MuFunctionVersion, cf: &'a mut CompiledFunction, vm: &'a VM) -> GraphColoring<'a> {
GraphColoring::start_with_spill_history(LinkedHashMap::new(), func, cf, vm) GraphColoring::start_with_spill_history(LinkedHashMap::new(), LinkedHashMap::new(), func, cf, vm)
} }
fn start_with_spill_history(spill_history: LinkedHashMap<MuID, P<Value>>, func: &'a mut MuFunctionVersion, cf: &'a mut CompiledFunction, vm: &'a VM) -> GraphColoring<'a> { fn start_with_spill_history(spill_history: LinkedHashMap<MuID, P<Value>>,
spill_scratch_temps: LinkedHashMap<MuID, MuID>,
func: &'a mut MuFunctionVersion, cf: &'a mut CompiledFunction, vm: &'a VM) -> GraphColoring<'a>
{
trace!("Initializing coloring allocator..."); trace!("Initializing coloring allocator...");
cf.mc().trace_mc(); cf.mc().trace_mc();
...@@ -94,7 +100,9 @@ impl <'a> GraphColoring<'a> { ...@@ -94,7 +100,9 @@ impl <'a> GraphColoring<'a> {
worklist_spill: Vec::new(), worklist_spill: Vec::new(),
spillable: LinkedHashMap::new(), spillable: LinkedHashMap::new(),
spilled_nodes: Vec::new(), spilled_nodes: Vec::new(),
spill_history: spill_history, spill_history: spill_history,
spill_scratch_temps: spill_scratch_temps,
worklist_freeze: LinkedHashSet::new(), worklist_freeze: LinkedHashSet::new(),
frozen_moves: LinkedHashSet::new(), frozen_moves: LinkedHashSet::new(),
...@@ -184,7 +192,7 @@ impl <'a> GraphColoring<'a> { ...@@ -184,7 +192,7 @@ impl <'a> GraphColoring<'a> {
self.rewrite_program(); self.rewrite_program();
return GraphColoring::start_with_spill_history(self.spill_history.clone(), self.func, self.cf, self.vm); return GraphColoring::start_with_spill_history(self.spill_history.clone(), self.spill_scratch_temps.clone(), self.func, self.cf, self.vm);
} }
self self
...@@ -657,7 +665,6 @@ impl <'a> GraphColoring<'a> { ...@@ -657,7 +665,6 @@ impl <'a> GraphColoring<'a> {
} }
} }
#[allow(unused_variables)]
fn rewrite_program(&mut self) { fn rewrite_program(&mut self) {
let spills = self.spills(); let spills = self.spills();
...@@ -675,8 +682,10 @@ impl <'a> GraphColoring<'a> { ...@@ -675,8 +682,10 @@ impl <'a> GraphColoring<'a> {
self.spill_history.insert(*reg_id, mem); self.spill_history.insert(*reg_id, mem);
} }
// though we are not using this right now let scratch_temps = backend::spill_rewrite(&spilled_mem, self.func, self.cf, self.vm);
let new_temps = backend::spill_rewrite(&spilled_mem, self.func, self.cf, self.vm); for (k, v) in scratch_temps {
self.spill_scratch_temps.insert(k, v);
}
} }
pub fn spills(&self) -> Vec<MuID> { pub fn spills(&self) -> Vec<MuID> {
...@@ -721,6 +730,10 @@ impl <'a> GraphColoring<'a> { ...@@ -721,6 +730,10 @@ impl <'a> GraphColoring<'a> {
self.spill_history.clone() self.spill_history.clone()
} }
pub fn get_spill_scratch_temps(&self) -> LinkedHashMap<MuID, MuID> {
self.spill_scratch_temps.clone()
}
pub fn get_coalesced(&self) -> LinkedHashMap<MuID, MuID> { pub fn get_coalesced(&self) -> LinkedHashMap<MuID, MuID> {
let mut ret = LinkedHashMap::new(); let mut ret = LinkedHashMap::new();
......
...@@ -42,8 +42,9 @@ impl RegisterAllocation { ...@@ -42,8 +42,9 @@ impl RegisterAllocation {
let reg_assignment = coloring.get_assignments(); let reg_assignment = coloring.get_assignments();
let reg_spilled = coloring.get_spill_history(); let reg_spilled = coloring.get_spill_history();
let reg_coalesced = coloring.get_coalesced(); let reg_coalesced = coloring.get_coalesced();
let spill_scratch_temps = coloring.get_spill_scratch_temps();
validate::validate_regalloc(&coloring.cf, &coloring.func, reg_assignment, reg_coalesced, reg_spilled) validate::validate_regalloc(&coloring.cf, &coloring.func, reg_assignment, reg_coalesced, reg_spilled, spill_scratch_temps);
} }
// replace regs // replace regs
......
...@@ -41,46 +41,89 @@ impl AliveEntries { ...@@ -41,46 +41,89 @@ impl AliveEntries {
ret ret
} }
pub fn find_entry_for_temp(&self, temp: MuID) -> Option<&RegisterEntry> { pub fn has_entries_for_temp(&self, temp: MuID) -> bool {
for entry in self.inner.values() { for entry in self.inner.values() {
if entry.match_temp(temp) { if entry.match_temp(temp) {
return Some(entry); return true;
} }
} }
None false
} }
pub fn find_entries_for_temp(&self, temp: MuID) -> Vec<&RegisterEntry> {
pub fn find_entry_for_temp_mut(&mut self, temp: MuID) -> Option<&mut RegisterEntry> { let mut ret = vec![];
for entry in self.inner.values() {
if entry.match_temp(temp) {
ret.push(entry);
}
}
ret
}
pub fn find_entries_for_temp_mut(&mut self, temp: MuID) -> Vec<&mut RegisterEntry> {
let mut ret = vec![];
for entry in self.inner.values_mut() { for entry in self.inner.values_mut() {
if entry.match_temp(temp) { if entry.match_temp(temp) {
return Some(entry) ret.push(entry);
} }
} }
ret
None
} }
pub fn find_entry_for_reg(&self, reg: MuID) -> Option<&RegisterEntry> { pub fn has_entries_for_reg(&self, reg: MuID) -> bool {
for entry in self.inner.values() { for entry in self.inner.values() {
if entry.match_reg(reg) { if entry.match_reg(reg) {
return Some(entry); return true;
} }
} }
false
None
} }
pub fn find_entries_for_reg(&self, reg: MuID) -> Vec<&RegisterEntry> {
pub fn find_entry_for_reg_mut(&mut self, reg: MuID) -> Option<&mut RegisterEntry> { let mut ret = vec![];
for entry in self.inner.values() {
if entry.match_reg(reg) {
ret.push(entry);
}
}
ret
}
pub fn find_entries_for_reg_mut(&mut self, reg: MuID) -> Vec<&mut RegisterEntry> {
let mut ret = vec![];
for entry in self.inner.values_mut() { for entry in self.inner.values_mut() {
if entry.match_reg(reg) { if entry.match_reg(reg) {
return Some(entry); ret.push(entry)
} }
} }
ret
}
None pub fn has_entries_for_mem(&self, mem: P<Value>) -> bool {
for entry in self.inner.values() {
if entry.match_stack_loc(mem.clone()) {
return true;
}
}
false
}
pub fn find_entries_for_mem(&self, mem: P<Value>) -> Vec<&RegisterEntry> {
let mut ret = vec![];
for entry in self.inner.values() {
if entry.match_stack_loc(mem.clone()) {
ret.push(entry)
}
}
ret
}
pub fn find_entries_for_mem_mut(&mut self, mem: P<Value>) -> Vec<&mut RegisterEntry> {
let mut ret = vec![];
for entry in self.inner.values_mut() {
if entry.match_stack_loc(mem.clone()) {
ret.push(entry)
}
}
ret
} }
pub fn new_alive_reg(&mut self, reg: MuID) { pub fn new_alive_reg(&mut self, reg: MuID) {
debug!("adding alive reg: {}", reg); debug!("adding alive reg: {}", reg);
...@@ -110,11 +153,13 @@ impl AliveEntries { ...@@ -110,11 +153,13 @@ impl AliveEntries {
pub fn add_temp_in_reg(&mut self, temp: MuID, reg: MuID) { pub fn add_temp_in_reg(&mut self, temp: MuID, reg: MuID) {
debug!("adding alive temp in reg: {} in {}", temp, reg); debug!("adding alive temp in reg: {} in {}", temp, reg);
let entry_exists = self.find_entry_for_temp(temp).is_some(); let entry_exists = self.has_entries_for_temp(temp);
if entry_exists { if entry_exists {
let mut entry = self.find_entry_for_temp_mut(temp).unwrap(); let mut entries = self.find_entries_for_temp_mut(temp);
entry.add_real_reg(reg); for entry in entries {
entry.add_real_reg(reg);
}
} else { } else {
let id = self.new_index(); let id = self.new_index();
let entry = RegisterEntry { let entry = RegisterEntry {
...@@ -127,6 +172,28 @@ impl AliveEntries { ...@@ -127,6 +172,28 @@ impl AliveEntries {
} }
} }
pub fn add_temp_in_mem(&mut self, temp: MuID, mem: P<Value>) {
debug!("alive alive temp in mem: {} in {}", temp, mem);
let entry_exists = self.has_entries_for_temp(temp);
if entry_exists {
let mut entries = self.find_entries_for_temp_mut(temp);
for entry in entries {
entry.add_stack_loc(mem.clone());
}
} else {
let id = self.new_index();
let entry = RegisterEntry {
temp: Some(temp),
real: vec![],
stack: vec![mem]
};
self.inner.insert(id, entry);
}
}
pub fn remove_reg(&mut self, reg: MuID) { pub fn remove_reg(&mut self, reg: MuID) {
debug!("removing alive reg: {}", reg); debug!("removing alive reg: {}", reg);
let mut indices = vec![]; let mut indices = vec![];
...@@ -185,6 +252,18 @@ impl RegisterEntry { ...@@ -185,6 +252,18 @@ impl RegisterEntry {
self.temp.clone() self.temp.clone()
} }
pub fn remove_real(&mut self, reg: MuID) {
if let Some(index) = vec_utils::find_value(&self.real, reg) {
self.real.remove(index);
}
}
pub fn remove_stack_loc(&mut self, mem: P<Value>) {
if let Some(index) = vec_utils::find_value(&self.stack, mem) {
self.stack.remove(index);
}
}
pub fn match_temp(&self, temp: MuID) -> bool { pub fn match_temp(&self, temp: MuID) -> bool {
if self.temp.is_some() && self.temp.unwrap() == temp { if self.temp.is_some() && self.temp.unwrap() == temp {
true true
...@@ -197,11 +276,21 @@ impl RegisterEntry { ...@@ -197,11 +276,21 @@ impl RegisterEntry {
vec_utils::find_value(&self.real, reg).is_some() vec_utils::find_value(&self.real, reg).is_some()
} }
pub fn match_stack_loc(&self, mem: P<Value>) -> bool {
vec_utils::find_value(&self.stack, mem).is_some()
}
pub fn add_real_reg(&mut self, reg: MuID) { pub fn add_real_reg(&mut self, reg: MuID) {
if vec_utils::find_value(&mut self.real, reg).is_none() { if vec_utils::find_value(&mut self.real, reg).is_none() {
self.real.push(reg); self.real.push(reg);
} }
} }
pub fn add_stack_loc(&mut self, mem: P<Value>) {
if vec_utils::find_value(&mut self.stack, mem.clone()).is_none() {
self.stack.push(mem)
}
}
} }
impl fmt::Display for RegisterEntry { impl fmt::Display for RegisterEntry {
......
...@@ -14,7 +14,8 @@ pub fn validate_regalloc(cf: &CompiledFunction, ...@@ -14,7 +14,8 @@ pub fn validate_regalloc(cf: &CompiledFunction,
func: &MuFunctionVersion, func: &MuFunctionVersion,
reg_assigned: LinkedHashMap<MuID, MuID>, reg_assigned: LinkedHashMap<MuID, MuID>,
reg_coalesced:LinkedHashMap<MuID, MuID>, reg_coalesced:LinkedHashMap<MuID, MuID>,
reg_spilled: LinkedHashMap<MuID, P<Value>>) reg_spilled: LinkedHashMap<MuID, P<Value>>,
spill_scratch_regs: LinkedHashMap<MuID, MuID>)
{ {
debug!("---Validating register allocation results---"); debug!("---Validating register allocation results---");
...@@ -58,15 +59,46 @@ pub fn validate_regalloc(cf: &CompiledFunction, ...@@ -58,15 +59,46 @@ pub fn validate_regalloc(cf: &CompiledFunction,
mc.trace_inst(i); mc.trace_inst(i);
if mc.is_jmp(i).is_some() { if mc.is_jmp(i).is_some() {
// we need to flow-sensitive analysis // we need to do flow-sensitive analysis
unimplemented!(); unimplemented!();
} }
// validate spill
if let Some(spill_loc) = mc.is_spill_load(i) {
// spill load is a move from spill location (mem) to temp
// its define is the scratch temp
let scratch_temp = mc.get_inst_reg_defines(i)[0];
let source_temp = get_source_temp_for_scratch(scratch_temp, &spill_scratch_regs);
add_spill_load(scratch_temp, source_temp, spill_loc, &reg_spilled, &mut alive);
} else if let Some(spill_loc) = mc.is_spill_store(i) {
// spill store is a move from scratch temp to mem
// it uses scratch temp as well as stack pointer (to refer to mem)
// we try to find the scratch temp
let scratch_temp = {
let uses = mc.get_inst_reg_uses(i);
let mut use_temps = vec![];
for reg in uses {
if reg >= MACHINE_ID_END {
use_temps.push(reg)
}
};
assert!(use_temps.len() == 1);
use_temps[0]
};
let source_temp = get_source_temp_for_scratch(scratch_temp, &spill_scratch_regs);
add_spill_store(scratch_temp, source_temp, spill_loc, &reg_spilled, &reg_coalesced, &mut alive);
}
// validate uses of registers
for reg_use in mc.get_inst_reg_uses(i) { for reg_use in mc.get_inst_reg_uses(i) {
validate_use(reg_use, &reg_assigned, &alive); validate_use(reg_use, &reg_assigned, &alive);
} }
// remove kills in the inst from alive entries // remove registers that die at this instruction from alive entries
if let Some(kills) = liveness.get_kills(i) { if let Some(kills) = liveness.get_kills(i) {
for reg in kills.iter() { for reg in kills.iter() {
kill_reg(*reg, &reg_assigned, &mut alive); kill_reg(*reg, &reg_assigned, &mut alive);
...@@ -90,6 +122,13 @@ pub fn validate_regalloc(cf: &CompiledFunction, ...@@ -90,6 +122,13 @@ pub fn validate_regalloc(cf: &CompiledFunction,
} }
} }
fn get_source_temp_for_scratch(scratch: MuID, spill_scratch_temps: &LinkedHashMap<MuID, MuID>) -> MuID {
match spill_scratch_temps.get(&scratch) {
Some(src) => get_source_temp_for_scratch(*src, spill_scratch_temps),
None => scratch
}
}
fn get_machine_reg(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>) -> MuID { fn get_machine_reg(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>) -> MuID {
// find machine regs // find machine regs
if reg < MACHINE_ID_END { if reg < MACHINE_ID_END {
...@@ -113,13 +152,15 @@ fn validate_use(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>, alive: &Ali ...@@ -113,13 +152,15 @@ fn validate_use(reg: MuID, reg_assigned: &LinkedHashMap<MuID, MuID>, alive: &Ali
let temp = reg; let temp = reg;
// ensure temp is assigned to the same machine reg in alive entries // ensure temp is assigned to the same machine reg in alive entries
if let Some(entry) = alive.find_entry_for_temp(temp) { if alive.has_entries_for_temp(temp) {
if !entry.match_reg(machine_reg) { alive.find_entries_for_temp(temp).iter().inspect(|entry| {
error!("Temp{}/MachineReg{} does not match at this point. ", temp, machine_reg); if !entry.match_reg(machine_reg) {