Add fixed_nonallocatable constraints when appropriate (#5253)
Plumb the set of allocatable registers through the OperandCollector and use it validate uses of fixed-nonallocatable registers, like %rsp on x86_64.
This commit is contained in:
@@ -1369,6 +1369,7 @@ impl MachInstEmit for Inst {
|
||||
}
|
||||
&Inst::MovFromPReg { rd, rm } => {
|
||||
let rd = allocs.next_writable(rd);
|
||||
allocs.next_fixed_nonallocatable(rm);
|
||||
let rm: Reg = rm.into();
|
||||
debug_assert!([
|
||||
regs::fp_reg(),
|
||||
@@ -1383,6 +1384,7 @@ impl MachInstEmit for Inst {
|
||||
Inst::Mov { size, rd, rm }.emit(&[], sink, emit_info, state);
|
||||
}
|
||||
&Inst::MovToPReg { rd, rm } => {
|
||||
allocs.next_fixed_nonallocatable(rd);
|
||||
let rd: Writable<Reg> = Writable::from_reg(rd.into());
|
||||
let rm = allocs.next(rm);
|
||||
debug_assert!([
|
||||
|
||||
@@ -655,25 +655,13 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
|
||||
collector.reg_use(rm);
|
||||
}
|
||||
&Inst::MovFromPReg { rd, rm } => {
|
||||
debug_assert!([
|
||||
regs::fp_reg(),
|
||||
regs::stack_reg(),
|
||||
regs::link_reg(),
|
||||
regs::pinned_reg()
|
||||
]
|
||||
.contains(&rm.into()));
|
||||
debug_assert!(rd.to_reg().is_virtual());
|
||||
collector.reg_def(rd);
|
||||
collector.reg_fixed_nonallocatable(rm);
|
||||
}
|
||||
&Inst::MovToPReg { rd, rm } => {
|
||||
debug_assert!([
|
||||
regs::fp_reg(),
|
||||
regs::stack_reg(),
|
||||
regs::link_reg(),
|
||||
regs::pinned_reg()
|
||||
]
|
||||
.contains(&rd.into()));
|
||||
debug_assert!(rm.is_virtual());
|
||||
collector.reg_fixed_nonallocatable(rd);
|
||||
collector.reg_use(rm);
|
||||
}
|
||||
&Inst::MovK { rd, rn, .. } => {
|
||||
@@ -1568,10 +1556,12 @@ impl Inst {
|
||||
}
|
||||
&Inst::MovFromPReg { rd, rm } => {
|
||||
let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64, allocs);
|
||||
allocs.next_fixed_nonallocatable(rm);
|
||||
let rm = show_ireg_sized(rm.into(), OperandSize::Size64);
|
||||
format!("mov {}, {}", rd, rm)
|
||||
}
|
||||
&Inst::MovToPReg { rd, rm } => {
|
||||
allocs.next_fixed_nonallocatable(rd);
|
||||
let rd = show_ireg_sized(rd.into(), OperandSize::Size64);
|
||||
let rm = pretty_print_ireg(rm, OperandSize::Size64, allocs);
|
||||
format!("mov {}, {}", rd, rm)
|
||||
|
||||
@@ -57,20 +57,11 @@ impl AArch64Backend {
|
||||
fn compile_vcode(
|
||||
&self,
|
||||
func: &Function,
|
||||
flags: shared_settings::Flags,
|
||||
) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
|
||||
let emit_info = EmitInfo::new(flags.clone());
|
||||
let emit_info = EmitInfo::new(self.flags.clone());
|
||||
let sigs = SigSet::new::<abi::AArch64MachineDeps>(func, &self.flags)?;
|
||||
let abi = abi::AArch64Callee::new(func, self, &self.isa_flags, &sigs)?;
|
||||
compile::compile::<AArch64Backend>(
|
||||
func,
|
||||
flags,
|
||||
self,
|
||||
abi,
|
||||
&self.machine_env,
|
||||
emit_info,
|
||||
sigs,
|
||||
)
|
||||
compile::compile::<AArch64Backend>(func, self, abi, emit_info, sigs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,10 +71,13 @@ impl TargetIsa for AArch64Backend {
|
||||
func: &Function,
|
||||
want_disasm: bool,
|
||||
) -> CodegenResult<CompiledCodeStencil> {
|
||||
let flags = self.flags();
|
||||
let (vcode, regalloc_result) = self.compile_vcode(func, flags.clone())?;
|
||||
let (vcode, regalloc_result) = self.compile_vcode(func)?;
|
||||
|
||||
let emit_result = vcode.emit(®alloc_result, want_disasm, flags.machine_code_cfg_info());
|
||||
let emit_result = vcode.emit(
|
||||
®alloc_result,
|
||||
want_disasm,
|
||||
self.flags.machine_code_cfg_info(),
|
||||
);
|
||||
let frame_size = emit_result.frame_size;
|
||||
let value_labels_ranges = emit_result.value_labels_ranges;
|
||||
let buffer = emit_result.buffer.finish();
|
||||
@@ -119,6 +113,10 @@ impl TargetIsa for AArch64Backend {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
fn machine_env(&self) -> &MachineEnv {
|
||||
&self.machine_env
|
||||
}
|
||||
|
||||
fn isa_flags(&self) -> Vec<shared_settings::Value> {
|
||||
self.isa_flags.iter().collect()
|
||||
}
|
||||
|
||||
@@ -227,6 +227,9 @@ pub trait TargetIsa: fmt::Display + Send + Sync {
|
||||
/// Get the ISA-independent flags that were used to make this trait object.
|
||||
fn flags(&self) -> &settings::Flags;
|
||||
|
||||
/// Get the ISA-dependent MachineEnv for managing register allocation.
|
||||
fn machine_env(&self) -> ®alloc2::MachineEnv;
|
||||
|
||||
/// Get the ISA-dependent flag values that were used to make this trait object.
|
||||
fn isa_flags(&self) -> Vec<settings::Value>;
|
||||
|
||||
|
||||
@@ -57,12 +57,11 @@ impl Riscv64Backend {
|
||||
fn compile_vcode(
|
||||
&self,
|
||||
func: &Function,
|
||||
flags: shared_settings::Flags,
|
||||
) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
|
||||
let emit_info = EmitInfo::new(flags.clone(), self.isa_flags.clone());
|
||||
let emit_info = EmitInfo::new(self.flags.clone(), self.isa_flags.clone());
|
||||
let sigs = SigSet::new::<abi::Riscv64MachineDeps>(func, &self.flags)?;
|
||||
let abi = abi::Riscv64Callee::new(func, self, &self.isa_flags, &sigs)?;
|
||||
compile::compile::<Riscv64Backend>(func, flags, self, abi, &self.mach_env, emit_info, sigs)
|
||||
compile::compile::<Riscv64Backend>(func, self, abi, emit_info, sigs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,11 +71,14 @@ impl TargetIsa for Riscv64Backend {
|
||||
func: &Function,
|
||||
want_disasm: bool,
|
||||
) -> CodegenResult<CompiledCodeStencil> {
|
||||
let flags = self.flags();
|
||||
let (vcode, regalloc_result) = self.compile_vcode(func, flags.clone())?;
|
||||
let (vcode, regalloc_result) = self.compile_vcode(func)?;
|
||||
|
||||
let want_disasm = want_disasm || log::log_enabled!(log::Level::Debug);
|
||||
let emit_result = vcode.emit(®alloc_result, want_disasm, flags.machine_code_cfg_info());
|
||||
let emit_result = vcode.emit(
|
||||
®alloc_result,
|
||||
want_disasm,
|
||||
self.flags.machine_code_cfg_info(),
|
||||
);
|
||||
let frame_size = emit_result.frame_size;
|
||||
let value_labels_ranges = emit_result.value_labels_ranges;
|
||||
let buffer = emit_result.buffer.finish();
|
||||
@@ -115,6 +117,10 @@ impl TargetIsa for Riscv64Backend {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
fn machine_env(&self) -> &MachineEnv {
|
||||
&self.mach_env
|
||||
}
|
||||
|
||||
fn isa_flags(&self) -> Vec<shared_settings::Value> {
|
||||
self.isa_flags.iter().collect()
|
||||
}
|
||||
|
||||
@@ -60,15 +60,7 @@ impl S390xBackend {
|
||||
let emit_info = EmitInfo::new(self.isa_flags.clone());
|
||||
let sigs = SigSet::new::<abi::S390xMachineDeps>(func, &self.flags)?;
|
||||
let abi = abi::S390xCallee::new(func, self, &self.isa_flags, &sigs)?;
|
||||
compile::compile::<S390xBackend>(
|
||||
func,
|
||||
self.flags.clone(),
|
||||
self,
|
||||
abi,
|
||||
&self.machine_env,
|
||||
emit_info,
|
||||
sigs,
|
||||
)
|
||||
compile::compile::<S390xBackend>(func, self, abi, emit_info, sigs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +109,10 @@ impl TargetIsa for S390xBackend {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
fn machine_env(&self) -> &MachineEnv {
|
||||
&self.machine_env
|
||||
}
|
||||
|
||||
fn isa_flags(&self) -> Vec<shared_settings::Value> {
|
||||
self.isa_flags.iter().collect()
|
||||
}
|
||||
|
||||
@@ -699,6 +699,7 @@ pub(crate) fn emit(
|
||||
}
|
||||
|
||||
Inst::MovFromPReg { src, dst } => {
|
||||
allocs.next_fixed_nonallocatable(*src);
|
||||
let src: Reg = (*src).into();
|
||||
debug_assert!([regs::rsp(), regs::rbp(), regs::pinned_reg()].contains(&src));
|
||||
let src = Gpr::new(src).unwrap();
|
||||
@@ -711,6 +712,7 @@ pub(crate) fn emit(
|
||||
Inst::MovToPReg { src, dst } => {
|
||||
let src = allocs.next(src.to_reg());
|
||||
let src = Gpr::new(src).unwrap();
|
||||
allocs.next_fixed_nonallocatable(*dst);
|
||||
let dst: Reg = (*dst).into();
|
||||
debug_assert!([regs::rsp(), regs::rbp(), regs::pinned_reg()].contains(&dst));
|
||||
let dst = WritableGpr::from_writable_reg(Writable::from_reg(dst)).unwrap();
|
||||
|
||||
@@ -1263,6 +1263,7 @@ impl PrettyPrint for Inst {
|
||||
}
|
||||
|
||||
Inst::MovFromPReg { src, dst } => {
|
||||
allocs.next_fixed_nonallocatable(*src);
|
||||
let src: Reg = (*src).into();
|
||||
let src = regs::show_ireg_sized(src, 8);
|
||||
let dst = pretty_print_reg(dst.to_reg().to_reg(), 8, allocs);
|
||||
@@ -1271,6 +1272,7 @@ impl PrettyPrint for Inst {
|
||||
|
||||
Inst::MovToPReg { src, dst } => {
|
||||
let src = pretty_print_reg(src.to_reg(), 8, allocs);
|
||||
allocs.next_fixed_nonallocatable(*dst);
|
||||
let dst: Reg = (*dst).into();
|
||||
let dst = regs::show_ireg_sized(dst, 8);
|
||||
format!("{} {}, {}", ljustify("movq".to_string()), src, dst)
|
||||
@@ -1919,14 +1921,14 @@ fn x64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandCol
|
||||
collector.reg_def(dst.to_writable_reg());
|
||||
}
|
||||
Inst::MovFromPReg { dst, src } => {
|
||||
debug_assert!([regs::rsp(), regs::rbp(), regs::pinned_reg()].contains(&(*src).into()));
|
||||
debug_assert!(dst.to_reg().to_reg().is_virtual());
|
||||
collector.reg_fixed_nonallocatable(*src);
|
||||
collector.reg_def(dst.to_writable_reg());
|
||||
}
|
||||
Inst::MovToPReg { dst, src } => {
|
||||
debug_assert!(src.to_reg().is_virtual());
|
||||
debug_assert!([regs::rsp(), regs::rbp(), regs::pinned_reg()].contains(&(*dst).into()));
|
||||
collector.reg_use(src.to_reg());
|
||||
collector.reg_fixed_nonallocatable(*dst);
|
||||
}
|
||||
Inst::XmmToGpr { src, dst, .. } => {
|
||||
collector.reg_use(src.to_reg());
|
||||
|
||||
@@ -48,14 +48,13 @@ impl X64Backend {
|
||||
fn compile_vcode(
|
||||
&self,
|
||||
func: &Function,
|
||||
flags: Flags,
|
||||
) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
|
||||
// This performs lowering to VCode, register-allocates the code, computes
|
||||
// block layout and finalizes branches. The result is ready for binary emission.
|
||||
let emit_info = EmitInfo::new(flags.clone(), self.x64_flags.clone());
|
||||
let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());
|
||||
let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;
|
||||
let abi = abi::X64Callee::new(&func, self, &self.x64_flags, &sigs)?;
|
||||
compile::compile::<Self>(&func, flags, self, abi, &self.reg_env, emit_info, sigs)
|
||||
compile::compile::<Self>(&func, self, abi, emit_info, sigs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +64,13 @@ impl TargetIsa for X64Backend {
|
||||
func: &Function,
|
||||
want_disasm: bool,
|
||||
) -> CodegenResult<CompiledCodeStencil> {
|
||||
let flags = self.flags();
|
||||
let (vcode, regalloc_result) = self.compile_vcode(func, flags.clone())?;
|
||||
let (vcode, regalloc_result) = self.compile_vcode(func)?;
|
||||
|
||||
let emit_result = vcode.emit(®alloc_result, want_disasm, flags.machine_code_cfg_info());
|
||||
let emit_result = vcode.emit(
|
||||
®alloc_result,
|
||||
want_disasm,
|
||||
self.flags.machine_code_cfg_info(),
|
||||
);
|
||||
let frame_size = emit_result.frame_size;
|
||||
let value_labels_ranges = emit_result.value_labels_ranges;
|
||||
let buffer = emit_result.buffer.finish();
|
||||
@@ -96,6 +98,10 @@ impl TargetIsa for X64Backend {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
fn machine_env(&self) -> &MachineEnv {
|
||||
&self.reg_env
|
||||
}
|
||||
|
||||
fn isa_flags(&self) -> Vec<shared_settings::Value> {
|
||||
self.x64_flags.iter().collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user