[clang] 8b15fc1 - [CIR] Fix FlattenCFG pattern rewriter contract violations (#192359)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 16 11:05:37 PDT 2026


Author: Bruno Cardoso Lopes
Date: 2026-04-16T11:05:31-07:00
New Revision: 8b15fc14f5314ceb8576629f3190d4c740590396

URL: https://github.com/llvm/llvm-project/commit/8b15fc14f5314ceb8576629f3190d4c740590396
DIFF: https://github.com/llvm/llvm-project/commit/8b15fc14f5314ceb8576629f3190d4c740590396.diff

LOG: [CIR] Fix FlattenCFG pattern rewriter contract violations (#192359)

Fix patterns in CIRFlattenCFGPass that modify IR but return failure(),
violating the MLIR greedy pattern rewriter contract. The contract
requires that if a pattern modifies IR, it must return success().

- CIRCleanupScopeOpFlattening: always return success() since IR is
modified (blocks split, regions inlined) before error paths
- Ternary op flattening: return success() instead of falling through
after emitError, since splitBlock/createBlock already modified IR
- Use rewriter.moveOpBefore() instead of direct defOp->moveBefore() to
properly notify the rewriter of IR mutations

Found by MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS=ON.
Test: flatten-cleanup-scope-nyi.cir (a silly one since it's testing an
error, but point still valid)

Added: 
    

Modified: 
    clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
index cae1a771a9694..48c47deb2bc0a 100644
--- a/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/FlattenCFG.cpp
@@ -537,7 +537,10 @@ class CIRTernaryOpFlattening : public mlir::OpRewritePattern<cir::TernaryOp> {
     mlir::Operation *trueTerminator = trueRegion.back().getTerminator();
     rewriter.setInsertionPointToEnd(&trueRegion.back());
 
-    // Handle both yield and unreachable terminators (throw expressions)
+    // Handle both yield and unreachable terminators (throw expressions).
+    // Note: IR has already been modified (splitBlock, createBlock above), so
+    // we must not return failure() from this point onward per the MLIR pattern
+    // rewriter contract.
     if (auto trueYieldOp = dyn_cast<cir::YieldOp>(trueTerminator)) {
       rewriter.replaceOpWithNewOp<cir::BrOp>(trueYieldOp, trueYieldOp.getArgs(),
                                              continueBlock);
@@ -547,7 +550,9 @@ class CIRTernaryOpFlattening : public mlir::OpRewritePattern<cir::TernaryOp> {
       trueTerminator->emitError("unexpected terminator in ternary true region, "
                                 "expected yield or unreachable, got: ")
           << trueTerminator->getName();
-      return mlir::failure();
+      // Return success because IR was already modified
+      // (splitBlock/createBlock).
+      return mlir::success();
     }
     rewriter.inlineRegionBefore(trueRegion, continueBlock);
 
@@ -568,7 +573,9 @@ class CIRTernaryOpFlattening : public mlir::OpRewritePattern<cir::TernaryOp> {
       falseTerminator->emitError("unexpected terminator in ternary false "
                                  "region, expected yield or unreachable, got: ")
           << falseTerminator->getName();
-      return mlir::failure();
+      // Return success because IR was already modified
+      // (splitBlock/createBlock).
+      return mlir::success();
     }
     rewriter.inlineRegionBefore(falseRegion, continueBlock);
 
@@ -914,7 +921,7 @@ class CIRCleanupScopeOpFlattening
       if (shouldSinkReturnOperand(operand, returnOp)) {
         // Sink the defining op to the dispatch block.
         mlir::Operation *defOp = operand.getDefiningOp();
-        defOp->moveBefore(destBlock, destBlock->end());
+        rewriter.moveOpBefore(defOp, destBlock, destBlock->end());
         returnValues.push_back(operand);
       } else {
         // Create an alloca in the function entry block.
@@ -1385,7 +1392,13 @@ class CIRCleanupScopeOpFlattening
     // Erase the original cleanup scope op.
     rewriter.eraseOp(cleanupOp);
 
-    return result;
+    // Always return success because the IR has been modified (blocks split,
+    // regions inlined, ops erased, etc.). The MLIR pattern rewriter contract
+    // requires that if a pattern modifies IR, it must return success(). Any
+    // errors from unsupported exit operations (e.g. goto) have already been
+    // reported via emitError and an unreachable terminator was placed as a
+    // placeholder.
+    return mlir::success();
   }
 
   mlir::LogicalResult


        


More information about the cfe-commits mailing list