[Mlir-commits] [mlir] [MLIR][Python] Support op adaptor for Python-defined operations (PR #183528)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Feb 26 06:12:07 PST 2026
https://github.com/PragmaTwice created https://github.com/llvm/llvm-project/pull/183528
Previously, in #177782, we added support for dialect conversion and generated an `OpAdaptor` subtype for every ODS-defined operation. In this PR, we will also generate `OpAdaptor` subtypes for Python-defined operations, so that they can be applied in dialect conversion as well.
>From d95cc8dc9491efa5e253ddbc1e764318d5854467 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Thu, 26 Feb 2026 22:07:07 +0800
Subject: [PATCH 1/2] [MLIR][Python] Support op adaptor for Python-defined
operations
---
mlir/python/mlir/dialects/ext.py | 50 +++++++++++++++++++++++++++++++-
mlir/test/python/dialects/ext.py | 8 +++++
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/mlir/python/mlir/dialects/ext.py b/mlir/python/mlir/dialects/ext.py
index 39aacf32dabb9..d88e25cced8f6 100644
--- a/mlir/python/mlir/dialects/ext.py
+++ b/mlir/python/mlir/dialects/ext.py
@@ -41,7 +41,17 @@
Region = ir.Region
register_dialect = _cext.register_dialect
-register_operation = _cext.register_operation
+
+
+def register_operation(dialect_cls: type) -> Callable[[type], type]:
+ register = _cext.register_operation(dialect_cls)
+
+ def decorator(op_cls: type) -> type:
+ register(op_cls)
+ _cext.register_op_adaptor(op_cls)(op_cls.Adaptor)
+ return op_cls
+
+ return decorator
def construct_instance(origin, args):
@@ -307,6 +317,13 @@ def __init_subclass__(
cls._generate_result_properties(results)
cls._generate_region_properties(regions)
+ cls.Adaptor = type(
+ "Adaptor",
+ (OperationAdator,),
+ dict(),
+ operation=cls,
+ )
+
dialect_obj.operations.append(cls)
@staticmethod
@@ -507,6 +524,37 @@ def _emit_operation(cls) -> None:
)
+class OperationAdator(ir.OpAdaptor):
+ @classmethod
+ def __init_subclass__(cls, *, operation: type):
+ cls.OPERATION_NAME = operation.OPERATION_NAME
+ cls._operation_cls = operation
+
+ operands, attrs, results, regions = partition_fields(operation._fields)
+
+ for attr in attrs:
+ setattr(
+ cls,
+ attr.name,
+ property(lambda self, name=attr.name: self.attributes[name]),
+ )
+
+ for i, operand in enumerate(operands):
+ if operation._ODS_OPERAND_SEGMENTS:
+
+ def getter(self, i=i, operand=operand):
+ operand_range = segmented_accessor(
+ self.operands,
+ self.attributes["operandSegmentSizes"],
+ i,
+ )
+ return normalize_value_range(operand_range, operand.variadicity)
+
+ setattr(cls, operand.name, property(getter))
+ else:
+ setattr(cls, operand.name, property(lambda self, i=i: self.operands[i]))
+
+
@dataclass
class ParamDef:
name: str
diff --git a/mlir/test/python/dialects/ext.py b/mlir/test/python/dialects/ext.py
index f9252bad37a39..5b3f9d8416517 100644
--- a/mlir/test/python/dialects/ext.py
+++ b/mlir/test/python/dialects/ext.py
@@ -91,6 +91,14 @@ class AddOp(Operation, dialect=MyInt, name="add"):
# CHECK: (self, /, value, *, loc=None, ip=None)
print(ConstantOp.__init__.__signature__)
+ # CHECK: True
+ print(issubclass(AddOp.Adaptor, OpAdaptor))
+ adaptor1 = AddOp.Adaptor(list(add1.operands), add1)
+ # CHECK: OpResult(%0 = "myint.constant"() {value = 2 : i32} : () -> i32)
+ print(adaptor1.lhs)
+ # CHECK: OpResult(%1 = "myint.constant"() {value = 3 : i32} : () -> i32)
+ print(adaptor1.rhs)
+
# CHECK: TEST: testExtDialect
@run
>From 5a5b254f50eb3e7756e057297eacc5b9855f72f8 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Thu, 26 Feb 2026 22:08:43 +0800
Subject: [PATCH 2/2] append
---
mlir/test/python/dialects/ext.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mlir/test/python/dialects/ext.py b/mlir/test/python/dialects/ext.py
index 5b3f9d8416517..2921615e75d54 100644
--- a/mlir/test/python/dialects/ext.py
+++ b/mlir/test/python/dialects/ext.py
@@ -94,6 +94,8 @@ class AddOp(Operation, dialect=MyInt, name="add"):
# CHECK: True
print(issubclass(AddOp.Adaptor, OpAdaptor))
adaptor1 = AddOp.Adaptor(list(add1.operands), add1)
+ # CHECK: myint.add
+ print(adaptor1.OPERATION_NAME)
# CHECK: OpResult(%0 = "myint.constant"() {value = 2 : i32} : () -> i32)
print(adaptor1.lhs)
# CHECK: OpResult(%1 = "myint.constant"() {value = 3 : i32} : () -> i32)
More information about the Mlir-commits
mailing list