diff --git a/crates/core/src/codegen.rs b/crates/core/src/codegen.rs index 46d26cc..44b1bf1 100644 --- a/crates/core/src/codegen.rs +++ b/crates/core/src/codegen.rs @@ -1088,10 +1088,12 @@ fn emit_do_loop(f: &mut Function, body: &[IrOp], is_plus_loop: bool, ctx: &mut E .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)) .instruction(&Instruction::LocalGet(limit_local)) - .instruction(&Instruction::I32GeS) + .instruction(&Instruction::I32Eq) .instruction(&Instruction::BrIf(1)) // break to $exit .instruction(&Instruction::Br(0)) // continue 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) 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::I32Const(1)); 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(limit_local)); - f.instruction(&Instruction::I32GeS); + f.instruction(&Instruction::I32Eq); f.instruction(&Instruction::BrIf(1)); // break to $exit } @@ -2829,9 +2832,11 @@ fn emit_consolidated_do_loop( .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)) .instruction(&Instruction::LocalGet(limit_local)) - .instruction(&Instruction::I32GeS) + .instruction(&Instruction::I32Eq) .instruction(&Instruction::BrIf(1)) .instruction(&Instruction::Br(0)) .instruction(&Instruction::End)