Skip to content

Commit 2a78ff0

Browse files
committed
refactor: lower control flow to cf dialect instead of scf
1 parent 4ce6559 commit 2a78ff0

24 files changed

Lines changed: 1287 additions & 1272 deletions

gpu_test/test_kernels.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,36 @@ def test_do_loop(kernel_runner: KernelRunner) -> None:
154154
assert result == [0, 1, 2, 3, 4]
155155

156156

157+
def test_multi_while(kernel_runner: KernelRunner) -> None:
158+
"""Multi-WHILE: two exit conditions from the same loop (interleaved CF).
159+
160+
20 BEGIN DUP 10 > WHILE DUP 2 MOD 0= WHILE 1 - REPEAT THEN
161+
Decrements while >10 AND even. 20→19 (odd, WHILE(2) exit) → result 19.
162+
"""
163+
result = kernel_runner.run(
164+
forth_source=(
165+
"PARAM DATA 256\n"
166+
"20 BEGIN DUP 10 > WHILE DUP 2 MOD 0= WHILE 1 - REPEAT THEN\n"
167+
"0 CELLS DATA + !"
168+
),
169+
)
170+
assert result[0] == 19
171+
172+
173+
def test_while_until(kernel_runner: KernelRunner) -> None:
174+
"""WHILE+UNTIL: two different exit mechanisms from the same loop (interleaved CF).
175+
176+
10 BEGIN DUP 0 > WHILE 1 - DUP 5 = UNTIL THEN
177+
Decrements while >0, stops early at 5. 10→9→…→5 (UNTIL exit) → result 5.
178+
"""
179+
result = kernel_runner.run(
180+
forth_source=(
181+
"PARAM DATA 256\n10 BEGIN DUP 0 > WHILE 1 - DUP 5 = UNTIL THEN\n0 CELLS DATA + !"
182+
),
183+
)
184+
assert result[0] == 5
185+
186+
157187
# --- GPU Indexing ---
158188

159189

include/warpforth/Conversion/Passes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def ConvertForthToMemRef
2828
let dependentDialects = ["mlir::memref::MemRefDialect",
2929
"mlir::arith::ArithDialect",
3030
"mlir::LLVM::LLVMDialect",
31-
"mlir::scf::SCFDialect"];
31+
"mlir::cf::ControlFlowDialect"];
3232
}
3333

3434
def ConvertForthToGPU : Pass<"convert-forth-to-gpu", "mlir::ModuleOp"> {

include/warpforth/Dialect/Forth/ForthOps.td

Lines changed: 24 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#define FORTH_OPS
99

1010
include "warpforth/Dialect/Forth/ForthDialect.td"
11-
include "mlir/Interfaces/ControlFlowInterfaces.td"
1211
include "mlir/Interfaces/SideEffectInterfaces.td"
1312

1413
//===----------------------------------------------------------------------===//
@@ -446,102 +445,48 @@ def Forth_ZeroEqOp : Forth_StackOpBase<"zero_eq"> {
446445
}
447446

448447
//===----------------------------------------------------------------------===//
449-
// Control flow operations.
448+
// Control flow support operations.
450449
//===----------------------------------------------------------------------===//
451450

452-
def Forth_YieldOp : Forth_Op<"yield", [Pure, Terminator, ReturnLike,
453-
ParentOneOf<["IfOp", "BeginUntilOp", "BeginWhileRepeatOp", "DoLoopOp"]>]> {
454-
let summary = "Yield stack from control flow region";
451+
def Forth_PopFlagOp : Forth_Op<"pop_flag", [Pure]> {
452+
let summary = "Pop top of stack as boolean flag";
455453
let description = [{
456-
Yields the current stack state from a control flow region back to
457-
the parent operation. Acts as a region terminator.
458-
When the optional `while_cond` attribute is present, the yield acts as
459-
a WHILE condition (continue when flag is non-zero) rather than
460-
UNTIL (exit when flag is non-zero).
454+
Pops the top value from the stack and returns it as an i1 flag
455+
(non-zero = true, zero = false). Used by IF, UNTIL, WHILE.
456+
Forth semantics: ( flag -- )
461457
}];
462-
let arguments = (ins Forth_StackType:$result, OptionalAttr<UnitAttr>:$while_cond);
458+
let arguments = (ins Forth_StackType:$input_stack);
459+
let results = (outs Forth_StackType:$output_stack, I1:$flag);
463460
let assemblyFormat = [{
464-
$result (`while_cond` $while_cond^)? attr-dict `:` type($result)
461+
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack) `,` type($flag)
465462
}];
466463
}
467464

468-
def Forth_IfOp : Forth_Op<"if", [RecursiveMemoryEffects,
469-
DeclareOpInterfaceMethods<RegionBranchOpInterface,
470-
["getEntrySuccessorOperands"]>]> {
471-
let summary = "Conditional execution";
465+
def Forth_PopOp : Forth_Op<"pop", [Pure]> {
466+
let summary = "Pop top of stack as i64 value";
472467
let description = [{
473-
Conditional execution. If the flag is non-zero, the then region executes;
474-
otherwise the else region executes. Each region must yield the resulting
475-
stack.
476-
Forth semantics: flag IF then-body ELSE else-body THEN
468+
Pops the top value from the stack and returns it as an i64.
469+
Used by DO to pop start and limit.
470+
Forth semantics: ( x -- )
477471
}];
478472
let arguments = (ins Forth_StackType:$input_stack);
479-
let results = (outs Forth_StackType:$output_stack);
480-
let regions = (region SizedRegion<1>:$then_region,
481-
SizedRegion<1>:$else_region);
482-
let hasCustomAssemblyFormat = 1;
483-
}
484-
485-
def Forth_BeginUntilOp : Forth_Op<"begin_until", [RecursiveMemoryEffects,
486-
DeclareOpInterfaceMethods<RegionBranchOpInterface,
487-
["getEntrySuccessorOperands"]>]> {
488-
let summary = "Post-test loop (do-while)";
489-
let description = [{
490-
BEGIN/UNTIL loop. Executes body, pops flag. If flag is zero, loops back.
491-
If non-zero, exits. Stack effect: ( -- ) with flag consumed each iteration.
492-
}];
493-
let arguments = (ins Forth_StackType:$input_stack);
494-
let results = (outs Forth_StackType:$output_stack);
495-
let regions = (region SizedRegion<1>:$body_region);
496-
let hasCustomAssemblyFormat = 1;
497-
}
498-
499-
def Forth_DoLoopOp : Forth_Op<"do_loop", [RecursiveMemoryEffects,
500-
DeclareOpInterfaceMethods<RegionBranchOpInterface,
501-
["getEntrySuccessorOperands"]>]> {
502-
let summary = "Counted loop (DO/LOOP)";
503-
let description = [{
504-
Pops start and limit from the stack, iterates from start to limit-1.
505-
Use forth.loop_index (I word) inside to access the current loop index.
506-
Stack effect: ( limit start -- )
507-
}];
508-
let arguments = (ins Forth_StackType:$input_stack);
509-
let results = (outs Forth_StackType:$output_stack);
510-
let regions = (region SizedRegion<1>:$body_region);
511-
let hasCustomAssemblyFormat = 1;
512-
}
513-
514-
def Forth_BeginWhileRepeatOp : Forth_Op<"begin_while_repeat",
515-
[RecursiveMemoryEffects,
516-
DeclareOpInterfaceMethods<RegionBranchOpInterface,
517-
["getEntrySuccessorOperands"]>]> {
518-
let summary = "Pre-test loop (BEGIN/WHILE/REPEAT)";
519-
let description = [{
520-
BEGIN/WHILE/REPEAT loop. The condition region runs first, WHILE pops flag.
521-
If flag is non-zero, the body region executes and loops back to condition.
522-
If flag is zero, the loop exits.
523-
Stack effect: ( -- ) with flag consumed each iteration.
473+
let results = (outs Forth_StackType:$output_stack, I64:$value);
474+
let assemblyFormat = [{
475+
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack) `,` type($value)
524476
}];
525-
let arguments = (ins Forth_StackType:$input_stack);
526-
let results = (outs Forth_StackType:$output_stack);
527-
let regions = (region SizedRegion<1>:$condition_region,
528-
SizedRegion<1>:$body_region);
529-
let hasCustomAssemblyFormat = 1;
530477
}
531478

532-
def Forth_LoopIndexOp : Forth_Op<"loop_index", [Pure]> {
533-
let summary = "Push loop index onto stack (I/J/K words)";
479+
def Forth_PushValueOp : Forth_Op<"push_value", [Pure]> {
480+
let summary = "Push dynamic i64 value onto stack";
534481
let description = [{
535-
Pushes the loop index at the given nesting depth onto the stack.
536-
depth=0 is I (innermost), depth=1 is J, depth=2 is K.
537-
Only valid inside nested forth.do_loop bodies at sufficient depth.
538-
( -- index )
482+
Pushes a dynamic i64 value onto the stack. Used by I/J/K to push
483+
the loop counter value.
484+
Forth semantics: ( -- x )
539485
}];
540-
let arguments = (ins Forth_StackType:$input_stack,
541-
DefaultValuedAttr<I64Attr, "0">:$depth);
486+
let arguments = (ins Forth_StackType:$input_stack, I64:$value);
542487
let results = (outs Forth_StackType:$output_stack);
543488
let assemblyFormat = [{
544-
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
489+
$input_stack `,` $value attr-dict `:` type($input_stack) `,` type($value) `->` type($output_stack)
545490
}];
546491
}
547492

lib/Conversion/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ add_mlir_library(MLIRConversionPasses
1212
MLIRGPUToNVVMTransforms
1313
MLIRGPUTransforms
1414
MLIRReconcileUnrealizedCasts
15-
MLIRSCFToControlFlow
1615
MLIRTransforms
1716
)
1817

lib/Conversion/ForthToMemRef/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ add_mlir_conversion_library(MLIRForthToMemRefConversion
1313
MLIRArithDialect
1414
MLIRLLVMDialect
1515
MLIRFuncDialect
16-
MLIRSCFDialect
16+
MLIRControlFlowDialect
1717
MLIRForth
1818
)

0 commit comments

Comments
 (0)