Implement coloring::iterate_solution().

It can happen that the currently live registers are blocking a smaller
register class completely, so the only way of solving the allocation
problem is to turn some of the live-through registers into solver
variables.

When the quick_solve attempt fails, try to free up registers in the
critical register class by turning live-through values into solver
variables.
This commit is contained in:
Jakob Stoklund Olesen
2017-09-29 14:38:30 -07:00
parent 86e22e7de5
commit 51a6901a7f
5 changed files with 181 additions and 6 deletions

View File

@@ -119,6 +119,7 @@ enc_i32_i64(x86.udivmodx, r.div, 0xf7, rrr=6)
enc_i32_i64(base.copy, r.umr, 0x89)
enc_i32_i64(base.regmove, r.rmov, 0x89)
enc_flt(base.regmove.b1, r.rmov, 0x89)
# Immediate instructions with sign-extended 8-bit and 32-bit immediate.
for inst, rrr in [

View File

@@ -167,7 +167,7 @@ impl RegClassData {
}
/// Returns true if `other` is a subclass of this register class.
/// A register class is considerd to be a subclass of itself.
/// A register class is considered to be a subclass of itself.
pub fn has_subclass<RCI: Into<RegClassIndex>>(&self, other: RCI) -> bool {
self.subclasses & (1 << other.into().0) != 0
}
@@ -276,6 +276,11 @@ impl RegInfo {
pub fn rc(&self, idx: RegClassIndex) -> RegClass {
&self.classes[idx.index()]
}
/// Get the top-level register class containing `rc`.
pub fn toprc(&self, rc: RegClass) -> RegClass {
&self.classes[rc.toprc as usize]
}
}
/// Temporary object that holds enough information to print a register unit.

View File

@@ -367,9 +367,10 @@ impl<'a> Context<'a> {
// Finally, we've fully programmed the constraint solver.
// We expect a quick solution in most cases.
let mut output_regs = self.solver.quick_solve().unwrap_or_else(
|_| self.iterate_solution(),
);
let mut output_regs = self.solver.quick_solve().unwrap_or_else(|rc| {
dbg!("quick_solve needs more registers in {}", rc);
self.iterate_solution(throughs, locations)
});
// The solution and/or fixed input constraints may require us to shuffle the set of live
@@ -731,8 +732,52 @@ impl<'a> Context<'a> {
///
/// We may need to move more registers around before a solution is possible. Use an iterative
/// algorithm that adds one more variable until a solution can be found.
fn iterate_solution(&self) -> AllocatableSet {
unimplemented!();
fn iterate_solution(
&mut self,
throughs: &[LiveValue],
locations: &mut ValueLocations,
) -> AllocatableSet {
loop {
dbg!("real_solve for {} variables", self.solver.vars().len());
let rc = match self.solver.real_solve() {
Ok(regs) => return regs,
Err(rc) => rc,
};
// Do we have any live-through `rc` registers that are not already variables?
assert!(
self.try_add_var(rc, throughs, locations),
"Ran out of registers in {}",
rc
);
}
}
/// Try to add an `rc` variable to the solver from the `throughs` set.
fn try_add_var(
&mut self,
rc: RegClass,
throughs: &[LiveValue],
locations: &mut ValueLocations,
) -> bool {
dbg!("Trying to add a {} reg from {} values", rc, throughs.len());
for lv in throughs {
if let Affinity::Reg(rci) = lv.affinity {
let rc2 = self.reginfo.rc(rci);
let reg2 = self.divert.reg(lv.value, locations);
if rc.contains(reg2) && self.solver.can_add_var(lv.value, rc2, reg2) {
// The new variable gets to roam the whole top-level register class because
// it is not actually constrained by the instruction. We just want it out
// of the way.
let toprc = self.reginfo.toprc(rc2);
self.solver.add_var(lv.value, toprc, reg2, &self.reginfo);
return true;
}
}
}
false
}
/// Emit `regmove` instructions as needed to move the live registers into place before the

View File

@@ -590,6 +590,18 @@ impl Solver {
self.find_solution()
}
/// Try harder to find a solution.
///
/// Call this method after `quick_solve()` fails.
///
/// This may return an error with a register class that has run out of registers. If registers
/// can be freed up in the starving class, this method can be called again after adding
/// variables for the freed registers.
pub fn real_solve(&mut self) -> Result<AllocatableSet, RegClass> {
// TODO: Sort variables to assign smallest register classes first.
self.find_solution()
}
/// Search for a solution with the current list of variables.
///
/// If a solution was found, returns `Ok(regs)` with the set of available registers on the
@@ -623,6 +635,11 @@ impl Solver {
pub fn vars(&self) -> &[Variable] {
&self.vars
}
/// Check if `value` can be added as a variable to help find a solution.
pub fn can_add_var(&mut self, _value: Value, constraint: RegClass, from: RegUnit) -> bool {
!self.regs_in.is_avail(constraint, from)
}
}
/// Interface for working with parallel copies once a solution has been found.