codegen: LOOP exits on index==limit (Forth 2012 boundary crossing)
This commit is contained in:
@@ -1088,10 +1088,12 @@ fn emit_do_loop(f: &mut Function, body: &[IrOp], is_plus_loop: bool, ctx: &mut E
|
|||||||
.instruction(&Instruction::End);
|
.instruction(&Instruction::End);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if index >= limit, exit
|
// Forth 2012: LOOP exits when the index crosses the boundary between
|
||||||
|
// limit-1 and limit. With step +1 that is exactly new_index == limit
|
||||||
|
// in wraparound arithmetic — start >= limit must wrap, not exit early.
|
||||||
f.instruction(&Instruction::LocalGet(index_local))
|
f.instruction(&Instruction::LocalGet(index_local))
|
||||||
.instruction(&Instruction::LocalGet(limit_local))
|
.instruction(&Instruction::LocalGet(limit_local))
|
||||||
.instruction(&Instruction::I32GeS)
|
.instruction(&Instruction::I32Eq)
|
||||||
.instruction(&Instruction::BrIf(1)) // break to $exit
|
.instruction(&Instruction::BrIf(1)) // break to $exit
|
||||||
.instruction(&Instruction::Br(0)) // continue loop
|
.instruction(&Instruction::Br(0)) // continue loop
|
||||||
.instruction(&Instruction::End) // end loop
|
.instruction(&Instruction::End) // end loop
|
||||||
@@ -1897,7 +1899,8 @@ fn emit_promoted_op(f: &mut Function, op: &IrOp, sim: &mut StackSim) {
|
|||||||
// Fix up stack for next iteration (LOOP body is stack-neutral)
|
// Fix up stack for next iteration (LOOP body is stack-neutral)
|
||||||
emit_promoted_loop_fixup(f, sim, &loop_top_stack);
|
emit_promoted_loop_fixup(f, sim, &loop_top_stack);
|
||||||
|
|
||||||
// LOOP: increment by 1, check >= limit
|
// LOOP: increment by 1, exit when new_index == limit
|
||||||
|
// (Forth 2012 boundary crossing; start >= limit wraps around)
|
||||||
f.instruction(&Instruction::LocalGet(index_local));
|
f.instruction(&Instruction::LocalGet(index_local));
|
||||||
f.instruction(&Instruction::I32Const(1));
|
f.instruction(&Instruction::I32Const(1));
|
||||||
f.instruction(&Instruction::I32Add);
|
f.instruction(&Instruction::I32Add);
|
||||||
@@ -1905,7 +1908,7 @@ fn emit_promoted_op(f: &mut Function, op: &IrOp, sim: &mut StackSim) {
|
|||||||
|
|
||||||
f.instruction(&Instruction::LocalGet(index_local));
|
f.instruction(&Instruction::LocalGet(index_local));
|
||||||
f.instruction(&Instruction::LocalGet(limit_local));
|
f.instruction(&Instruction::LocalGet(limit_local));
|
||||||
f.instruction(&Instruction::I32GeS);
|
f.instruction(&Instruction::I32Eq);
|
||||||
f.instruction(&Instruction::BrIf(1)); // break to $exit
|
f.instruction(&Instruction::BrIf(1)); // break to $exit
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2829,9 +2832,11 @@ fn emit_consolidated_do_loop(
|
|||||||
.instruction(&Instruction::End);
|
.instruction(&Instruction::End);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forth 2012 boundary crossing: exit when new_index == limit
|
||||||
|
// (start >= limit wraps around instead of exiting early).
|
||||||
f.instruction(&Instruction::LocalGet(index_local))
|
f.instruction(&Instruction::LocalGet(index_local))
|
||||||
.instruction(&Instruction::LocalGet(limit_local))
|
.instruction(&Instruction::LocalGet(limit_local))
|
||||||
.instruction(&Instruction::I32GeS)
|
.instruction(&Instruction::I32Eq)
|
||||||
.instruction(&Instruction::BrIf(1))
|
.instruction(&Instruction::BrIf(1))
|
||||||
.instruction(&Instruction::Br(0))
|
.instruction(&Instruction::Br(0))
|
||||||
.instruction(&Instruction::End)
|
.instruction(&Instruction::End)
|
||||||
|
|||||||
Reference in New Issue
Block a user