[Mlir-commits] [mlir] [MLIR][Python][NO MERGE] Support Python-defined passes in MLIR (PR #157369)
    llvmlistbot at llvm.org 
    llvmlistbot at llvm.org
       
    Sun Sep  7 20:04:53 PDT 2025
    
    
  
================
@@ -157,6 +159,44 @@ void mlir::python::populatePassManagerSubmodule(nb::module_ &m) {
           "pipeline"_a,
           "Add textual pipeline elements to the pass manager. Throws a "
           "ValueError if the pipeline can't be parsed.")
+      .def(
+          "add_python_pass",
+          [](PyPassManager &passManager, const std::string &name,
+             const std::string &argument, const std::string &description,
+             const std::string &opName, const nb::callable &run) {
+            MlirTypeIDAllocator typeIDAllocator = mlirTypeIDAllocatorCreate();
+            MlirTypeID passID =
+                mlirTypeIDAllocatorAllocateTypeID(typeIDAllocator);
+            MlirExternalPassCallbacks callbacks;
+            callbacks.construct = [](void *obj) {
+              (void)nb::handle(static_cast<PyObject *>(obj)).inc_ref();
+            };
+            callbacks.destruct = [](void *obj) {
+              (void)nb::handle(static_cast<PyObject *>(obj)).dec_ref();
+            };
+            callbacks.clone = [](void *obj) {
+              auto src = nb::handle(static_cast<PyObject *>(obj));
+              nb::callable dst;
+              nb::inst_copy(dst, src);
+              return static_cast<void *>(dst.ptr());
----------------
PragmaTwice wrote:
Yeah `clone` is quite tricky since in the python side I'm not sure how to call it : )
>From the code, it seems that we first call `callback.clone`, and then call `callback.construct` in constructing an `ExternalPass`, so maybe here the pointer `dst.ptr()` will be dangling since the `nb::callable` is destructed (`callable::~callable` is called) and the ref_count become 0?
I think it is related to whether we `inc_ref` in the `callback.construct`. Maybe we can have such a design:
- in `callback.construct` we do not call `inc_ref`, it leaves to who pass the object into the `ExternalPass`;
- in `callback.clone`, we first call `inc_ref` and then pass the object (call `.release()` to prevent the `nb::object::~object` from decreasing the ref count), so that the ref count of this object can be 1, and in `callback.destruct` it is decreased to 0 and destructed;
- before the call to `mlirCreateExternalPass`, we first call `inc_ref` for the object to increase the ref count so that it should be valid at least before `callback.destruct`.
https://github.com/llvm/llvm-project/pull/157369
    
    
More information about the Mlir-commits
mailing list