Avoid diverting values that are live on an outgoing CFG edge.

When try_add_var is looking for values that can be moved out of the way
in order to satisfy constraints for the current instruction, avoid
values that are live on a CFG edge originating at the current (branch)
instruction.

These values must be in their globally assigned location when entering
the branch destination EBB.

This is covered by the existing regalloc/iterate.cton test case which
fails with an upcoming commit.
This commit is contained in:
Jakob Stoklund Olesen
2017-10-06 14:50:33 -07:00
parent 0c4500897f
commit 12a8d6cce1

View File

@@ -711,7 +711,9 @@ impl<'a> Context<'a> {
if let Affinity::Reg(rci) = lv.affinity {
let rc2 = self.reginfo.rc(rci);
let reg2 = self.divert.reg(lv.value, &self.cur.func.locations);
if rc.contains(reg2) && self.solver.can_add_var(lv.value, rc2, reg2) {
if rc.contains(reg2) && self.solver.can_add_var(lv.value, rc2, reg2) &&
!self.is_live_on_outgoing_edge(lv.value)
{
// 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.
@@ -724,6 +726,31 @@ impl<'a> Context<'a> {
false
}
/// Determine if `value` is live on a CFG edge from the current instruction.
///
/// This means that the current instruction is a branch and `value` is live in to one of the
/// branch destinations. Branch arguments and EBB parameters are not considered live on the
/// edge.
fn is_live_on_outgoing_edge(&self, value: Value) -> bool {
use ir::instructions::BranchInfo::*;
let inst = self.cur.current_inst().expect("Not on an instruction");
match self.cur.func.dfg[inst].analyze_branch(&self.cur.func.dfg.value_lists) {
NotABranch => false,
SingleDest(ebb, _) => {
let lr = &self.liveness[value];
lr.is_livein(ebb, &self.cur.func.layout)
}
Table(jt) => {
let lr = &self.liveness[value];
!lr.is_local() &&
self.cur.func.jump_tables[jt].entries().any(|(_, ebb)| {
lr.is_livein(ebb, &self.cur.func.layout)
})
}
}
}
/// Emit `regmove` instructions as needed to move the live registers into place before the
/// instruction. Also update `self.divert` accordingly.
///