diff --git a/ykrt/src/compile/jitc_yk/aot_ir.rs b/ykrt/src/compile/jitc_yk/aot_ir.rs index 2e5d5ae89..446c2b276 100644 --- a/ykrt/src/compile/jitc_yk/aot_ir.rs +++ b/ykrt/src/compile/jitc_yk/aot_ir.rs @@ -595,6 +595,10 @@ pub(crate) struct IntegerType { } impl IntegerType { + pub(crate) fn num_bits(&self) -> u32 { + self.num_bits + } + fn const_to_str(&self, c: &Constant) -> String { // FIXME: For now we just handle common integer types, but eventually we will need to // implement printing of aribitrarily-sized (in bits) integers. Consider using a bigint @@ -768,6 +772,12 @@ pub(crate) struct Constant { bytes: Vec, } +impl Constant { + pub(crate) fn bytes(&self) -> &[u8] { + &self.bytes + } +} + impl IRDisplay for Constant { fn to_str(&self, m: &Module) -> String { m.types[self.type_idx].const_to_str(self) @@ -899,6 +909,14 @@ impl Module { &self.types[instr.type_idx] } + pub(crate) fn constant(&self, co: &ConstantOperand) -> &Constant { + &self.consts[co.const_idx] + } + + pub(crate) fn const_type(&self, c: &Constant) -> &Type { + &self.types[c.type_idx] + } + // FIXME: rename this to `is_def()`, which we've decided is a beter name. // FIXME: also move this to the `Instruction` type. fn instr_generates_value(&self, i: &Instruction) -> bool { diff --git a/ykrt/src/compile/jitc_yk/jit_ir.rs b/ykrt/src/compile/jitc_yk/jit_ir.rs index 5aeb8d49b..acc793b87 100644 --- a/ykrt/src/compile/jitc_yk/jit_ir.rs +++ b/ykrt/src/compile/jitc_yk/jit_ir.rs @@ -340,18 +340,12 @@ impl LoadArgInstruction { pub struct LoadGlobalInstruction { /// The pointer to load from. global_idx: GlobalIdx, - /// The type of the pointee. - ty_idx: TypeIdx, } impl LoadGlobalInstruction { - pub(crate) fn new( - global_idx: aot_ir::GlobalIdx, - ty_idx: TypeIdx, - ) -> Result { + pub(crate) fn new(global_idx: aot_ir::GlobalIdx) -> Result { Ok(Self { global_idx: GlobalIdx::from_aot(global_idx)?, - ty_idx, }) } } @@ -380,7 +374,7 @@ pub struct CallInstruction { impl fmt::Display for CallInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LoadArg") + write!(f, "Call") } } @@ -520,9 +514,17 @@ impl PtrAddInstruction { let ptr = self.ptr; ptr.get() } + fn offset(&self) -> u32 { self.off } + + pub(crate) fn new(ptr: Operand, off: u32) -> Self { + Self { + ptr: PackedOperand::new(&ptr), + off, + } + } } impl fmt::Display for PtrAddInstruction { @@ -674,7 +676,7 @@ mod tests { assert_eq!(mem::size_of::(), 7); assert_eq!(mem::size_of::(), 4); assert_eq!(mem::size_of::(), 6); - assert_eq!(mem::size_of::(), 6); + assert_eq!(mem::size_of::(), 3); assert_eq!(mem::size_of::(), 6); assert_eq!(mem::size_of::(), 6); assert!(mem::size_of::() <= mem::size_of::()); diff --git a/ykrt/src/compile/jitc_yk/trace_builder.rs b/ykrt/src/compile/jitc_yk/trace_builder.rs index 2f5d584eb..718974d81 100644 --- a/ykrt/src/compile/jitc_yk/trace_builder.rs +++ b/ykrt/src/compile/jitc_yk/trace_builder.rs @@ -96,6 +96,7 @@ impl<'a> TraceBuilder<'a> { aot_ir::Opcode::Load => self.handle_load(inst), aot_ir::Opcode::Call => self.handle_call(inst), aot_ir::Opcode::Store => self.handle_store(inst), + aot_ir::Opcode::PtrAdd => self.handle_ptradd(inst), _ => todo!("{:?}", inst), }?; @@ -129,6 +130,15 @@ impl<'a> TraceBuilder<'a> { let instridx = self.local_map[lvo.instr_id()]; jit_ir::Operand::Local(instridx) } + aot_ir::Operand::Constant(_co) => { + todo!() + } + aot_ir::Operand::Global(go) => { + let load = jit_ir::LoadGlobalInstruction::new(go.index())?; + let idx = self.next_instr_id()?; + self.jit_mod.push(load.into()); + jit_ir::Operand::Local(idx) + } aot_ir::Operand::Unimplemented(_) => { // FIXME: for now we push an arbitrary constant. let constidx = self @@ -149,7 +159,7 @@ impl<'a> TraceBuilder<'a> { let ty_idx = jit_ir::TypeIdx::from_aot(inst.type_idx())?; if let aot_ir::Operand::Global(go) = inst.operand(0) { // Generate a special load instruction for globals. - Ok(jit_ir::LoadGlobalInstruction::new(go.index(), ty_idx)?.into()) + Ok(jit_ir::LoadGlobalInstruction::new(go.index())?.into()) } else { let jit_op = self.handle_operand(inst.operand(0))?; Ok(jit_ir::LoadInstruction::new(jit_op, ty_idx).into()) @@ -181,6 +191,30 @@ impl<'a> TraceBuilder<'a> { } } + fn handle_ptradd( + &mut self, + inst: &aot_ir::Instruction, + ) -> Result { + let target = self.handle_operand(inst.operand(0))?; + if let aot_ir::Operand::Constant(co) = inst.operand(1) { + let c = self.aot_mod.constant(co); + if let aot_ir::Type::Integer(it) = self.aot_mod.const_type(c) { + // Convert the offset into a 32 bit value, as that is the maximum we can fit into + // the jit_ir::PtrAddInstruction. + let offset: u32 = match it.num_bits() { + 64 => u64::from_ne_bytes(c.bytes()[0..8].try_into().unwrap()) + .try_into() + .map_err(|_| { + CompilationError::Unrecoverable("ptradd offset too big".into()) + }), + _ => panic!(), + }?; + return Ok(jit_ir::PtrAddInstruction::new(target, offset).into()); + }; + } + panic!() + } + /// Entry point for building an IR trace. /// /// Consumes the trace builder, returning a JIT module.