Skip to main content

luaur_code_gen/functions/
build_entry_function_code_gen_a_64.rs

1use crate::enums::address_kind_a_64::AddressKindA64;
2use crate::records::address_a_64::AddressA64;
3use crate::records::assembly_builder_a_64::AssemblyBuilderA64;
4use crate::records::entry_locations_code_gen_a_64::EntryLocations;
5use crate::records::register_a_64::RegisterA64;
6use crate::records::unwind_builder::UnwindBuilder;
7use luaur_vm::records::call_info::CallInfo as CallInfoRecord;
8use luaur_vm::records::lua_state::lua_State as lua_StateRecord;
9use luaur_vm::records::lua_t_value::lua_TValue as TValueRecord;
10use luaur_vm::records::proto::Proto as ProtoRecord;
11use luaur_vm::type_aliases::value::Value;
12
13fn mem(base: RegisterA64, data: i32) -> AddressA64 {
14    AddressA64 {
15        kind: AddressKindA64::imm,
16        base,
17        offset: RegisterA64::noreg,
18        data,
19    }
20}
21
22trait UnwindBuilderExt {
23    fn start_function(&mut self);
24    fn prologue_a_64(&mut self, prologue_size: u32, stack_size: u32, regs: &[RegisterA64]);
25    fn finish_function(&mut self, begin_offset: u32, end_offset: u32);
26}
27
28impl UnwindBuilderExt for UnwindBuilder {
29    fn start_function(&mut self) {}
30    fn prologue_a_64(&mut self, _prologue_size: u32, _stack_size: u32, _regs: &[RegisterA64]) {}
31    fn finish_function(&mut self, _begin_offset: u32, _end_offset: u32) {}
32}
33
34const SP: RegisterA64 = RegisterA64 {
35    bits: (31 << 3) | 0,
36};
37const X0: RegisterA64 = RegisterA64 { bits: (0 << 3) | 2 };
38const X1: RegisterA64 = RegisterA64 { bits: (1 << 3) | 2 };
39const X2: RegisterA64 = RegisterA64 { bits: (2 << 3) | 2 };
40const X3: RegisterA64 = RegisterA64 { bits: (3 << 3) | 2 };
41const X9: RegisterA64 = RegisterA64 { bits: (9 << 3) | 2 };
42const X19: RegisterA64 = RegisterA64 {
43    bits: (19 << 3) | 2,
44};
45const X20: RegisterA64 = RegisterA64 {
46    bits: (20 << 3) | 2,
47};
48const X21: RegisterA64 = RegisterA64 {
49    bits: (21 << 3) | 2,
50};
51const X22: RegisterA64 = RegisterA64 {
52    bits: (22 << 3) | 2,
53};
54const X23: RegisterA64 = RegisterA64 {
55    bits: (23 << 3) | 2,
56};
57const X24: RegisterA64 = RegisterA64 {
58    bits: (24 << 3) | 2,
59};
60const X25: RegisterA64 = RegisterA64 {
61    bits: (25 << 3) | 2,
62};
63const X29: RegisterA64 = RegisterA64 {
64    bits: (29 << 3) | 2,
65};
66const X30: RegisterA64 = RegisterA64 {
67    bits: (30 << 3) | 2,
68};
69
70const K_STACK_SIZE: u16 = 128;
71
72pub fn build_entry_function_assembly_builder_a_64_unwind_builder(
73    build: &mut AssemblyBuilderA64,
74    unwind: &mut UnwindBuilder,
75) -> EntryLocations {
76    let mut locations = EntryLocations::default();
77
78    locations.start = build.set_label();
79
80    build.sub_register_a_64_register_a_64_u16(SP, SP, K_STACK_SIZE);
81    build.stp(X29, X30, mem(SP, 0));
82
83    build.stp(X19, X20, mem(SP, 16));
84    build.stp(X21, X22, mem(SP, 32));
85    build.stp(X23, X24, mem(SP, 48));
86    build.str(X25, mem(SP, 64));
87
88    build.mov_register_a_64_register_a_64(X29, SP);
89
90    locations.prologueEnd = build.set_label();
91
92    let prologue_size =
93        build.get_label_offset(&locations.prologueEnd) - build.get_label_offset(&locations.start);
94
95    let r_state = X19;
96    let r_native_context = X20;
97    let r_global_state = X21;
98    let r_base = X22;
99    let r_constants = X23;
100    let r_code = X24;
101    let r_closure = X25;
102
103    build.mov_register_a_64_register_a_64(r_state, X0);
104    build.mov_register_a_64_register_a_64(r_native_context, X3);
105    build.ldr(
106        r_global_state,
107        mem(X0, core::mem::offset_of!(lua_StateRecord, global) as i32),
108    );
109    build.ldr(
110        r_base,
111        mem(X0, core::mem::offset_of!(lua_StateRecord, base) as i32),
112    );
113
114    build.ldp(
115        r_constants,
116        r_code,
117        mem(X1, core::mem::offset_of!(ProtoRecord, k) as i32),
118    );
119
120    build.ldr(
121        X9,
122        mem(X0, core::mem::offset_of!(lua_StateRecord, ci) as i32),
123    );
124    build.ldr(
125        X9,
126        mem(X9, core::mem::offset_of!(CallInfoRecord, func) as i32),
127    );
128    build.ldr(
129        r_closure,
130        mem(
131            X9,
132            core::mem::offset_of!(TValueRecord, value) as i32
133                + core::mem::offset_of!(Value, gc) as i32,
134        ),
135    );
136
137    build.br(X2);
138
139    locations.epilogueStart = build.set_label();
140
141    build.ldr(X25, mem(SP, 64));
142    build.ldp(X23, X24, mem(SP, 48));
143    build.ldp(X21, X22, mem(SP, 32));
144    build.ldp(X19, X20, mem(SP, 16));
145    build.ldp(X29, X30, mem(SP, 0));
146    build.add_register_a_64_register_a_64_u16(SP, SP, K_STACK_SIZE);
147
148    build.ret();
149
150    unwind.start_function();
151    unwind.prologue_a_64(
152        prologue_size as u32,
153        K_STACK_SIZE as u32,
154        &[X29, X30, X19, X20, X21, X22, X23, X24, X25],
155    );
156    unwind.finish_function(build.get_label_offset(&locations.start), 0xffffffff);
157
158    locations
159}