Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
fa7dadbdeb
|
|||
| d5acdc0e7b |
+23
-20
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2012,15 +2015,13 @@ fn emit_promoted_op(f: &mut Function, op: &IrOp, sim: &mut StackSim) {
|
|||||||
// Outside loops, RFetch shouldn't appear in promoted code
|
// Outside loops, RFetch shouldn't appear in promoted code
|
||||||
}
|
}
|
||||||
|
|
||||||
IrOp::LoopJ => {
|
IrOp::LoopJ if sim.loop_index_stack.len() >= 2 => {
|
||||||
if sim.loop_index_stack.len() >= 2 {
|
|
||||||
let (outer_index, _) = sim.loop_index_stack[sim.loop_index_stack.len() - 2];
|
let (outer_index, _) = sim.loop_index_stack[sim.loop_index_stack.len() - 2];
|
||||||
let result = sim.alloc();
|
let result = sim.alloc();
|
||||||
f.instruction(&Instruction::LocalGet(outer_index));
|
f.instruction(&Instruction::LocalGet(outer_index));
|
||||||
f.instruction(&Instruction::LocalSet(result));
|
f.instruction(&Instruction::LocalSet(result));
|
||||||
sim.push(result);
|
sim.push(result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
IrOp::Exit => {
|
IrOp::Exit => {
|
||||||
// Write remaining promoted locals back to memory stack, then return
|
// Write remaining promoted locals back to memory stack, then return
|
||||||
@@ -2147,16 +2148,16 @@ fn needs_f64_locals(ops: &[IrOp]) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body } => {
|
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body }
|
||||||
if needs_f64_locals(body) {
|
if needs_f64_locals(body) =>
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
IrOp::BeginWhileRepeat { test, body }
|
||||||
IrOp::BeginWhileRepeat { test, body } => {
|
if needs_f64_locals(test) || needs_f64_locals(body) =>
|
||||||
if needs_f64_locals(test) || needs_f64_locals(body) {
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
IrOp::BeginDoubleWhileRepeat {
|
IrOp::BeginDoubleWhileRepeat {
|
||||||
outer_test,
|
outer_test,
|
||||||
inner_test,
|
inner_test,
|
||||||
@@ -2209,16 +2210,16 @@ fn body_needs_return_stack(ops: &[IrOp]) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body } => {
|
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body }
|
||||||
if body_needs_return_stack(body) {
|
if body_needs_return_stack(body) =>
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
IrOp::BeginWhileRepeat { test, body }
|
||||||
IrOp::BeginWhileRepeat { test, body } => {
|
if body_needs_return_stack(test) || body_needs_return_stack(body) =>
|
||||||
if body_needs_return_stack(test) || body_needs_return_stack(body) {
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
IrOp::BeginDoubleWhileRepeat {
|
IrOp::BeginDoubleWhileRepeat {
|
||||||
outer_test,
|
outer_test,
|
||||||
inner_test,
|
inner_test,
|
||||||
@@ -2831,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)
|
||||||
|
|||||||
@@ -131,11 +131,9 @@ pub fn export_module(
|
|||||||
fn collect_external_calls(ops: &[IrOp], ir_ids: &HashSet<WordId>, host_ids: &mut HashSet<WordId>) {
|
fn collect_external_calls(ops: &[IrOp], ir_ids: &HashSet<WordId>, host_ids: &mut HashSet<WordId>) {
|
||||||
for op in ops {
|
for op in ops {
|
||||||
match op {
|
match op {
|
||||||
IrOp::Call(id) | IrOp::TailCall(id) => {
|
IrOp::Call(id) | IrOp::TailCall(id) if !ir_ids.contains(id) => {
|
||||||
if !ir_ids.contains(id) {
|
|
||||||
host_ids.insert(*id);
|
host_ids.insert(*id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
IrOp::If {
|
IrOp::If {
|
||||||
then_body,
|
then_body,
|
||||||
else_body,
|
else_body,
|
||||||
|
|||||||
@@ -591,16 +591,16 @@ fn contains_call_to(ops: &[IrOp], target: WordId) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body } => {
|
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body }
|
||||||
if contains_call_to(body, target) {
|
if contains_call_to(body, target) =>
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
IrOp::BeginWhileRepeat { test, body }
|
||||||
IrOp::BeginWhileRepeat { test, body } => {
|
if contains_call_to(test, target) || contains_call_to(body, target) =>
|
||||||
if contains_call_to(test, target) || contains_call_to(body, target) {
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
IrOp::BeginDoubleWhileRepeat {
|
IrOp::BeginDoubleWhileRepeat {
|
||||||
outer_test,
|
outer_test,
|
||||||
inner_test,
|
inner_test,
|
||||||
@@ -651,16 +651,14 @@ fn contains_exit(ops: &[IrOp]) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body } => {
|
IrOp::DoLoop { body, .. } | IrOp::BeginUntil { body } | IrOp::BeginAgain { body }
|
||||||
if contains_exit(body) {
|
if contains_exit(body) =>
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
IrOp::BeginWhileRepeat { test, body } if contains_exit(test) || contains_exit(body) => {
|
||||||
IrOp::BeginWhileRepeat { test, body } => {
|
|
||||||
if contains_exit(test) || contains_exit(body) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,8 +397,7 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
let seed = SystemTime::now()
|
let seed = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.map(|d| d.as_nanos() as u64)
|
.map_or(0xDEAD_BEEF_CAFE_BABE, |d| d.as_nanos() as u64);
|
||||||
.unwrap_or(0xDEAD_BEEF_CAFE_BABE);
|
|
||||||
Arc::new(Mutex::new(if seed == 0 {
|
Arc::new(Mutex::new(if seed == 0 {
|
||||||
0xDEAD_BEEF_CAFE_BABE
|
0xDEAD_BEEF_CAFE_BABE
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ fn probe_gforth(candidate: &str) -> bool {
|
|||||||
.arg("-e")
|
.arg("-e")
|
||||||
.arg("bye")
|
.arg("bye")
|
||||||
.output()
|
.output()
|
||||||
.map(|o| o.status.success())
|
.is_ok_and(|o| o.status.success())
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_gforth() -> Option<&'static str> {
|
fn find_gforth() -> Option<&'static str> {
|
||||||
|
|||||||
Reference in New Issue
Block a user