Skip to main content

luaur_code_gen/methods/
ir_lowering_a_64_temp_addr.rs

1use crate::enums::address_kind_a_64::AddressKindA64;
2use crate::enums::ir_op_kind::IrOpKind;
3use crate::enums::ir_value_kind::IrValueKind;
4use crate::enums::kind_a_64::KindA64;
5use crate::functions::emit_add_offset::emit_add_offset;
6use crate::functions::get_cmd_value_kind::get_cmd_value_kind;
7use crate::functions::vm_const_op::vm_const_op;
8use crate::functions::vm_reg_op::vm_reg_op;
9use crate::macros::codegen_assert::CODEGEN_ASSERT;
10use crate::records::address_a_64::AddressA64;
11use crate::records::ir_lowering_a_64::IrLoweringA64;
12use crate::records::ir_op::IrOp;
13use crate::records::register_a_64::RegisterA64;
14use luaur_vm::type_aliases::t_value::TValue;
15
16const K_MAX_IMMEDIATE: usize = 4095;
17
18const fn reg(kind: KindA64, index: u8) -> RegisterA64 {
19    RegisterA64 {
20        bits: kind as u8 | (index << 3),
21    }
22}
23
24const R_BASE: RegisterA64 = reg(KindA64::x, 25);
25const R_CONSTANTS: RegisterA64 = reg(KindA64::x, 22);
26
27fn mem(base: RegisterA64, data: i32) -> AddressA64 {
28    AddressA64 {
29        kind: AddressKindA64::imm,
30        base,
31        offset: RegisterA64::noreg,
32        data,
33    }
34}
35
36impl IrLoweringA64 {
37    pub fn ir_lowering_a_64_temp_addr(
38        &mut self,
39        op: IrOp,
40        offset: i32,
41        temp_storage: RegisterA64,
42    ) -> AddressA64 {
43        CODEGEN_ASSERT!(offset % 4 == 0);
44        CODEGEN_ASSERT!(offset >= 0 && (offset as usize / 4) <= K_MAX_IMMEDIATE);
45
46        if op.kind() == IrOpKind::VmReg {
47            return mem(
48                R_BASE,
49                vm_reg_op(op) * core::mem::size_of::<TValue>() as i32 + offset,
50            );
51        } else if op.kind() == IrOpKind::VmConst {
52            let constant_offset =
53                vm_const_op(op) as usize * core::mem::size_of::<TValue>() + offset as usize;
54
55            if constant_offset / 4 <= AddressA64::kMaxOffset {
56                return mem(R_CONSTANTS, constant_offset as i32);
57            }
58
59            let temp = if temp_storage == RegisterA64::noreg {
60                self.regs.alloc_temp(KindA64::x)
61            } else {
62                temp_storage
63            };
64            CODEGEN_ASSERT!(
65                temp.kind() == KindA64::x,
66                "temp storage, when provided, must be an 'x' register"
67            );
68
69            unsafe {
70                emit_add_offset(&mut *self.build, temp, R_CONSTANTS, constant_offset);
71            }
72            return mem(temp, 0);
73        } else if op.kind() == IrOpKind::Inst {
74            unsafe {
75                CODEGEN_ASSERT!(
76                    get_cmd_value_kind((*self.function).inst_op(op).cmd) == IrValueKind::Pointer
77                );
78            }
79            return mem(self.ir_lowering_a_64_reg_op(op), offset);
80        }
81
82        CODEGEN_ASSERT!(false, "Unsupported instruction form");
83        mem(RegisterA64::noreg, 0)
84    }
85}