Commit e53f5d4f authored by qinsoon's avatar qinsoon

[wip] also verifying spilling

parent 7c234f21
......@@ -11,7 +11,7 @@
</content>
<orderEntry type="inheritedJdk" />
<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="Cargo &lt;mu&gt;" level="project" />
</component>
</module>
\ No newline at end of file
......@@ -500,6 +500,28 @@ impl MachineCode for ASMCode {
_ => 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> {
&self.code[index].succs
......@@ -3373,14 +3395,16 @@ pub fn spill_rewrite(
spills: &LinkedHashMap<MuID, P<Value>>,
func: &mut MuFunctionVersion,
cf: &mut CompiledFunction,
vm: &VM) -> Vec<P<Value>>
vm: &VM) -> LinkedHashMap<MuID, MuID>
{
trace!("spill rewrite for x86_64 asm backend");
trace!("code before spilling");
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
let mut spill_code_before: LinkedHashMap<usize, Vec<Box<ASMCode>>> = LinkedHashMap::new();
......@@ -3407,8 +3431,10 @@ pub fn spill_rewrite(
// generate a random new temporary
let temp_ty = val_reg.ty.clone();
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);
spilled_scratch_temps.insert(temp.id(), reg);
// generate a load
let code = {
......@@ -3453,7 +3479,8 @@ pub fn spill_rewrite(
} else {
let temp_ty = val_reg.ty.clone();
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
};
......@@ -3499,5 +3526,5 @@ pub fn spill_rewrite(
trace!("code after spilling");
cf.mc().trace_mc();
new_nodes
spilled_scratch_temps
}
......@@ -44,7 +44,10 @@ pub struct GraphColoring<'a> {
worklist_spill: Vec<NodeIndex>,
spillable: LinkedHashMap<MuID, bool>,
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>,
frozen_moves: LinkedHashSet<Move>,
......@@ -55,10 +58,13 @@ pub struct GraphColoring<'a> {
impl <'a> 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...");
cf.mc().trace_mc();
......@@ -94,7 +100,9 @@ impl <'a> GraphColoring<'a> {
worklist_spill: Vec::new(),
spillable: LinkedHashMap::new(),
spilled_nodes: Vec::new(),
spill_history: spill_history,
spill_scratch_temps: spill_scratch_temps,
worklist_freeze: LinkedHashSet::new(),
frozen_moves: LinkedHashSet::new(),
......@@ -184,7 +192,7 @@ impl <'a> GraphColoring<'a> {
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
......@@ -657,7 +665,6 @@ impl <'a> GraphColoring<'a> {
}
}
#[allow(unused_variables)]
fn rewrite_program(&mut self) {
let spills = self.spills();
......@@ -675,8 +682,10 @@ impl <'a> GraphColoring<'a> {
self.spill_history.insert(*reg_id, mem);
}
// though we are not using this right now
let new_temps = backend::spill_rewrite(&spilled_mem, self.func, self.cf, self.vm);
let scratch_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> {
......@@ -721,6 +730,10 @@ impl <'a> GraphColoring<'a> {
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> {
let mut ret = LinkedHashMap::new();
......
......@@ -42,8 +42,9 @@ impl RegisterAllocation {
let reg_assignment = coloring.get_assignments();
let reg_spilled = coloring.get_spill_history();
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
......
......@@ -41,46 +41,89 @@ impl AliveEntries {
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() {
if entry.match_temp(temp) {
return Some(entry);
return true;
}
}
None
false
}
pub fn find_entry_for_temp_mut(&mut self, temp: MuID) -> Option<&mut RegisterEntry> {
pub fn find_entries_for_temp(&self, temp: MuID) -> Vec<&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() {
if entry.match_temp(temp) {
return Some(entry)
ret.push(entry);
}
}
None
ret
}
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() {
if entry.match_reg(reg) {
return Some(entry);
return true;
}
}
None
false
}
pub fn find_entry_for_reg_mut(&mut self, reg: MuID) -> Option<&mut RegisterEntry> {
pub fn find_entries_for_reg(&self, reg: MuID) -> Vec<&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() {
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) {
debug!("adding alive reg: {}", reg);
......@@ -110,11 +153,13 @@ impl AliveEntries {
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();
let entry_exists = self.has_entries_for_temp(temp);
if entry_exists {
let mut entry = self.find_entry_for_temp_mut(temp).unwrap();
entry.add_real_reg(reg);
let mut entries = self.find_entries_for_temp_mut(temp);
for entry in entries {
entry.add_real_reg(reg);
}
} else {
let id = self.new_index();
let entry = RegisterEntry {
......@@ -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) {
debug!("removing alive reg: {}", reg);
let mut indices = vec![];
......@@ -185,6 +252,18 @@ impl RegisterEntry {
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 {
if self.temp.is_some() && self.temp.unwrap() == temp {
true
......@@ -197,11 +276,21 @@ impl RegisterEntry {
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) {
if vec_utils::find_value(&mut self.real, reg).is_none() {
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 {
......
......@@ -162,6 +162,9 @@ pub trait MachineCode {
fn is_using_mem_op(&self, index: usize) -> bool;
fn is_jmp(&self, index: usize) -> Option<MuName>;
fn is_label(&self, index: usize) -> Option<MuName>;
fn is_spill_load(&self, index: usize) -> Option<P<Value>>;
fn is_spill_store(&self, index: usize) -> Option<P<Value>>;
fn get_succs(&self, index: usize) -> &Vec<usize>;
fn get_preds(&self, index: usize) -> &Vec<usize>;
......
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