Allocate a temporary for 64-bit constant loads in the s390x backend (#5357)

Avoid reusing a destination virtual register for 64-bit constants in the s390x backend. This change addresses a case identified by the regalloc2 ssa validator, as the destination register was written to twice when constants were generated via the MachInst::gen_constant function.
This commit is contained in:
Trevor Elliott
2022-11-30 17:01:14 -08:00
committed by GitHub
parent 0e65f87e37
commit c16f2956db
2 changed files with 14 additions and 8 deletions

View File

@@ -104,7 +104,7 @@ pub fn mem_finalize(
} else { } else {
let tmp = writable_spilltmp_reg(); let tmp = writable_spilltmp_reg();
assert!(base != tmp.to_reg()); assert!(base != tmp.to_reg());
insts.extend(Inst::load_constant64(tmp, off as u64)); insts.extend(Inst::load_constant64(tmp, off as u64, |_| tmp));
MemArg::reg_plus_reg(base, tmp.to_reg(), mem.get_flags()) MemArg::reg_plus_reg(base, tmp.to_reg(), mem.get_flags())
} }
} }

View File

@@ -335,7 +335,12 @@ impl Inst {
} }
/// Create an instruction that loads a 64-bit integer constant. /// Create an instruction that loads a 64-bit integer constant.
pub fn load_constant64(rd: Writable<Reg>, value: u64) -> SmallVec<[Inst; 4]> { pub fn load_constant64<F: FnMut(Type) -> Writable<Reg>>(
rd: Writable<Reg>,
value: u64,
mut alloc_tmp: F,
) -> SmallVec<[Inst; 4]> {
crate::trace!("loading a constant! {}", value);
if let Ok(imm) = i16::try_from(value as i64) { if let Ok(imm) = i16::try_from(value as i64) {
// 16-bit signed immediate // 16-bit signed immediate
smallvec![Inst::Mov64SImm16 { rd, imm }] smallvec![Inst::Mov64SImm16 { rd, imm }]
@@ -353,12 +358,13 @@ impl Inst {
let hi = value & 0xffff_ffff_0000_0000u64; let hi = value & 0xffff_ffff_0000_0000u64;
let lo = value & 0x0000_0000_ffff_ffffu64; let lo = value & 0x0000_0000_ffff_ffffu64;
let hi_rd = alloc_tmp(types::I64);
if let Some(imm) = UImm16Shifted::maybe_from_u64(hi) { if let Some(imm) = UImm16Shifted::maybe_from_u64(hi) {
// 16-bit shifted immediate // 16-bit shifted immediate
insts.push(Inst::Mov64UImm16Shifted { rd, imm }); insts.push(Inst::Mov64UImm16Shifted { rd: hi_rd, imm });
} else if let Some(imm) = UImm32Shifted::maybe_from_u64(hi) { } else if let Some(imm) = UImm32Shifted::maybe_from_u64(hi) {
// 32-bit shifted immediate // 32-bit shifted immediate
insts.push(Inst::Mov64UImm32Shifted { rd, imm }); insts.push(Inst::Mov64UImm32Shifted { rd: hi_rd, imm });
} else { } else {
unreachable!(); unreachable!();
} }
@@ -367,14 +373,14 @@ impl Inst {
// 16-bit shifted immediate // 16-bit shifted immediate
insts.push(Inst::Insert64UImm16Shifted { insts.push(Inst::Insert64UImm16Shifted {
rd, rd,
ri: rd.to_reg(), ri: hi_rd.to_reg(),
imm, imm,
}); });
} else if let Some(imm) = UImm32Shifted::maybe_from_u64(lo) { } else if let Some(imm) = UImm32Shifted::maybe_from_u64(lo) {
// 32-bit shifted immediate // 32-bit shifted immediate
insts.push(Inst::Insert64UImm32Shifted { insts.push(Inst::Insert64UImm32Shifted {
rd, rd,
ri: rd.to_reg(), ri: hi_rd.to_reg(),
imm, imm,
}); });
} else { } else {
@@ -1172,7 +1178,7 @@ impl MachInst for Inst {
to_regs: ValueRegs<Writable<Reg>>, to_regs: ValueRegs<Writable<Reg>>,
value: u128, value: u128,
ty: Type, ty: Type,
_alloc_tmp: F, alloc_tmp: F,
) -> SmallVec<[Inst; 4]> { ) -> SmallVec<[Inst; 4]> {
let to_reg = to_regs let to_reg = to_regs
.only_reg() .only_reg()
@@ -1204,7 +1210,7 @@ impl MachInst for Inst {
)); ));
ret ret
} }
types::I64 | types::R64 => Inst::load_constant64(to_reg, value as u64), types::I64 | types::R64 => Inst::load_constant64(to_reg, value as u64, alloc_tmp),
types::I8 | types::I16 | types::I32 => Inst::load_constant32(to_reg, value as u32), types::I8 | types::I16 | types::I32 => Inst::load_constant32(to_reg, value as u32),
_ => unreachable!(), _ => unreachable!(),
} }