[Mlir-commits] [mlir] [MLIR] Configure CompositeFixedPointPass's convergence-failure behavior (PR #218394)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Aug 24 05:49:39 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Vadim Curcă (VadimCurca)

<details>
<summary>Changes</summary>

Add an option to `CompositeFixedPointPass` controlling what happens if the pass fails to converge within max-iterations: emit a warning (default), emit an error and fail the pass, or do nothing.

---
Full diff: https://github.com/llvm/llvm-project/pull/218394.diff


6 Files Affected:

- (added) mlir/include/mlir/Transforms/CompositePass.h (+27) 
- (modified) mlir/include/mlir/Transforms/Passes.h (+4-1) 
- (modified) mlir/include/mlir/Transforms/Passes.td (+12) 
- (modified) mlir/lib/Transforms/CompositePass.cpp (+19-7) 
- (added) mlir/test/Transforms/composite-pass-convergence-failure.mlir (+18) 
- (modified) mlir/test/lib/Transforms/TestCompositePass.cpp (+30) 


``````````diff
diff --git a/mlir/include/mlir/Transforms/CompositePass.h b/mlir/include/mlir/Transforms/CompositePass.h
new file mode 100644
index 0000000000000..8fe117c3c41a0
--- /dev/null
+++ b/mlir/include/mlir/Transforms/CompositePass.h
@@ -0,0 +1,27 @@
+//===- CompositePass.h - Composite pass utilities ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_TRANSFORMS_COMPOSITEPASS_H
+#define MLIR_TRANSFORMS_COMPOSITEPASS_H
+
+namespace mlir {
+
+/// Action to take when `CompositeFixedPointPass` fails to converge within
+/// its configured maximum number of iterations.
+enum class ConvergenceFailureAction {
+  /// Emit a warning.
+  Warn,
+  /// Emit an error and fail the pass.
+  Error,
+  /// Do nothing.
+  Silent,
+};
+
+} // namespace mlir
+
+#endif // MLIR_TRANSFORMS_COMPOSITEPASS_H
diff --git a/mlir/include/mlir/Transforms/Passes.h b/mlir/include/mlir/Transforms/Passes.h
index 313755fde3479..51c8934f9df86 100644
--- a/mlir/include/mlir/Transforms/Passes.h
+++ b/mlir/include/mlir/Transforms/Passes.h
@@ -16,6 +16,7 @@
 
 #include "mlir/Pass/Pass.h"
 #include "mlir/Pass/PassManager.h"
+#include "mlir/Transforms/CompositePass.h"
 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
 #include "mlir/Transforms/LocationSnapshot.h"
 #include "mlir/Transforms/ViewOpGraph.h"
@@ -92,7 +93,9 @@ std::unique_ptr<Pass> createPrintOpStatsPass(raw_ostream &os, bool printAsJSON);
 /// or maximum number of iterations reached.
 std::unique_ptr<Pass> createCompositeFixedPointPass(
     std::string name, llvm::function_ref<void(OpPassManager &)> populateFunc,
-    int maxIterations = 10);
+    int maxIterations = 10,
+    ConvergenceFailureAction convergenceFailureAction =
+        ConvergenceFailureAction::Warn);
 
 //===----------------------------------------------------------------------===//
 // Registration
diff --git a/mlir/include/mlir/Transforms/Passes.td b/mlir/include/mlir/Transforms/Passes.td
index 74ac370ea950b..0af26837fb5e9 100644
--- a/mlir/include/mlir/Transforms/Passes.td
+++ b/mlir/include/mlir/Transforms/Passes.td
@@ -609,6 +609,18 @@ def CompositeFixedPointPass : Pass<"composite-fixed-point-pass"> {
       "Composite pass inner pipeline">,
     Option<"maxIter", "max-iterations", "int", /*default=*/"10",
       "Maximum number of iterations if inner pipeline">,
+    Option<"convergenceFailureAction", "on-convergence-failure",
+      "mlir::ConvergenceFailureAction",
+      /*default=*/"mlir::ConvergenceFailureAction::Warn",
+      "Action to take if the pass fails to converge within max-iterations",
+      [{::llvm::cl::values(
+        clEnumValN(mlir::ConvergenceFailureAction::Warn, "warn",
+         "Emit a warning (default)"),
+        clEnumValN(mlir::ConvergenceFailureAction::Error, "error",
+         "Emit an error and fail the pass"),
+        clEnumValN(mlir::ConvergenceFailureAction::Silent, "silent",
+         "Do nothing")
+       )}]>,
   ];
 }
 
diff --git a/mlir/lib/Transforms/CompositePass.cpp b/mlir/lib/Transforms/CompositePass.cpp
index cb806c65972a8..d5d2e1fcefae5 100644
--- a/mlir/lib/Transforms/CompositePass.cpp
+++ b/mlir/lib/Transforms/CompositePass.cpp
@@ -29,9 +29,10 @@ struct CompositeFixedPointPass final
 
   CompositeFixedPointPass(
       std::string name_, llvm::function_ref<void(OpPassManager &)> populateFunc,
-      int maxIterations) {
+      int maxIterations, ConvergenceFailureAction convergenceFailureActionArg) {
     name = std::move(name_);
     maxIter = maxIterations;
+    convergenceFailureAction = convergenceFailureActionArg;
     populateFunc(dynamicPM);
 
     llvm::raw_string_ostream os(pipelineStr);
@@ -76,9 +77,20 @@ struct CompositeFixedPointPass final
         return signalPassFailure();
 
       if (currentIter++ >= maxIterVal) {
-        op->emitWarning("Composite pass \"" + llvm::Twine(name) +
-                        "\"+ didn't converge in " + llvm::Twine(maxIterVal) +
-                        " iterations");
+        std::string message = ("Composite pass \"" + llvm::Twine(name) +
+                               "\"+ didn't converge in " +
+                               llvm::Twine(maxIterVal) + " iterations")
+                                  .str();
+        switch (convergenceFailureAction) {
+        case ConvergenceFailureAction::Warn:
+          op->emitWarning(message);
+          break;
+        case ConvergenceFailureAction::Error:
+          op->emitError(message);
+          return signalPassFailure();
+        case ConvergenceFailureAction::Silent:
+          break;
+        }
         break;
       }
 
@@ -100,8 +112,8 @@ struct CompositeFixedPointPass final
 
 std::unique_ptr<Pass> mlir::createCompositeFixedPointPass(
     std::string name, llvm::function_ref<void(OpPassManager &)> populateFunc,
-    int maxIterations) {
+    int maxIterations, ConvergenceFailureAction convergenceFailureAction) {
 
-  return std::make_unique<CompositeFixedPointPass>(std::move(name),
-                                                   populateFunc, maxIterations);
+  return std::make_unique<CompositeFixedPointPass>(
+      std::move(name), populateFunc, maxIterations, convergenceFailureAction);
 }
diff --git a/mlir/test/Transforms/composite-pass-convergence-failure.mlir b/mlir/test/Transforms/composite-pass-convergence-failure.mlir
new file mode 100644
index 0000000000000..48019dc949f26
--- /dev/null
+++ b/mlir/test/Transforms/composite-pass-convergence-failure.mlir
@@ -0,0 +1,18 @@
+// RUN: mlir-opt %s --composite-fixed-point-pass="name=Test pipeline='any(test-increment-attr)' max-iterations=3 on-convergence-failure=warn" 2>&1 | FileCheck %s --check-prefix=CHECK-WARN
+// RUN: not mlir-opt %s --composite-fixed-point-pass="name=Test pipeline='any(test-increment-attr)' max-iterations=3 on-convergence-failure=error" 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+// RUN: mlir-opt %s --composite-fixed-point-pass="name=Test pipeline='any(test-increment-attr)' max-iterations=3 on-convergence-failure=silent" 2>&1 | FileCheck %s --check-prefix=CHECK-SILENT
+
+// The "test-increment-attr" pass mutates the op on every run, so the composite
+// pass never reaches a fixed point and always exhausts max-iterations,
+// regardless of the input IR.
+
+// CHECK-WARN: warning: Composite pass "Test"+ didn't converge in 3 iterations
+// CHECK-WARN: test.counter = 4
+
+// CHECK-ERROR: error: Composite pass "Test"+ didn't converge in 3 iterations
+
+// CHECK-SILENT-NOT: didn't converge
+// CHECK-SILENT: test.counter = 4
+func.func @test() {
+  return
+}
diff --git a/mlir/test/lib/Transforms/TestCompositePass.cpp b/mlir/test/lib/Transforms/TestCompositePass.cpp
index 5c0d93cc0d64e..9db2281162ce9 100644
--- a/mlir/test/lib/Transforms/TestCompositePass.cpp
+++ b/mlir/test/lib/Transforms/TestCompositePass.cpp
@@ -10,11 +10,39 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/Pass/Pass.h"
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Pass/PassRegistry.h"
 #include "mlir/Transforms/Passes.h"
 
+using namespace mlir;
+
+namespace {
+/// A pass that increments an attribute on the operation on every run,
+/// guaranteeing that it never reaches a fixed point. Used to test
+/// `CompositeFixedPointPass`'s convergence-failure handling.
+struct TestIncrementAttrPass
+    : public PassWrapper<TestIncrementAttrPass, OperationPass<>> {
+  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestIncrementAttrPass)
+
+  StringRef getArgument() const final { return "test-increment-attr"; }
+  StringRef getDescription() const final {
+    return "Test pass that increments an attribute on the operation on "
+           "every run, so it never reaches a fixed point";
+  }
+
+  void runOnOperation() override {
+    Operation *op = getOperation();
+    int64_t counter = 0;
+    if (auto attr = op->getAttrOfType<IntegerAttr>("test.counter"))
+      counter = attr.getInt();
+    op->setAttr("test.counter", Builder(op).getI64IntegerAttr(counter + 1));
+  }
+};
+} // namespace
+
 namespace mlir {
 namespace test {
 void registerTestCompositePass() {
@@ -33,6 +61,8 @@ void registerTestCompositePass() {
         return success();
       },
       [](function_ref<void(const detail::PassOptions &)>) {});
+
+  PassRegistration<TestIncrementAttrPass>();
 }
 } // namespace test
 } // namespace mlir

``````````

</details>


https://github.com/llvm/llvm-project/pull/218394


More information about the Mlir-commits mailing list