Skip to main content

luaur_code_gen/methods/
ir_lowering_a_64_temp_addr_buffer.rs

1use 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}