When multiple dialects share td `#includes` (e.g. `affine` includes
`arith`), each dialect's `*_enum_gen.py` file registers attribute
builders under the same keys, causing "already registered" errors on the
second import; the first commit checks in such a case which currently
fails on main:
```
# | RuntimeError: Attribute builder for 'Arith_CmpFPredicateAttr' is already registered with func: <function _arith_cmpfpredicateattr at 0x78d13cbe9a80>
```
This PR implements a two-pronged fix:
1. Add `allow_existing=True` to `register_attribute_builder` (and the
underlying C++ `registerAttributeBuilder`). When set, silently skips
registration if the key already exists (first-wins semantics). This
handles `EnumInfo`-based builders which have no dialect prefix (e.g.
`AtomicRMWKindAttr`, `Arith_CmpFPredicateAttr`), which may be emitted by
every dialect whose td file includes the defining file;
2. Filter `EnumAttr` builders by `-bind-dialect` in
`EnumPythonBindingGen.cpp` and register them under dialect qualified
keys (`"dialect.AttrName"`). Update `OpPythonBindingGen.cpp` to look up
the same qualified keys for EnumAttr typed op attributes (detected via
`isSubClassOf("EnumAttr")`). Pass `-bind-dialect` from
`AddMLIRPython.cmake`.
This approach incurs no changes to `ir.py` registrations (no "builtin."
prefix), and no manual builder additions to individual dialect Python
files (unlike the previous attempt
https://github.com/llvm/llvm-project/pull/117918).
Note, this PR was "clauded" not "coded".
236 lines
5.5 KiB
Python
236 lines
5.5 KiB
Python
# RUN: %PYTHON %s | FileCheck %s
|
|
|
|
from mlir.ir import *
|
|
from mlir.dialects import index, arith
|
|
|
|
|
|
def run(f):
|
|
print("\nTEST:", f.__name__)
|
|
with Context() as ctx, Location.unknown():
|
|
module = Module.create()
|
|
with InsertionPoint(module.body):
|
|
f(ctx)
|
|
print(module)
|
|
|
|
|
|
# CHECK-LABEL: TEST: testConstantOp
|
|
@run
|
|
def testConstantOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
# CHECK: %{{.*}} = index.constant 42
|
|
|
|
|
|
# CHECK-LABEL: TEST: testBoolConstantOp
|
|
@run
|
|
def testBoolConstantOp(ctx):
|
|
a = index.BoolConstantOp(value=True)
|
|
# CHECK: %{{.*}} = index.bool.constant true
|
|
|
|
|
|
# CHECK-LABEL: TEST: testAndOp
|
|
@run
|
|
def testAndOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.AndOp(a, a)
|
|
# CHECK: %{{.*}} = index.and %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testOrOp
|
|
@run
|
|
def testOrOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.OrOp(a, a)
|
|
# CHECK: %{{.*}} = index.or %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testXOrOp
|
|
@run
|
|
def testXOrOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.XOrOp(a, a)
|
|
# CHECK: %{{.*}} = index.xor %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testCastSOp
|
|
@run
|
|
def testCastSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = arith.ConstantOp(value=23, result=IntegerType.get_signless(64))
|
|
c = index.CastSOp(input=a, output=IntegerType.get_signless(32))
|
|
d = index.CastSOp(input=b, output=IndexType.get())
|
|
# CHECK: %{{.*}} = index.casts %{{.*}} : index to i32
|
|
# CHECK: %{{.*}} = index.casts %{{.*}} : i64 to index
|
|
|
|
|
|
# CHECK-LABEL: TEST: testCastUOp
|
|
@run
|
|
def testCastUOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = arith.ConstantOp(value=23, result=IntegerType.get_signless(64))
|
|
c = index.CastUOp(input=a, output=IntegerType.get_signless(32))
|
|
d = index.CastUOp(input=b, output=IndexType.get())
|
|
# CHECK: %{{.*}} = index.castu %{{.*}} : index to i32
|
|
# CHECK: %{{.*}} = index.castu %{{.*}} : i64 to index
|
|
|
|
|
|
# CHECK-LABEL: TEST: testCeilDivSOp
|
|
@run
|
|
def testCeilDivSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.CeilDivSOp(a, a)
|
|
# CHECK: %{{.*}} = index.ceildivs %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testCeilDivUOp
|
|
@run
|
|
def testCeilDivUOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.CeilDivUOp(a, a)
|
|
# CHECK: %{{.*}} = index.ceildivu %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testCmpOp
|
|
@run
|
|
def testCmpOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=23)
|
|
pred = AttrBuilder.get("index.IndexCmpPredicateAttr")("slt", context=ctx)
|
|
r = index.CmpOp(pred, lhs=a, rhs=b)
|
|
# CHECK: %{{.*}} = index.cmp slt(%{{.*}}, %{{.*}})
|
|
|
|
|
|
# CHECK-LABEL: TEST: testAddOp
|
|
@run
|
|
def testAddOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.AddOp(a, a)
|
|
# CHECK: %{{.*}} = index.add %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testSubOp
|
|
@run
|
|
def testSubOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.SubOp(a, a)
|
|
# CHECK: %{{.*}} = index.sub %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testMulOp
|
|
@run
|
|
def testMulOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.MulOp(a, a)
|
|
# CHECK: %{{.*}} = index.mul %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testDivSOp
|
|
@run
|
|
def testDivSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.DivSOp(a, a)
|
|
# CHECK: %{{.*}} = index.divs %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testDivUOp
|
|
@run
|
|
def testDivUOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.DivUOp(a, a)
|
|
# CHECK: %{{.*}} = index.divu %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testFloorDivSOp
|
|
@run
|
|
def testFloorDivSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
r = index.FloorDivSOp(a, a)
|
|
# CHECK: %{{.*}} = index.floordivs %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testMaxSOp
|
|
@run
|
|
def testMaxSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=23)
|
|
r = index.MaxSOp(a, b)
|
|
# CHECK: %{{.*}} = index.maxs %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testMaxUOp
|
|
@run
|
|
def testMaxUOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=23)
|
|
r = index.MaxUOp(a, b)
|
|
# CHECK: %{{.*}} = index.maxu %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testMinSOp
|
|
@run
|
|
def testMinSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=23)
|
|
r = index.MinSOp(a, b)
|
|
# CHECK: %{{.*}} = index.mins %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testMinUOp
|
|
@run
|
|
def testMinUOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=23)
|
|
r = index.MinUOp(a, b)
|
|
# CHECK: %{{.*}} = index.minu %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testRemSOp
|
|
@run
|
|
def testRemSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=23)
|
|
r = index.RemSOp(a, b)
|
|
# CHECK: %{{.*}} = index.rems %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testRemUOp
|
|
@run
|
|
def testRemUOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=23)
|
|
r = index.RemUOp(a, b)
|
|
# CHECK: %{{.*}} = index.remu %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testShlOp
|
|
@run
|
|
def testShlOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=3)
|
|
r = index.ShlOp(a, b)
|
|
# CHECK: %{{.*}} = index.shl %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testShrSOp
|
|
@run
|
|
def testShrSOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=3)
|
|
r = index.ShrSOp(a, b)
|
|
# CHECK: %{{.*}} = index.shrs %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testShrUOp
|
|
@run
|
|
def testShrUOp(ctx):
|
|
a = index.ConstantOp(value=42)
|
|
b = index.ConstantOp(value=3)
|
|
r = index.ShrUOp(a, b)
|
|
# CHECK: %{{.*}} = index.shru %{{.*}}, %{{.*}}
|
|
|
|
|
|
# CHECK-LABEL: TEST: testSizeOfOp
|
|
@run
|
|
def testSizeOfOp(ctx):
|
|
r = index.SizeOfOp()
|
|
# CHECK: %{{.*}} = index.sizeof
|