diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td --- a/mlir/include/mlir/IR/OpBase.td +++ b/mlir/include/mlir/IR/OpBase.td @@ -1636,6 +1636,8 @@ Pred predicate = pred; } +// Op contains regions where dominance is not a required property +def DominanceFreeScope : NativeOpTrait<"DominanceFreeScope">; // Op defines an affine scope. def AffineScope : NativeOpTrait<"AffineScope">; // Op defines an automatic allocation scope. diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h --- a/mlir/include/mlir/IR/OpDefinition.h +++ b/mlir/include/mlir/IR/OpDefinition.h @@ -1036,6 +1036,20 @@ } }; +/// A trait of region-holding operations that do not require the +/// SSA-Dominance property. This is useful for scopes with semantics +/// that doesn't correspond with the traditional notion of a CDFG. +/// For more details, see `Traits.md#DominanceFreeScope`. +template +class DominanceFreeScope : public TraitBase { +public: + static LogicalResult verifyTrait(Operation *op) { + static_assert(!ConcreteType::template hasTrait(), + "expected operation to have one or more regions"); + return success(); + } +}; + /// A trait of region holding operations that defines a new scope for polyhedral /// optimization purposes. Any SSA values of 'index' type that either dominate /// such an operation or are used at the top-level of such an operation diff --git a/mlir/lib/IR/Verifier.cpp b/mlir/lib/IR/Verifier.cpp --- a/mlir/lib/IR/Verifier.cpp +++ b/mlir/lib/IR/Verifier.cpp @@ -29,6 +29,7 @@ #include "mlir/IR/Dialect.h" #include "mlir/IR/Dominance.h" #include "mlir/IR/Operation.h" +#include "mlir/IR/OpDefinition.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/PrettyStackTrace.h" @@ -59,8 +60,9 @@ LogicalResult verifyOperation(Operation &op); /// Verify the dominance within the given IR unit. - LogicalResult verifyDominance(Region ®ion); + LogicalResult verifyDominance(Region ®ion, bool inDominanceScope); LogicalResult verifyDominance(Operation &op); + LogicalResult verifyDominanceOfContainedRegions(Operation &op); /// Emit an error for the given block. InFlightDiagnostic emitError(Block &bb, const Twine &message) { @@ -96,9 +98,8 @@ // verifier to be resilient to malformed code. DominanceInfo theDomInfo(&op); domInfo = &theDomInfo; - for (auto ®ion : op.getRegions()) - if (failed(verifyDominance(region))) - return failure(); + if(failed(verifyDominanceOfContainedRegions(op))) + return failure(); domInfo = nullptr; return success(); @@ -221,11 +222,11 @@ return success(); } -LogicalResult OperationVerifier::verifyDominance(Region ®ion) { +LogicalResult OperationVerifier::verifyDominance(Region ®ion, bool inDominanceScope) { // Verify the dominance of each of the held operations. for (auto &block : region) - // Dominance is only reachable inside reachable blocks. - if (domInfo->isReachableFromEntry(&block)) + // Dominance is only meaningful inside reachable blocks. + if (inDominanceScope && domInfo->isReachableFromEntry(&block)) for (auto &op : block) { if (failed(verifyDominance(op))) return failure(); @@ -234,9 +235,8 @@ // Verify the dominance of each of the nested blocks within this // operation, even if the operation itself is not reachable. for (auto &op : block) - for (auto ®ion : op.getRegions()) - if (failed(verifyDominance(region))) - return failure(); + if (failed(verifyDominanceOfContainedRegions(op))) + return failure(); return success(); } @@ -255,11 +255,19 @@ return failure(); } - // Verify the dominance of each of the nested blocks within this operation. + if (failed(verifyDominanceOfContainedRegions(op))) { + return failure(); + } + + return success(); +} + +// Verify the dominance of each of the nested blocks within this operation. +LogicalResult OperationVerifier::verifyDominanceOfContainedRegions(Operation &op) { + bool inDominanceScope = !op.hasTrait(); for (auto ®ion : op.getRegions()) - if (failed(verifyDominance(region))) + if (failed(verifyDominance(region, inDominanceScope))) return failure(); - return success(); } diff --git a/mlir/test/IR/traits.mlir b/mlir/test/IR/traits.mlir --- a/mlir/test/IR/traits.mlir +++ b/mlir/test/IR/traits.mlir @@ -350,3 +350,38 @@ %0:4 = "test.attr_sized_results"() {result_segment_sizes = dense<[0, 2, 1, 1]>: vector<4xi32>} : () -> (i32, i32, i32, i32) return } + +// ----- + +func @succededDominanceFreeScope() -> () { + test.dominance_free_scope { + // %1 is not dominated by its definition. + %2:3 = "bar"(%1) : (i64) -> (i1,i1,i1) // CHECK: [[VAL2:%.*]]:3 = "bar"([[VAL3:%.*]]) : (i64) -> (i1, i1, i1) + br ^bb4 // CHECK: br ^bb2 +^bb2: // CHECK: ^bb1: // pred: ^bb1 + br ^bb2 // CHECK: br ^bb1 +^bb4: // CHECK: ^bb2: // pred: ^bb0 + %1 = "foo"() : ()->i64 // CHECK: [[VAL3]] = "foo"() : () -> i64 + } + return +} // CHECK: } + +// ----- + +func @illegalCDFGInsideDominanceFreeScope() -> () { + test.dominance_free_scope { + func @test() -> i1 { +^bb1: +// expected-error @+1 {{operand #0 does not dominate this use}} + %2:3 = "bar"(%1) : (i64) -> (i1,i1,i1) + br ^bb4 +^bb2: + br ^bb2 +^bb4: + %1 = "foo"() : ()->i64 // expected-note {{operand defined here}} + return %2#1 : i1 + } + "terminator"() : () -> () + } + return +} // CHECK: } diff --git a/mlir/test/lib/Dialect/Test/TestDialect.cpp b/mlir/test/lib/Dialect/Test/TestDialect.cpp --- a/mlir/test/lib/Dialect/Test/TestDialect.cpp +++ b/mlir/test/lib/Dialect/Test/TestDialect.cpp @@ -201,6 +201,22 @@ } //===----------------------------------------------------------------------===// +// Test DominanceFreeScopeOp +//===----------------------------------------------------------------------===// + +static ParseResult parseDominanceFreeScopeOp(OpAsmParser &parser, + OperationState &result) { + // Parse the body region, and reuse the operand info as the argument info. + Region *body = result.addRegion(); + return parser.parseRegion(*body, /*arguments=*/{}, /*argTypes=*/{}); +} + +static void print(OpAsmPrinter &p, DominanceFreeScopeOp op) { + p << "test.dominance_free_scope "; + p.printRegion(op.region(), /*printEntryBlockArgs=*/false); +} + +//===----------------------------------------------------------------------===// // Test AffineScopeOp //===----------------------------------------------------------------------===// diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td --- a/mlir/test/lib/Dialect/Test/TestOps.td +++ b/mlir/test/lib/Dialect/Test/TestOps.td @@ -1166,6 +1166,17 @@ let printer = [{ return ::print(p, *this); }]; } +def DominanceFreeScopeOp : TEST_Op<"dominance_free_scope", [DominanceFreeScope]> { + let summary = "dominance-free scope operation"; + let description = [{ + Test op that defines a new domainance-free scope. + }]; + + let regions = (region AnyRegion:$region); + let parser = [{ return ::parse$cppClass(parser, result); }]; + let printer = [{ return ::print(p, *this); }]; +} + def AffineScopeOp : TEST_Op<"affine_scope", [AffineScope]> { let summary = "affine scope operation"; let description = [{