diff --git a/cranelift/codegen/src/machinst/reg.rs b/cranelift/codegen/src/machinst/reg.rs index 4a550d3fa36d..2705c74c90a0 100644 --- a/cranelift/codegen/src/machinst/reg.rs +++ b/cranelift/codegen/src/machinst/reg.rs @@ -293,24 +293,10 @@ pub struct OperandCollector<'a, 'env, F: Fn(VReg) -> VReg> { renamer: F, } -macro_rules! debug_assert_allocatable { - ($env:expr, $reg:expr) => { - if cfg!(debug_assertions) { - let class = $reg.class() as usize; - if let Some(reg) = pinned_vreg_to_preg($reg) { - assert!( - $env.preferred_regs_by_class[class] - .iter() - .copied() - .any(|r| r == reg) - || $env.non_preferred_regs_by_class[class] - .iter() - .copied() - .any(|r| r == reg) - ); - } - } - }; +macro_rules! debug_assert_is_virtual { + ($reg:expr) => { + debug_assert!($reg.is_virtual(), "`{:?}` was used, but is not virtual", $reg); + } } impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, F> { @@ -326,6 +312,22 @@ impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, F> { } } + pub fn is_allocatable_preg(&self, reg: PReg) -> bool { + let class = reg.class() as usize; + self.machine_env.preferred_regs_by_class[class] + .iter() + .copied() + .any(|r| r == reg) + || self.machine_env.non_preferred_regs_by_class[class] + .iter() + .copied() + .any(|r| r == reg) + } + + pub fn is_allocatable_reg(&self, reg: Reg) -> bool { + pinned_vreg_to_preg(reg.0).map_or(false, |preg| self.is_allocatable_preg(preg)) + } + /// Add an operand. fn add_operand(&mut self, operand: Operand) { let vreg = (self.renamer)(operand.vreg()); @@ -345,17 +347,20 @@ impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, F> { /// Add a register use, at the start of the instruction (`Before` /// position). pub fn reg_use(&mut self, reg: Reg) { + debug_assert_is_virtual!(reg); 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) { + debug_assert_is_virtual!(reg); self.add_operand(Operand::reg_use_at_end(reg.into())); } /// Add multiple register uses. pub fn reg_uses(&mut self, regs: &[Reg]) { for ® in regs { + debug_assert_is_virtual!(reg); self.reg_use(reg); } } @@ -364,12 +369,14 @@ impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, F> { /// position). Use only when this def will be written after all /// uses are read. pub fn reg_def(&mut self, reg: Writable) { + debug_assert_is_virtual!(reg.to_reg()); self.add_operand(Operand::reg_def(reg.to_reg().into())); } /// Add multiple register defs. pub fn reg_defs(&mut self, regs: &[Writable]) { for ® in regs { + debug_assert_is_virtual!(reg.to_reg()); self.reg_def(reg); } } @@ -379,13 +386,15 @@ impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, 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) { + debug_assert_is_virtual!(reg.to_reg()); 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_allocatable!(self.machine_env, rreg.0); + debug_assert_is_virtual!(reg); + debug_assert!(self.is_allocatable_reg(rreg)); let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg"); self.add_operand(Operand::reg_fixed_use(reg.into(), rreg.into())); } @@ -393,7 +402,8 @@ impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, F> { /// 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, rreg: Reg) { - debug_assert_allocatable!(self.machine_env, rreg.0); + debug_assert_is_virtual!(reg.to_reg()); + debug_assert!(self.is_allocatable_reg(rreg)); let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg"); self.add_operand(Operand::reg_fixed_def(reg.to_reg().into(), rreg.into())); } @@ -402,6 +412,7 @@ impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, 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, idx: usize) { + debug_assert_is_virtual!(reg.to_reg()); if reg.to_reg().to_virtual_reg().is_some() { self.add_operand(Operand::reg_reuse_def(reg.to_reg().into(), idx)); } else { @@ -417,6 +428,11 @@ impl<'a, 'env, F: Fn(VReg) -> VReg> OperandCollector<'a, 'env, F> { /// are written by the instruction, so must be reserved (not used) /// for the whole instruction, but are not used afterward. pub fn reg_clobbers(&mut self, regs: PRegSet) { + if cfg!(debug_assertions) { + for reg in regs.clone() { + debug_assert!(self.is_allocatable_preg(reg)); + } + } self.clobbers.union_from(regs); } }