Generate more fixed_nonallocatable constraints, and add debug assertions (#5132)

Add assertions to the OperandCollector that show we're not using pinned vregs, and use reg_fixed_nonallocatable constraints when a real register is used with other constraint generation functions like reg_use etc.
This commit is contained in:
Trevor Elliott
2022-11-28 10:31:56 -08:00
committed by GitHub
parent 951bdcb2cf
commit 54a6d2f79a

View File

@@ -358,13 +358,23 @@ impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
/// Add a register use, at the start of the instruction (`Before`
/// position).
pub fn reg_use(&mut self, reg: Reg) {
if let Some(rreg) = reg.to_real_reg() {
self.reg_fixed_nonallocatable(rreg.into());
} else {
debug_assert!(reg.is_virtual());
self.add_operand(Operand::reg_use(reg.into()));
}
}
/// Add a register use, at the end of the instruction (`After` position).
pub fn reg_late_use(&mut self, reg: Reg) {
if let Some(rreg) = reg.to_real_reg() {
self.reg_fixed_nonallocatable(rreg.into());
} else {
debug_assert!(reg.is_virtual());
self.add_operand(Operand::reg_use_at_end(reg.into()));
}
}
/// Add multiple register uses.
pub fn reg_uses(&mut self, regs: &[Reg]) {
@@ -377,8 +387,13 @@ impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
/// position). Use only when this def will be written after all
/// uses are read.
pub fn reg_def(&mut self, reg: Writable<Reg>) {
if let Some(rreg) = reg.to_reg().to_real_reg() {
self.reg_fixed_nonallocatable(rreg.into());
} else {
debug_assert!(reg.to_reg().is_virtual());
self.add_operand(Operand::reg_def(reg.to_reg().into()));
}
}
/// Add multiple register defs.
pub fn reg_defs(&mut self, regs: &[Writable<Reg>]) {
@@ -392,20 +407,29 @@ impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
/// when the def may be written before all uses are read; the
/// regalloc will ensure that it does not overwrite any uses.
pub fn reg_early_def(&mut self, reg: Writable<Reg>) {
if let Some(rreg) = reg.to_reg().to_real_reg() {
self.reg_fixed_nonallocatable(rreg.into());
} else {
debug_assert!(reg.to_reg().is_virtual());
self.add_operand(Operand::reg_def_at_start(reg.to_reg().into()));
}
}
/// Add a register "fixed use", which ties a vreg to a particular
/// RealReg at this point.
pub fn reg_fixed_use(&mut self, reg: Reg, rreg: Reg) {
debug_assert!(reg.is_virtual());
let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg");
debug_assert!(self.is_allocatable_preg(rreg.into()));
self.add_operand(Operand::reg_fixed_use(reg.into(), rreg.into()));
}
/// Add a register "fixed def", which ties a vreg to a particular
/// RealReg at this point.
pub fn reg_fixed_def(&mut self, reg: Writable<Reg>, rreg: Reg) {
debug_assert!(reg.to_reg().is_virtual());
let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg");
debug_assert!(self.is_allocatable_preg(rreg.into()));
self.add_operand(Operand::reg_fixed_def(reg.to_reg().into(), rreg.into()));
}
@@ -413,14 +437,17 @@ impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
/// allocation. The index of that earlier operand (relative to the
/// current instruction's start of operands) must be known.
pub fn reg_reuse_def(&mut self, reg: Writable<Reg>, idx: usize) {
if reg.to_reg().to_virtual_reg().is_some() {
self.add_operand(Operand::reg_reuse_def(reg.to_reg().into(), idx));
if let Some(rreg) = reg.to_reg().to_real_reg() {
// In some cases we see real register arguments to a reg_reuse_def
// constraint. We assume the creator knows what they're doing
// here, though we do also require that the real register be a
// fixed-nonallocatable register.
self.reg_fixed_nonallocatable(rreg.into());
} else {
// Sometimes destination registers that reuse a source are
// given with RealReg args. In this case, we assume the
// creator of the instruction knows what they are doing
// and just emit a normal def to the pinned vreg.
self.add_operand(Operand::reg_def(reg.to_reg().into()));
// The operand we're reusing must not be fixed-nonallocatable, as
// that would imply that the register has been allocated to a
// virtual register.
self.add_operand(Operand::reg_reuse_def(reg.to_reg().into(), idx));
}
}