[Mlir-commits] [mlir] [mlir][Pass] Fix crash when applying a pass to an optional interface (PR #169262)

Matthias Springer llvmlistbot at llvm.org
Sun Nov 23 17:45:32 PST 2025


https://github.com/matthias-springer created https://github.com/llvm/llvm-project/pull/169262

Interfaces can be optional: whether an op implements an interface or not
can depend on the state of the operation.

```
// An optional code block for adding additional "classof" logic. This can
// be used to better enable "optional" interfaces, where an entity only
// implements the interface if some dynamic characteristic holds.
// `$_attr`/`$_op`/`$_type` may be used to refer to an instance of the
// interface instance being checked.
code extraClassOf = "";
```

The current `Pass::canScheduleOn(RegisteredOperationName)` is
insufficient. This commit adds an additional overload to inspect
`Operation *`.

This commit fixes a crash when scheduling an `InterfacePass` for an
optional interface on an operation that does not actually implement the
interface.

This is a re-upload of #168499, which was reverted.


>From d51988e6b1c69a4cf87ac9580a4630ba64762397 Mon Sep 17 00:00:00 2001
From: Matthias Springer <me at m-sp.org>
Date: Thu, 20 Nov 2025 17:51:44 +0800
Subject: [PATCH 1/2] [mlir][Pass] Fix crash when applying a pass to an
 optional interface (#168499)

Interfaces can be optional: whether an op implements an interface or not
can depend on the state of the operation.

```
  // An optional code block for adding additional "classof" logic. This can
  // be used to better enable "optional" interfaces, where an entity only
  // implements the interface if some dynamic characteristic holds.
  // `$_attr`/`$_op`/`$_type` may be used to refer to an instance of the
  // interface instance being checked.
  code extraClassOf = "";
```

The current `Pass::canScheduleOn(RegisteredOperationName)` is
insufficient. This commit adds an additional overload to inspect
`Operation *`.

This commit fixes a crash when scheduling an `InterfacePass` for an
optional interface on an operation that does not actually implement the
interface.
---
 mlir/include/mlir/Pass/Pass.h                          |  8 ++++++++
 mlir/lib/Pass/Pass.cpp                                 |  6 +++---
 mlir/test/Dialect/Transform/test-pass-application.mlir |  2 +-
 mlir/test/Pass/invalid-unsupported-operation.mlir      | 10 ++++++++++
 mlir/test/Pass/pipeline-invalid.mlir                   |  2 +-
 5 files changed, 23 insertions(+), 5 deletions(-)
 create mode 100644 mlir/test/Pass/invalid-unsupported-operation.mlir

diff --git a/mlir/include/mlir/Pass/Pass.h b/mlir/include/mlir/Pass/Pass.h
index 16893c6db87b1..448a688243491 100644
--- a/mlir/include/mlir/Pass/Pass.h
+++ b/mlir/include/mlir/Pass/Pass.h
@@ -193,6 +193,13 @@ class Pass {
   /// This is useful for generic operation passes to add restrictions on the
   /// operations they operate on.
   virtual bool canScheduleOn(RegisteredOperationName opName) const = 0;
+  virtual bool canScheduleOn(Operation *op) const {
+    std::optional<RegisteredOperationName> registeredInfo =
+        op->getName().getRegisteredInfo();
+    if (!registeredInfo)
+      return false;
+    return canScheduleOn(*registeredInfo);
+  }
 
   /// Schedule an arbitrary pass pipeline on the provided operation.
   /// This can be invoke any time in a pass to dynamic schedule more passes.
@@ -436,6 +443,7 @@ class InterfacePass : public OperationPass<> {
   /// Indicate if the current pass can be scheduled on the given operation type.
   /// For an InterfacePass, this checks if the operation implements the given
   /// interface.
+  bool canScheduleOn(Operation *op) const final { return isa<InterfaceT>(op); }
   bool canScheduleOn(RegisteredOperationName opName) const final {
     return opName.hasInterface<InterfaceT>();
   }
diff --git a/mlir/lib/Pass/Pass.cpp b/mlir/lib/Pass/Pass.cpp
index 521c7c6be17b6..75f882606e0ab 100644
--- a/mlir/lib/Pass/Pass.cpp
+++ b/mlir/lib/Pass/Pass.cpp
@@ -559,9 +559,9 @@ LogicalResult OpToOpPassAdaptor::run(Pass *pass, Operation *op,
     return op->emitOpError() << "trying to schedule a pass on an operation not "
                                 "marked as 'IsolatedFromAbove'";
   }
-  if (!pass->canScheduleOn(*op->getName().getRegisteredInfo())) {
-    return op->emitOpError()
-           << "trying to schedule a pass on an unsupported operation";
+  if (!pass->canScheduleOn(op)) {
+    return op->emitOpError() << "trying to schedule pass '" << pass->getName()
+                             << "' on an unsupported operation";
   }
 
   // Initialize the pass state with a callback for the pass to dynamically
diff --git a/mlir/test/Dialect/Transform/test-pass-application.mlir b/mlir/test/Dialect/Transform/test-pass-application.mlir
index ce8f69c58701d..4806daf7ce73f 100644
--- a/mlir/test/Dialect/Transform/test-pass-application.mlir
+++ b/mlir/test/Dialect/Transform/test-pass-application.mlir
@@ -386,7 +386,7 @@ module attributes {transform.with_named_sequence} {
 // -----
 
 module attributes {transform.with_named_sequence} {
-  // expected-error @below {{trying to schedule a pass on an unsupported operation}}
+  // expected-error @below {{trying to schedule pass 'DuplicateFunctionEliminationPass' on an unsupported operation}}
   // expected-note @below {{target op}}
   func.func @invalid_target_op_type() {
     return
diff --git a/mlir/test/Pass/invalid-unsupported-operation.mlir b/mlir/test/Pass/invalid-unsupported-operation.mlir
new file mode 100644
index 0000000000000..0ff49448c1daf
--- /dev/null
+++ b/mlir/test/Pass/invalid-unsupported-operation.mlir
@@ -0,0 +1,10 @@
+// RUN: mlir-opt %s -test-print-liveness -split-input-file -verify-diagnostics
+
+// Unnamed modules do not implement SymbolOpInterface.
+// expected-error @+1 {{trying to schedule pass '(anonymous namespace)::TestLivenessPass' on an unsupported operation}}
+module {}
+
+// -----
+
+// Named modules implement SymbolOpInterface.
+module @named_module {}
diff --git a/mlir/test/Pass/pipeline-invalid.mlir b/mlir/test/Pass/pipeline-invalid.mlir
index 948a13384bc75..4116e127a24a6 100644
--- a/mlir/test/Pass/pipeline-invalid.mlir
+++ b/mlir/test/Pass/pipeline-invalid.mlir
@@ -15,5 +15,5 @@ arith.constant 0
 
 // -----
 
-// expected-error at below {{trying to schedule a pass on an unsupported operation}}
+// expected-error at below {{trying to schedule pass '(anonymous namespace)::TestFunctionPass' on an unsupported operation}}
 module {}

>From c7156154390e9732ce9fa075bd3e51bb26c29252 Mon Sep 17 00:00:00 2001
From: Matthias Springer <me at m-sp.org>
Date: Mon, 24 Nov 2025 01:43:54 +0000
Subject: [PATCH 2/2] fix tests

---
 mlir/test/Pass/invalid-unsupported-operation.mlir | 2 +-
 mlir/test/Pass/pipeline-invalid.mlir              | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/mlir/test/Pass/invalid-unsupported-operation.mlir b/mlir/test/Pass/invalid-unsupported-operation.mlir
index 0ff49448c1daf..1ee458412f924 100644
--- a/mlir/test/Pass/invalid-unsupported-operation.mlir
+++ b/mlir/test/Pass/invalid-unsupported-operation.mlir
@@ -1,7 +1,7 @@
 // RUN: mlir-opt %s -test-print-liveness -split-input-file -verify-diagnostics
 
 // Unnamed modules do not implement SymbolOpInterface.
-// expected-error @+1 {{trying to schedule pass '(anonymous namespace)::TestLivenessPass' on an unsupported operation}}
+// expected-error-re @+1 {{trying to schedule pass '{{.*}}TestLivenessPass' on an unsupported operation}}
 module {}
 
 // -----
diff --git a/mlir/test/Pass/pipeline-invalid.mlir b/mlir/test/Pass/pipeline-invalid.mlir
index 4116e127a24a6..bff2b1c1ea5bf 100644
--- a/mlir/test/Pass/pipeline-invalid.mlir
+++ b/mlir/test/Pass/pipeline-invalid.mlir
@@ -15,5 +15,5 @@ arith.constant 0
 
 // -----
 
-// expected-error at below {{trying to schedule pass '(anonymous namespace)::TestFunctionPass' on an unsupported operation}}
+// expected-error-re at below {{trying to schedule pass '{{.*}}TestFunctionPass' on an unsupported operation}}
 module {}



More information about the Mlir-commits mailing list