}
}
+/// Checks if all operations in a given region have at least one attached region
+/// that implements the RegionBranchOpInterface. This is not required in edge
+/// cases, where we have a single attached region and the parent operation has
+/// no results.
+static bool validateSupportedControlFlow(Region ®ion) {
+ bool success = true;
+ region.walk([&success](Operation *operation) {
+ auto regions = operation->getRegions();
+ // Walk over all operations in a region and check if the operation has at
+ // least one region and implements the RegionBranchOpInterface. If there
+ // is an operation that does not fulfill this condition, we cannot apply
+ // the deallocation steps. Furthermore, we accept cases, where we have a
+ // region that returns no results, since, in that case, the intra-region
+ // control flow does not affect the transformation.
+ size_t size = regions.size();
+ if (((size == 1 && !operation->getResults().empty()) || size > 1) &&
+ !dyn_cast<RegionBranchOpInterface>(operation)) {
+ operation->emitError("All operations with attached regions need to "
+ "implement the RegionBranchOpInterface.");
+ success = false;
+ }
+ });
+ return success;
+}
+
namespace {
//===----------------------------------------------------------------------===//
if (backedges.size()) {
getFunction().emitError(
"Structured control-flow loops are supported only.");
- return;
+ return signalPassFailure();
+ }
+
+ // Check that the control flow structures are supported.
+ if (!validateSupportedControlFlow(getFunction().getRegion())) {
+ return signalPassFailure();
}
// Place all required temporary alloc, copy and dealloc nodes.
-// RUN: mlir-opt -buffer-deallocation -split-input-file %s | FileCheck %s
+// RUN: mlir-opt -verify-diagnostics -buffer-deallocation -split-input-file %s | FileCheck %s
// This file checks the behaviour of BufferDeallocation pass for moving and
// inserting missing DeallocOps in their correct positions. Furthermore,
// The BufferDeallocation transformation should fail on this explicit
// control-flow loop since they are not supported.
-// CHECK-LABEL: func @loop_dynalloc
+// expected-error@+1 {{Structured control-flow loops are supported only}}
func @loop_dynalloc(
%arg0 : i32,
%arg1 : i32,
return
}
-// expected-error@+1 {{Structured control-flow loops are supported only}}
-
// -----
// Test Case: explicit control-flow loop with a dynamically allocated buffer.
// The BufferDeallocation transformation should fail on this explicit
// control-flow loop since they are not supported.
-// CHECK-LABEL: func @do_loop_alloc
+// expected-error@+1 {{Structured control-flow loops are supported only}}
func @do_loop_alloc(
%arg0 : i32,
%arg1 : i32,
return
}
-// expected-error@+1 {{Structured control-flow loops are supported only}}
-
// -----
// CHECK-LABEL: func @assumingOp(
// CHECK-NEXT: shape.assuming_yield %[[RETURNING_ALLOC]]
// CHECK: test.copy(%[[ASSUMING_RESULT:.*]], %[[ARG2]])
// CHECK-NEXT: dealloc %[[ASSUMING_RESULT]]
+
+// -----
+
+// Test Case: The op "test.bar" does not implement the RegionBranchOpInterface.
+// This is not allowed in buffer deallocation.
+
+func @noRegionBranchOpInterface() {
+// expected-error@+1 {{All operations with attached regions need to implement the RegionBranchOpInterface.}}
+ %0 = "test.bar"() ( {
+// expected-error@+1 {{All operations with attached regions need to implement the RegionBranchOpInterface.}}
+ %1 = "test.bar"() ( {
+ "test.yield"() : () -> ()
+ }) : () -> (i32)
+ "test.yield"() : () -> ()
+ }) : () -> (i32)
+ "test.terminator"() : () -> ()
+}