From c24f64de3b93ecac85ca67cb46dc37303890b3b1 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 27 Jun 2017 16:04:50 -0700 Subject: [PATCH] Process ghost instruction kills during coloring. Ghost instructions don't generate code, but they can keep registers alive. The coloring pass needs to process values killed by ghost instructions so it knows when the registers are freed up. Also track register pressure changes from ghost kills in the spiller. --- lib/cretonne/src/regalloc/coloring.rs | 40 ++++++++++++++++++- lib/cretonne/src/regalloc/diversion.rs | 15 +++++++ .../src/regalloc/live_value_tracker.rs | 10 +++++ lib/cretonne/src/regalloc/spilling.rs | 7 +++- 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/lib/cretonne/src/regalloc/coloring.rs b/lib/cretonne/src/regalloc/coloring.rs index 56244bcc3c..878656ae84 100644 --- a/lib/cretonne/src/regalloc/coloring.rs +++ b/lib/cretonne/src/regalloc/coloring.rs @@ -147,8 +147,11 @@ impl<'a> Context<'a> { &mut regs, &mut func.locations, &func.signature); - tracker.drop_dead(inst); + } else { + let (_throughs, kills) = tracker.process_ghost(inst); + self.process_ghost_kills(kills, &mut regs, &func.locations); } + tracker.drop_dead(inst); } } @@ -377,6 +380,9 @@ impl<'a> Context<'a> { } } } + + self.forget_diverted(kills); + *regs = output_regs; } @@ -569,4 +575,36 @@ impl<'a> Context<'a> { dfg.ins(pos).regmove(m.value, m.from, m.to); } } + + /// Forget about any register diversions in `kills`. + fn forget_diverted(&mut self, kills: &[LiveValue]) { + if self.divert.is_empty() { + return; + } + + for lv in kills { + if lv.affinity.is_reg() { + self.divert.remove(lv.value); + } + } + } + + /// Process kills on a ghost instruction. + /// - Forget diversions. + /// - Free killed registers. + fn process_ghost_kills(&mut self, + kills: &[LiveValue], + regs: &mut AllocatableSet, + locations: &ValueLocations) { + for lv in kills { + if let Affinity::Reg(rci) = lv.affinity { + let rc = self.reginfo.rc(rci); + let reg = match self.divert.remove(lv.value) { + Some(r) => r, + None => locations[lv.value].unwrap_reg(), + }; + regs.free(rc, reg); + } + } + } } diff --git a/lib/cretonne/src/regalloc/diversion.rs b/lib/cretonne/src/regalloc/diversion.rs index e8e8d3d190..e07b694ab9 100644 --- a/lib/cretonne/src/regalloc/diversion.rs +++ b/lib/cretonne/src/regalloc/diversion.rs @@ -51,6 +51,11 @@ impl RegDiversions { self.current.clear() } + /// Are there any diversions? + pub fn is_empty(&self) -> bool { + self.current.is_empty() + } + /// Get the current diversion of `value`, if any. pub fn diversion(&self, value: Value) -> Option<&Diversion> { self.current.iter().find(|d| d.value == value) @@ -83,6 +88,16 @@ impl RegDiversions { self.current.push(Diversion::new(value, from, to)); } } + + /// Drop any recorded register move for `value`. + /// + /// Returns the `to` register of the removed diversion. + pub fn remove(&mut self, value: Value) -> Option { + self.current + .iter() + .position(|d| d.value == value) + .map(|i| self.current.swap_remove(i).to) + } } #[cfg(test)] diff --git a/lib/cretonne/src/regalloc/live_value_tracker.rs b/lib/cretonne/src/regalloc/live_value_tracker.rs index ccaf6c9209..b243b93923 100644 --- a/lib/cretonne/src/regalloc/live_value_tracker.rs +++ b/lib/cretonne/src/regalloc/live_value_tracker.rs @@ -280,6 +280,16 @@ impl LiveValueTracker { &self.live.values[first_def..]) } + /// Prepare to move past a ghost instruction. + /// + /// This is like `process_inst`, except any defs are ignored. + /// + /// Returns `(throughs, kills)`. + pub fn process_ghost(&mut self, inst: Inst) -> (&[LiveValue], &[LiveValue]) { + let first_kill = self.live.live_after(inst); + self.live.values.as_slice().split_at(first_kill) + } + /// Drop the values that are now dead after moving past `inst`. /// /// This removes both live values that were killed by `inst` and dead defines on `inst` itself. diff --git a/lib/cretonne/src/regalloc/spilling.rs b/lib/cretonne/src/regalloc/spilling.rs index f1feff3f4b..09559c9d26 100644 --- a/lib/cretonne/src/regalloc/spilling.rs +++ b/lib/cretonne/src/regalloc/spilling.rs @@ -129,9 +129,12 @@ impl<'a> Context<'a> { while let Some(inst) = pos.next_inst() { if let Some(constraints) = self.encinfo.operand_constraints(self.encodings[inst]) { self.visit_inst(inst, constraints, &mut pos, dfg, tracker); - tracker.drop_dead(inst); - self.process_spills(tracker); + } else { + let (_throughs, kills) = tracker.process_ghost(inst); + self.free_regs(kills); } + tracker.drop_dead(inst); + self.process_spills(tracker); } }