diff --git a/lib/codegen/src/regalloc/coloring.rs b/lib/codegen/src/regalloc/coloring.rs index 8ce42737d6..d040140984 100644 --- a/lib/codegen/src/regalloc/coloring.rs +++ b/lib/codegen/src/regalloc/coloring.rs @@ -654,10 +654,10 @@ impl<'a> Context<'a> { where Pred: FnMut(&LiveRange, LiveRangeContext) -> bool, { - for rdiv in self.divert.all() { + for (&value, rdiv) in self.divert.iter() { let lr = self .liveness - .get(rdiv.value) + .get(value) .expect("Missing live range for diverted register"); if pred(lr, self.liveness.context(&self.cur.func.layout)) { if let Affinity::Reg(rci) = lr.affinity { @@ -665,7 +665,7 @@ impl<'a> Context<'a> { // Stack diversions should not be possible here. The only live transiently // during `shuffle_inputs()`. self.solver.reassign_in( - rdiv.value, + value, rc, rdiv.to.unwrap_reg(), rdiv.from.unwrap_reg(), @@ -673,7 +673,7 @@ impl<'a> Context<'a> { } else { panic!( "Diverted register {} with {} affinity", - rdiv.value, + value, lr.affinity.display(&self.reginfo) ); } diff --git a/lib/codegen/src/regalloc/diversion.rs b/lib/codegen/src/regalloc/diversion.rs index 3572acd543..090bf936c9 100644 --- a/lib/codegen/src/regalloc/diversion.rs +++ b/lib/codegen/src/regalloc/diversion.rs @@ -7,11 +7,12 @@ //! These register diversions are local to an EBB. No values can be diverted when entering a new //! EBB. +use fx::FxHashMap; use ir::{InstructionData, Opcode}; use ir::{StackSlot, Value, ValueLoc, ValueLocations}; use isa::{RegInfo, RegUnit}; +use std::collections::hash_map::{Entry, Iter}; use std::fmt; -use std::vec::Vec; /// A diversion of a value from its original location to a new register or stack location. /// @@ -22,8 +23,6 @@ use std::vec::Vec; /// the current one. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Diversion { - /// The value that is diverted. - pub value: Value, /// The original value location. pub from: ValueLoc, /// The current value location. @@ -32,22 +31,22 @@ pub struct Diversion { impl Diversion { /// Make a new diversion. - pub fn new(value: Value, from: ValueLoc, to: ValueLoc) -> Self { + pub fn new(from: ValueLoc, to: ValueLoc) -> Self { debug_assert!(from.is_assigned() && to.is_assigned()); - Self { value, from, to } + Self { from, to } } } /// Keep track of diversions in an EBB. pub struct RegDiversions { - current: Vec, + current: FxHashMap, } impl RegDiversions { /// Create a new empty diversion tracker. pub fn new() -> Self { Self { - current: Vec::new(), + current: FxHashMap::default(), } } @@ -63,12 +62,12 @@ impl RegDiversions { /// Get the current diversion of `value`, if any. pub fn diversion(&self, value: Value) -> Option<&Diversion> { - self.current.iter().find(|d| d.value == value) + self.current.get(&value) } /// Get all current diversions. - pub fn all(&self) -> &[Diversion] { - self.current.as_slice() + pub fn iter(&self) -> Iter<'_, Value, Diversion> { + self.current.iter() } /// Get the current location for `value`. Fall back to the assignment map for non-diverted @@ -95,15 +94,22 @@ impl RegDiversions { /// The `from` location must match an existing `to` location, if any. pub fn divert(&mut self, value: Value, from: ValueLoc, to: ValueLoc) { debug_assert!(from.is_assigned() && to.is_assigned()); - if let Some(i) = self.current.iter().position(|d| d.value == value) { - debug_assert_eq!(self.current[i].to, from, "Bad regmove chain for {}", value); - if self.current[i].from != to { - self.current[i].to = to; - } else { - self.current.swap_remove(i); + match self.current.entry(value) { + Entry::Occupied(mut e) => { + // TODO: non-lexical lifetimes should allow removal of the scope and early return. + { + let d = e.get_mut(); + debug_assert_eq!(d.to, from, "Bad regmove chain for {}", value); + if d.from != to { + d.to = to; + return; + } + } + e.remove(); + } + Entry::Vacant(e) => { + e.insert(Diversion::new(from, to)); } - } else { - self.current.push(Diversion::new(value, from, to)); } } @@ -154,10 +160,7 @@ impl RegDiversions { /// /// Returns the `to` location 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) + self.current.remove(&value).map(|d| d.to) } /// Return an object that can display the diversions. @@ -172,11 +175,11 @@ pub struct DisplayDiversions<'a>(&'a RegDiversions, Option<&'a RegInfo>); impl<'a> fmt::Display for DisplayDiversions<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{")?; - for div in self.0.all() { + for (value, div) in self.0.iter() { write!( f, " {}: {} -> {}", - div.value, + value, div.from.display(self.1), div.to.display(self.1) )? @@ -201,7 +204,6 @@ mod tests { assert_eq!( divs.diversion(v1), Some(&Diversion { - value: v1, from: ValueLoc::Reg(10), to: ValueLoc::Reg(12), }) diff --git a/lib/codegen/src/verifier/locations.rs b/lib/codegen/src/verifier/locations.rs index 4962ef916b..f03a2bed37 100644 --- a/lib/codegen/src/verifier/locations.rs +++ b/lib/codegen/src/verifier/locations.rs @@ -318,14 +318,14 @@ impl<'a> LocationVerifier<'a> { dfg.display_inst(inst, self.isa) ), SingleDest(ebb, _) => { - for d in divert.all() { - let lr = &liveness[d.value]; + for (&value, d) in divert.iter() { + let lr = &liveness[value]; if lr.is_livein(ebb, liveness.context(&self.func.layout)) { return fatal!( errors, inst, "{} is diverted to {} and live in to {}", - d.value, + value, d.to.display(&self.reginfo), ebb ); @@ -333,15 +333,15 @@ impl<'a> LocationVerifier<'a> { } } Table(jt, ebb) => { - for d in divert.all() { - let lr = &liveness[d.value]; + 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)) { return fatal!( errors, inst, "{} is diverted to {} and live in to {}", - d.value, + value, d.to.display(&self.reginfo), ebb ); @@ -353,7 +353,7 @@ impl<'a> LocationVerifier<'a> { errors, inst, "{} is diverted to {} and live in to {}", - d.value, + value, d.to.display(&self.reginfo), ebb ); diff --git a/lib/entity/src/map.rs b/lib/entity/src/map.rs index dbec7b2f11..c7ced088f7 100644 --- a/lib/entity/src/map.rs +++ b/lib/entity/src/map.rs @@ -97,6 +97,7 @@ where } /// Resize the map to have `n` entries by adding default entries as needed. + #[inline] pub fn resize(&mut self, n: usize) { self.elems.resize(n, self.default.clone()); } @@ -125,6 +126,7 @@ where K: EntityRef, V: Clone, { + #[inline] fn index_mut(&mut self, k: K) -> &mut V { let i = k.index(); if i >= self.elems.len() {