[Mlir-commits] [mlir] 0425332 - [mlir] Added new RegionBranchTerminatorOpInterface and adapted uses of hasTrait<ReturnLike>.

Marcel Koester llvmlistbot at llvm.org
Sun Jul 25 21:50:04 PDT 2021


Author: Marcel Koester
Date: 2021-07-26T06:39:31+02:00
New Revision: 0425332015f479a89226c684c33659aa9cfff4b5

URL: https://github.com/llvm/llvm-project/commit/0425332015f479a89226c684c33659aa9cfff4b5
DIFF: https://github.com/llvm/llvm-project/commit/0425332015f479a89226c684c33659aa9cfff4b5.diff

LOG: [mlir] Added new RegionBranchTerminatorOpInterface and adapted uses of hasTrait<ReturnLike>.

This CL adds a new RegionBranchTerminatorOpInterface to query information about operands that can be
passed to successor regions. Similar to the BranchOpInterface, it allows to freely define the
involved operands. However, in contrast to the BranchOpInterface, it expects an additional region
number to distinguish between various use cases which might require different operands passed to
different regions.

Moreover, we added new utility functions (namely getMutableRegionBranchSuccessorOperands and
getRegionBranchSuccessorOperands) to query (mutable) operand ranges for operations equiped with the
ReturnLike trait and/or implementing the newly added interface.  This simplifies reasoning about
terminators in the scope of the nested regions.

We also adjusted the SCF.ConditionOp to benefit from the newly added capabilities.

Differential Revision: https://reviews.llvm.org/D105018

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/SCF/SCFOps.td
    mlir/include/mlir/Interfaces/ControlFlowInterfaces.h
    mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
    mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp
    mlir/lib/Analysis/BufferViewFlowAnalysis.cpp
    mlir/lib/Analysis/DataFlowAnalysis.cpp
    mlir/lib/Dialect/SCF/SCF.cpp
    mlir/lib/Interfaces/ControlFlowInterfaces.cpp
    mlir/lib/Transforms/BufferDeallocation.cpp
    mlir/lib/Transforms/BufferOptimizations.cpp
    mlir/test/Dialect/SCF/invalid.mlir
    mlir/test/Transforms/sccp-structured.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/SCF/SCFOps.td b/mlir/include/mlir/Dialect/SCF/SCFOps.td
index feb862d31ae0..77d32aed733b 100644
--- a/mlir/include/mlir/Dialect/SCF/SCFOps.td
+++ b/mlir/include/mlir/Dialect/SCF/SCFOps.td
@@ -36,8 +36,12 @@ class SCF_Op<string mnemonic, list<OpTrait> traits = []> :
   let parser = [{ return ::parse$cppClass(parser, result); }];
 }
 
-def ConditionOp : SCF_Op<"condition",
-                         [HasParent<"WhileOp">, NoSideEffect, Terminator]> {
+def ConditionOp : SCF_Op<"condition", [
+  HasParent<"WhileOp">,
+  DeclareOpInterfaceMethods<RegionBranchTerminatorOpInterface>,
+  NoSideEffect,
+  Terminator
+]> {
   let summary = "loop continuation condition";
   let description = [{
     This operation accepts the continuation (i.e., inverse of exit) condition

diff  --git a/mlir/include/mlir/Interfaces/ControlFlowInterfaces.h b/mlir/include/mlir/Interfaces/ControlFlowInterfaces.h
index 57ff63fbf784..761a37894744 100644
--- a/mlir/include/mlir/Interfaces/ControlFlowInterfaces.h
+++ b/mlir/include/mlir/Interfaces/ControlFlowInterfaces.h
@@ -86,6 +86,32 @@ class RegionSuccessor {
   ValueRange inputs;
 };
 
+//===----------------------------------------------------------------------===//
+// RegionBranchTerminatorOpInterface
+//===----------------------------------------------------------------------===//
+
+/// Returns true if the given operation is either annotated with the
+/// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`.
+bool isRegionReturnLike(Operation *operation);
+
+/// Returns the mutable operands that are passed to the region with the given
+/// `regionIndex`. If the operation does not implement the
+/// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the
+/// result will be `llvm::None`. In all other cases, the resulting
+/// `OperandRange` represents all operands that are passed to the specified
+/// successor region. If `regionIndex` is `llvm::None`, all operands that are
+/// passed to the parent operation will be returned.
+Optional<MutableOperandRange>
+getMutableRegionBranchSuccessorOperands(Operation *operation,
+                                        Optional<unsigned> regionIndex);
+
+/// Returns the read only operands that are passed to the region with the given
+/// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more
+/// information.
+Optional<OperandRange>
+getRegionBranchSuccessorOperands(Operation *operation,
+                                 Optional<unsigned> regionIndex);
+
 //===----------------------------------------------------------------------===//
 // ControlFlow Traits
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td b/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
index b12d62b52925..38396a195238 100644
--- a/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
+++ b/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
@@ -45,8 +45,7 @@ def BranchOpInterface : OpInterface<"BranchOpInterface"> {
       }],
       "::mlir::Optional<::mlir::OperandRange>", "getSuccessorOperands",
       (ins "unsigned":$index), [{}], [{
-        ConcreteOp *op = static_cast<ConcreteOp *>(this);
-        auto operands = op->getMutableSuccessorOperands(index);
+        auto operands = $_op.getMutableSuccessorOperands(index);
         return operands ? ::mlir::Optional<::mlir::OperandRange>(*operands) : ::llvm::None;
       }]
     >,
@@ -174,6 +173,54 @@ def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// RegionBranchTerminatorOpInterface
+//===----------------------------------------------------------------------===//
+
+def RegionBranchTerminatorOpInterface :
+  OpInterface<"RegionBranchTerminatorOpInterface"> {
+  let description = [{
+    This interface provides information for branching terminator operations
+    in the presence of a parent RegionBranchOpInterface implementation. It
+    specifies which operands are passed to which successor region.
+  }];
+  let cppNamespace = "::mlir";
+
+  let methods = [
+    InterfaceMethod<[{
+        Returns a mutable range of operands that are semantically "returned" by
+        passing them to the region successor given by `index`.  If `index` is
+        None, this function returns the operands that are passed as a result to
+        the parent operation.
+      }],
+      "::mlir::MutableOperandRange", "getMutableSuccessorOperands",
+      (ins "::mlir::Optional<unsigned>":$index)
+    >,
+    InterfaceMethod<[{
+        Returns a range of operands that are semantically "returned" by passing
+        them to the region successor given by `index`.  If `index` is None, this
+        function returns the operands that are passed as a result to the parent
+        operation.
+      }],
+      "::mlir::OperandRange", "getSuccessorOperands",
+      (ins "::mlir::Optional<unsigned>":$index), [{}],
+      /*defaultImplementation=*/[{
+        return $_op.getMutableSuccessorOperands(index);
+      }]
+    >
+  ];
+
+  let verify = [{
+    static_assert(ConcreteOp::template hasTrait<OpTrait::IsTerminator>(),
+                  "expected operation to be a terminator");
+    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroResult>(),
+                  "expected operation to have zero results");
+    static_assert(ConcreteOp::template hasTrait<OpTrait::ZeroSuccessor>(),
+                  "expected operation to have zero successors");
+    return success();
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // ControlFlow Traits
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp b/mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp
index 062443a39619..ae2cb0bae632 100644
--- a/mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp
+++ b/mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp
@@ -74,12 +74,14 @@ static void collectUnderlyingAddressValues(RegionBranchOpInterface branch,
   };
 
   // Check branches from the parent operation.
+  Optional<unsigned> regionIndex;
   if (region) {
+    // Determine the actual region number from the passed region.
+    regionIndex = region->getRegionNumber();
     if (Optional<unsigned> operandIndex =
             getOperandIndexIfPred(/*predIndex=*/llvm::None)) {
       collectUnderlyingAddressValues(
-          branch.getSuccessorEntryOperands(
-              region->getRegionNumber())[*operandIndex],
+          branch.getSuccessorEntryOperands(*regionIndex)[*operandIndex],
           maxDepth, visited, output);
     }
   }
@@ -89,8 +91,12 @@ static void collectUnderlyingAddressValues(RegionBranchOpInterface branch,
     if (Optional<unsigned> operandIndex = getOperandIndexIfPred(i)) {
       for (Block &block : op->getRegion(i)) {
         Operation *term = block.getTerminator();
-        if (term->hasTrait<OpTrait::ReturnLike>()) {
-          collectUnderlyingAddressValues(term->getOperand(*operandIndex),
+        // Try to determine possible region-branch successor operands for the
+        // current region.
+        auto successorOperands =
+            getRegionBranchSuccessorOperands(term, regionIndex);
+        if (successorOperands) {
+          collectUnderlyingAddressValues((*successorOperands)[*operandIndex],
                                          maxDepth, visited, output);
         } else if (term->getNumSuccessors()) {
           // Otherwise, if this terminator may exit the region we can't make

diff  --git a/mlir/lib/Analysis/BufferViewFlowAnalysis.cpp b/mlir/lib/Analysis/BufferViewFlowAnalysis.cpp
index bdf7bbae0318..45766a25f791 100644
--- a/mlir/lib/Analysis/BufferViewFlowAnalysis.cpp
+++ b/mlir/lib/Analysis/BufferViewFlowAnalysis.cpp
@@ -101,12 +101,18 @@ void BufferViewFlowAnalysis::build(Operation *op) {
       regionInterface.getSuccessorRegions(region.getRegionNumber(),
                                           successorRegions);
       for (RegionSuccessor &successorRegion : successorRegions) {
+        // Determine the current region index (if any).
+        Optional<unsigned> regionIndex;
+        Region *regionSuccessor = successorRegion.getSuccessor();
+        if (regionSuccessor)
+          regionIndex = regionSuccessor->getRegionNumber();
         // Iterate over all immediate terminator operations and wire the
-        // successor inputs with the operands of each terminator.
+        // successor inputs with the successor operands of each terminator.
         for (Block &block : region) {
-          Operation &terminator = *block.getTerminator();
-          if (terminator.hasTrait<OpTrait::ReturnLike>()) {
-            registerDependencies(terminator.getOperands(),
+          auto successorOperands = getRegionBranchSuccessorOperands(
+              block.getTerminator(), regionIndex);
+          if (successorOperands) {
+            registerDependencies(*successorOperands,
                                  successorRegion.getSuccessorInputs());
           }
         }

diff  --git a/mlir/lib/Analysis/DataFlowAnalysis.cpp b/mlir/lib/Analysis/DataFlowAnalysis.cpp
index fde9f2c15867..b5a5e17fd2c3 100644
--- a/mlir/lib/Analysis/DataFlowAnalysis.cpp
+++ b/mlir/lib/Analysis/DataFlowAnalysis.cpp
@@ -562,26 +562,29 @@ void ForwardDataFlowSolver::visitTerminatorOperation(
     if (regionSuccessors.empty())
       return;
 
+    // Try to get "region-like" successor operands if possible in order to
+    // propagate the operand states to the successors.
+    if (isRegionReturnLike(op)) {
+      return visitRegionSuccessors(
+          parentOp, regionSuccessors, [&](Optional<unsigned> regionIndex) {
+            // Determine the individual region successor operands for the given
+            // region index (if any).
+            return *getRegionBranchSuccessorOperands(op, regionIndex);
+          });
+    }
+
     // If this terminator is not "region-like", conservatively mark all of the
     // successor values as having reached the pessimistic fixpoint.
-    if (!op->hasTrait<OpTrait::ReturnLike>()) {
-      for (auto &it : regionSuccessors) {
-        // If the successor is a region, mark the entry block as executable so
-        // that we visit operations defined within. If the successor is the
-        // parent operation, we simply mark the control flow results as having
-        // reached the pessimistic state.
-        if (Region *region = it.getSuccessor())
-          markEntryBlockExecutable(region, /*markPessimisticFixpoint=*/true);
-        else
-          markAllPessimisticFixpointAndVisitUsers(it.getSuccessorInputs());
-      }
-      return;
+    for (auto &it : regionSuccessors) {
+      // If the successor is a region, mark the entry block as executable so
+      // that we visit operations defined within. If the successor is the
+      // parent operation, we simply mark the control flow results as having
+      // reached the pessimistic state.
+      if (Region *region = it.getSuccessor())
+        markEntryBlockExecutable(region, /*markPessimisticFixpoint=*/true);
+      else
+        markAllPessimisticFixpointAndVisitUsers(it.getSuccessorInputs());
     }
-
-    // Otherwise, propagate the operand lattice states to the successors.
-    OperandRange operands = op->getOperands();
-    return visitRegionSuccessors(parentOp, regionSuccessors,
-                                 [&](Optional<unsigned>) { return operands; });
   }
 
   // Try to resolve to a specific set of successors with the current optimistic

diff  --git a/mlir/lib/Dialect/SCF/SCF.cpp b/mlir/lib/Dialect/SCF/SCF.cpp
index ef1238da5f34..238816288036 100644
--- a/mlir/lib/Dialect/SCF/SCF.cpp
+++ b/mlir/lib/Dialect/SCF/SCF.cpp
@@ -235,6 +235,16 @@ void ExecuteRegionOp::getCanonicalizationPatterns(RewritePatternSet &results,
   results.add<SingleBlockExecuteInliner, MultiBlockExecuteInliner>(context);
 }
 
+//===----------------------------------------------------------------------===//
+// ConditionOp
+//===----------------------------------------------------------------------===//
+
+MutableOperandRange
+ConditionOp::getMutableSuccessorOperands(Optional<unsigned> index) {
+  // Pass all operands except the condition to the successor region.
+  return argsMutable();
+}
+
 //===----------------------------------------------------------------------===//
 // ForOp
 //===----------------------------------------------------------------------===//
@@ -2173,18 +2183,6 @@ static LogicalResult verify(scf::WhileOp op) {
   if (!beforeTerminator)
     return failure();
 
-  TypeRange trailingTerminatorOperands = beforeTerminator.args().getTypes();
-  if (failed(verifyTypeRangesMatch(op, trailingTerminatorOperands,
-                                   op.after().getArgumentTypes(),
-                                   "trailing operands of the 'before' block "
-                                   "terminator and 'after' region arguments")))
-    return failure();
-
-  if (failed(verifyTypeRangesMatch(
-          op, trailingTerminatorOperands, op.getResultTypes(),
-          "trailing operands of the 'before' block terminator and op results")))
-    return failure();
-
   auto afterTerminator = verifyAndGetTerminator<scf::YieldOp>(
       op, op.after(),
       "expects the 'after' region to terminate with 'scf.yield'");

diff  --git a/mlir/lib/Interfaces/ControlFlowInterfaces.cpp b/mlir/lib/Interfaces/ControlFlowInterfaces.cpp
index 57641e26935d..498517b8f63f 100644
--- a/mlir/lib/Interfaces/ControlFlowInterfaces.cpp
+++ b/mlir/lib/Interfaces/ControlFlowInterfaces.cpp
@@ -176,25 +176,26 @@ LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) {
   for (unsigned regionNo : llvm::seq(0U, op->getNumRegions())) {
     Region &region = op->getRegion(regionNo);
 
-    // Since the interface cannot distinguish between 
diff erent ReturnLike
-    // ops within the region branching to 
diff erent successors, all ReturnLike
-    // ops in this region should have the same operand types. We will then use
-    // one of them as the representative for type matching.
+    // Since there can be multiple `ReturnLike` terminators or others
+    // implementing the `RegionBranchTerminatorOpInterface`, all should have the
+    // same operand types when passing them to the same region.
 
-    Operation *regionReturn = nullptr;
+    Optional<OperandRange> regionReturnOperands;
     for (Block &block : region) {
       Operation *terminator = block.getTerminator();
-      if (!terminator->hasTrait<OpTrait::ReturnLike>())
+      auto terminatorOperands =
+          getRegionBranchSuccessorOperands(terminator, regionNo);
+      if (!terminatorOperands)
         continue;
 
-      if (!regionReturn) {
-        regionReturn = terminator;
+      if (!regionReturnOperands) {
+        regionReturnOperands = terminatorOperands;
         continue;
       }
 
       // Found more than one ReturnLike terminator. Make sure the operand types
       // match with the first one.
-      if (regionReturn->getOperandTypes() != terminator->getOperandTypes())
+      if (regionReturnOperands->getTypes() != terminatorOperands->getTypes())
         return op->emitOpError("Region #")
                << regionNo
                << " operands mismatch between return-like terminators";
@@ -204,11 +205,11 @@ LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) {
         [&](Optional<unsigned> regionNo) -> Optional<TypeRange> {
       // If there is no return-like terminator, the op itself should verify
       // type consistency.
-      if (!regionReturn)
+      if (!regionReturnOperands)
         return llvm::None;
 
-      // All successors get the same set of operands.
-      return TypeRange(regionReturn->getOperands().getTypes());
+      // All successors get the same set of operand types.
+      return TypeRange(regionReturnOperands->getTypes());
     };
 
     if (failed(verifyTypesAlongAllEdges(op, regionNo, inputTypesFromRegion)))
@@ -217,3 +218,49 @@ LogicalResult detail::verifyTypesAlongControlFlowEdges(Operation *op) {
 
   return success();
 }
+
+//===----------------------------------------------------------------------===//
+// RegionBranchTerminatorOpInterface
+//===----------------------------------------------------------------------===//
+
+/// Returns true if the given operation is either annotated with the
+/// `ReturnLike` trait or implements the `RegionBranchTerminatorOpInterface`.
+bool mlir::isRegionReturnLike(Operation *operation) {
+  return dyn_cast<RegionBranchTerminatorOpInterface>(operation) ||
+         operation->hasTrait<OpTrait::ReturnLike>();
+}
+
+/// Returns the mutable operands that are passed to the region with the given
+/// `regionIndex`. If the operation does not implement the
+/// `RegionBranchTerminatorOpInterface` and is not marked as `ReturnLike`, the
+/// result will be `llvm::None`. In all other cases, the resulting
+/// `OperandRange` represents all operands that are passed to the specified
+/// successor region. If `regionIndex` is `llvm::None`, all operands that are
+/// passed to the parent operation will be returned.
+Optional<MutableOperandRange>
+mlir::getMutableRegionBranchSuccessorOperands(Operation *operation,
+                                              Optional<unsigned> regionIndex) {
+  // Try to query a RegionBranchTerminatorOpInterface to determine
+  // all successor operands that will be passed to the successor
+  // input arguments.
+  if (auto regionTerminatorInterface =
+          dyn_cast<RegionBranchTerminatorOpInterface>(operation))
+    return regionTerminatorInterface.getMutableSuccessorOperands(regionIndex);
+
+  // TODO: The ReturnLike trait should imply a default implementation of the
+  // RegionBranchTerminatorOpInterface. This would make this code significantly
+  // easier. Furthermore, this may even make this function obsolete.
+  if (operation->hasTrait<OpTrait::ReturnLike>())
+    return MutableOperandRange(operation);
+  return llvm::None;
+}
+
+/// Returns the read only operands that are passed to the region with the given
+/// `regionIndex`. See `getMutableRegionBranchSuccessorOperands` for more
+/// information.
+Optional<OperandRange>
+mlir::getRegionBranchSuccessorOperands(Operation *operation,
+                                       Optional<unsigned> regionIndex) {
+  auto range = getMutableRegionBranchSuccessorOperands(operation, regionIndex);
+  return range ? Optional<OperandRange>(*range) : llvm::None;
+}

diff  --git a/mlir/lib/Transforms/BufferDeallocation.cpp b/mlir/lib/Transforms/BufferDeallocation.cpp
index d15a18b640d7..43d654e2d989 100644
--- a/mlir/lib/Transforms/BufferDeallocation.cpp
+++ b/mlir/lib/Transforms/BufferDeallocation.cpp
@@ -68,8 +68,8 @@ static void walkReturnOperations(Region *region,
                                  std::function<void(Operation *)> func) {
   for (Block &block : *region) {
     Operation *terminator = block.getTerminator();
-    // Skip non-return-like terminators.
-    if (terminator->hasTrait<OpTrait::ReturnLike>())
+    // Skip non region-return-like terminators.
+    if (isRegionReturnLike(terminator))
       func(terminator);
   }
 }
@@ -390,12 +390,15 @@ class BufferDeallocation : BufferPlacementTransformationBase {
       // new buffer allocations. Thereby, the appropriate terminator operand
       // will be adjusted to point to the newly allocated buffer instead.
       walkReturnOperations(&region, [&](Operation *terminator) {
+        // Get the actual mutable operands for this terminator op.
+        auto terminatorOperands = *getMutableRegionBranchSuccessorOperands(
+            terminator, region.getRegionNumber());
         // Extract the source value from the current terminator.
-        Value sourceValue = terminator->getOperand(operandIndex);
+        Value sourceValue = ((OperandRange)terminatorOperands)[operandIndex];
         // Create a new clone at the current location of the terminator.
         Value clone = introduceCloneBuffers(sourceValue, terminator);
         // Wire clone and terminator operand.
-        terminator->setOperand(operandIndex, clone);
+        terminatorOperands.slice(operandIndex, 1).assign(clone);
       });
     }
   }

diff  --git a/mlir/lib/Transforms/BufferOptimizations.cpp b/mlir/lib/Transforms/BufferOptimizations.cpp
index 1b87b8c32b11..ee4f5d54d504 100644
--- a/mlir/lib/Transforms/BufferOptimizations.cpp
+++ b/mlir/lib/Transforms/BufferOptimizations.cpp
@@ -64,8 +64,7 @@ leavesAllocationScope(Region *parentRegion,
       // If there is at least one alias that leaves the parent region, we know
       // that this alias escapes the whole region and hence the associated
       // allocation leaves allocation scope.
-      if (use->hasTrait<OpTrait::ReturnLike>() &&
-          use->getParentRegion() == parentRegion)
+      if (isRegionReturnLike(use) && use->getParentRegion() == parentRegion)
         return true;
     }
   }

diff  --git a/mlir/test/Dialect/SCF/invalid.mlir b/mlir/test/Dialect/SCF/invalid.mlir
index 22f9b0b4e589..9fe176c802a2 100644
--- a/mlir/test/Dialect/SCF/invalid.mlir
+++ b/mlir/test/Dialect/SCF/invalid.mlir
@@ -462,7 +462,7 @@ func @while_bad_terminator() {
 
 func @while_cross_region_type_mismatch() {
   %true = constant true
-  // expected-error at +1 {{expects the same number of trailing operands of the 'before' block terminator and 'after' region arguments}}
+  // expected-error at +1 {{'scf.while' op  region control flow edge from Region #0 to Region #1: source has 0 operands, but target successor needs 1}}
   scf.while : () -> () {
     scf.condition(%true)
   } do {
@@ -475,8 +475,7 @@ func @while_cross_region_type_mismatch() {
 
 func @while_cross_region_type_mismatch() {
   %true = constant true
-  // expected-error at +2 {{expects the same types for trailing operands of the 'before' block terminator and 'after' region arguments}}
-  // expected-note at +1 {{for argument 0, found 'i1' and 'i32}}
+  // expected-error at +1 {{'scf.while' op  along control flow edge from Region #0 to Region #1: source type #0 'i1' should match input type #0 'i32'}}
   scf.while : () -> () {
     scf.condition(%true) %true : i1
   } do {
@@ -489,7 +488,7 @@ func @while_cross_region_type_mismatch() {
 
 func @while_result_type_mismatch() {
   %true = constant true
-  // expected-error at +1 {{expects the same number of trailing operands of the 'before' block terminator and op results}}
+  // expected-error at +1 {{'scf.while' op  region control flow edge from Region #0 to parent results: source has 1 operands, but target successor needs 0}}
   scf.while : () -> () {
     scf.condition(%true) %true : i1
   } do {

diff  --git a/mlir/test/Transforms/sccp-structured.mlir b/mlir/test/Transforms/sccp-structured.mlir
index 02b236531e10..8270048c86c3 100644
--- a/mlir/test/Transforms/sccp-structured.mlir
+++ b/mlir/test/Transforms/sccp-structured.mlir
@@ -131,14 +131,13 @@ func @loop_inner_control_flow(%arg0 : index, %arg1 : index, %arg2 : index) -> i3
   return %result : i32
 }
 
-/// Test that we can properly visit region successors when the terminator is not
-/// return-like.
-
-// CHECK-LABEL: func @overdefined_non_returnlike(
-func @overdefined_non_returnlike(%arg1 : i32) {
-  // CHECK: scf.while (%[[ARG:.*]] = %[[INPUT:.*]])
-  // CHECK-NEXT: %[[COND:.*]] = cmpi slt, %[[ARG]], %{{.*}} : i32
-  // CHECK-NEXT: scf.condition(%[[COND]]) %[[ARG]] : i32
+/// Test that we can properly visit region successors when the terminator
+/// implements the RegionBranchTerminatorOpInterface.
+
+// CHECK-LABEL: func @loop_region_branch_terminator_op(
+func @loop_region_branch_terminator_op(%arg1 : i32) {
+  // CHECK:      %c2_i32 = constant 2 : i32
+  // CHECK-NEXT: return
 
   %c2_i32 = constant 2 : i32
    %0 = scf.while (%arg2 = %c2_i32) : (i32) -> (i32) {


        


More information about the Mlir-commits mailing list