Solver variables keep track of where they came from.

The register constraint solver has two kinds of variables:

1. Live values that were already in a register, and
2. Values defined by the instruction.

Make a record of the original register holding the first kind of value.
This commit is contained in:
Jakob Stoklund Olesen
2017-05-10 12:31:59 -07:00
parent 4dda3e02f1
commit f8e466d60e
2 changed files with 39 additions and 26 deletions

View File

@@ -357,7 +357,7 @@ impl<'a> Context<'a> {
.unwrap_or_else(|_| self.iterate_solution());
// Apply the solution to the defs.
for v in self.solver.vars().iter().filter(|&v| v.is_define) {
for v in self.solver.vars().iter().filter(|&v| v.is_define()) {
*locations.ensure(v.value) = ValueLoc::Reg(v.solution);
}

View File

@@ -129,6 +129,10 @@ pub struct Variable {
/// The value whose register assignment we're looking for.
pub value: Value,
/// Original register unit holding this live value before the instruction, or `None` for a
/// value that is defined by the instruction.
from: Option<RegUnit>,
/// Avoid interference on the input side.
is_input: bool,
@@ -138,9 +142,6 @@ pub struct Variable {
/// Avoid interference with the global registers.
is_global: bool,
/// The value is defined by the current instruction.
pub is_define: bool,
/// Number of registers available in the domain of this variable.
domain: u16,
@@ -152,6 +153,37 @@ pub struct Variable {
}
impl Variable {
fn new_live(value: Value, constraint: RegClass, from: RegUnit) -> Variable {
Variable {
value,
constraint,
from: Some(from),
is_input: true,
is_output: true,
is_global: false,
domain: 0,
solution: !0,
}
}
fn new_def(value: Value, constraint: RegClass) -> Variable {
Variable {
value,
constraint,
from: None,
is_input: false,
is_output: true,
is_global: false,
domain: 0,
solution: !0,
}
}
/// Does this variable represent a value defined by the current instruction?
pub fn is_define(&self) -> bool {
self.from.is_none()
}
/// Get an iterator over possible register choices, given the available registers on the input
/// and output sides respectively.
fn iter(&self, iregs: &AllocatableSet, oregs: &AllocatableSet) -> RegSetIter {
@@ -179,7 +211,7 @@ impl fmt::Display for Variable {
if self.is_global {
write!(f, ", global")?;
}
if self.is_define {
if self.is_define() {
write!(f, ", def")?;
}
if self.domain > 0 {
@@ -369,16 +401,7 @@ impl Solver {
self.regs_out.free(constraint, from);
}
self.vars
.push(Variable {
value,
constraint,
is_input: true,
is_output: true,
is_global: false,
is_define: false,
domain: 0,
solution: !0,
});
.push(Variable::new_live(value, constraint, from));
}
/// Check for conflicts between fixed input assignments and existing live values.
@@ -474,17 +497,7 @@ impl Solver {
/// This is similar to `add_var`, except the value doesn't have a prior register assignment.
pub fn add_def(&mut self, value: Value, constraint: RegClass) {
debug_assert!(self.inputs_done);
self.vars
.push(Variable {
value,
constraint,
is_input: false,
is_output: true,
is_global: false,
is_define: true,
domain: 0,
solution: !0,
});
self.vars.push(Variable::new_def(value, constraint));
}
}