diff --git a/cranelift/codegen/src/regalloc/coloring.rs b/cranelift/codegen/src/regalloc/coloring.rs index f7fb50129f..c6c48bf78c 100644 --- a/cranelift/codegen/src/regalloc/coloring.rs +++ b/cranelift/codegen/src/regalloc/coloring.rs @@ -588,8 +588,8 @@ impl<'a> Context<'a> { // Copy register assignments from tied inputs to tied outputs. if let Some(constraints) = constraints { if constraints.tied_ops { - for (op, lv) in constraints.outs.iter().zip(defs) { - if let ConstraintKind::Tied(num) = op.kind { + for (constraint, lv) in constraints.outs.iter().zip(defs) { + if let ConstraintKind::Tied(num) = constraint.kind { let arg = self.cur.func.dfg.inst_args(inst)[num as usize]; let reg = self.divert.reg(arg, &self.cur.func.locations); self.cur.func.locations[lv.value] = ValueLoc::Reg(reg); @@ -650,46 +650,46 @@ impl<'a> Context<'a> { /// Program the input-side constraints for `inst` into the constraint solver. fn program_input_constraints(&mut self, inst: Inst, constraints: &[OperandConstraint]) { - for (op, &value) in constraints + for (constraint, &arg_val) in constraints .iter() .zip(self.cur.func.dfg.inst_args(inst)) - .filter(|&(op, _)| op.kind != ConstraintKind::Stack) + .filter(|&(constraint, _)| constraint.kind != ConstraintKind::Stack) { // Reload pass is supposed to ensure that all arguments to register operands are // already in a register. - let cur_reg = self.divert.reg(value, &self.cur.func.locations); - match op.kind { + let cur_reg = self.divert.reg(arg_val, &self.cur.func.locations); + match constraint.kind { ConstraintKind::FixedReg(regunit) => { // Add the fixed constraint even if `cur_reg == regunit`. // It is possible that we will want to convert the value to a variable later, // and this identity assignment prevents that from happening. self.solver - .reassign_in(value, op.regclass, cur_reg, regunit); + .reassign_in(arg_val, constraint.regclass, cur_reg, regunit); } ConstraintKind::FixedTied(regunit) => { // The pinned register may not be part of a fixed tied requirement. If this // becomes the case, then it must be changed to a different register. debug_assert!( - !self.is_pinned_reg(op.regclass, regunit), + !self.is_pinned_reg(constraint.regclass, regunit), "see comment above" ); // See comment right above. self.solver - .reassign_in(value, op.regclass, cur_reg, regunit); + .reassign_in(arg_val, constraint.regclass, cur_reg, regunit); } ConstraintKind::Tied(_) => { - if self.is_pinned_reg(op.regclass, cur_reg) { + if self.is_pinned_reg(constraint.regclass, cur_reg) { // Divert the pinned register; it shouldn't be reused for a tied input. - if self.solver.can_add_var(op.regclass, cur_reg) { - self.solver.add_var(value, op.regclass, cur_reg); + if self.solver.can_add_var(constraint.regclass, cur_reg) { + self.solver.add_var(arg_val, constraint.regclass, cur_reg); } - } else if !op.regclass.contains(cur_reg) { - self.solver.add_var(value, op.regclass, cur_reg); + } else if !constraint.regclass.contains(cur_reg) { + self.solver.add_var(arg_val, constraint.regclass, cur_reg); } } ConstraintKind::Reg => { - if !op.regclass.contains(cur_reg) { - self.solver.add_var(value, op.regclass, cur_reg); + if !constraint.regclass.contains(cur_reg) { + self.solver.add_var(arg_val, constraint.regclass, cur_reg); } } ConstraintKind::Stack => unreachable!(), @@ -714,22 +714,25 @@ impl<'a> Context<'a> { .expect("Current instruction not encoded") .ins; - for (op, &value) in constraints.iter().zip(self.cur.func.dfg.inst_args(inst)) { - match op.kind { + for (constraint, &arg_val) in constraints.iter().zip(self.cur.func.dfg.inst_args(inst)) { + match constraint.kind { ConstraintKind::Reg | ConstraintKind::Tied(_) => { - let cur_reg = self.divert.reg(value, &self.cur.func.locations); + let cur_reg = self.divert.reg(arg_val, &self.cur.func.locations); // This is the opposite condition of `program_input_constraints()`. The pinned // register mustn't be added back as a variable. - if op.regclass.contains(cur_reg) && !self.is_pinned_reg(op.regclass, cur_reg) { + if constraint.regclass.contains(cur_reg) + && !self.is_pinned_reg(constraint.regclass, cur_reg) + { // 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. + // the new variable as killed or live-through. let layout = &self.cur.func.layout; - if self.liveness[value].killed_at(inst, layout.pp_ebb(inst), layout) { - self.solver.add_killed_var(value, op.regclass, cur_reg); + if self.liveness[arg_val].killed_at(inst, layout.pp_ebb(inst), layout) { + self.solver + .add_killed_var(arg_val, constraint.regclass, cur_reg); } else { - self.solver.add_through_var(value, op.regclass, cur_reg); + self.solver + .add_through_var(arg_val, constraint.regclass, cur_reg); } } } @@ -862,6 +865,10 @@ impl<'a> Context<'a> { let toprc = self.reginfo.toprc(rci); let reg = self.divert.reg(lv.value, &self.cur.func.locations); if self.solver.is_fixed_input_conflict(toprc, reg) { + debug!( + "adding var to divert fixed input conflict for {}", + toprc.info.display_regunit(reg) + ); self.solver.add_var(lv.value, toprc, reg); } } @@ -879,15 +886,15 @@ impl<'a> Context<'a> { replace_global_defines: &mut bool, global_regs: &RegisterSet, ) { - for (op, lv) in constraints.iter().zip(defs) { - match op.kind { + for (constraint, lv) in constraints.iter().zip(defs) { + match constraint.kind { ConstraintKind::FixedReg(reg) | ConstraintKind::FixedTied(reg) => { - self.add_fixed_output(lv.value, op.regclass, reg, throughs); - if !lv.is_local && !global_regs.is_avail(op.regclass, reg) { + self.add_fixed_output(lv.value, constraint.regclass, reg, throughs); + if !lv.is_local && !global_regs.is_avail(constraint.regclass, reg) { debug!( "Fixed output {} in {}:{} is not available in global regs", lv.value, - op.regclass, + constraint.regclass, self.reginfo.display_regunit(reg) ); *replace_global_defines = true; @@ -976,13 +983,14 @@ impl<'a> Context<'a> { replace_global_defines: &mut bool, global_regs: &RegisterSet, ) { - for (op, lv) in constraints.iter().zip(defs) { - match op.kind { + for (constraint, lv) in constraints.iter().zip(defs) { + match constraint.kind { ConstraintKind::FixedReg(_) | ConstraintKind::FixedTied(_) | ConstraintKind::Stack => continue, ConstraintKind::Reg => { - self.solver.add_def(lv.value, op.regclass, !lv.is_local); + self.solver + .add_def(lv.value, constraint.regclass, !lv.is_local); } ConstraintKind::Tied(num) => { // Find the input operand we're tied to. @@ -992,16 +1000,16 @@ impl<'a> Context<'a> { if let Some(reg) = self.solver - .add_tied_input(arg, op.regclass, reg, !lv.is_local) + .add_tied_input(arg, constraint.regclass, reg, !lv.is_local) { // The value we're tied to has been assigned to a fixed register. // We need to make sure that fixed output register is compatible with the // global register set. - if !lv.is_local && !global_regs.is_avail(op.regclass, reg) { + if !lv.is_local && !global_regs.is_avail(constraint.regclass, reg) { debug!( "Tied output {} in {}:{} is not available in global regs", lv.value, - op.regclass, + constraint.regclass, self.reginfo.display_regunit(reg) ); *replace_global_defines = true; diff --git a/cranelift/codegen/src/regalloc/pressure.rs b/cranelift/codegen/src/regalloc/pressure.rs index 73c7fbc1a3..3783a78e28 100644 --- a/cranelift/codegen/src/regalloc/pressure.rs +++ b/cranelift/codegen/src/regalloc/pressure.rs @@ -48,20 +48,20 @@ use cranelift_codegen_shared::constants::MAX_TRACKED_TOP_RCS; /// Everything but the counts is static information computed from the constructor arguments. #[derive(Default)] struct TopRC { - // Number of registers currently used from this register class. + /// Number of registers currently used from this register class. base_count: u32, transient_count: u32, - // Max number of registers that can be allocated. + /// Max number of registers that can be allocated. limit: u32, - // Register units per register. + /// Register units per register. width: u8, - // The first aliasing top-level RC. + /// The first aliasing top-level RC. first_toprc: u8, - // The number of aliasing top-level RCs. + /// The number of aliasing top-level RCs. num_toprcs: u8, } @@ -72,11 +72,11 @@ impl TopRC { } pub struct Pressure { - // Bit mask of top-level register classes that are aliased by other top-level register classes. - // Unaliased register classes can use a simpler interference algorithm. + /// Bit mask of top-level register classes that are aliased by other top-level register classes. + /// Unaliased register classes can use a simpler interference algorithm. aliased: RegClassMask, - // Current register counts per top-level register class. + /// Current register counts per top-level register class. toprc: [TopRC; MAX_TRACKED_TOP_RCS], } diff --git a/cranelift/codegen/src/regalloc/solver.rs b/cranelift/codegen/src/regalloc/solver.rs index 5b63b2825a..5a3e1df908 100644 --- a/cranelift/codegen/src/regalloc/solver.rs +++ b/cranelift/codegen/src/regalloc/solver.rs @@ -265,6 +265,7 @@ pub enum Move { from: RegUnit, to: RegUnit, }, + #[allow(dead_code)] // rustc doesn't see it isn't dead. Spill { value: Value, rc: RegClass, @@ -283,7 +284,7 @@ impl Move { /// Create a register move from an assignment, but not for identity assignments. fn with_assignment(a: &Assignment) -> Option { if a.from != a.to { - Some(Move::Reg { + Some(Self::Reg { value: a.value, from: a.from, to: a.to, @@ -298,16 +299,16 @@ impl Move { #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))] fn from_reg(&self) -> Option<(RegClass, RegUnit)> { match *self { - Move::Reg { rc, from, .. } | Move::Spill { rc, from, .. } => Some((rc, from)), - Move::Fill { .. } => None, + Self::Reg { rc, from, .. } | Self::Spill { rc, from, .. } => Some((rc, from)), + Self::Fill { .. } => None, } } /// Get the "to" register and register class, if possible. fn to_reg(&self) -> Option<(RegClass, RegUnit)> { match *self { - Move::Reg { rc, to, .. } | Move::Fill { rc, to, .. } => Some((rc, to)), - Move::Spill { .. } => None, + Self::Reg { rc, to, .. } | Self::Fill { rc, to, .. } => Some((rc, to)), + Self::Spill { .. } => None, } } @@ -315,8 +316,8 @@ impl Move { fn replace_to_reg(&mut self, new: RegUnit) -> RegUnit { mem::replace( match *self { - Move::Reg { ref mut to, .. } | Move::Fill { ref mut to, .. } => to, - Move::Spill { .. } => panic!("No to register in a spill {}", self), + Self::Reg { ref mut to, .. } | Self::Fill { ref mut to, .. } => to, + Self::Spill { .. } => panic!("No to register in a spill {}", self), }, new, ) @@ -325,13 +326,13 @@ impl Move { /// Convert this `Reg` move to a spill to `slot` and return the old "to" register. fn change_to_spill(&mut self, slot: usize) -> RegUnit { match self.clone() { - Move::Reg { + Self::Reg { value, rc, from, to, } => { - *self = Move::Spill { + *self = Self::Spill { value, rc, from, @@ -346,14 +347,14 @@ impl Move { /// Get the value being moved. fn value(&self) -> Value { match *self { - Move::Reg { value, .. } | Move::Fill { value, .. } | Move::Spill { value, .. } => value, + Self::Reg { value, .. } | Self::Fill { value, .. } | Self::Spill { value, .. } => value, } } /// Get the associated register class. fn rc(&self) -> RegClass { match *self { - Move::Reg { rc, .. } | Move::Fill { rc, .. } | Move::Spill { rc, .. } => rc, + Self::Reg { rc, .. } | Self::Fill { rc, .. } | Self::Spill { rc, .. } => rc, } } } @@ -361,7 +362,7 @@ impl Move { impl fmt::Display for Move { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Move::Reg { + Self::Reg { value, from, to, @@ -374,7 +375,7 @@ impl fmt::Display for Move { rc.info.display_regunit(from), rc.info.display_regunit(to) ), - Move::Spill { + Self::Spill { value, from, to_slot, @@ -387,7 +388,7 @@ impl fmt::Display for Move { rc.info.display_regunit(from), to_slot ), - Move::Fill { + Self::Fill { value, from_slot, to, @@ -593,67 +594,57 @@ impl Solver { /// instruction. /// /// This function should be called after `inputs_done()` only. Use `add_var()` before. - pub fn add_killed_var(&mut self, value: Value, constraint: RegClass, from: RegUnit) { + pub fn add_killed_var(&mut self, value: Value, rc: RegClass, from: RegUnit) { debug!( "add_killed_var({}:{}, from={})", value, - constraint, - constraint.info.display_regunit(from) + rc, + rc.info.display_regunit(from) ); debug_assert!(self.inputs_done); - self.add_live_var(value, constraint, from, false); + self.add_live_var(value, rc, from, false); } /// Add an extra input-side variable representing a value that is live through the current /// instruction. /// /// This function should be called after `inputs_done()` only. Use `add_var()` before. - pub fn add_through_var(&mut self, value: Value, constraint: RegClass, from: RegUnit) { + pub fn add_through_var(&mut self, value: Value, rc: RegClass, from: RegUnit) { debug!( "add_through_var({}:{}, from={})", value, - constraint, - constraint.info.display_regunit(from) + rc, + rc.info.display_regunit(from) ); debug_assert!(self.inputs_done); - self.add_live_var(value, constraint, from, true); + self.add_live_var(value, rc, from, true); } /// Shared code for `add_var`, `add_killed_var`, and `add_through_var`. /// /// Add a variable that is live before the instruction, and possibly live through. Merge /// constraints if the value has already been added as a variable or fixed assignment. - fn add_live_var( - &mut self, - value: Value, - constraint: RegClass, - from: RegUnit, - live_through: bool, - ) { + fn add_live_var(&mut self, value: Value, rc: RegClass, from: RegUnit, live_through: bool) { // Check for existing entries for this value. - if self.regs_in.is_avail(constraint, from) { + if self.regs_in.is_avail(rc, from) { // There could be an existing variable entry. if let Some(v) = self.vars.iter_mut().find(|v| v.value == value) { // We have an existing variable entry for `value`. Combine the constraints. - if let Some(rc) = v.constraint.intersect(constraint) { + if let Some(rc) = v.constraint.intersect(rc) { debug!("-> combining constraint with {} yields {}", v, rc); v.constraint = rc; return; } else { // The spiller should have made sure the same value is not used with disjoint // constraints. - panic!("Incompatible constraints: {} + {}", constraint, v) + panic!("Incompatible constraints: {} + {}", rc, v) } } // No variable, then it must be a fixed reassignment. if let Some(a) = self.assignments.get(value) { debug!("-> already fixed assignment {}", a); - debug_assert!( - constraint.contains(a.to), - "Incompatible constraints for {}", - value - ); + debug_assert!(rc.contains(a.to), "Incompatible constraints for {}", value); return; } @@ -661,12 +652,12 @@ impl Solver { panic!("Wrong from register for {}", value); } - let new_var = Variable::new_live(value, constraint, from, live_through); + let new_var = Variable::new_live(value, rc, from, live_through); debug!("-> new var: {}", new_var); - self.regs_in.free(constraint, from); + self.regs_in.free(rc, from); if self.inputs_done && live_through { - self.regs_out.free(constraint, from); + self.regs_out.free(rc, from); } self.vars.push(new_var); } @@ -1007,7 +998,7 @@ impl Solver { self.moves .extend(self.assignments.values().filter_map(Move::with_assignment)); - if !(self.moves.is_empty()) { + if !self.moves.is_empty() { debug!("collect_moves: {}", DisplayList(&self.moves)); } }