Regalloc: rename "constraint" to "rc" and "op" to "constraint";
This commit is contained in:
committed by
Dan Gohman
parent
05cc8823c2
commit
beca77c2f8
@@ -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;
|
||||||
|
|||||||
@@ -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],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user