luaur_code_gen/functions/
emit_inst_for_g_loop.rs1use crate::enums::abix_64::ABIX64;
2use crate::enums::condition_x_64::ConditionX64;
3use crate::enums::size_x_64::SizeX64;
4use crate::functions::luau_reg::luau_reg;
5use crate::functions::luau_reg_address::luau_reg_address;
6use crate::functions::luau_reg_tag::luau_reg_tag;
7use crate::functions::luau_reg_value::luau_reg_value;
8use crate::functions::set_luau_reg::set_luau_reg;
9use crate::records::assembly_builder_x_64::AssemblyBuilderX64;
10use crate::records::ir_call_wrapper_x_64::IrCallWrapperX64;
11use crate::records::ir_data::k_invalid_inst_idx;
12use crate::records::ir_op::IrOp;
13use crate::records::ir_reg_alloc_x_64::IrRegAllocX64;
14use crate::records::label::Label;
15use crate::records::native_context::NativeContext;
16use crate::records::operand_x_64::OperandX64;
17use crate::records::register_x_64::RegisterX64;
18use luaur_vm::enums::lua_type::lua_Type;
19use luaur_vm::records::lua_table::LuaTable;
20use luaur_vm::type_aliases::t_value::TValue;
21
22pub fn emit_inst_for_g_loop(
23 regs: &mut IrRegAllocX64,
24 build: &mut AssemblyBuilderX64,
25 ra: i32,
26 aux: i32,
27 loop_repeat: &mut Label,
28) {
29 crate::macros::codegen_assert::CODEGEN_ASSERT!(aux >= 0);
30
31 let (table, index) = if luaur_common::FFlag::LuauCodegenSuggestArgumentRegisterX64.get() {
32 (
33 IrCallWrapperX64::suggest_argument_register::<1>(SizeX64::qword, build),
34 IrCallWrapperX64::suggest_argument_register::<2>(SizeX64::qword, build),
35 )
36 } else if build.abi == ABIX64::Windows {
37 (RegisterX64::rdx, RegisterX64::r8)
38 } else {
39 (RegisterX64::rsi, RegisterX64::rdx)
40 };
41
42 let elem_ptr = RegisterX64::rax;
43
44 build.mov(OperandX64::reg(table), luau_reg_value(ra + 1));
45 build.mov(OperandX64::reg(index), luau_reg_value(ra + 2));
46
47 build.mov(
48 OperandX64::reg(sized(elem_ptr, SizeX64::dword)),
49 OperandX64::reg(sized(index, SizeX64::dword)),
50 );
51 build.shl(
52 OperandX64::reg(sized(elem_ptr, SizeX64::dword)),
53 OperandX64::imm(K_TVALUE_SIZE_LOG2),
54 );
55 build.add(
56 OperandX64::reg(elem_ptr),
57 mem(
58 SizeX64::qword,
59 table,
60 core::mem::offset_of!(LuaTable, array) as i32,
61 ),
62 );
63
64 for i in 2..aux {
65 build.mov(
66 luau_reg_tag(ra + 3 + i),
67 OperandX64::imm(lua_Type::LUA_TNIL as i32),
68 );
69 }
70
71 let mut skip_array = Label::default();
72 let mut skip_array_nil = Label::default();
73
74 let mut array_loop = Label::default();
75 build.set_label(&mut array_loop);
76 build.cmp(
77 OperandX64::reg(sized(index, SizeX64::dword)),
78 mem(
79 SizeX64::dword,
80 table,
81 core::mem::offset_of!(LuaTable, sizearray) as i32,
82 ),
83 );
84 build.jcc(ConditionX64::NotBelow, &mut skip_array);
85
86 build.inc(OperandX64::reg(index));
87
88 build.cmp(
89 mem(
90 SizeX64::dword,
91 elem_ptr,
92 core::mem::offset_of!(TValue, tt) as i32,
93 ),
94 OperandX64::imm(lua_Type::LUA_TNIL as i32),
95 );
96 build.jcc(ConditionX64::Equal, &mut skip_array_nil);
97
98 build.mov(luau_reg_value(ra + 2), OperandX64::reg(index));
99
100 build.vcvtsi2sd(
101 OperandX64::reg(xmm(0)),
102 OperandX64::reg(xmm(0)),
103 OperandX64::reg(sized(index, SizeX64::dword)),
104 );
105 build.vmovsd_operand_x_64_operand_x_64(luau_reg_value(ra + 3), OperandX64::reg(xmm(0)));
106 build.mov(
107 luau_reg_tag(ra + 3),
108 OperandX64::imm(lua_Type::LUA_TNUMBER as i32),
109 );
110
111 set_luau_reg(build, xmm(2), ra + 4, mem(SizeX64::xmmword, elem_ptr, 0));
112
113 build.jmp_label(loop_repeat);
114
115 build.set_label_label(&mut skip_array_nil);
116 build.add(
117 OperandX64::reg(elem_ptr),
118 OperandX64::imm(core::mem::size_of::<TValue>() as i32),
119 );
120 build.jmp_label(&mut array_loop);
121
122 build.set_label_label(&mut skip_array);
123
124 if luaur_common::FFlag::LuauCodeGenCallWrapperEmitInst.get() {
125 regs.take_reg(table, k_invalid_inst_idx);
126 regs.take_reg(index, k_invalid_inst_idx);
127
128 let mut call_wrapper = IrCallWrapperX64::ir_call_wrapper_x_64_ir_call_wrapper_x_64(
129 regs,
130 build,
131 k_invalid_inst_idx,
132 );
133 call_wrapper.add_argument_size_x_64_operand_x_64_ir_op(
134 SizeX64::qword,
135 OperandX64::reg(r_state()),
136 IrOp::ir_op(),
137 );
138 call_wrapper.add_argument_size_x_64_operand_x_64_ir_op(
139 SizeX64::qword,
140 OperandX64::reg(table),
141 IrOp::ir_op(),
142 );
143 call_wrapper.add_argument_size_x_64_operand_x_64_ir_op(
144 SizeX64::qword,
145 OperandX64::reg(index),
146 IrOp::ir_op(),
147 );
148 call_wrapper.add_argument_size_x_64_operand_x_64_ir_op(
149 SizeX64::qword,
150 luau_reg_address(ra),
151 IrOp::ir_op(),
152 );
153 call_wrapper
154 .call(&native_context_slot(
155 core::mem::offset_of!(NativeContext, forgLoopNodeIter) as i32,
156 ));
157 } else {
158 let r_arg1 = if build.abi == ABIX64::Windows {
159 RegisterX64::rcx
160 } else {
161 RegisterX64::rdi
162 };
163 let r_arg4 = if build.abi == ABIX64::Windows {
164 RegisterX64::r9
165 } else {
166 RegisterX64::rcx
167 };
168
169 build.mov(OperandX64::reg(r_arg1), OperandX64::reg(r_state()));
170 build.lea_operand_x_64_operand_x_64(OperandX64::reg(r_arg4), luau_reg_address(ra));
171 build.call_operand_x_64(native_context_slot(core::mem::offset_of!(
172 NativeContext,
173 forgLoopNodeIter
174 ) as i32));
175 }
176
177 build.test(
178 OperandX64::reg(sized(RegisterX64::rax, SizeX64::byte)),
179 OperandX64::reg(sized(RegisterX64::rax, SizeX64::byte)),
180 );
181 build.jcc(ConditionX64::NotZero, loop_repeat);
182}
183
184const K_TVALUE_SIZE_LOG2: i32 = 4;
185
186const fn reg(index: u8, size: SizeX64) -> RegisterX64 {
187 RegisterX64 {
188 bits: (index << RegisterX64::INDEX_SHIFT) | size as u8,
189 }
190}
191
192const fn sized(reg: RegisterX64, size: SizeX64) -> RegisterX64 {
193 RegisterX64 {
194 bits: (reg.index() << RegisterX64::INDEX_SHIFT) | size as u8,
195 }
196}
197
198const fn xmm(index: u8) -> RegisterX64 {
199 reg(index, SizeX64::xmmword)
200}
201
202const fn r_state() -> RegisterX64 {
203 reg(15, SizeX64::qword)
204}
205
206const fn r_native_context() -> RegisterX64 {
207 reg(13, SizeX64::qword)
208}
209
210fn mem(size: SizeX64, base: RegisterX64, disp: i32) -> OperandX64 {
211 OperandX64::mem(size, RegisterX64::noreg, 1, base, disp)
212}
213
214fn native_context_slot(disp: i32) -> OperandX64 {
215 mem(SizeX64::qword, r_native_context(), disp)
216}