Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions gpu_test/test_kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,36 @@ def test_do_loop(kernel_runner: KernelRunner) -> None:
assert result == [0, 1, 2, 3, 4]


def test_multi_while(kernel_runner: KernelRunner) -> None:
"""Multi-WHILE: two exit conditions from the same loop (interleaved CF).

20 BEGIN DUP 10 > WHILE DUP 2 MOD 0= WHILE 1 - REPEAT THEN
Decrements while >10 AND even. 20→19 (odd, WHILE(2) exit) → result 19.
"""
result = kernel_runner.run(
forth_source=(
"PARAM DATA 256\n"
"20 BEGIN DUP 10 > WHILE DUP 2 MOD 0= WHILE 1 - REPEAT THEN\n"
"0 CELLS DATA + !"
),
)
assert result[0] == 19


def test_while_until(kernel_runner: KernelRunner) -> None:
"""WHILE+UNTIL: two different exit mechanisms from the same loop (interleaved CF).

10 BEGIN DUP 0 > WHILE 1 - DUP 5 = UNTIL THEN
Decrements while >0, stops early at 5. 10→9→…→5 (UNTIL exit) → result 5.
"""
result = kernel_runner.run(
forth_source=(
"PARAM DATA 256\n10 BEGIN DUP 0 > WHILE 1 - DUP 5 = UNTIL THEN\n0 CELLS DATA + !"
),
)
assert result[0] == 5


# --- GPU Indexing ---


Expand Down
2 changes: 1 addition & 1 deletion include/warpforth/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def ConvertForthToMemRef
let dependentDialects = ["mlir::memref::MemRefDialect",
"mlir::arith::ArithDialect",
"mlir::LLVM::LLVMDialect",
"mlir::scf::SCFDialect"];
"mlir::cf::ControlFlowDialect"];
}

def ConvertForthToGPU : Pass<"convert-forth-to-gpu", "mlir::ModuleOp"> {
Expand Down
103 changes: 24 additions & 79 deletions include/warpforth/Dialect/Forth/ForthOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#define FORTH_OPS

include "warpforth/Dialect/Forth/ForthDialect.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/SideEffectInterfaces.td"

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -446,102 +445,48 @@ def Forth_ZeroEqOp : Forth_StackOpBase<"zero_eq"> {
}

//===----------------------------------------------------------------------===//
// Control flow operations.
// Control flow support operations.
//===----------------------------------------------------------------------===//

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

def Forth_IfOp : Forth_Op<"if", [RecursiveMemoryEffects,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getEntrySuccessorOperands"]>]> {
let summary = "Conditional execution";
def Forth_PopOp : Forth_Op<"pop", [Pure]> {
let summary = "Pop top of stack as i64 value";
let description = [{
Conditional execution. If the flag is non-zero, the then region executes;
otherwise the else region executes. Each region must yield the resulting
stack.
Forth semantics: flag IF then-body ELSE else-body THEN
Pops the top value from the stack and returns it as an i64.
Used by DO to pop start and limit.
Forth semantics: ( x -- )
}];
let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);
let regions = (region SizedRegion<1>:$then_region,
SizedRegion<1>:$else_region);
let hasCustomAssemblyFormat = 1;
}

def Forth_BeginUntilOp : Forth_Op<"begin_until", [RecursiveMemoryEffects,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getEntrySuccessorOperands"]>]> {
let summary = "Post-test loop (do-while)";
let description = [{
BEGIN/UNTIL loop. Executes body, pops flag. If flag is zero, loops back.
If non-zero, exits. Stack effect: ( -- ) with flag consumed each iteration.
}];
let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);
let regions = (region SizedRegion<1>:$body_region);
let hasCustomAssemblyFormat = 1;
}

def Forth_DoLoopOp : Forth_Op<"do_loop", [RecursiveMemoryEffects,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getEntrySuccessorOperands"]>]> {
let summary = "Counted loop (DO/LOOP)";
let description = [{
Pops start and limit from the stack, iterates from start to limit-1.
Use forth.loop_index (I word) inside to access the current loop index.
Stack effect: ( limit start -- )
}];
let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);
let regions = (region SizedRegion<1>:$body_region);
let hasCustomAssemblyFormat = 1;
}

def Forth_BeginWhileRepeatOp : Forth_Op<"begin_while_repeat",
[RecursiveMemoryEffects,
DeclareOpInterfaceMethods<RegionBranchOpInterface,
["getEntrySuccessorOperands"]>]> {
let summary = "Pre-test loop (BEGIN/WHILE/REPEAT)";
let description = [{
BEGIN/WHILE/REPEAT loop. The condition region runs first, WHILE pops flag.
If flag is non-zero, the body region executes and loops back to condition.
If flag is zero, the loop exits.
Stack effect: ( -- ) with flag consumed each iteration.
let results = (outs Forth_StackType:$output_stack, I64:$value);
let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack) `,` type($value)
}];
let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);
let regions = (region SizedRegion<1>:$condition_region,
SizedRegion<1>:$body_region);
let hasCustomAssemblyFormat = 1;
}

def Forth_LoopIndexOp : Forth_Op<"loop_index", [Pure]> {
let summary = "Push loop index onto stack (I/J/K words)";
def Forth_PushValueOp : Forth_Op<"push_value", [Pure]> {
let summary = "Push dynamic i64 value onto stack";
let description = [{
Pushes the loop index at the given nesting depth onto the stack.
depth=0 is I (innermost), depth=1 is J, depth=2 is K.
Only valid inside nested forth.do_loop bodies at sufficient depth.
( -- index )
Pushes a dynamic i64 value onto the stack. Used by I/J/K to push
the loop counter value.
Forth semantics: ( -- x )
}];
let arguments = (ins Forth_StackType:$input_stack,
DefaultValuedAttr<I64Attr, "0">:$depth);
let arguments = (ins Forth_StackType:$input_stack, I64:$value);
let results = (outs Forth_StackType:$output_stack);
let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
$input_stack `,` $value attr-dict `:` type($input_stack) `,` type($value) `->` type($output_stack)
}];
}

Expand Down
1 change: 0 additions & 1 deletion lib/Conversion/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ add_mlir_library(MLIRConversionPasses
MLIRGPUToNVVMTransforms
MLIRGPUTransforms
MLIRReconcileUnrealizedCasts
MLIRSCFToControlFlow
MLIRTransforms
)

Expand Down
2 changes: 1 addition & 1 deletion lib/Conversion/ForthToMemRef/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ add_mlir_conversion_library(MLIRForthToMemRefConversion
MLIRArithDialect
MLIRLLVMDialect
MLIRFuncDialect
MLIRSCFDialect
MLIRControlFlowDialect
MLIRForth
)
Loading