Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Python Bindings] error while printing a python generated module in c++ #90795

Open
ravil-mobile opened this issue May 1, 2024 · 7 comments
Open
Labels
mlir:python MLIR Python bindings

Comments

@ravil-mobile
Copy link

ravil-mobile commented May 1, 2024

Hi all,

I would like to build a small EDSL. The idea is to have the dsl frontend in python and handle lowering in c++.
Here is a very small example which I wrote to reproduce the error:

from mlir.ir import Context, Module, get_dialect_registry
from mlir.ir import InsertionPoint, Location, F32Type
from mlir.dialects import func, arith
from mlir.dialects import arith
from edsl_cpp import entry


def main():
  registry = get_dialect_registry()
  context = Context()
  context.append_dialect_registry(registry)
  module = None
  with context:
    module = Module.create(Location.unknown())
    with InsertionPoint(module.body), Location.unknown():
      fp_type = F32Type.get()
      function = func.FuncOp("test", ([fp_type, fp_type, fp_type], [fp_type]))
    
      with InsertionPoint(function.add_entry_block()) as block:
        one = function.arguments[0]
        two = function.arguments[1]
        mult_res = arith.MulFOp(one, two)
    
        three = function.arguments[2]
        res = arith.AddFOp(mult_res, three)
        func.ReturnOp([res])

  entry(module._CAPIPtr)


if __name__ == "__main__":
  main()
#include <pybind11/pybind11.h>
#include "mlir/CAPI/IR.h"
#include "mlir-c/IR.h"
#include "mlir-c/RegisterEverything.h"
#include "mlir-c/Bindings/Python/Interop.h"
#include "mlir/CAPI/Support.h"
#include <stdexcept>

PYBIND11_MODULE(edsl_cpp, m) {
  m.doc() = "edsl python bindings";
  m.def("entry", [](pybind11::object capsule){
    MlirModule mlirModule = mlirPythonCapsuleToModule(capsule.ptr());
    if (mlirModuleIsNull(mlirModule)) {
      throw std::runtime_error("empty module");
    }
    MlirContext context = mlirModuleGetContext(mlirModule);
    if (mlirContextIsNull(context)) {
      throw std::runtime_error("empty context");
    }
    auto module = unwrap(mlirModule);
    module->dump();
  });
}

If necessary, I can share the whole source code. Anyway, when I am executing the python script I get the following error:

dialect has no registered type printing hook
UNREACHABLE executed at <path-to-llvm>/llvm-project/mlir/include/mlir/IR/Dialect.h:111!

Does anybody have an idea what is missing in my example?
I can dump a module in python without any problem by something is wrong in the cpp-part.

I am using 461274b81d8641eab64d494accddc81d7db8a09e commit but I bet it is going to be the same with the main branch.

@EugeneZelenko EugeneZelenko added mlir:python MLIR Python bindings and removed new issue labels May 1, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented May 1, 2024

@llvm/issue-subscribers-mlir-python

Author: None (ravil-mobile)

Hi all,

I would like to build a small EDSL. The idea is to have the dsl frontend in python and handle lowering in c++.
Here is a small example:

from mlir.ir import Context, Module, get_dialect_registry
from mlir.ir import InsertionPoint, Location, F32Type
from mlir.dialects import func, arith
from mlir.dialects import arith
from edsl_cpp import entry


def main():
  registry = get_dialect_registry()
  context = Context()
  context.append_dialect_registry(registry)
  module = None
  with context:
    module = Module.create(Location.unknown())
    with InsertionPoint(module.body), Location.unknown():
      fp_type = F32Type.get()
      function = func.FuncOp("test", ([fp_type, fp_type, fp_type], [fp_type]))
    
      with InsertionPoint(function.add_entry_block()) as block:
        one = function.arguments[0]
        two = function.arguments[1]
        mult_res = arith.MulFOp(one, two)
    
        three = function.arguments[2]
        res = arith.AddFOp(mult_res, three)
        func.ReturnOp([res])

  entry(module._CAPIPtr)


if __name__ == "__main__":
  main()
#include &lt;pybind11/pybind11.h&gt;
#include "mlir/CAPI/IR.h"
#include "mlir-c/IR.h"
#include "mlir-c/RegisterEverything.h"
#include "mlir-c/Bindings/Python/Interop.h"
#include "mlir/CAPI/Support.h"
#include &lt;stdexcept&gt;

PYBIND11_MODULE(edsl_cpp, m) {
  m.doc() = "edsl python bindings";
  m.def("entry", [](pybind11::object capsule){
    MlirModule mlirModule = mlirPythonCapsuleToModule(capsule.ptr());
    if (mlirModuleIsNull(mlirModule)) {
      throw std::runtime_error("empty module");
    }
    MlirContext context = mlirModuleGetContext(mlirModule);
    if (mlirContextIsNull(context)) {
      throw std::runtime_error("empty context");
    }
    auto module = unwrap(mlirModule);
    mlir::AsmState state(module);
    module-&gt;dump();
  });
}

If necessary, I can share the whole source code. Anyway, when I am executing the python script I get the following error:

dialect has no registered type printing hook
UNREACHABLE executed at &lt;path-to-llvm&gt;/llvm-project/mlir/include/mlir/IR/Dialect.h:111!

Does anybody have an idea what is missing in my example?
I can dump a module in python without any problem by something is wrong in the cpp-part.

@ravil-mobile ravil-mobile changed the title [Python Binding] error while printing a python generated module in c++ [Python Bindings] error while printing a python generated module in c++ May 1, 2024
@makslevental
Copy link
Contributor

You're trying to print outside of the with context - just indent entry(module._CAPIPtr).

@ravil-mobile
Copy link
Author

You're trying to print outside of the with context - just indent entry(module._CAPIPtr).

Indenting entry(module._CAPIPtr) to the right results in the same error.

Actually, I create a context outside of the with statement. So, context is a local variable of main. It is supposed to be destroyed at the end of the function

@makslevental
Copy link
Contributor

This kind of stuff

  m.def("entry", [](pybind11::object capsule){
    MlirModule mlirModule = mlirPythonCapsuleToModule(capsule.ptr());
    ...
    auto module = unwrap(mlirModule);
    module->dump();

is "sharp edges". It can be done but takes some careful coordination. I can help you debug further but I'm gonna need to see more of the source. Feel free to ping me on the discord (same handle).

@ravil-mobile
Copy link
Author

This kind of stuff

  m.def("entry", [](pybind11::object capsule){
    MlirModule mlirModule = mlirPythonCapsuleToModule(capsule.ptr());
    ...
    auto module = unwrap(mlirModule);
    module->dump();

is "sharp edges". It can be done but takes some careful coordination. I can help you debug further but I'm gonna need to see more of the source. Feel free to ping me on the discord (same handle).

Thanks @makslevental,

You can find the source code here: https://github.com/ravil-mobile/edsl-mlir/tree/main

@makslevental
Copy link
Contributor

makslevental commented May 2, 2024

Well for starters, dialect_libs and extension_libs in

target_link_libraries(edsl_cpp PUBLIC
  ${dialect_libs}
  ${extension_libs}
  MLIREdslEntry
)

in your CMakeLists txt aren't actually defined/set to anything (so you're not actually linking your C extension to anything).

But overall I would advise you to not diverge from using upstream CMake targets/functions/helpers - I realize they're complex and verbose but it's damn near impossible to get things to build/work without them (and you'd probably end up re-rolling most of them even if you did do it "lone wolf" style).

@ravil-mobile
Copy link
Author

ravil-mobile commented May 2, 2024

Well for starters, dialect_libs and extension_libs in

target_link_libraries(edsl_cpp PUBLIC
  ${dialect_libs}
  ${extension_libs}
  MLIREdslEntry
)

in your CMakeLists txt aren't actually defined/set to anything (so you're not actually linking your C extension to anything).

But overall I would advise you to not diverge from using upstream CMake targets/functions/helpers - I realize they're complex and verbose but it's damn near impossible to get things to build/work without them (and you'd probably end up re-rolling most of them even if you did do it "lone wolf" style).

@makslevental, yes. You are correct.

Library, in this particular case, is handled here

https://github.com/ravil-mobile/edsl-mlir/blob/main/edsl/compiler/lib/CMakeLists.txt

https://github.com/ravil-mobile/edsl-mlir/blob/d8e8d57dd9131cb338677941fc045a92bfd678c8/edsl/compiler/CMakeLists.txt#L37

It doesn't seem to be a problem.

I did try to explicitly link all the stuff which I am using - e.g.,

target_link_libraries(edsl_cpp PUBLIC
  MLIRSupport
  MLIRAsmParser
  MLIRExecutionEngine
  MLIRDialect
  MLIRDialectUtils
  MLIRArithDialect
  MLIREdslEntry
)

But the problem remains.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:python MLIR Python bindings
Projects
None yet
Development

No branches or pull requests

4 participants