Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate more fixed_nonallocatable constraints, and add debug assertions #5132

Merged
merged 2 commits into from
Nov 28, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions cranelift/codegen/src/machinst/reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,22 @@ 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) {
self.add_operand(Operand::reg_use(reg.into()));
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) {
self.add_operand(Operand::reg_use_at_end(reg.into()));
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.
Expand All @@ -377,7 +387,12 @@ 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>) {
self.add_operand(Operand::reg_def(reg.to_reg().into()));
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.
Expand All @@ -392,35 +407,47 @@ 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>) {
self.add_operand(Operand::reg_def_at_start(reg.to_reg().into()));
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()));
}

/// Add a register def that reuses an earlier use-operand's
/// 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));
}
}

Expand Down