From 5beb10e77a8cdd7203597ab4d1d72518482e861e Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 12 Sep 2019 19:32:43 +0200 Subject: [PATCH] Regalloc: remove the transient LiveRangeContext data structure; --- cranelift/codegen/src/regalloc/coalescing.rs | 29 ++-- cranelift/codegen/src/regalloc/coloring.rs | 28 ++-- .../src/regalloc/live_value_tracker.rs | 3 +- cranelift/codegen/src/regalloc/liveness.rs | 12 +- cranelift/codegen/src/regalloc/liverange.rs | 136 +++++------------- cranelift/codegen/src/regalloc/spilling.rs | 7 +- cranelift/codegen/src/value_label.rs | 9 +- cranelift/codegen/src/verifier/cssa.rs | 8 +- cranelift/codegen/src/verifier/liveness.rs | 11 +- cranelift/codegen/src/verifier/locations.rs | 8 +- 10 files changed, 108 insertions(+), 143 deletions(-) diff --git a/cranelift/codegen/src/regalloc/coalescing.rs b/cranelift/codegen/src/regalloc/coalescing.rs index 4ba19ebbf4..8a1f1d81bb 100644 --- a/cranelift/codegen/src/regalloc/coalescing.rs +++ b/cranelift/codegen/src/regalloc/coalescing.rs @@ -199,7 +199,8 @@ impl<'a> Context<'a> { if self.liveness[param].reaches_use( pred_inst, pred_ebb, - self.liveness.context(&self.func.layout), + self.liveness.forest(), + &self.func.layout, ) { self.isolate_param(ebb, param); } @@ -240,7 +241,6 @@ impl<'a> Context<'a> { // `ebb`, it can never be used as an EBB argument. let interference = { let lr = &self.liveness[arg]; - let ctx = self.liveness.context(&self.func.layout); // There are two ways the argument value can interfere with `ebb`: // @@ -255,7 +255,7 @@ impl<'a> Context<'a> { ); // The only other possibility is that `arg` is live-in to `ebb`. - lr.is_livein(ebb, ctx) + lr.is_livein(ebb, self.liveness.forest(), &self.func.layout) }; if interference { @@ -435,8 +435,12 @@ impl<'a> Context<'a> { // Check for interference between `parent` and `value`. Since `parent` dominates // `value`, we only have to check if it overlaps the definition. - let ctx = self.liveness.context(&self.func.layout); - if self.liveness[parent.value].overlaps_def(node.def, node.ebb, ctx) { + if self.liveness[parent.value].overlaps_def( + node.def, + node.ebb, + self.liveness.forest(), + &self.func.layout, + ) { // The two values are interfering, so they can't be in the same virtual register. debug!("-> interference: {} overlaps def of {}", parent, value); return false; @@ -593,7 +597,6 @@ impl<'a> Context<'a> { // This gives us the closest dominating value def for each of the values. self.forest.clear(); self.values.clear(); - let ctx = self.liveness.context(&self.func.layout); for node in nodes { // Accumulate ordered values for the new vreg. if node.is_value() { @@ -623,7 +626,12 @@ impl<'a> Context<'a> { // Check if the parent value interferes with the virtual copy. let inst = node.def.unwrap_inst(); if node.set_id != parent.set_id - && self.liveness[parent.value].reaches_use(inst, node.ebb, ctx) + && self.liveness[parent.value].reaches_use( + inst, + node.ebb, + self.liveness.forest(), + &self.func.layout, + ) { debug!( " - interference: {} overlaps vcopy at {}:{}", @@ -647,7 +655,12 @@ impl<'a> Context<'a> { // Both node and parent are values, so check for interference. debug_assert!(node.is_value() && parent.is_value()); if node.set_id != parent.set_id - && self.liveness[parent.value].overlaps_def(node.def, node.ebb, ctx) + && self.liveness[parent.value].overlaps_def( + node.def, + node.ebb, + self.liveness.forest(), + &self.func.layout, + ) { // The two values are interfering. debug!(" - interference: {} overlaps def of {}", parent, node.value); diff --git a/cranelift/codegen/src/regalloc/coloring.rs b/cranelift/codegen/src/regalloc/coloring.rs index 1e69c342a9..23a546a479 100644 --- a/cranelift/codegen/src/regalloc/coloring.rs +++ b/cranelift/codegen/src/regalloc/coloring.rs @@ -54,7 +54,7 @@ use crate::regalloc::affinity::Affinity; use crate::regalloc::diversion::RegDiversions; use crate::regalloc::live_value_tracker::{LiveValue, LiveValueTracker}; use crate::regalloc::liveness::Liveness; -use crate::regalloc::liverange::{LiveRange, LiveRangeContext}; +use crate::regalloc::liverange::{LiveRange, LiveRangeForest}; use crate::regalloc::register_set::RegisterSet; use crate::regalloc::solver::{Solver, SolverError}; use crate::timing; @@ -461,7 +461,7 @@ impl<'a> Context<'a> { "Can't handle EBB arguments: {}", self.cur.display_inst(inst) ); - self.undivert_regs(|lr, _| !lr.is_local()); + self.undivert_regs(|lr, _, _| !lr.is_local()); } } @@ -725,8 +725,13 @@ impl<'a> Context<'a> { // This code runs after calling `solver.inputs_done()` so we must identify // the new variable as killed or live-through. Always special-case the // pinned register as a through variable. - let ctx = self.liveness.context(&self.cur.func.layout); - if self.liveness[value].killed_at(inst, ctx.order.pp_ebb(inst), ctx) { + let layout = &self.cur.func.layout; + if self.liveness[value].killed_at( + inst, + layout.pp_ebb(inst), + self.liveness.forest(), + layout, + ) { self.solver.add_killed_var(value, op.regclass, cur_reg); } else { self.solver.add_through_var(value, op.regclass, cur_reg); @@ -755,7 +760,7 @@ impl<'a> Context<'a> { // // Values with a global live range that are not live in to `dest` could appear as branch // arguments, so they can't always be un-diverted. - self.undivert_regs(|lr, ctx| lr.is_livein(dest, ctx)); + self.undivert_regs(|lr, forest, layout| lr.is_livein(dest, forest, layout)); // Now handle the EBB arguments. let br_args = self.cur.func.dfg.inst_variable_args(inst); @@ -825,14 +830,14 @@ impl<'a> Context<'a> { /// are reallocated to their global register assignments. fn undivert_regs(&mut self, mut pred: Pred) where - Pred: FnMut(&LiveRange, LiveRangeContext) -> bool, + Pred: FnMut(&LiveRange, &LiveRangeForest, &Layout) -> bool, { for (&value, rdiv) in self.divert.iter() { let lr = self .liveness .get(value) .expect("Missing live range for diverted register"); - if pred(lr, self.liveness.context(&self.cur.func.layout)) { + if pred(lr, self.liveness.forest(), &self.cur.func.layout) { if let Affinity::Reg(rci) = lr.affinity { let rc = self.reginfo.rc(rci); // Stack diversions should not be possible here. They only live transiently @@ -1080,20 +1085,21 @@ impl<'a> Context<'a> { use crate::ir::instructions::BranchInfo::*; let inst = self.cur.current_inst().expect("Not on an instruction"); - let ctx = self.liveness.context(&self.cur.func.layout); + let layout = &self.cur.func.layout; + let forest = self.liveness.forest(); match self.cur.func.dfg.analyze_branch(inst) { NotABranch => false, SingleDest(ebb, _) => { let lr = &self.liveness[value]; - lr.is_livein(ebb, ctx) + lr.is_livein(ebb, forest, layout) } Table(jt, ebb) => { let lr = &self.liveness[value]; !lr.is_local() - && (ebb.map_or(false, |ebb| lr.is_livein(ebb, ctx)) + && (ebb.map_or(false, |ebb| lr.is_livein(ebb, forest, layout)) || self.cur.func.jump_tables[jt] .iter() - .any(|ebb| lr.is_livein(*ebb, ctx))) + .any(|ebb| lr.is_livein(*ebb, forest, layout))) } } } diff --git a/cranelift/codegen/src/regalloc/live_value_tracker.rs b/cranelift/codegen/src/regalloc/live_value_tracker.rs index 1b08862e37..adfe56c410 100644 --- a/cranelift/codegen/src/regalloc/live_value_tracker.rs +++ b/cranelift/codegen/src/regalloc/live_value_tracker.rs @@ -191,7 +191,6 @@ impl LiveValueTracker { .idom_sets .get(&idom) .expect("No stored live set for dominator"); - let ctx = liveness.context(layout); // Get just the values that are live-in to `ebb`. for &value in idom_live_list.as_slice(&self.idom_pool) { let lr = liveness @@ -199,7 +198,7 @@ impl LiveValueTracker { .expect("Immediate dominator value has no live range"); // Check if this value is live-in here. - if let Some(endpoint) = lr.livein_local_end(ebb, ctx) { + if let Some(endpoint) = lr.livein_local_end(ebb, liveness.forest(), layout) { self.live.push(value, endpoint, lr); } } diff --git a/cranelift/codegen/src/regalloc/liveness.rs b/cranelift/codegen/src/regalloc/liveness.rs index 7b31aedd54..1ace6bf6d1 100644 --- a/cranelift/codegen/src/regalloc/liveness.rs +++ b/cranelift/codegen/src/regalloc/liveness.rs @@ -181,7 +181,7 @@ use crate::ir::dfg::ValueDef; use crate::ir::{Ebb, Function, Inst, Layout, ProgramPoint, Value}; use crate::isa::{EncInfo, OperandConstraint, TargetIsa}; use crate::regalloc::affinity::Affinity; -use crate::regalloc::liverange::{LiveRange, LiveRangeContext, LiveRangeForest}; +use crate::regalloc::liverange::{LiveRange, LiveRangeForest}; use crate::timing; use core::mem; use core::ops::Index; @@ -314,16 +314,16 @@ impl Liveness { } } + /// Current forest storage. + pub fn forest(&self) -> &LiveRangeForest { + &self.forest + } + /// Current live ranges. pub fn ranges(&self) -> &LiveRangeSet { &self.ranges } - /// Get a context needed for working with a `LiveRange`. - pub fn context<'a>(&'a self, layout: &'a Layout) -> LiveRangeContext<'a, Layout> { - LiveRangeContext::new(layout, &self.forest) - } - /// Clear all data structures in this liveness analysis. pub fn clear(&mut self) { self.ranges.clear(); diff --git a/cranelift/codegen/src/regalloc/liverange.rs b/cranelift/codegen/src/regalloc/liverange.rs index 49d7f23cb2..6465b9ab8e 100644 --- a/cranelift/codegen/src/regalloc/liverange.rs +++ b/cranelift/codegen/src/regalloc/liverange.rs @@ -179,32 +179,6 @@ pub struct GenericLiveRange { po: PhantomData<*const PO>, } -/// Context information needed to query a `LiveRange`. -pub struct LiveRangeContext<'a, PO: 'a + ProgramOrder> { - /// Ordering of EBBs. - pub order: &'a PO, - /// Memory pool. - pub forest: &'a bforest::MapForest, -} - -impl<'a, PO: ProgramOrder> LiveRangeContext<'a, PO> { - /// Make a new context. - pub fn new(order: &'a PO, forest: &'a bforest::MapForest) -> Self { - Self { order, forest } - } -} - -impl<'a, PO: ProgramOrder> Clone for LiveRangeContext<'a, PO> { - fn clone(&self) -> Self { - LiveRangeContext { - order: self.order, - forest: self.forest, - } - } -} - -impl<'a, PO: ProgramOrder> Copy for LiveRangeContext<'a, PO> {} - /// Forest of B-trees used for storing live ranges. pub type LiveRangeForest = bforest::MapForest; @@ -371,13 +345,13 @@ impl GenericLiveRange { /// If the live range is live through all of `ebb`, the terminator of `ebb` is a correct /// answer, but it is also possible that an even later program point is returned. So don't /// depend on the returned `Inst` to belong to `ebb`. - pub fn livein_local_end(&self, ebb: Ebb, ctx: LiveRangeContext) -> Option { - let cmp = Cmp(ctx.order); + pub fn livein_local_end(&self, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> Option { + let cmp = Cmp(order); self.liveins - .get_or_less(ebb, ctx.forest, &cmp) + .get_or_less(ebb, forest, &cmp) .and_then(|(_, inst)| { // We have an entry that ends at `inst`. - if ctx.order.cmp(inst, ebb) == Ordering::Greater { + if order.cmp(inst, ebb) == Ordering::Greater { Some(inst) } else { None @@ -388,16 +362,16 @@ impl GenericLiveRange { /// Is this value live-in to `ebb`? /// /// An EBB argument is not considered to be live in. - pub fn is_livein(&self, ebb: Ebb, ctx: LiveRangeContext) -> bool { - self.livein_local_end(ebb, ctx).is_some() + pub fn is_livein(&self, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> bool { + self.livein_local_end(ebb, forest, order).is_some() } /// Get all the live-in intervals. /// /// Note that the intervals are stored in a compressed form so each entry may span multiple /// EBBs where the value is live in. - pub fn liveins<'a>(&'a self, ctx: LiveRangeContext<'a, PO>) -> bforest::MapIter<'a, Ebb, Inst> { - self.liveins.iter(ctx.forest) + pub fn liveins<'a>(&'a self, forest: &'a LiveRangeForest) -> bforest::MapIter<'a, Ebb, Inst> { + self.liveins.iter(forest) } /// Check if this live range overlaps a definition in `ebb`. @@ -405,7 +379,8 @@ impl GenericLiveRange { &self, def: ExpandedProgramPoint, ebb: Ebb, - ctx: LiveRangeContext, + forest: &LiveRangeForest, + order: &PO, ) -> bool { // Two defs at the same program point always overlap, even if one is dead. if def == self.def_begin.into() { @@ -413,38 +388,39 @@ impl GenericLiveRange { } // Check for an overlap with the local range. - if ctx.order.cmp(def, self.def_begin) != Ordering::Less - && ctx.order.cmp(def, self.def_end) == Ordering::Less + if order.cmp(def, self.def_begin) != Ordering::Less + && order.cmp(def, self.def_end) == Ordering::Less { return true; } // Check for an overlap with a live-in range. - match self.livein_local_end(ebb, ctx) { - Some(inst) => ctx.order.cmp(def, inst) == Ordering::Less, + match self.livein_local_end(ebb, forest, order) { + Some(inst) => order.cmp(def, inst) == Ordering::Less, None => false, } } /// Check if this live range reaches a use at `user` in `ebb`. - pub fn reaches_use(&self, user: Inst, ebb: Ebb, ctx: LiveRangeContext) -> bool { + pub fn reaches_use(&self, user: Inst, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> bool { // Check for an overlap with the local range. - if ctx.order.cmp(user, self.def_begin) == Ordering::Greater - && ctx.order.cmp(user, self.def_end) != Ordering::Greater + if order.cmp(user, self.def_begin) == Ordering::Greater + && order.cmp(user, self.def_end) != Ordering::Greater { return true; } // Check for an overlap with a live-in range. - match self.livein_local_end(ebb, ctx) { - Some(inst) => ctx.order.cmp(user, inst) != Ordering::Greater, + match self.livein_local_end(ebb, forest, order) { + Some(inst) => order.cmp(user, inst) != Ordering::Greater, None => false, } } /// Check if this live range is killed at `user` in `ebb`. - pub fn killed_at(&self, user: Inst, ebb: Ebb, ctx: LiveRangeContext) -> bool { - self.def_local_end() == user.into() || self.livein_local_end(ebb, ctx) == Some(user) + pub fn killed_at(&self, user: Inst, ebb: Ebb, forest: &LiveRangeForest, order: &PO) -> bool { + self.def_local_end() == user.into() + || self.livein_local_end(ebb, forest, order) == Some(user) } } @@ -457,7 +433,7 @@ impl SparseMapValue for GenericLiveRange { #[cfg(test)] mod tests { - use super::{GenericLiveRange, LiveRangeContext}; + use super::GenericLiveRange; use crate::bforest; use crate::entity::EntityRef; use crate::ir::{Ebb, Inst, Value}; @@ -560,18 +536,17 @@ mod tests { let e2 = Ebb::new(2); let lr = GenericLiveRange::new(v0, i1.into(), Default::default()); let forest = &bforest::MapForest::new(); - let ctx = LiveRangeContext::new(PO, forest); assert!(lr.is_dead()); assert!(lr.is_local()); assert_eq!(lr.def(), i1.into()); assert_eq!(lr.def_local_end(), i1.into()); - assert_eq!(lr.livein_local_end(e2, ctx), None); - PO.validate(&lr, ctx.forest); + assert_eq!(lr.livein_local_end(e2, forest, PO), None); + PO.validate(&lr, forest); // A dead live range overlaps its own def program point. - assert!(lr.overlaps_def(i1.into(), e0, ctx)); - assert!(!lr.overlaps_def(i2.into(), e0, ctx)); - assert!(!lr.overlaps_def(e0.into(), e0, ctx)); + assert!(lr.overlaps_def(i1.into(), e0, forest, PO)); + assert!(!lr.overlaps_def(i2.into(), e0, forest, PO)); + assert!(!lr.overlaps_def(e0.into(), e0, forest, PO)); } #[test] @@ -580,14 +555,13 @@ mod tests { let e2 = Ebb::new(2); let lr = GenericLiveRange::new(v0, e2.into(), Default::default()); let forest = &bforest::MapForest::new(); - let ctx = LiveRangeContext::new(PO, forest); assert!(lr.is_dead()); assert!(lr.is_local()); assert_eq!(lr.def(), e2.into()); assert_eq!(lr.def_local_end(), e2.into()); // The def interval of an EBB argument does not count as live-in. - assert_eq!(lr.livein_local_end(e2, ctx), None); - PO.validate(&lr, ctx.forest); + assert_eq!(lr.livein_local_end(e2, forest, PO), None); + PO.validate(&lr, forest); } #[test] @@ -664,25 +638,16 @@ mod tests { // Adding a live-in interval. assert_eq!(lr.extend_in_ebb(e20, i22, PO, forest), true); PO.validate(&lr, forest); - assert_eq!( - lr.livein_local_end(e20, LiveRangeContext::new(PO, forest)), - Some(i22) - ); + assert_eq!(lr.livein_local_end(e20, forest, PO), Some(i22)); // Non-extending the live-in. assert_eq!(lr.extend_in_ebb(e20, i21, PO, forest), false); - assert_eq!( - lr.livein_local_end(e20, LiveRangeContext::new(PO, forest)), - Some(i22) - ); + assert_eq!(lr.livein_local_end(e20, forest, PO), Some(i22)); // Extending the existing live-in. assert_eq!(lr.extend_in_ebb(e20, i23, PO, forest), false); PO.validate(&lr, forest); - assert_eq!( - lr.livein_local_end(e20, LiveRangeContext::new(PO, forest)), - Some(i23) - ); + assert_eq!(lr.livein_local_end(e20, forest, PO), Some(i23)); } #[test] @@ -699,52 +664,29 @@ mod tests { let forest = &mut bforest::MapForest::new(); assert_eq!(lr.extend_in_ebb(e30, i31, PO, forest), true); - assert_eq!( - lr.liveins(LiveRangeContext::new(PO, forest)) - .collect::>(), - [(e30, i31)] - ); + assert_eq!(lr.liveins(forest).collect::>(), [(e30, i31)]); // Coalesce to previous assert_eq!(lr.extend_in_ebb(e40, i41, PO, forest), true); - assert_eq!( - lr.liveins(LiveRangeContext::new(PO, forest)) - .collect::>(), - [(e30, i41)] - ); + assert_eq!(lr.liveins(forest).collect::>(), [(e30, i41)]); // Coalesce to next assert_eq!(lr.extend_in_ebb(e20, i21, PO, forest), true); - assert_eq!( - lr.liveins(LiveRangeContext::new(PO, forest)) - .collect::>(), - [(e20, i41)] - ); + assert_eq!(lr.liveins(forest).collect::>(), [(e20, i41)]); let mut lr = GenericLiveRange::new(v0, i11.into(), Default::default()); assert_eq!(lr.extend_in_ebb(e40, i41, PO, forest), true); - assert_eq!( - lr.liveins(LiveRangeContext::new(PO, forest)) - .collect::>(), - [(e40, i41)] - ); + assert_eq!(lr.liveins(forest).collect::>(), [(e40, i41)]); assert_eq!(lr.extend_in_ebb(e20, i21, PO, forest), true); assert_eq!( - lr.liveins(LiveRangeContext::new(PO, forest)) - .collect::>(), + lr.liveins(forest).collect::>(), [(e20, i21), (e40, i41)] ); // Coalesce to previous and next assert_eq!(lr.extend_in_ebb(e30, i31, PO, forest), true); - assert_eq!( - lr.liveins(LiveRangeContext::new(PO, forest)) - .collect::>(), - [(e20, i41)] - ); + assert_eq!(lr.liveins(forest).collect::>(), [(e20, i41)]); } - - // TODO: Add more tests that exercise the binary search algorithm. } diff --git a/cranelift/codegen/src/regalloc/spilling.rs b/cranelift/codegen/src/regalloc/spilling.rs index f45dd41c94..0012ad01d8 100644 --- a/cranelift/codegen/src/regalloc/spilling.rs +++ b/cranelift/codegen/src/regalloc/spilling.rs @@ -319,17 +319,18 @@ impl<'a> Context<'a> { for (idx, (op, &arg)) in constraints.ins.iter().zip(args).enumerate() { let mut reguse = RegUse::new(arg, idx, op.regclass.into()); let lr = &self.liveness[arg]; - let ctx = self.liveness.context(&self.cur.func.layout); match op.kind { ConstraintKind::Stack => continue, ConstraintKind::FixedReg(_) => reguse.fixed = true, ConstraintKind::Tied(_) => { // A tied operand must kill the used value. - reguse.tied = !lr.killed_at(inst, ebb, ctx); + reguse.tied = + !lr.killed_at(inst, ebb, self.liveness.forest(), &self.cur.func.layout); } ConstraintKind::FixedTied(_) => { reguse.fixed = true; - reguse.tied = !lr.killed_at(inst, ebb, ctx); + reguse.tied = + !lr.killed_at(inst, ebb, self.liveness.forest(), &self.cur.func.layout); } ConstraintKind::Reg => {} } diff --git a/cranelift/codegen/src/value_label.rs b/cranelift/codegen/src/value_label.rs index 2bd3bdc13d..d3d1e0672c 100644 --- a/cranelift/codegen/src/value_label.rs +++ b/cranelift/codegen/src/value_label.rs @@ -96,8 +96,8 @@ where ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase let encinfo = isa.encoding_info(); let values_locations = &func.locations; - let liveness_context = regalloc.liveness().context(&func.layout); let liveness_ranges = regalloc.liveness().ranges(); + let liveness_forest = regalloc.liveness().forest(); let mut ranges = HashMap::new(); let mut add_range = |label, range: (u32, u32), loc: ValueLoc| { @@ -126,7 +126,10 @@ where // Remove killed values. tracked_values.retain(|(x, label, start_offset, last_loc)| { let range = liveness_ranges.get(*x); - if range.expect("value").killed_at(inst, ebb, liveness_context) { + if range + .expect("value") + .killed_at(inst, ebb, &liveness_forest, &func.layout) + { add_range(*label, (*start_offset, end_offset), *last_loc); return false; } @@ -173,7 +176,7 @@ where // Ignore dead/inactive Values. let range = liveness_ranges.get(*v); match range { - Some(r) => r.reaches_use(inst, ebb, liveness_context), + Some(r) => r.reaches_use(inst, ebb, &liveness_forest, &func.layout), None => false, } }); diff --git a/cranelift/codegen/src/verifier/cssa.rs b/cranelift/codegen/src/verifier/cssa.rs index 6014ff8030..3878f096d1 100644 --- a/cranelift/codegen/src/verifier/cssa.rs +++ b/cranelift/codegen/src/verifier/cssa.rs @@ -118,8 +118,12 @@ impl<'a> CssaVerifier<'a> { if self.preorder.dominates(prev_ebb, def_ebb) && self.domtree.dominates(prev_def, def, &self.func.layout) { - let ctx = self.liveness.context(&self.func.layout); - if self.liveness[prev_val].overlaps_def(def, def_ebb, ctx) { + if self.liveness[prev_val].overlaps_def( + def, + def_ebb, + self.liveness.forest(), + &self.func.layout, + ) { return fatal!( errors, val, diff --git a/cranelift/codegen/src/verifier/liveness.rs b/cranelift/codegen/src/verifier/liveness.rs index 11cde21e6f..37b59c154d 100644 --- a/cranelift/codegen/src/verifier/liveness.rs +++ b/cranelift/codegen/src/verifier/liveness.rs @@ -64,7 +64,6 @@ impl<'a> LivenessVerifier<'a> { /// Check all instructions. fn check_insts(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> { - let lr_ctx = self.liveness.context(&self.func.layout); for ebb in self.func.layout.ebbs() { for inst in self.func.layout.ebb_insts(ebb) { let encoding = self.func.encodings[inst]; @@ -107,8 +106,8 @@ impl<'a> LivenessVerifier<'a> { None => return fatal!(errors, inst, "{} has no live range", val), }; - debug_assert!(lr_ctx.order.inst_ebb(inst).unwrap() == ebb); - if !lr.reaches_use(inst, ebb, lr_ctx) { + debug_assert!(self.func.layout.inst_ebb(inst).unwrap() == ebb); + if !lr.reaches_use(inst, ebb, self.liveness.forest(), &self.func.layout) { return fatal!(errors, inst, "{} is not live at this use", val); } @@ -180,7 +179,7 @@ impl<'a> LivenessVerifier<'a> { } // Now check the live-in intervals against the CFG. - for (mut ebb, end) in lr.liveins(self.liveness.context(l)) { + for (mut ebb, end) in lr.liveins(self.liveness.forest()) { if !l.is_ebb_inserted(ebb) { return fatal!( errors, @@ -204,13 +203,11 @@ impl<'a> LivenessVerifier<'a> { } }; - let lr_ctx = self.liveness.context(&self.func.layout); - // Check all the EBBs in the interval independently. loop { // If `val` is live-in at `ebb`, it must be live at all the predecessors. for BasicBlock { inst: pred, ebb } in self.cfg.pred_iter(ebb) { - if !lr.reaches_use(pred, ebb, lr_ctx) { + if !lr.reaches_use(pred, ebb, self.liveness.forest(), &self.func.layout) { return fatal!( errors, pred, diff --git a/cranelift/codegen/src/verifier/locations.rs b/cranelift/codegen/src/verifier/locations.rs index cf17ae13de..d32bb7e4bd 100644 --- a/cranelift/codegen/src/verifier/locations.rs +++ b/cranelift/codegen/src/verifier/locations.rs @@ -334,10 +334,10 @@ impl<'a> LocationVerifier<'a> { let lr = &liveness[value]; if is_after_branch && unique_predecessor { // Forward diversions based on the targeted branch. - if !lr.is_livein(ebb, liveness.context(&self.func.layout)) { + if !lr.is_livein(ebb, liveness.forest(), &self.func.layout) { val_to_remove.push(value) } - } else if lr.is_livein(ebb, liveness.context(&self.func.layout)) { + } else if lr.is_livein(ebb, liveness.forest(), &self.func.layout) { return fatal!( errors, inst, @@ -359,7 +359,7 @@ impl<'a> LocationVerifier<'a> { for (&value, d) in divert.iter() { let lr = &liveness[value]; if let Some(ebb) = ebb { - if lr.is_livein(ebb, liveness.context(&self.func.layout)) { + if lr.is_livein(ebb, liveness.forest(), &self.func.layout) { return fatal!( errors, inst, @@ -371,7 +371,7 @@ impl<'a> LocationVerifier<'a> { } } for ebb in self.func.jump_tables[jt].iter() { - if lr.is_livein(*ebb, liveness.context(&self.func.layout)) { + if lr.is_livein(*ebb, liveness.forest(), &self.func.layout) { return fatal!( errors, inst,