Fix fuzzbug: add checker metadata for new vreg on multi-fixed-reg fixup move.
When an instruction uses the same vreg constrained to multiple different fixed registers, the allocator converts all but one of the fixed constraints to `Any` and then records a special fixup move that copies the value to the other fixed registers just before the instruction. This allows the allocator to maintain the invariant that a value lives in only one place at a time throughout most of its logic, and constrains the complexity-fallout of this corner case to just a special last-minute edit. Unfortunately some recent CPU time thrown at the fuzzer has uncovered a subtle interaction with the redundant move eliminator that confuses the checker. Specifically, when the correct value is *already* in the second constrained fixed reg, because of an unrelated other move (e.g. because of a blockparam or other vreg moved from the original), the redundant move eliminator can delete the fixup move without telling the checker that it has done so. Such an optimization is perfectly valid, and the generated code is correct; but the checker thinks that some other vreg (the one that was copied from the original) is in the second preg, and panics. The fix is to use the mechanism that indicates "this move defines a new vreg" (emitting a `defalloc` checker-instruction) to force the checker to understand that after the fixup move, the given preg actually contains the appropriate vreg.
This commit is contained in:
@@ -331,7 +331,7 @@ pub struct Env<'a, F: Function> {
|
||||
// was to the approprate PReg.
|
||||
//
|
||||
// (progpoint, copy-from-preg, copy-to-preg, to-slot)
|
||||
pub multi_fixed_reg_fixups: Vec<(ProgPoint, PRegIndex, PRegIndex, usize)>,
|
||||
pub multi_fixed_reg_fixups: Vec<(ProgPoint, PRegIndex, PRegIndex, VRegIndex, usize)>,
|
||||
|
||||
pub inserted_moves: Vec<InsertedMove>,
|
||||
|
||||
|
||||
@@ -1167,6 +1167,7 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
ProgPoint,
|
||||
PRegIndex,
|
||||
PRegIndex,
|
||||
VRegIndex,
|
||||
usize,
|
||||
)>| {
|
||||
if last_point.is_some() && Some(pos) != last_point {
|
||||
@@ -1189,7 +1190,7 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
let orig_preg = first_preg[idx];
|
||||
if orig_preg != preg_idx {
|
||||
log::trace!(" -> duplicate; switching to constraint Reg");
|
||||
fixups.push((pos, orig_preg, preg_idx, slot));
|
||||
fixups.push((pos, orig_preg, preg_idx, vreg_idx, slot));
|
||||
*op = Operand::new(
|
||||
op.vreg(),
|
||||
OperandConstraint::Reg,
|
||||
|
||||
@@ -685,21 +685,22 @@ impl<'a, F: Function> Env<'a, F> {
|
||||
}
|
||||
|
||||
// Handle multi-fixed-reg constraints by copying.
|
||||
for (progpoint, from_preg, to_preg, slot) in
|
||||
for (progpoint, from_preg, to_preg, to_vreg, slot) in
|
||||
std::mem::replace(&mut self.multi_fixed_reg_fixups, vec![])
|
||||
{
|
||||
log::trace!(
|
||||
"multi-fixed-move constraint at {:?} from p{} to p{}",
|
||||
"multi-fixed-move constraint at {:?} from p{} to p{} for v{}",
|
||||
progpoint,
|
||||
from_preg.index(),
|
||||
to_preg.index()
|
||||
to_preg.index(),
|
||||
to_vreg.index(),
|
||||
);
|
||||
self.insert_move(
|
||||
progpoint,
|
||||
InsertMovePrio::MultiFixedReg,
|
||||
Allocation::reg(self.pregs[from_preg.index()].reg),
|
||||
Allocation::reg(self.pregs[to_preg.index()].reg),
|
||||
None,
|
||||
Some(self.vreg_regs[to_vreg.index()]),
|
||||
);
|
||||
self.set_alloc(
|
||||
progpoint.inst(),
|
||||
|
||||
Reference in New Issue
Block a user