Skip to content

Commit 7dacb38

Browse files
authored
Merge pull request coredac#223 from ShangkunLi/safe-return
Enable the safe return in neura dataflow ir
2 parents 5e719bc + e200777 commit 7dacb38

42 files changed

Lines changed: 1638 additions & 1441 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

include/NeuraDialect/NeuraOps.td

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def Neura_KernelOp : Op<NeuraDialect, "kernel", [RecursiveMemoryEffects, SingleB
5959
}
6060

6161
// Yield operation for fused_op and kernel regions.
62-
def Neura_YieldOp : Op<NeuraDialect, "yield", [Terminator, Pure, ReturnLike, HasParent<"FusedOp, KernelOp">]> {
62+
def Neura_YieldOp : Op<NeuraDialect, "yield", [Terminator, Pure, ReturnLike]> {
6363
let summary = "Yield values from a neura.kernel or neura.fused_op region.";
6464
let description = [{
6565
Returns values from a neura.kernel or neura.fused_op region to the parent operation.
@@ -79,6 +79,8 @@ def Neura_YieldOp : Op<NeuraDialect, "yield", [Terminator, Pure, ReturnLike, Has
7979
];
8080

8181
let assemblyFormat = [{($values^ `:` type($values))? attr-dict}];
82+
83+
let hasVerifier = 1;
8284
}
8385

8486

@@ -375,6 +377,46 @@ def Neura_ReturnOp : Op<NeuraDialect, "return", [Terminator]> {
375377
// let assemblyFormat = "($values^)? `,` attr-dict";
376378
}
377379

380+
// Defines a return operation for void functions in dataflow mode.
381+
def Neura_ReturnVoidOp : Op<NeuraDialect, "return_void", []>{
382+
let summary = "Return operation for void functions in dataflow mode.";
383+
let description = [{
384+
Terminates a void function. The trigger operand provides the execution
385+
condition in dataflow mode - the return executes when the trigger becomes valid.
386+
387+
Without a trigger (empty operands), this represents a static return that
388+
always executes. After canonicalization, void returns should have triggers.
389+
390+
Example:
391+
neura.return_void %cond : !neura.data<i1, i1> // In dataflow mode
392+
...
393+
neura.yield // Function ends here.
394+
395+
This is NOT a terminator - the block ends with neura.yield instead.
396+
}];
397+
let arguments = (ins Optional<AnyType>:$trigger);
398+
let assemblyFormat = "($trigger^ `:` type($trigger))? attr-dict";
399+
}
400+
401+
// Defines a return operation for non-void fnctions in dataflow mode.
402+
def Neura_ReturnValueOp : Op<NeuraDialect, "return_value", []>{
403+
let summary = "Return operation for non-void functions in dataflow mode.";
404+
let description = [{
405+
Represents a return point for non-void functions in dataflow mode.
406+
The value operand provides the return value and the trigger operand.
407+
408+
This is NOT a terminator - the block ends with neura.yield instead.
409+
410+
Example:
411+
neura.return_value %ret_val : !neura.data<i32, i1> // In dataflow mode
412+
...
413+
neura.yield // Function ends here.
414+
}];
415+
let arguments = (ins Variadic<AnyType>:$values);
416+
let assemblyFormat = "($values^ `:` type($values))? attr-dict";
417+
}
418+
419+
378420
// Defines a cast operation for type conversion.
379421
def Neura_CastOp : Op<NeuraDialect, "cast">{
380422
let summary = "Generic type conversion operation";

include/NeuraDialect/NeuraPasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ std::unique_ptr<mlir::Pass> createTransformCtrlToDataFlowPass();
2525
std::unique_ptr<mlir::Pass> createLeveragePredicatedValuePass();
2626
std::unique_ptr<mlir::Pass> createMapToAcceleratorPass();
2727
std::unique_ptr<mlir::Pass> createGenerateCodePass();
28+
std::unique_ptr<mlir::Pass> createCanonicalizeReturnPass();
2829
std::unique_ptr<mlir::Pass> createCanonicalizeLiveInPass();
2930
std::unique_ptr<mlir::Pass> createPromoteFuncArgToConstPass();
3031
std::unique_ptr<mlir::Pass> createTransformToSteerControlPass();

include/NeuraDialect/NeuraPasses.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ def FuseLoopControl: Pass<"fuse-loop-control", "ModuleOp">{
7575
let constructor = "neura::createFuseLoopControlPass()";
7676
}
7777

78+
def CanonicalizeReturn : Pass<"canonicalize-return", "ModuleOp">{
79+
let summary = "Adds execution conditions to void return operations";
80+
let description = [{
81+
This pass processes void functions and adds trigger conditions to their
82+
return operations. For void functions, the return operation needs an
83+
execution condition to properly trigger in dataflow mode.
84+
85+
This pass should run before CanonicalizeLiveIn and TransformCtrlToDataFlow.
86+
}];
87+
let constructor = "neura::createCanonicalizeReturnPass()";
88+
}
89+
7890
def CanonicalizeLiveIn : Pass<"canonicalize-live-in", "ModuleOp"> {
7991
let summary = "Canonicalizes live-in values/operations in each basic block.";
8092
let description = [{

lib/NeuraDialect/Mapping/mapping_util.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ OperationKind getOperationKindFromMlirOp(Operation *op) {
126126
// Returns true if the operation does not need CGRA tile placement.
127127
bool is_non_materialized(Operation *op) {
128128
// Returns true if the operation does not need CGRA tile placement.
129-
return mlir::isa<neura::ReserveOp, neura::CtrlMovOp, neura::DataMovOp>(op);
129+
return mlir::isa<neura::ReserveOp, neura::CtrlMovOp, neura::DataMovOp,
130+
neura::YieldOp>(op);
130131
}
131132

132133
} // namespace neura

lib/NeuraDialect/NeuraOps.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,35 @@
11
#include "NeuraDialect/NeuraOps.h"
22
#include "NeuraDialect/NeuraDialect.h"
3+
#include "mlir/Dialect/Func/IR/FuncOps.h"
4+
#include "mlir/IR/Attributes.h"
35
#include "mlir/IR/Builders.h"
46
#include "mlir/IR/OpImplementation.h"
57
#include "llvm/Support/LogicalResult.h"
68

79
using namespace mlir;
810
using namespace mlir::neura;
911

12+
LogicalResult YieldOp::verify() {
13+
Operation *parent_op = (*this)->getParentOp();
14+
15+
if (!parent_op) {
16+
return emitOpError("must have a parent operation.");
17+
}
18+
19+
// Allows yield in FusedOp and KernelOp
20+
if (isa<FusedOp>(parent_op) || isa<KernelOp>(parent_op)) {
21+
return success();
22+
}
23+
24+
// Allows yield in func.func (for dataflow mode)
25+
if (isa<func::FuncOp>(parent_op)) {
26+
return success();
27+
}
28+
29+
return emitOpError("expects parent op to be one of 'neura.fused_op', "
30+
"'neura.kernel', or 'func.func'");
31+
}
32+
1033
LogicalResult PhiStartOp::verify() {
1134
// Checks if this phi_start is inside a fused_op.
1235
Operation *parent_op = getOperation()->getParentOp();

lib/NeuraDialect/NeuraPasses.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void mlir::neura::registerNeuraConversionPassPipeline() {
2525
pm.addPass(mlir::createLowerLlvmToNeuraPass());
2626
pm.addPass(mlir::createPrintOpGraphPass(os));
2727

28+
pm.addPass(mlir::neura::createCanonicalizeReturnPass());
2829
pm.addPass(mlir::neura::createCanonicalizeCastPass());
2930
pm.addPass(mlir::neura::createPromoteFuncArgToConstPass());
3031
pm.addPass(mlir::neura::createFoldConstantPass());

lib/NeuraDialect/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_mlir_library(
1010
LeveragePredicatedValuePass.cpp
1111
MapToAcceleratorPass.cpp
1212
GenerateCodePass.cpp
13+
CanonicalizeReturnPass.cpp
1314
CanonicalizeLiveInPass.cpp
1415
CanonicalizeCastPass.cpp
1516
PromoteFuncArgToConstPass.cpp

0 commit comments

Comments
 (0)