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
33 changes: 33 additions & 0 deletions lib/Translation/ForthToMLIR/ForthToMLIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,39 @@ LogicalResult ForthParser::parseBody(Value &stack) {
builder.setInsertionPointToStart(exitBlock);
stack = exitBlock->getArgument(0);

//=== LEAVE ===
} else if (word == "LEAVE") {
consume();

if (loopStack.empty()) {
return emitError("LEAVE without matching DO");
}

Region *parentRegion = builder.getInsertionBlock()->getParent();
auto &ctx = loopStack.back();

// Continue parsing in a dead block to avoid inserting after a
// terminator. Use a dummy cond_br to create a reachable dead block that
// carries a stack argument, keeping cf->memref type conversion
// consistent.
auto *deadBlock = createStackBlock(parentRegion, loc);
Value cond = builder.create<arith::ConstantOp>(
loc, builder.getI1Type(), builder.getBoolAttr(true));
builder.create<cf::CondBranchOp>(loc, cond, ctx.exit, ValueRange{stack},
deadBlock, ValueRange{stack});
builder.setInsertionPointToStart(deadBlock);
stack = deadBlock->getArgument(0);

//=== UNLOOP ===
} else if (word == "UNLOOP") {
consume();

if (loopStack.empty()) {
return emitError("UNLOOP without matching DO");
}

(void)loopStack.pop_back_val();

//=== DO ===
} else if (word == "DO") {
consume();
Expand Down
37 changes: 37 additions & 0 deletions test/Conversion/ForthToMemRef/leave.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// RUN: %warpforth-opt --convert-forth-to-memref %s | %FileCheck %s

// Test: DO...LEAVE...LOOP lowers to CF branch to loop exit.
// Forth: 10 0 DO LEAVE LOOP

// CHECK-LABEL: func.func private @main
// CHECK: %[[STACK:.*]] = memref.alloca() : memref<256xi64>
// CHECK: cf.br ^bb1(%[[STACK]], %{{.*}} : memref<256xi64>, index)
// CHECK: ^bb1(%{{.*}}: memref<256xi64>, %{{.*}}: index):
// CHECK: cf.cond_br %{{.*}}, ^bb2(%{{.*}}: memref<256xi64>, index), ^bb3(%{{.*}}: memref<256xi64>, index)
// CHECK: ^bb2(%{{.*}}: memref<256xi64>, %{{.*}}: index):
// CHECK-NEXT: cf.br ^bb3(%{{.*}}: memref<256xi64>, index)
// CHECK: ^bb3(%{{.*}}: memref<256xi64>, %{{.*}}: index):
// CHECK: return

module {
func.func private @main() {
%0 = forth.stack !forth.stack
%1 = forth.literal %0 10 : !forth.stack -> !forth.stack
%2 = forth.literal %1 0 : !forth.stack -> !forth.stack
%output_stack, %value = forth.pop %2 : !forth.stack -> !forth.stack, i64
%output_stack_0, %value_1 = forth.pop %output_stack : !forth.stack -> !forth.stack, i64
%alloca = memref.alloca() : memref<1xi64>
%c0 = arith.constant 0 : index
memref.store %value, %alloca[%c0] : memref<1xi64>
cf.br ^bb1(%output_stack_0 : !forth.stack)
^bb1(%3: !forth.stack):
%c0_2 = arith.constant 0 : index
%4 = memref.load %alloca[%c0_2] : memref<1xi64>
%5 = arith.cmpi slt, %4, %value_1 : i64
cf.cond_br %5, ^bb2(%3 : !forth.stack), ^bb3(%3 : !forth.stack)
^bb2(%6: !forth.stack):
cf.br ^bb3(%6 : !forth.stack)
^bb3(%7: !forth.stack):
return
}
}
15 changes: 15 additions & 0 deletions test/Pipeline/leave.forth
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
\ RUN: %warpforth-translate --forth-to-mlir %s | %warpforth-opt --warpforth-pipeline | %FileCheck %s
\ RUN: %warpforth-translate --forth-to-mlir %s | %warpforth-opt --convert-forth-to-memref --convert-scf-to-cf --convert-forth-to-gpu | %FileCheck %s --check-prefix=MID

\ Verify that LEAVE through the full pipeline produces a gpu.binary
\ CHECK: gpu.binary @warpforth_module

\ Verify intermediate MLIR: gpu.func with CF control flow
\ MID: gpu.module @warpforth_module
\ MID: gpu.func @main(%arg0: memref<4xi64> {forth.param_name = "DATA"}) kernel
\ MID: cf.br
\ MID: cf.cond_br
\ MID: gpu.return

PARAM DATA 4
10 0 DO LEAVE LOOP DATA 0 CELLS + !
22 changes: 22 additions & 0 deletions test/Translation/Forth/leave-conditional.forth
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
\ RUN: %warpforth-translate --forth-to-mlir %s | %FileCheck %s

\ Verify conditional LEAVE preserves the loop backedge for non-LEAVE paths.

\ CHECK: cf.br ^bb1(%{{.*}} : !forth.stack)
\ CHECK: ^bb1(%[[CHK:.*]]: !forth.stack):
\ CHECK: cf.cond_br %{{.*}}, ^bb2(%[[CHK]] : !forth.stack), ^bb[[EXIT:[0-9]+]](%[[CHK]] : !forth.stack)
\ CHECK: ^bb2(%[[B:.*]]: !forth.stack):
\ CHECK: cf.cond_br %{{.*}}, ^bb[[LEAVE:[0-9]+]](%{{.*}} : !forth.stack), ^bb[[JOIN:[0-9]+]](%{{.*}} : !forth.stack)
\ CHECK: ^bb[[EXIT]](%{{.*}}: !forth.stack):
\ CHECK: return
\ CHECK: ^bb[[LEAVE]](%{{.*}}: !forth.stack):
\ CHECK: cf.cond_br %{{.*}}, ^bb[[EXIT]](%{{.*}} : !forth.stack), ^bb[[DEAD:[0-9]+]](%{{.*}} : !forth.stack)
\ CHECK: ^bb[[JOIN]](%{{.*}}: !forth.stack):
\ CHECK: cf.br ^bb1(%{{.*}} : !forth.stack)
\ CHECK: ^bb[[DEAD]](%{{.*}}: !forth.stack):
\ CHECK: cf.br ^bb[[JOIN]](%{{.*}} : !forth.stack)

10 0 DO
I 5 = IF LEAVE THEN
1 DROP
LOOP
17 changes: 17 additions & 0 deletions test/Translation/Forth/leave.forth
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
\ RUN: %warpforth-translate --forth-to-mlir %s | %FileCheck %s

\ Verify LEAVE branches to the loop exit block.

\ CHECK: %[[S0:.*]] = forth.stack !forth.stack
\ CHECK-NEXT: %[[S1:.*]] = forth.literal %[[S0]] 10 : !forth.stack -> !forth.stack
\ CHECK-NEXT: %[[S2:.*]] = forth.literal %[[S1]] 0 : !forth.stack -> !forth.stack
\ CHECK: cf.br ^bb1(%{{.*}} : !forth.stack)
\ CHECK: ^bb1(%[[B1:.*]]: !forth.stack):
\ CHECK: cf.cond_br %{{.*}}, ^bb2(%[[B1]] : !forth.stack), ^bb[[EXIT:[0-9]+]](%[[B1]] : !forth.stack)
\ CHECK: ^bb2(%[[B2:.*]]: !forth.stack):
\ CHECK-NEXT: %[[TRUE:.*]] = arith.constant true
\ CHECK-NEXT: cf.cond_br %[[TRUE]], ^bb[[EXIT:[0-9]+]](%[[B2]] : !forth.stack), ^bb{{[0-9]+}}(%[[B2]] : !forth.stack)
\ CHECK: ^bb[[EXIT]](%[[B3:.*]]: !forth.stack):
\ CHECK-NEXT: return

10 0 DO LEAVE LOOP
3 changes: 3 additions & 0 deletions test/Translation/Forth/unloop-without-do-error.forth
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s
\ CHECK: UNLOOP without matching DO
UNLOOP