luaur_code_gen/methods/
ir_lowering_a_64_temp_addr.rs1use 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}