Spill whole virtual registers at a time.
When the spiller decides to spill a value, bring along all of the values in its virtual register. This ensures that we won't have problems with computing register pressure around EBB arguments. They will always be register-to-register or stack-to-stack with related values using the same stack slot. This also means that the reloading pass won't have to deal with spilled EBB arguments.
This commit is contained in:
@@ -66,14 +66,14 @@ impl Context {
|
||||
// phases.
|
||||
self.tracker.clear();
|
||||
|
||||
// First pass: Liveness analysis.
|
||||
// Pass: Liveness analysis.
|
||||
self.liveness.compute(isa, func, cfg);
|
||||
|
||||
if isa.flags().enable_verifier() {
|
||||
verify_liveness(isa, func, cfg, &self.liveness)?;
|
||||
}
|
||||
|
||||
// Coalesce and create conventional SSA form.
|
||||
// Pass: Coalesce and create conventional SSA form.
|
||||
self.coalescing
|
||||
.conventional_ssa(isa,
|
||||
func,
|
||||
@@ -88,12 +88,13 @@ impl Context {
|
||||
}
|
||||
|
||||
|
||||
// Second pass: Spilling.
|
||||
// Pass: Spilling.
|
||||
self.spilling
|
||||
.run(isa,
|
||||
func,
|
||||
domtree,
|
||||
&mut self.liveness,
|
||||
&self.virtregs,
|
||||
&mut self.topo,
|
||||
&mut self.tracker);
|
||||
|
||||
@@ -102,7 +103,7 @@ impl Context {
|
||||
verify_liveness(isa, func, cfg, &self.liveness)?;
|
||||
}
|
||||
|
||||
// Third pass: Reload.
|
||||
// Pass: Reload.
|
||||
self.reload
|
||||
.run(isa,
|
||||
func,
|
||||
@@ -116,7 +117,7 @@ impl Context {
|
||||
verify_liveness(isa, func, cfg, &self.liveness)?;
|
||||
}
|
||||
|
||||
// Fourth pass: Coloring.
|
||||
// Pass: Coloring.
|
||||
self.coloring
|
||||
.run(isa,
|
||||
func,
|
||||
|
||||
@@ -25,6 +25,7 @@ use regalloc::affinity::Affinity;
|
||||
use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
|
||||
use regalloc::liveness::Liveness;
|
||||
use regalloc::pressure::Pressure;
|
||||
use regalloc::virtregs::VirtRegs;
|
||||
use topo_order::TopoOrder;
|
||||
|
||||
/// Persistent data structures for the spilling pass.
|
||||
@@ -48,6 +49,7 @@ struct Context<'a> {
|
||||
// References to contextual data structures we need.
|
||||
domtree: &'a DominatorTree,
|
||||
liveness: &'a mut Liveness,
|
||||
virtregs: &'a VirtRegs,
|
||||
topo: &'a mut TopoOrder,
|
||||
|
||||
// Current register pressure.
|
||||
@@ -77,6 +79,7 @@ impl Spilling {
|
||||
func: &mut Function,
|
||||
domtree: &DominatorTree,
|
||||
liveness: &mut Liveness,
|
||||
virtregs: &VirtRegs,
|
||||
topo: &mut TopoOrder,
|
||||
tracker: &mut LiveValueTracker) {
|
||||
dbg!("Spilling for:\n{}", func.display(isa));
|
||||
@@ -91,6 +94,7 @@ impl Spilling {
|
||||
locations: &mut func.locations,
|
||||
domtree,
|
||||
liveness,
|
||||
virtregs,
|
||||
topo,
|
||||
pressure: Pressure::new(®info, &usable_regs),
|
||||
spills: &mut self.spills,
|
||||
@@ -374,15 +378,17 @@ impl<'a> Context<'a> {
|
||||
let rc = self.reginfo.rc(rci);
|
||||
self.pressure.free(rc);
|
||||
self.spills.push(value);
|
||||
|
||||
// Assign a spill slot.
|
||||
// TODO: phi-related values should use the same spill slot.
|
||||
let ss = self.stack_slots.make_spill_slot(dfg.value_type(value));
|
||||
*self.locations.ensure(value) = ValueLoc::Stack(ss);
|
||||
dbg!("Spilled {}:{} to {} -> {}", value, rc, ss, self.pressure);
|
||||
dbg!("Spilled {}:{} -> {}", value, rc, self.pressure);
|
||||
} else {
|
||||
panic!("Cannot spill {} that was already on the stack", value);
|
||||
}
|
||||
|
||||
// Assign a spill slot for the whole virtual register.
|
||||
let ss = self.stack_slots.make_spill_slot(dfg.value_type(value));
|
||||
for &v in self.virtregs.congruence_class(&value) {
|
||||
self.liveness.spill(v);
|
||||
*self.locations.ensure(v) = ValueLoc::Stack(ss);
|
||||
}
|
||||
}
|
||||
|
||||
/// Process any pending spills in the `self.spills` vector.
|
||||
|
||||
Reference in New Issue
Block a user