luaur_code_gen/functions/
translate_inst_for_n_loop.rs1use crate::enums::ir_cmd::IrCmd;
2use crate::enums::ir_condition::IrCondition;
3use crate::enums::ir_op_kind::IrOpKind;
4use crate::records::ir_builder::IrBuilder;
5use crate::type_aliases::instruction_ir_builder::Instruction;
6
7use luaur_common::enums::luau_opcode::LuauOpcode;
8use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
9use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
10
11use crate::functions::get_jump_target::get_jump_target;
12use crate::functions::get_op_length::get_op_length;
13use crate::macros::codegen_assert::CODEGEN_ASSERT;
14
15pub fn translate_inst_for_n_loop(build: &mut IrBuilder, pc: *const Instruction, pcpos: i32) {
16 let ra = LUAU_INSN_A(unsafe { *pc }) as u8;
17
18 let repeat_jump_target = get_jump_target(unsafe { *pc }, pcpos as u32);
19 let loop_repeat = build.block_at_inst(repeat_jump_target as u32);
20 let op = LuauOpcode::from(LUAU_INSN_OP(unsafe { *pc }) as u8);
21 let op_length = get_op_length(op);
22 let loop_exit = build.block_at_inst((pcpos + op_length) as u32);
23
24 CODEGEN_ASSERT!(!build.numeric_loop_stack.is_empty());
25 let loop_info = build.numeric_loop_stack.last().copied().unwrap();
26 let step_k = loop_info.step;
27
28 if repeat_jump_target != loop_info.startpc {
29 let pcpos_op = build.const_uint(pcpos as u32);
30 build.inst_ir_cmd_ir_op(IrCmd::INTERRUPT, pcpos_op);
31 }
32
33 let reg_limit = build.vm_reg(ra);
34 let limit = build.inst_ir_cmd_ir_op(IrCmd::LOAD_DOUBLE, reg_limit);
35 let step = if step_k.kind() == IrOpKind::Undef {
36 let reg_step = build.vm_reg(ra + 1);
37 build.inst_ir_cmd_ir_op(IrCmd::LOAD_DOUBLE, reg_step)
38 } else {
39 step_k
40 };
41
42 let reg_idx = build.vm_reg(ra + 2);
43 let mut idx = build.inst_ir_cmd_ir_op(IrCmd::LOAD_DOUBLE, reg_idx);
44 idx = build.inst_ir_cmd_ir_op_ir_op(IrCmd::ADD_NUM, idx, step);
45 let reg_idx = build.vm_reg(ra + 2);
46 build.inst_ir_cmd_ir_op_ir_op(IrCmd::STORE_DOUBLE, reg_idx, idx);
47
48 if step_k.kind() == IrOpKind::Undef {
49 build.inst_ir_cmd_ir_op_ir_op_ir_op_ir_op_ir_op(
50 IrCmd::JUMP_FORN_LOOP_COND,
51 idx,
52 limit,
53 step,
54 loop_repeat,
55 loop_exit,
56 );
57 } else {
58 let step_n = build.function.double_op(step_k);
59
60 let reg_step = build.vm_reg(ra + 1);
61 let one = build.const_int(1);
62 build.inst_ir_cmd_ir_op_ir_op(IrCmd::MARK_USED, reg_step, one);
63
64 let cond = if step_n > 0.0 {
65 IrCondition::LessEqual
66 } else {
67 IrCondition::LessEqual
68 };
69 let cond_op = build.cond(cond);
70
71 if step_n > 0.0 {
72 build.inst_ir_cmd_ir_op_ir_op_ir_op_ir_op_ir_op(
73 IrCmd::JUMP_CMP_NUM,
74 idx,
75 limit,
76 cond_op,
77 loop_repeat,
78 loop_exit,
79 );
80 } else {
81 build.inst_ir_cmd_ir_op_ir_op_ir_op_ir_op_ir_op(
82 IrCmd::JUMP_CMP_NUM,
83 limit,
84 idx,
85 cond_op,
86 loop_repeat,
87 loop_exit,
88 );
89 }
90 }
91
92 if build.is_internal_block(loop_exit) {
93 build.begin_block(loop_exit);
94 }
95}