[Mlir-commits] [mlir] 240a9cb - [MLIR][Python] Allow `Attribute` to denote unconstrained attributes in Python-defined ops (#224679)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Sep 25 19:54:06 PDT 2026
Author: Twice
Date: 2026-09-26T10:53:59+08:00
New Revision: 240a9cb75dd9210cae8e987700d0ef6537b723cb
URL: https://github.com/llvm/llvm-project/commit/240a9cb75dd9210cae8e987700d0ef6537b723cb
DIFF: https://github.com/llvm/llvm-project/commit/240a9cb75dd9210cae8e987700d0ef6537b723cb.diff
LOG: [MLIR][Python] Allow `Attribute` to denote unconstrained attributes in Python-defined ops (#224679)
Operation definitions support attribute constraints such as
`IntegerAttr`, `StringAttr`, and `IntegerAttr | StringAttr`, but
currently reject `Attribute` itself.
This change allows `Attribute` to denote an unconstrained attribute,
accepting both built-in and Python-defined attributes:
```python
class MyOp(MyDialect.Operation, name="my_op"):
arg: Operand
attr: Attribute
res: Result
```
This complements the unconstrained `Operand` and `Result` annotations
introduced in #220216. The annotation also works with `attribute()`
field specifiers, including `kw_only` and `default_factory`.
Assisted-by: Codex / GPT6
Added:
Modified:
mlir/python/mlir/dialects/ext.py
mlir/test/python/dialects/ext.py
Removed:
################################################################################
diff --git a/mlir/python/mlir/dialects/ext.py b/mlir/python/mlir/dialects/ext.py
index 491008f86023f..6f00ed4ada9bd 100644
--- a/mlir/python/mlir/dialects/ext.py
+++ b/mlir/python/mlir/dialects/ext.py
@@ -294,6 +294,11 @@ def from_type_hint(name, type_, specifier) -> "FieldDef":
raise TypeError(
f"only `attribute` field specifier can be used for attribute fields"
)
+
+ # `Attribute` denotes an unconstrained attribute.
+ if type_ is Attribute:
+ type_ = Any
+
return AttributeDef(
name,
variadicity,
diff --git a/mlir/test/python/dialects/ext.py b/mlir/test/python/dialects/ext.py
index bbaca38dd130d..5595bbefb0c0d 100644
--- a/mlir/test/python/dialects/ext.py
+++ b/mlir/test/python/dialects/ext.py
@@ -200,6 +200,79 @@ class BareVariadicOp(TestBare.Operation, name="bare_variadic"):
print(len(empty.ins), empty.maybe_in, len(empty.outs), empty.maybe_out)
+# CHECK: TEST: testBareAttribute
+ at run
+def testBareAttribute():
+ class TestBareAttr(Dialect, name="ext_bare_attr"):
+ pass
+
+ class CustomAttr(TestBareAttr.Attribute, name="custom"):
+ value: StringAttr
+
+ class BareOp(TestBareAttr.Operation, name="bare"):
+ lhs: Attribute
+ rhs: Attribute
+
+ class BareSpecifierOp(TestBareAttr.Operation, name="bare_specifier"):
+ a: Attribute = attribute()
+ b: Attribute = attribute(kw_only=True)
+ c: Attribute = attribute(default_factory=lambda: StringAttr.get("default"))
+
+ with Context(), Location.unknown():
+ TestBareAttr.load()
+
+ # CHECK: irdl.dialect @ext_bare_attr {
+ # CHECK: irdl.attribute @custom {
+ # CHECK: %0 = irdl.base "#builtin.string"
+ # CHECK: irdl.parameters(value: %0)
+ # CHECK: }
+ # CHECK: irdl.operation @bare {
+ # CHECK: %0 = irdl.any
+ # CHECK: %1 = irdl.any
+ # CHECK: irdl.attributes {"lhs" = %0, "rhs" = %1}
+ # CHECK: }
+ # CHECK: irdl.operation @bare_specifier {
+ # CHECK: %0 = irdl.any
+ # CHECK: %1 = irdl.any
+ # CHECK: %2 = irdl.any
+ # CHECK: irdl.attributes {"a" = %0, "b" = %1, "c" = %2}
+ # CHECK: }
+ # CHECK: }
+ print(TestBareAttr._mlir_module)
+
+ # CHECK: (self, /, lhs, rhs, *, loc=None, ip=None)
+ print(BareOp.__init__.__signature__)
+ # CHECK: (self, /, a, *, b, c=None, loc=None, ip=None)
+ print(BareSpecifierOp.__init__.__signature__)
+
+ i32 = IntegerType.get_signless(32)
+ iattr = IntegerAttr.get(i32, 42)
+ sattr = StringAttr.get("hello")
+ tattr = TypeAttr.get(i32)
+ custom = CustomAttr.get(sattr)
+ module = Module.create()
+ with InsertionPoint(module.body):
+ bare = BareOp(iattr, sattr)
+ BareOp(sattr, iattr)
+ defaulted = BareSpecifierOp(custom, b=tattr)
+ overridden = BareSpecifierOp(tattr, b=UnitAttr.get(), c=iattr)
+
+ assert module.operation.verify()
+ # CHECK: "ext_bare_attr.bare"() {lhs = 42 : i32, rhs = "hello"} : () -> ()
+ # CHECK: "ext_bare_attr.bare"() {lhs = "hello", rhs = 42 : i32} : () -> ()
+ # CHECK: "ext_bare_attr.bare_specifier"() {a = #ext_bare_attr.custom<"hello">, b = i32, c = "default"} : () -> ()
+ # CHECK: "ext_bare_attr.bare_specifier"() {a = i32, b, c = 42 : i32} : () -> ()
+ print(module)
+
+ # Different bare attributes are constrained independently.
+ # CHECK: 42 : i32 "hello"
+ print(bare.lhs, bare.rhs)
+ # CHECK: #ext_bare_attr.custom<"hello"> i32 "default"
+ print(defaulted.a, defaulted.b, defaulted.c)
+ # CHECK: i32 unit 42 : i32
+ print(overridden.a, overridden.b, overridden.c)
+
+
# CHECK: TEST: testDialectLoadInMultipleContexts
@run
def testDialectLoadInMultipleContexts():
More information about the Mlir-commits
mailing list