From 9487b885da866e7dbe45b18cfd11516c9fb4dd5c Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 23 Jun 2017 10:43:59 -0700 Subject: [PATCH] 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. --- lib/cretonne/src/regalloc/context.rs | 11 ++++++----- lib/cretonne/src/regalloc/spilling.rs | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/cretonne/src/regalloc/context.rs b/lib/cretonne/src/regalloc/context.rs index 78e1595747..0908b02a1c 100644 --- a/lib/cretonne/src/regalloc/context.rs +++ b/lib/cretonne/src/regalloc/context.rs @@ -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, diff --git a/lib/cretonne/src/regalloc/spilling.rs b/lib/cretonne/src/regalloc/spilling.rs index 7311de5d5d..f1feff3f4b 100644 --- a/lib/cretonne/src/regalloc/spilling.rs +++ b/lib/cretonne/src/regalloc/spilling.rs @@ -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.