luaur_code_gen/methods/
ir_lowering_a_64_temp_addr_buffer.rs1use crate::enums::address_kind_a_64::AddressKindA64;
2use crate::enums::ir_op_kind::IrOpKind;
3use crate::enums::kind_a_64::KindA64;
4use crate::functions::emit_add_offset::emit_add_offset;
5use crate::functions::produces_dirty_high_register_bits::produces_dirty_high_register_bits;
6use crate::macros::codegen_assert::CODEGEN_ASSERT;
7use crate::records::address_a_64::AddressA64;
8use crate::records::ir_lowering_a_64::IrLoweringA64;
9use crate::records::ir_op::IrOp;
10use crate::records::register_a_64::RegisterA64;
11use luaur_vm::enums::lua_type::lua_Type;
12use luaur_vm::records::luau_buffer::LuauBuffer;
13use luaur_vm::records::udata::Udata;
14
15fn mem(base: RegisterA64, data: i32) -> AddressA64 {
16 AddressA64 {
17 kind: AddressKindA64::imm,
18 base,
19 offset: RegisterA64::noreg,
20 data,
21 }
22}
23
24impl IrLoweringA64 {
25 pub fn ir_lowering_a_64_temp_addr_buffer(
26 &mut self,
27 buffer_op: IrOp,
28 index_op: IrOp,
29 tag: u8,
30 ) -> AddressA64 {
31 CODEGEN_ASSERT!(tag == lua_Type::LUA_TUSERDATA as u8 || tag == lua_Type::LUA_TBUFFER as u8);
32
33 let data_offset = if tag == lua_Type::LUA_TBUFFER as u8 {
34 (core::mem::size_of::<LuauBuffer>() - core::mem::size_of::<[core::ffi::c_char; 1]>())
35 as i32
36 } else {
37 core::mem::offset_of!(Udata, data) as i32
38 };
39
40 if index_op.kind() == IrOpKind::Inst {
41 unsafe {
42 CODEGEN_ASSERT!(!produces_dirty_high_register_bits(
43 (*self.function).inst_op(index_op).cmd
44 ));
45 }
46
47 let temp = self.regs.alloc_temp(KindA64::x);
48 let buffer = self.ir_lowering_a_64_reg_op(buffer_op);
49 let index = self.ir_lowering_a_64_reg_op(index_op);
50 unsafe {
51 (*self.build)
52 .add_register_a_64_register_a_64_register_a_64_i32(temp, buffer, index, 0);
53 }
54 return mem(temp, data_offset);
55 } else if index_op.kind() == IrOpKind::Constant {
56 let buffer = self.ir_lowering_a_64_reg_op(buffer_op);
57 let index = unsafe { (*self.function).int_op(index_op) };
58
59 if (index as u32).wrapping_add(data_offset as u32) <= 255 {
60 return mem(buffer, index + data_offset);
61 }
62
63 if index < 0 {
64 return mem(buffer, data_offset);
65 }
66
67 let temp = self.regs.alloc_temp(KindA64::x);
68 unsafe {
69 emit_add_offset(&mut *self.build, temp, buffer, index as usize);
70 }
71 return mem(temp, data_offset);
72 }
73
74 CODEGEN_ASSERT!(false, "Unsupported instruction form");
75 mem(RegisterA64::noreg, 0)
76 }
77}