Early defs reserve a register for whole instruction. (#32)
The `Operand` abstraction allows a def to be positioned at the "early" point of an instruction, before its effect and alongside its normal uses. This is intended to allow the embedder to express that a def may be written before all uses are read, so it should not conflict with the uses. It's also convenient to use early defs to express temporaries, which should be available throughout a regalloc-level instruction's emitted sequence. In such a case, the register should not be used again after the instruction, so it is dead following the instruction. Strictly speaking, and according to regalloc2 prior to this PR, then the temp will *only* conflict with the uses at the early-point, and not the defs at the late-point (after the instruction), because it's dead past its point of definition. But for a temp we really want it to register conflicts not just with the normal uses but with the normal defs as well. This PR changes the semantics so that an early def builds a liverange that spans the early- and late-point of an instruction when the vreg is dead flowing down from the instruction, giving the semantics we want for temps.
This commit is contained in:
@@ -943,11 +943,13 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
OperandKind::Mod => self.cfginfo.block_entry[block.index()],
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let to = match operand.kind() {
|
||||
OperandKind::Def => pos.next(),
|
||||
OperandKind::Mod => pos.next().next(), // both Before and After positions
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// We want to we want to span
|
||||
// until Before of the next
|
||||
// inst. This ensures that early
|
||||
// defs used for temps on an
|
||||
// instruction are reserved across
|
||||
// the whole instruction.
|
||||
let to = ProgPoint::before(pos.inst().next());
|
||||
lr = self.add_liverange_to_vreg(
|
||||
VRegIndex::new(operand.vreg().vreg()),
|
||||
CodeRange { from, to },
|
||||
|
||||
Reference in New Issue
Block a user