Propagate affinities for EBB arguments.

A priory, an EBB argument value only gets an affinity if it is used
directly by a non-ghost instruction. A use by a branch passing arguments
to an EBB doesn't count.

When an EBB argument value does have an affinity, the values passed by
all the predecessors must also have affinities. This can cause EBB
argument values to get affinities recursively.

- Add a second pass to the liveness computation for propagating EBB
  argument affinities, possibly recursively.
- Verify EBB argument affinities correctly: A value passed to a branch
  must have an affinity only if the corresponding EBB argument value in
  the destination has an affinity.
This commit is contained in:
Jakob Stoklund Olesen
2017-06-29 10:30:26 -07:00
parent e7a543ea33
commit 588ef0ad2f
3 changed files with 87 additions and 2 deletions

View File

@@ -93,7 +93,7 @@ impl<'a> LivenessVerifier<'a> {
}
// Check the uses.
for &val in self.func.dfg.inst_args(inst) {
for (idx, &val) in self.func.dfg.inst_args(inst).iter().enumerate() {
let lr = match self.liveness.get(val) {
Some(lr) => lr,
None => return err!(inst, "{} has no live range", val),
@@ -104,7 +104,10 @@ impl<'a> LivenessVerifier<'a> {
if encoding.is_legal() {
// A legal instruction is not allowed to depend on ghost values.
if lr.affinity.is_none() {
//
// A branch argument can be a ghost value if the corresponding destination
// EBB argument is a ghost value.
if lr.affinity.is_none() && !self.is_ghost_branch_argument(inst, idx) {
return err!(inst,
"{} is a ghost value used by a real [{}] instruction",
val,
@@ -134,6 +137,32 @@ impl<'a> LivenessVerifier<'a> {
}
}
/// Is argument `argnum` on `inst` a branch argument that leads to a ghost EBB argument?
fn is_ghost_branch_argument(&self, inst: Inst, argnum: usize) -> bool {
let dest = match self.func.dfg[inst].branch_destination() {
Some(d) => d,
None => return false,
};
let fixed_args = self.func.dfg[inst]
.opcode()
.constraints()
.fixed_value_arguments();
if argnum < fixed_args {
return false;
}
// If the EBB argument value in the destination is a ghost value, we'll allow a ghost
// branch argument.
self.func
.dfg
.ebb_args(dest)
.get(argnum - fixed_args)
.and_then(|&v| self.liveness.get(v))
.map(|lr| lr.affinity.is_none())
.unwrap_or(false)
}
/// Check the integrity of the live range `lr`.
fn check_lr(&self, def: ProgramPoint, val: Value, lr: &LiveRange) -> Result {
let l = &self.func.layout;