[Mlir-commits] [mlir] 922b26c - Add Python bindings for the builtin dialect
Mehdi Amini
llvmlistbot at llvm.org
Thu Jan 21 14:50:19 PST 2021
Author: Mehdi Amini
Date: 2021-01-21T22:44:44Z
New Revision: 922b26cde4d1c89a5fa90e6a1d6d97d0f8eace6d
URL: https://github.com/llvm/llvm-project/commit/922b26cde4d1c89a5fa90e6a1d6d97d0f8eace6d
DIFF: https://github.com/llvm/llvm-project/commit/922b26cde4d1c89a5fa90e6a1d6d97d0f8eace6d.diff
LOG: Add Python bindings for the builtin dialect
This includes some minor customization for FuncOp and ModuleOp.
Differential Revision: https://reviews.llvm.org/D95022
Added:
mlir/lib/Bindings/Python/BuiltinOps.td
mlir/lib/Bindings/Python/mlir/dialects/_builtin.py
mlir/test/Bindings/Python/.style.yapf
mlir/test/Bindings/Python/dialects/builtin.py
Modified:
mlir/lib/Bindings/Python/CMakeLists.txt
mlir/lib/Bindings/Python/mlir/dialects/__init__.py
mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp
Removed:
################################################################################
diff --git a/mlir/lib/Bindings/Python/BuiltinOps.td b/mlir/lib/Bindings/Python/BuiltinOps.td
new file mode 100644
index 000000000000..ecbb8227d490
--- /dev/null
+++ b/mlir/lib/Bindings/Python/BuiltinOps.td
@@ -0,0 +1,15 @@
+//===-- BuiltinOps.td - Entry point for builtin bindings ---*- tablegen -*-===//
+//
+// 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 PYTHON_BINDINGS_BUILTIN_OPS
+#define PYTHON_BINDINGS_BUILTIN_OPS
+
+include "mlir/Bindings/Python/Attributes.td"
+include "mlir/IR/BuiltinOps.td"
+
+#endif
diff --git a/mlir/lib/Bindings/Python/CMakeLists.txt b/mlir/lib/Bindings/Python/CMakeLists.txt
index 1749ea2e5472..951aa7883c90 100644
--- a/mlir/lib/Bindings/Python/CMakeLists.txt
+++ b/mlir/lib/Bindings/Python/CMakeLists.txt
@@ -11,6 +11,7 @@ set(PY_SRC_FILES
mlir/ir.py
mlir/dialects/__init__.py
mlir/dialects/_linalg.py
+ mlir/dialects/_builtin.py
mlir/ir.py
mlir/passmanager.py
mlir/transforms/__init__.py
@@ -36,6 +37,11 @@ endforeach()
# Generate dialect-specific bindings.
################################################################################
+add_mlir_dialect_python_bindings(MLIRBindingsPythonBuiltinOps
+ TD_FILE BuiltinOps.td
+ DIALECT_NAME builtin)
+add_dependencies(MLIRBindingsPythonSources MLIRBindingsPythonBuiltinOps)
+
add_mlir_dialect_python_bindings(MLIRBindingsPythonLinalgOps
TD_FILE LinalgOps.td
DIALECT_NAME linalg
diff --git a/mlir/lib/Bindings/Python/mlir/dialects/__init__.py b/mlir/lib/Bindings/Python/mlir/dialects/__init__.py
index 9c003b415438..f5a71bf88700 100644
--- a/mlir/lib/Bindings/Python/mlir/dialects/__init__.py
+++ b/mlir/lib/Bindings/Python/mlir/dialects/__init__.py
@@ -43,7 +43,7 @@ def class_decorator(parent_opview_cls: type):
except AttributeError:
# Try to default resolve it.
try:
- select_mixin = getattr(ext_module, parent_opview_cls.__name__)
+ mixin_cls = getattr(ext_module, parent_opview_cls.__name__)
except AttributeError:
pass
else:
diff --git a/mlir/lib/Bindings/Python/mlir/dialects/_builtin.py b/mlir/lib/Bindings/Python/mlir/dialects/_builtin.py
new file mode 100644
index 000000000000..8d430d5a50da
--- /dev/null
+++ b/mlir/lib/Bindings/Python/mlir/dialects/_builtin.py
@@ -0,0 +1,93 @@
+# 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
+from mlir.ir import *
+
+
+class ModuleOp:
+ """Specialization for the module op class."""
+
+ def __init__(self, loc=None, ip=None):
+ super().__init__(
+ self._ods_build_default(operands=[], results=[], loc=loc, ip=ip))
+ body = self.regions[0].blocks.append()
+ with InsertionPoint(body):
+ Operation.create("module_terminator")
+
+ @property
+ def body(self):
+ return self.regions[0].blocks[0]
+
+
+class FuncOp:
+ """Specialization for the func op class."""
+
+ def __init__(self,
+ name,
+ type,
+ visibility,
+ body_builder=None,
+ loc=None,
+ ip=None):
+ """
+ Create a FuncOp with the provided `name`, `type`, and `visibility`.
+ - `name` is a string representing the function name.
+ - `type` is either a FunctionType or a pair of list describing inputs and
+ results.
+ - `visibility` is a string matching `public`, `private`, or `nested`. The
+ empty string implies a private visibility.
+ - `body_builder` is an optional callback, when provided a new entry block
+ is created and the callback is invoked with the new op as argument within
+ an InsertionPoint context already set for the block. The callback is
+ expected to insert a terminator in the block.
+ """
+ sym_name = StringAttr.get(str(name))
+
+ # If the type is passed as a tuple, build a FunctionType on the fly.
+ if isinstance(type, tuple):
+ type = FunctionType.get(inputs=type[0], results=type[1])
+
+ type = TypeAttr.get(type)
+ sym_visibility = StringAttr.get(
+ str(visibility)) if visibility is not None else None
+ super().__init__(sym_name, type, sym_visibility, loc, ip)
+ if body_builder:
+ entry_block = self.add_entry_block()
+ with InsertionPoint(entry_block):
+ body_builder(self)
+
+ @property
+ def is_external(self):
+ return len(self.regions[0].blocks) == 0
+
+ @property
+ def body(self):
+ return self.regions[0]
+
+ @property
+ def type(self):
+ return FunctionType(TypeAttr(self.attributes["type"]).value)
+
+ @property
+ def visibility(self):
+ return self.attributes["sym_visibility"]
+
+ @property
+ def name(self):
+ return self.attributes["sym_name"]
+
+ @property
+ def entry_block(self):
+ if self.is_external:
+ raise IndexError('External function does not have a body')
+ return self.regions[0].blocks[0]
+
+ def add_entry_block(self):
+ '''
+ Add an entry block to the function body using the function signature to infer block arguments
+ Returns the newly created block
+ '''
+ if not self.is_external:
+ raise IndexError('The function already has an entry block!')
+ self.body.blocks.append(*self.type.inputs)
+ return self.body.blocks[0]
diff --git a/mlir/test/Bindings/Python/.style.yapf b/mlir/test/Bindings/Python/.style.yapf
new file mode 100644
index 000000000000..9ef1dc15ba62
--- /dev/null
+++ b/mlir/test/Bindings/Python/.style.yapf
@@ -0,0 +1,4 @@
+[style]
+ based_on_style = google
+ column_limit = 80
+ indent_width = 2
diff --git a/mlir/test/Bindings/Python/dialects/builtin.py b/mlir/test/Bindings/Python/dialects/builtin.py
new file mode 100644
index 000000000000..447a255f6021
--- /dev/null
+++ b/mlir/test/Bindings/Python/dialects/builtin.py
@@ -0,0 +1,69 @@
+# RUN: %PYTHON %s | FileCheck %s
+
+from mlir.ir import *
+import mlir.dialects.builtin as builtin
+import mlir.dialects.std as std
+
+
+def run(f):
+ print("\nTEST:", f.__name__)
+ f()
+
+
+# CHECK-LABEL: TEST: testBuildFuncOp
+def testBuildFuncOp():
+ ctx = Context()
+ with Location.unknown(ctx) as loc:
+ m = builtin.ModuleOp()
+
+ f32 = F32Type.get()
+ tensor_type = RankedTensorType.get((2, 3, 4), f32)
+ with InsertionPoint.at_block_begin(m.body):
+ func = builtin.FuncOp(name="some_func",
+ type=FunctionType.get(
+ inputs=[tensor_type, tensor_type],
+ results=[tensor_type]),
+ visibility="nested")
+ # CHECK: Name is: "some_func"
+ print("Name is: ", func.name)
+
+ # CHECK: Type is: (tensor<2x3x4xf32>, tensor<2x3x4xf32>) -> tensor<2x3x4xf32>
+ print("Type is: ", func.type)
+
+ # CHECK: Visibility is: "nested"
+ print("Visibility is: ", func.visibility)
+
+ try:
+ entry_block = func.entry_block
+ except IndexError as e:
+ # CHECK: External function does not have a body
+ print(e)
+
+ with InsertionPoint(func.add_entry_block()):
+ std.ReturnOp([func.entry_block.arguments[0]])
+ pass
+
+ try:
+ func.add_entry_block()
+ except IndexError as e:
+ # CHECK: The function already has an entry block!
+ print(e)
+
+ # Try the callback builder and passing type as tuple.
+ func = builtin.FuncOp(name="some_other_func",
+ type=([tensor_type, tensor_type], [tensor_type]),
+ visibility="nested",
+ body_builder=lambda func: std.ReturnOp(
+ [func.entry_block.arguments[0]]))
+
+ # CHECK: module {
+ # CHECK: func nested @some_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
+ # CHECK: return %arg0 : tensor<2x3x4xf32>
+ # CHECK: }
+ # CHECK: func nested @some_other_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
+ # CHECK: return %arg0 : tensor<2x3x4xf32>
+ # CHECK: }
+ print(m)
+
+
+run(testBuildFuncOp)
diff --git a/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp b/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp
index 0197bfb15577..94bfd58ab3a5 100644
--- a/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpPythonBindingGen.cpp
@@ -716,6 +716,10 @@ static bool emitAllOps(const llvm::RecordKeeper &records, raw_ostream &os) {
os << llvm::formatv(fileHeader, clDialectName.getValue());
os << llvm::formatv(dialectClassTemplate, clDialectName.getValue());
+
+ if (clDialectName == "builtin")
+ clDialectName = "";
+
for (const llvm::Record *rec : records.getAllDerivedDefinitions("Op")) {
Operator op(rec);
if (op.getDialectName() == clDialectName.getValue())
More information about the Mlir-commits
mailing list