Don't allow EBB parameters to be ghost values.

Ghost instructions and values are supposed to be stored as metadata
alongside the compiled program such that the ghost values can be
computed from the real register/stack values when the program is stopped
for debugging or de-optimization.

If we allow an EBB parameter to be a ghost value, we have no way of
computing its real value using ghost instructions. We would need to know
a complete execution trace of the stopped program to figure out which
values were passed to the ghost parameter.

Instead we require EBB parameters to be real values materialized in
registers or on the stack. We use the regclass_for_abi_type() TargetIsa
callback to determine the initial register class for these parameters.
They can then be spilled later if needed.

Fixes #215.
This commit is contained in:
Jakob Stoklund Olesen
2018-01-11 16:35:19 -08:00
parent 5e094034d4
commit cacba1a58f
3 changed files with 48 additions and 86 deletions

View File

@@ -100,7 +100,7 @@ impl<'a> LivenessVerifier<'a> {
}
// Check the uses.
for (idx, &val) in self.func.dfg.inst_args(inst).iter().enumerate() {
for &val in self.func.dfg.inst_args(inst) {
let lr = match self.liveness.get(val) {
Some(lr) => lr,
None => return err!(inst, "{} has no live range", val),
@@ -111,10 +111,7 @@ impl<'a> LivenessVerifier<'a> {
if encoding.is_legal() {
// A legal instruction is not allowed to depend on ghost values.
//
// 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) {
if lr.affinity.is_none() {
return err!(
inst,
"{} is a ghost value used by a real [{}] instruction",
@@ -147,32 +144,6 @@ 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_params(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;