[mlir][python] Makes C++ extension code relocatable by way of a macro.

* Resolves a TODO by making this configurable by downstreams.
* This seems to be the last thing allowing full use of the Python bindings as a library within another project (i.e. be embedding them).

Differential Revision: https://reviews.llvm.org/D108523
This commit is contained in:
Stella Laurenzo 2021-08-22 13:43:55 -07:00
parent 79b55e5038
commit e78b745cf2
2 changed files with 50 additions and 29 deletions

View File

@ -30,19 +30,44 @@
#include "mlir-c/IntegerSet.h"
#include "mlir-c/Pass.h"
#define MLIR_PYTHON_CAPSULE_AFFINE_EXPR "mlir.ir.AffineExpr._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_AFFINE_MAP "mlir.ir.AffineMap._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_ATTRIBUTE "mlir.ir.Attribute._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_CONTEXT "mlir.ir.Context._CAPIPtr"
// The 'mlir' Python package is relocatable and supports co-existing in multiple
// projects. Each project must define its outer package prefix with this define
// in order to provide proper isolation and local name resolution.
// The default is for the upstream "import mlir" package layout.
// Note that this prefix is internally stringified, allowing it to be passed
// unquoted on the compiler command line without shell quote escaping issues.
#ifndef MLIR_PYTHON_PACKAGE_PREFIX
#define MLIR_PYTHON_PACKAGE_PREFIX mlir.
#endif
// Makes a fully-qualified name relative to the MLIR python package.
#define MLIR_PYTHON_STRINGIZE(s) #s
#define MLIR_PYTHON_STRINGIZE_ARG(arg) MLIR_PYTHON_STRINGIZE(arg)
#define MAKE_MLIR_PYTHON_QUALNAME(local) \
MLIR_PYTHON_STRINGIZE_ARG(MLIR_PYTHON_PACKAGE_PREFIX) local
#define MLIR_PYTHON_CAPSULE_AFFINE_EXPR \
MAKE_MLIR_PYTHON_QUALNAME("ir.AffineExpr._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_AFFINE_MAP \
MAKE_MLIR_PYTHON_QUALNAME("ir.AffineMap._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_ATTRIBUTE \
MAKE_MLIR_PYTHON_QUALNAME("ir.Attribute._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_CONTEXT \
MAKE_MLIR_PYTHON_QUALNAME("ir.Context._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE \
"mlir.execution_engine.ExecutionEngine._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_INTEGER_SET "mlir.ir.IntegerSet._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_LOCATION "mlir.ir.Location._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_MODULE "mlir.ir.Module._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_OPERATION "mlir.ir.Operation._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_TYPE "mlir.ir.Type._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_PASS_MANAGER "mlir.passmanager.PassManager._CAPIPtr"
#define MLIR_PYTHON_CAPSULE_VALUE "mlir.ir.Value._CAPIPtr"
MAKE_MLIR_PYTHON_QUALNAME("execution_engine.ExecutionEngine._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_INTEGER_SET \
MAKE_MLIR_PYTHON_QUALNAME("ir.IntegerSet._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_LOCATION \
MAKE_MLIR_PYTHON_QUALNAME("ir.Location._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_MODULE \
MAKE_MLIR_PYTHON_QUALNAME("ir.Module._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_OPERATION \
MAKE_MLIR_PYTHON_QUALNAME("ir.Operation._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_TYPE MAKE_MLIR_PYTHON_QUALNAME("ir.Type._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_PASS_MANAGER \
MAKE_MLIR_PYTHON_QUALNAME("passmanager.PassManager._CAPIPtr")
#define MLIR_PYTHON_CAPSULE_VALUE MAKE_MLIR_PYTHON_QUALNAME("ir.Value._CAPIPtr")
/** Attribute on MLIR Python objects that expose their C-API pointer.
* This will be a type-specific capsule created as per one of the helpers

View File

@ -30,10 +30,6 @@
namespace py = pybind11;
// TODO: Move this to Interop.h and make it externally configurable/use it
// consistently to locate the "import mlir" top-level.
#define MLIR_PYTHON_PACKAGE_PREFIX "mlir."
// Raw CAPI type casters need to be declared before use, so always include them
// first.
namespace pybind11 {
@ -76,7 +72,7 @@ struct type_caster<MlirAffineMap> {
static handle cast(MlirAffineMap v, return_value_policy, handle) {
py::object capsule =
py::reinterpret_steal<py::object>(mlirPythonAffineMapToCapsule(v));
return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("AffineMap")
.attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
.release();
@ -98,7 +94,7 @@ struct type_caster<MlirAttribute> {
static handle cast(MlirAttribute v, return_value_policy, handle) {
py::object capsule =
py::reinterpret_steal<py::object>(mlirPythonAttributeToCapsule(v));
return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("Attribute")
.attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
.release();
@ -115,7 +111,7 @@ struct type_caster<MlirContext> {
// TODO: This raises an error of "No current context" currently.
// Update the implementation to pretty-print the helpful error that the
// core implementations print in this case.
src = py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
src = py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("Context")
.attr("current");
}
@ -144,7 +140,7 @@ struct type_caster<MlirLocation> {
static handle cast(MlirLocation v, return_value_policy, handle) {
py::object capsule =
py::reinterpret_steal<py::object>(mlirPythonLocationToCapsule(v));
return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("Location")
.attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
.release();
@ -166,7 +162,7 @@ struct type_caster<MlirModule> {
static handle cast(MlirModule v, return_value_policy, handle) {
py::object capsule =
py::reinterpret_steal<py::object>(mlirPythonModuleToCapsule(v));
return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("Module")
.attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
.release();
@ -190,7 +186,7 @@ struct type_caster<MlirOperation> {
return py::none();
py::object capsule =
py::reinterpret_steal<py::object>(mlirPythonOperationToCapsule(v));
return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("Operation")
.attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
.release();
@ -226,7 +222,7 @@ struct type_caster<MlirType> {
static handle cast(MlirType t, return_value_policy, handle) {
py::object capsule =
py::reinterpret_steal<py::object>(mlirPythonTypeToCapsule(t));
return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("Type")
.attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
.release();
@ -266,7 +262,7 @@ public:
}
template <typename Func, typename... Extra>
pure_subclass &def(const char *name, Func &&f, const Extra &...extra) {
pure_subclass &def(const char *name, Func &&f, const Extra &... extra) {
py::cpp_function cf(
std::forward<Func>(f), py::name(name), py::is_method(py::none()),
py::sibling(py::getattr(thisClass, name, py::none())), extra...);
@ -276,7 +272,7 @@ public:
template <typename Func, typename... Extra>
pure_subclass &def_property_readonly(const char *name, Func &&f,
const Extra &...extra) {
const Extra &... extra) {
py::cpp_function cf(
std::forward<Func>(f), py::name(name), py::is_method(py::none()),
py::sibling(py::getattr(thisClass, name, py::none())), extra...);
@ -288,7 +284,7 @@ public:
template <typename Func, typename... Extra>
pure_subclass &def_staticmethod(const char *name, Func &&f,
const Extra &...extra) {
const Extra &... extra) {
static_assert(!std::is_member_function_pointer<Func>::value,
"def_staticmethod(...) called with a non-static member "
"function pointer");
@ -301,7 +297,7 @@ public:
template <typename Func, typename... Extra>
pure_subclass &def_classmethod(const char *name, Func &&f,
const Extra &...extra) {
const Extra &... extra) {
static_assert(!std::is_member_function_pointer<Func>::value,
"def_classmethod(...) called with a non-static member "
"function pointer");
@ -329,7 +325,7 @@ public:
IsAFunctionTy isaFunction)
: mlir_attribute_subclass(
scope, attrClassName, isaFunction,
py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir")
py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
.attr("Attribute")) {}
/// Subclasses with a provided mlir.ir.Attribute super-class. This must
@ -381,7 +377,7 @@ public:
IsAFunctionTy isaFunction)
: mlir_type_subclass(
scope, typeClassName, isaFunction,
py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir").attr("Type")) {}
py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")).attr("Type")) {}
/// Subclasses with a provided mlir.ir.Type super-class. This must
/// be used if the subclass is being defined in the same extension module