Fix optimizer bug: TailCall inside If not converted on inline
When the tail-call pass converted a Call to TailCall inside an If branch, and the inliner subsequently inlined that word, the TailCall was not converted back to Call in nested control-flow bodies. The TailCall codegen emits a Return instruction, which would exit the *caller* instead of just the inlined callee — silently corrupting the return stack. Root cause: the inliner only converted top-level TailCalls in the body (line-by-line iteration), missing TailCalls nested inside If/DoLoop/Begin structures. Fix: add detailcall() that recursively walks the entire IR tree and converts all TailCall ops back to Call before inlining. This unblocks defining complex Forth words (like SM/REM, FM/MOD) that use DABS → DNEGATE → D+ chains with return-stack operations inside conditional branches. 426 tests pass (including new regression test).
This commit is contained in:
@@ -7944,6 +7944,18 @@ mod tests {
|
||||
assert_eq!(eval_stack("-1 0 10 WITHIN"), vec![0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inline_tailcall_rstack_interaction() {
|
||||
// Regression: inlining a word that had a TailCall inside an If branch
|
||||
// caused the TailCall's Return to exit the *caller*, corrupting the
|
||||
// return stack. The fix: detailcall() recursively converts TailCall
|
||||
// back to Call inside all nested control-flow bodies when inlining.
|
||||
assert_eq!(
|
||||
eval_stack(": T 42 >R 99 >R -7 -1 DABS R> R> ; T"),
|
||||
vec![42, 99, 0, 7]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_do_loop_with_i_and_step() {
|
||||
// +LOOP with step of 2
|
||||
|
||||
Reference in New Issue
Block a user