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

Deal with input register aliasing. #1473

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
30 changes: 24 additions & 6 deletions ykrt/src/compile/jitc_yk/codegen/x64/lsregalloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,30 @@ impl<'a> LSRegAlloc<'a> {

/// The parts of the register allocator needed for general purpose registers.
impl LSRegAlloc<'_> {
/// Forcibly assign the machine register `reg`, which must be in the [RegState::Empty] state,
/// to the value produced by instruction `iidx`.
pub(crate) fn force_assign_inst_gp_reg(&mut self, iidx: InstIdx, reg: Rq) {
debug_assert!(!self.gp_regset.is_set(reg));
self.gp_regset.set(reg);
self.gp_reg_states[usize::from(reg.code())] = RegState::FromInst(iidx);
/// Forcibly assign the machine register `reg` to the value produced by instruction `iidx`.
/// Note that if this register is already used, a spill will be generated instead.
pub(crate) fn force_assign_inst_gp_reg(&mut self, asm: &mut Assembler, iidx: InstIdx, reg: Rq) {
if self.gp_regset.is_set(reg) {
debug_assert_eq!(self.spills[usize::from(iidx)], SpillState::Empty);
// Input values alias to a single register. To avoid the rest of the register allocator
// having to think about this, we "dealias" the values by spilling.
let inst = self.m.inst_no_copies(iidx);
let size = inst.def_byte_size(self.m);
self.stack.align(size); // FIXME
let frame_off = self.stack.grow(size);
let off = i32::try_from(frame_off).unwrap();
match size {
1 => dynasm!(asm; mov BYTE [rbp - off], Rb(reg.code())),
2 => dynasm!(asm; mov WORD [rbp - off], Rw(reg.code())),
4 => dynasm!(asm; mov DWORD [rbp - off], Rd(reg.code())),
8 => dynasm!(asm; mov QWORD [rbp - off], Rq(reg.code())),
_ => unreachable!(),
}
self.spills[usize::from(iidx)] = SpillState::Stack(off);
} else {
self.gp_regset.set(reg);
self.gp_reg_states[usize::from(reg.code())] = RegState::FromInst(iidx);
}
}

/// Forcibly assign the floating point register `reg`, which must be in the [RegState::Empty] state,
Expand Down
31 changes: 30 additions & 1 deletion ykrt/src/compile/jitc_yk/codegen/x64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,7 @@ impl<'a> Assemble<'a> {
debug_assert!(size <= REG64_BYTESIZE);
match m {
VarLocation::Register(reg_alloc::Register::GP(reg)) => {
self.ra.force_assign_inst_gp_reg(iidx, reg);
self.ra.force_assign_inst_gp_reg(&mut self.asm, iidx, reg);
}
VarLocation::Register(reg_alloc::Register::FP(reg)) => {
self.ra.force_assign_inst_fp_reg(iidx, reg);
Expand Down Expand Up @@ -4381,4 +4381,33 @@ mod tests {
",
);
}

#[test]
fn cg_aliasing_loadtis() {
let mut m = jit_ir::Module::new(0, 0).unwrap();

// Create two trace inputs whose locations alias.
let loc = yksmp::Location::Register(13, 1, 0, [].into());
m.push_tiloc(loc);
let ti_inst = jit_ir::LoadTraceInputInst::new(0, m.int8_tyidx());
let op1 = m.push_and_make_operand(ti_inst.clone().into()).unwrap();
let op2 = m.push_and_make_operand(ti_inst.into()).unwrap();

let add_inst = jit_ir::BinOpInst::new(op1, jit_ir::BinOp::Add, op2);
m.push(add_inst.into()).unwrap();

let mt = MT::new().unwrap();
let hl = HotLocation {
kind: HotLocationKind::Tracing,
tracecompilation_errors: 0,
};

Assemble::new(&m, None, None)
.unwrap()
.codegen(mt, Arc::new(Mutex::new(hl)), None)
.unwrap()
.as_any()
.downcast::<X64CompiledTrace>()
.unwrap();
}
}