Skip to content

Structured control flow gaps vs standard Forth #16

@tetsuo-cpp

Description

@tetsuo-cpp

Summary

WarpForth uses structured control flow (MLIR scf dialect regions) via a recursive-descent parser, while standard Forth uses a control-flow stack that allows arbitrary interleaving of control-flow words. This means several valid standard Forth constructs cannot be expressed in WarpForth.

Root Cause

WarpForth's parser expects each control-flow construct to match a fixed pattern (IF...ELSE...THEN, BEGIN...UNTIL, BEGIN...WHILE...REPEAT, DO...LOOP). This inherits from MLIR's scf dialect, which only provides structured control flow (scf.if, scf.while, scf.for).

Standard Forth's control-flow stack is just a stack of orig (forward branch) and dest (backward branch target) entries. Words push/pop freely with no nesting requirement.

Missing Features

High impact for GPU kernels

Feature Standard Forth Notes
LEAVE / UNLOOP Early exit from DO...LOOP Very common in search/scan patterns. Workaround: restructure as BEGIN...WHILE...REPEAT with a flag
EXIT Early return from a word Common in utility words with multiple exit conditions. Workaround: single-exit restructuring with deeper IF/ELSE nesting
J Outer DO...LOOP index Important for matrix/2D operations — common GPU workloads. Workaround: manually save outer index on the data stack

Medium impact

Feature Standard Forth Notes
Multiple WHILEs BEGIN c1 WHILE c2 WHILE body REPEAT THEN Well-known idiom for multi-condition exit. Workaround: combine conditions with AND/OR
+LOOP Arbitrary loop step Useful for strided iteration. Workaround: BEGIN...WHILE...REPEAT with manual counter

Low/no impact for GPU kernels

Feature Why
BEGIN...AGAIN Infinite loops hang the GPU; trivial workaround BEGIN 0 UNTIL
?DO...LOOP WarpForth's DO already behaves like ?DO (zero-trip safe via scf.for)
RECURSE Recursion is dangerous on GPUs (tiny call stacks, thread divergence)
CS-PICK / CS-ROLL Exotic metaprogramming, never used in kernel code
Cross-boundary control flow e.g. BEGIN ... IF ... UNTIL ... THEN — essentially never written in practice

Possible Approaches

  • Incremental: add the high-impact features one at a time within the structured model (e.g. J is straightforward, EXIT/LEAVE may require flag-based lowering)
  • Architectural: lower to cf.br/cf.cond_br (the cf dialect) for unstructured control flow, then run a restructuring pass for GPU codegen — major change, likely not worth it given the GPU kernel use case

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions