Regalloc: rename "constraint" to "rc" and "op" to "constraint";

This commit is contained in:
Benjamin Bouvier
2019-10-08 18:03:58 +02:00
committed by Dan Gohman
parent 05cc8823c2
commit beca77c2f8
3 changed files with 84 additions and 85 deletions

View File

@@ -588,8 +588,8 @@ impl<'a> Context<'a> {
// Copy register assignments from tied inputs to tied outputs. // Copy register assignments from tied inputs to tied outputs.
if let Some(constraints) = constraints { if let Some(constraints) = constraints {
if constraints.tied_ops { if constraints.tied_ops {
for (op, lv) in constraints.outs.iter().zip(defs) { for (constraint, lv) in constraints.outs.iter().zip(defs) {
if let ConstraintKind::Tied(num) = op.kind { if let ConstraintKind::Tied(num) = constraint.kind {
let arg = self.cur.func.dfg.inst_args(inst)[num as usize]; let arg = self.cur.func.dfg.inst_args(inst)[num as usize];
let reg = self.divert.reg(arg, &self.cur.func.locations); let reg = self.divert.reg(arg, &self.cur.func.locations);
self.cur.func.locations[lv.value] = ValueLoc::Reg(reg); 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. /// Program the input-side constraints for `inst` into the constraint solver.
fn program_input_constraints(&mut self, inst: Inst, constraints: &[OperandConstraint]) { fn program_input_constraints(&mut self, inst: Inst, constraints: &[OperandConstraint]) {
for (op, &value) in constraints for (constraint, &arg_val) in constraints
.iter() .iter()
.zip(self.cur.func.dfg.inst_args(inst)) .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 // Reload pass is supposed to ensure that all arguments to register operands are
// already in a register. // already in a register.
let cur_reg = self.divert.reg(value, &self.cur.func.locations); let cur_reg = self.divert.reg(arg_val, &self.cur.func.locations);
match op.kind { match constraint.kind {
ConstraintKind::FixedReg(regunit) => { ConstraintKind::FixedReg(regunit) => {
// Add the fixed constraint even if `cur_reg == 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, // It is possible that we will want to convert the value to a variable later,
// and this identity assignment prevents that from happening. // and this identity assignment prevents that from happening.
self.solver self.solver
.reassign_in(value, op.regclass, cur_reg, regunit); .reassign_in(arg_val, constraint.regclass, cur_reg, regunit);
} }
ConstraintKind::FixedTied(regunit) => { ConstraintKind::FixedTied(regunit) => {
// The pinned register may not be part of a fixed tied requirement. If this // 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. // becomes the case, then it must be changed to a different register.
debug_assert!( debug_assert!(
!self.is_pinned_reg(op.regclass, regunit), !self.is_pinned_reg(constraint.regclass, regunit),
"see comment above" "see comment above"
); );
// See comment right above. // See comment right above.
self.solver self.solver
.reassign_in(value, op.regclass, cur_reg, regunit); .reassign_in(arg_val, constraint.regclass, cur_reg, regunit);
} }
ConstraintKind::Tied(_) => { 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. // Divert the pinned register; it shouldn't be reused for a tied input.
if self.solver.can_add_var(op.regclass, cur_reg) { if self.solver.can_add_var(constraint.regclass, cur_reg) {
self.solver.add_var(value, op.regclass, cur_reg); self.solver.add_var(arg_val, constraint.regclass, cur_reg);
} }
} else if !op.regclass.contains(cur_reg) { } else if !constraint.regclass.contains(cur_reg) {
self.solver.add_var(value, op.regclass, cur_reg); self.solver.add_var(arg_val, constraint.regclass, cur_reg);
} }
} }
ConstraintKind::Reg => { ConstraintKind::Reg => {
if !op.regclass.contains(cur_reg) { if !constraint.regclass.contains(cur_reg) {
self.solver.add_var(value, op.regclass, cur_reg); self.solver.add_var(arg_val, constraint.regclass, cur_reg);
} }
} }
ConstraintKind::Stack => unreachable!(), ConstraintKind::Stack => unreachable!(),
@@ -714,22 +714,25 @@ impl<'a> Context<'a> {
.expect("Current instruction not encoded") .expect("Current instruction not encoded")
.ins; .ins;
for (op, &value) in constraints.iter().zip(self.cur.func.dfg.inst_args(inst)) { for (constraint, &arg_val) in constraints.iter().zip(self.cur.func.dfg.inst_args(inst)) {
match op.kind { match constraint.kind {
ConstraintKind::Reg | ConstraintKind::Tied(_) => { 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 // This is the opposite condition of `program_input_constraints()`. The pinned
// register mustn't be added back as a variable. // 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 // This code runs after calling `solver.inputs_done()` so we must identify
// the new variable as killed or live-through. Always special-case the // the new variable as killed or live-through.
// pinned register as a through variable.
let layout = &self.cur.func.layout; let layout = &self.cur.func.layout;
if self.liveness[value].killed_at(inst, layout.pp_ebb(inst), layout) { if self.liveness[arg_val].killed_at(inst, layout.pp_ebb(inst), layout) {
self.solver.add_killed_var(value, op.regclass, cur_reg); self.solver
.add_killed_var(arg_val, constraint.regclass, cur_reg);
} else { } 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 toprc = self.reginfo.toprc(rci);
let reg = self.divert.reg(lv.value, &self.cur.func.locations); let reg = self.divert.reg(lv.value, &self.cur.func.locations);
if self.solver.is_fixed_input_conflict(toprc, reg) { 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); self.solver.add_var(lv.value, toprc, reg);
} }
} }
@@ -879,15 +886,15 @@ impl<'a> Context<'a> {
replace_global_defines: &mut bool, replace_global_defines: &mut bool,
global_regs: &RegisterSet, global_regs: &RegisterSet,
) { ) {
for (op, lv) in constraints.iter().zip(defs) { for (constraint, lv) in constraints.iter().zip(defs) {
match op.kind { match constraint.kind {
ConstraintKind::FixedReg(reg) | ConstraintKind::FixedTied(reg) => { ConstraintKind::FixedReg(reg) | ConstraintKind::FixedTied(reg) => {
self.add_fixed_output(lv.value, op.regclass, reg, throughs); self.add_fixed_output(lv.value, constraint.regclass, reg, throughs);
if !lv.is_local && !global_regs.is_avail(op.regclass, reg) { if !lv.is_local && !global_regs.is_avail(constraint.regclass, reg) {
debug!( debug!(
"Fixed output {} in {}:{} is not available in global regs", "Fixed output {} in {}:{} is not available in global regs",
lv.value, lv.value,
op.regclass, constraint.regclass,
self.reginfo.display_regunit(reg) self.reginfo.display_regunit(reg)
); );
*replace_global_defines = true; *replace_global_defines = true;
@@ -976,13 +983,14 @@ impl<'a> Context<'a> {
replace_global_defines: &mut bool, replace_global_defines: &mut bool,
global_regs: &RegisterSet, global_regs: &RegisterSet,
) { ) {
for (op, lv) in constraints.iter().zip(defs) { for (constraint, lv) in constraints.iter().zip(defs) {
match op.kind { match constraint.kind {
ConstraintKind::FixedReg(_) ConstraintKind::FixedReg(_)
| ConstraintKind::FixedTied(_) | ConstraintKind::FixedTied(_)
| ConstraintKind::Stack => continue, | ConstraintKind::Stack => continue,
ConstraintKind::Reg => { 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) => { ConstraintKind::Tied(num) => {
// Find the input operand we're tied to. // Find the input operand we're tied to.
@@ -992,16 +1000,16 @@ impl<'a> Context<'a> {
if let Some(reg) = if let Some(reg) =
self.solver 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. // 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 // We need to make sure that fixed output register is compatible with the
// global register set. // 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!( debug!(
"Tied output {} in {}:{} is not available in global regs", "Tied output {} in {}:{} is not available in global regs",
lv.value, lv.value,
op.regclass, constraint.regclass,
self.reginfo.display_regunit(reg) self.reginfo.display_regunit(reg)
); );
*replace_global_defines = true; *replace_global_defines = true;

View File

@@ -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. /// Everything but the counts is static information computed from the constructor arguments.
#[derive(Default)] #[derive(Default)]
struct TopRC { struct TopRC {
// Number of registers currently used from this register class. /// Number of registers currently used from this register class.
base_count: u32, base_count: u32,
transient_count: u32, transient_count: u32,
// Max number of registers that can be allocated. /// Max number of registers that can be allocated.
limit: u32, limit: u32,
// Register units per register. /// Register units per register.
width: u8, width: u8,
// The first aliasing top-level RC. /// The first aliasing top-level RC.
first_toprc: u8, first_toprc: u8,
// The number of aliasing top-level RCs. /// The number of aliasing top-level RCs.
num_toprcs: u8, num_toprcs: u8,
} }
@@ -72,11 +72,11 @@ impl TopRC {
} }
pub struct Pressure { pub struct Pressure {
// Bit mask of top-level register classes that are aliased by other top-level register classes. /// 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. /// Unaliased register classes can use a simpler interference algorithm.
aliased: RegClassMask, aliased: RegClassMask,
// Current register counts per top-level register class. /// Current register counts per top-level register class.
toprc: [TopRC; MAX_TRACKED_TOP_RCS], toprc: [TopRC; MAX_TRACKED_TOP_RCS],
} }

View File

@@ -265,6 +265,7 @@ pub enum Move {
from: RegUnit, from: RegUnit,
to: RegUnit, to: RegUnit,
}, },
#[allow(dead_code)] // rustc doesn't see it isn't dead.
Spill { Spill {
value: Value, value: Value,
rc: RegClass, rc: RegClass,
@@ -283,7 +284,7 @@ impl Move {
/// Create a register move from an assignment, but not for identity assignments. /// Create a register move from an assignment, but not for identity assignments.
fn with_assignment(a: &Assignment) -> Option<Self> { fn with_assignment(a: &Assignment) -> Option<Self> {
if a.from != a.to { if a.from != a.to {
Some(Move::Reg { Some(Self::Reg {
value: a.value, value: a.value,
from: a.from, from: a.from,
to: a.to, to: a.to,
@@ -298,16 +299,16 @@ impl Move {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))] #[cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))]
fn from_reg(&self) -> Option<(RegClass, RegUnit)> { fn from_reg(&self) -> Option<(RegClass, RegUnit)> {
match *self { match *self {
Move::Reg { rc, from, .. } | Move::Spill { rc, from, .. } => Some((rc, from)), Self::Reg { rc, from, .. } | Self::Spill { rc, from, .. } => Some((rc, from)),
Move::Fill { .. } => None, Self::Fill { .. } => None,
} }
} }
/// Get the "to" register and register class, if possible. /// Get the "to" register and register class, if possible.
fn to_reg(&self) -> Option<(RegClass, RegUnit)> { fn to_reg(&self) -> Option<(RegClass, RegUnit)> {
match *self { match *self {
Move::Reg { rc, to, .. } | Move::Fill { rc, to, .. } => Some((rc, to)), Self::Reg { rc, to, .. } | Self::Fill { rc, to, .. } => Some((rc, to)),
Move::Spill { .. } => None, Self::Spill { .. } => None,
} }
} }
@@ -315,8 +316,8 @@ impl Move {
fn replace_to_reg(&mut self, new: RegUnit) -> RegUnit { fn replace_to_reg(&mut self, new: RegUnit) -> RegUnit {
mem::replace( mem::replace(
match *self { match *self {
Move::Reg { ref mut to, .. } | Move::Fill { ref mut to, .. } => to, Self::Reg { ref mut to, .. } | Self::Fill { ref mut to, .. } => to,
Move::Spill { .. } => panic!("No to register in a spill {}", self), Self::Spill { .. } => panic!("No to register in a spill {}", self),
}, },
new, new,
) )
@@ -325,13 +326,13 @@ impl Move {
/// Convert this `Reg` move to a spill to `slot` and return the old "to" register. /// Convert this `Reg` move to a spill to `slot` and return the old "to" register.
fn change_to_spill(&mut self, slot: usize) -> RegUnit { fn change_to_spill(&mut self, slot: usize) -> RegUnit {
match self.clone() { match self.clone() {
Move::Reg { Self::Reg {
value, value,
rc, rc,
from, from,
to, to,
} => { } => {
*self = Move::Spill { *self = Self::Spill {
value, value,
rc, rc,
from, from,
@@ -346,14 +347,14 @@ impl Move {
/// Get the value being moved. /// Get the value being moved.
fn value(&self) -> Value { fn value(&self) -> Value {
match *self { 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. /// Get the associated register class.
fn rc(&self) -> RegClass { fn rc(&self) -> RegClass {
match *self { 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 { impl fmt::Display for Move {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
Move::Reg { Self::Reg {
value, value,
from, from,
to, to,
@@ -374,7 +375,7 @@ impl fmt::Display for Move {
rc.info.display_regunit(from), rc.info.display_regunit(from),
rc.info.display_regunit(to) rc.info.display_regunit(to)
), ),
Move::Spill { Self::Spill {
value, value,
from, from,
to_slot, to_slot,
@@ -387,7 +388,7 @@ impl fmt::Display for Move {
rc.info.display_regunit(from), rc.info.display_regunit(from),
to_slot to_slot
), ),
Move::Fill { Self::Fill {
value, value,
from_slot, from_slot,
to, to,
@@ -593,67 +594,57 @@ impl Solver {
/// instruction. /// instruction.
/// ///
/// This function should be called after `inputs_done()` only. Use `add_var()` before. /// 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!( debug!(
"add_killed_var({}:{}, from={})", "add_killed_var({}:{}, from={})",
value, value,
constraint, rc,
constraint.info.display_regunit(from) rc.info.display_regunit(from)
); );
debug_assert!(self.inputs_done); 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 /// Add an extra input-side variable representing a value that is live through the current
/// instruction. /// instruction.
/// ///
/// This function should be called after `inputs_done()` only. Use `add_var()` before. /// 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!( debug!(
"add_through_var({}:{}, from={})", "add_through_var({}:{}, from={})",
value, value,
constraint, rc,
constraint.info.display_regunit(from) rc.info.display_regunit(from)
); );
debug_assert!(self.inputs_done); 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`. /// 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 /// 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. /// constraints if the value has already been added as a variable or fixed assignment.
fn add_live_var( fn add_live_var(&mut self, value: Value, rc: RegClass, from: RegUnit, live_through: bool) {
&mut self,
value: Value,
constraint: RegClass,
from: RegUnit,
live_through: bool,
) {
// Check for existing entries for this value. // 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. // There could be an existing variable entry.
if let Some(v) = self.vars.iter_mut().find(|v| v.value == value) { if let Some(v) = self.vars.iter_mut().find(|v| v.value == value) {
// We have an existing variable entry for `value`. Combine the constraints. // 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); debug!("-> combining constraint with {} yields {}", v, rc);
v.constraint = rc; v.constraint = rc;
return; return;
} else { } else {
// The spiller should have made sure the same value is not used with disjoint // The spiller should have made sure the same value is not used with disjoint
// constraints. // constraints.
panic!("Incompatible constraints: {} + {}", constraint, v) panic!("Incompatible constraints: {} + {}", rc, v)
} }
} }
// No variable, then it must be a fixed reassignment. // No variable, then it must be a fixed reassignment.
if let Some(a) = self.assignments.get(value) { if let Some(a) = self.assignments.get(value) {
debug!("-> already fixed assignment {}", a); debug!("-> already fixed assignment {}", a);
debug_assert!( debug_assert!(rc.contains(a.to), "Incompatible constraints for {}", value);
constraint.contains(a.to),
"Incompatible constraints for {}",
value
);
return; return;
} }
@@ -661,12 +652,12 @@ impl Solver {
panic!("Wrong from register for {}", value); 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); debug!("-> new var: {}", new_var);
self.regs_in.free(constraint, from); self.regs_in.free(rc, from);
if self.inputs_done && live_through { if self.inputs_done && live_through {
self.regs_out.free(constraint, from); self.regs_out.free(rc, from);
} }
self.vars.push(new_var); self.vars.push(new_var);
} }
@@ -1007,7 +998,7 @@ impl Solver {
self.moves self.moves
.extend(self.assignments.values().filter_map(Move::with_assignment)); .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)); debug!("collect_moves: {}", DisplayList(&self.moves));
} }
} }