xref: /llvm-project/mlir/test/python/dialects/python_test.py (revision 392622d0848b2d0da951d3a4da6fb390a83f812b)
1# RUN: %PYTHON %s pybind11 | FileCheck %s
2# RUN: %PYTHON %s nanobind | FileCheck %s
3
4import sys
5from mlir.ir import *
6import mlir.dialects.func as func
7import mlir.dialects.python_test as test
8import mlir.dialects.tensor as tensor
9import mlir.dialects.arith as arith
10
11if sys.argv[1] == "pybind11":
12    from mlir._mlir_libs._mlirPythonTestPybind11 import (
13        TestAttr,
14        TestType,
15        TestTensorValue,
16        TestIntegerRankedTensorType,
17    )
18
19    test.register_python_test_dialect(get_dialect_registry(), use_nanobind=False)
20elif sys.argv[1] == "nanobind":
21    from mlir._mlir_libs._mlirPythonTestNanobind import (
22        TestAttr,
23        TestType,
24        TestTensorValue,
25        TestIntegerRankedTensorType,
26    )
27
28    test.register_python_test_dialect(get_dialect_registry(), use_nanobind=True)
29else:
30    raise ValueError("Expected pybind11 or nanobind as argument")
31
32
33def run(f):
34    print("\nTEST:", f.__name__)
35    f()
36    return f
37
38
39# CHECK-LABEL: TEST: testAttributes
40@run
41def testAttributes():
42    with Context() as ctx, Location.unknown():
43        #
44        # Check op construction with attributes.
45        #
46
47        i32 = IntegerType.get_signless(32)
48        one = IntegerAttr.get(i32, 1)
49        two = IntegerAttr.get(i32, 2)
50        unit = UnitAttr.get()
51
52        # CHECK: python_test.attributed_op  {
53        # CHECK-DAG: mandatory_i32 = 1 : i32
54        # CHECK-DAG: optional_i32 = 2 : i32
55        # CHECK-DAG: unit
56        # CHECK: }
57        op = test.AttributedOp(one, optional_i32=two, unit=unit)
58        print(f"{op}")
59
60        # CHECK: python_test.attributed_op  {
61        # CHECK: mandatory_i32 = 2 : i32
62        # CHECK: }
63        op2 = test.AttributedOp(two)
64        print(f"{op2}")
65
66        #
67        # Check generic "attributes" access and mutation.
68        #
69
70        assert "additional" not in op.attributes
71
72        # CHECK: python_test.attributed_op  {
73        # CHECK-DAG: additional = 1 : i32
74        # CHECK-DAG: mandatory_i32 = 2 : i32
75        # CHECK: }
76        op2.attributes["additional"] = one
77        print(f"{op2}")
78
79        # CHECK: python_test.attributed_op  {
80        # CHECK-DAG: additional = 2 : i32
81        # CHECK-DAG: mandatory_i32 = 2 : i32
82        # CHECK: }
83        op2.attributes["additional"] = two
84        print(f"{op2}")
85
86        # CHECK: python_test.attributed_op  {
87        # CHECK-NOT: additional = 2 : i32
88        # CHECK:     mandatory_i32 = 2 : i32
89        # CHECK: }
90        del op2.attributes["additional"]
91        print(f"{op2}")
92
93        try:
94            print(op.attributes["additional"])
95        except KeyError:
96            pass
97        else:
98            assert False, "expected KeyError on unknown attribute key"
99
100        #
101        # Check accessors to defined attributes.
102        #
103
104        # CHECK: Mandatory: 1
105        # CHECK: Optional: 2
106        # CHECK: Unit: True
107        print(f"Mandatory: {op.mandatory_i32.value}")
108        print(f"Optional: {op.optional_i32.value}")
109        print(f"Unit: {op.unit}")
110
111        # CHECK: Mandatory: 2
112        # CHECK: Optional: None
113        # CHECK: Unit: False
114        print(f"Mandatory: {op2.mandatory_i32.value}")
115        print(f"Optional: {op2.optional_i32}")
116        print(f"Unit: {op2.unit}")
117
118        # CHECK: Mandatory: 2
119        # CHECK: Optional: None
120        # CHECK: Unit: False
121        op.mandatory_i32 = two
122        op.optional_i32 = None
123        op.unit = False
124        print(f"Mandatory: {op.mandatory_i32.value}")
125        print(f"Optional: {op.optional_i32}")
126        print(f"Unit: {op.unit}")
127        assert "optional_i32" not in op.attributes
128        assert "unit" not in op.attributes
129
130        try:
131            op.mandatory_i32 = None
132        except ValueError:
133            pass
134        else:
135            assert False, "expected ValueError on setting a mandatory attribute to None"
136
137        # CHECK: Optional: 2
138        op.optional_i32 = two
139        print(f"Optional: {op.optional_i32.value}")
140
141        # CHECK: Optional: None
142        del op.optional_i32
143        print(f"Optional: {op.optional_i32}")
144
145        # CHECK: Unit: False
146        op.unit = None
147        print(f"Unit: {op.unit}")
148        assert "unit" not in op.attributes
149
150        # CHECK: Unit: True
151        op.unit = True
152        print(f"Unit: {op.unit}")
153
154        # CHECK: Unit: False
155        del op.unit
156        print(f"Unit: {op.unit}")
157
158
159# CHECK-LABEL: TEST: attrBuilder
160@run
161def attrBuilder():
162    with Context() as ctx, Location.unknown():
163        # CHECK: python_test.attributes_op
164        op = test.AttributesOp(
165            # CHECK-DAG: x_affinemap = affine_map<() -> (2)>
166            x_affinemap=AffineMap.get_constant(2),
167            # CHECK-DAG: x_affinemaparr = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>]
168            x_affinemaparr=[AffineMap.get_identity(3)],
169            # CHECK-DAG: x_arr = [true, "x"]
170            x_arr=[BoolAttr.get(True), StringAttr.get("x")],
171            x_boolarr=[False, True],  # CHECK-DAG: x_boolarr = [false, true]
172            x_bool=True,  # CHECK-DAG: x_bool = true
173            x_dboolarr=[True, False],  # CHECK-DAG: x_dboolarr = array<i1: true, false>
174            x_df16arr=[21, 22],  # CHECK-DAG: x_df16arr = array<i16: 21, 22>
175            # CHECK-DAG: x_df32arr = array<f32: 2.300000e+01, 2.400000e+01>
176            x_df32arr=[23, 24],
177            # CHECK-DAG: x_df64arr = array<f64: 2.500000e+01, 2.600000e+01>
178            x_df64arr=[25, 26],
179            x_di32arr=[0, 1],  # CHECK-DAG: x_di32arr = array<i32: 0, 1>
180            # CHECK-DAG: x_di64arr = array<i64: 1, 2>
181            x_di64arr=[1, 2],
182            x_di8arr=[2, 3],  # CHECK-DAG: x_di8arr = array<i8: 2, 3>
183            # CHECK-DAG: x_dictarr = [{a = false}]
184            x_dictarr=[{"a": BoolAttr.get(False)}],
185            x_dict={"b": BoolAttr.get(True)},  # CHECK-DAG: x_dict = {b = true}
186            x_f32=-2.25,  # CHECK-DAG: x_f32 = -2.250000e+00 : f32
187            # CHECK-DAG: x_f32arr = [2.000000e+00 : f32, 3.000000e+00 : f32]
188            x_f32arr=[2.0, 3.0],
189            x_f64=4.25,  # CHECK-DAG: x_f64 = 4.250000e+00 : f64
190            x_f64arr=[4.0, 8.0],  # CHECK-DAG: x_f64arr = [4.000000e+00, 8.000000e+00]
191            # CHECK-DAG: x_f64elems = dense<[8.000000e+00, 1.600000e+01]> : tensor<2xf64>
192            x_f64elems=[8.0, 16.0],
193            # CHECK-DAG: x_flatsymrefarr = [@symbol1, @symbol2]
194            x_flatsymrefarr=["symbol1", "symbol2"],
195            x_flatsymref="symbol3",  # CHECK-DAG: x_flatsymref = @symbol3
196            x_i1=0,  # CHECK-DAG: x_i1 = false
197            x_i16=42,  # CHECK-DAG: x_i16 = 42 : i16
198            x_i32=6,  # CHECK-DAG: x_i32 = 6 : i32
199            x_i32arr=[4, 5],  # CHECK-DAG: x_i32arr = [4 : i32, 5 : i32]
200            x_i32elems=[5, 6],  # CHECK-DAG: x_i32elems = dense<[5, 6]> : tensor<2xi32>
201            x_i64=9,  # CHECK-DAG: x_i64 = 9 : i64
202            x_i64arr=[7, 8],  # CHECK-DAG: x_i64arr = [7, 8]
203            x_i64elems=[8, 9],  # CHECK-DAG: x_i64elems = dense<[8, 9]> : tensor<2xi64>
204            x_i64svecarr=[10, 11],  # CHECK-DAG: x_i64svecarr = [10, 11]
205            x_i8=11,  # CHECK-DAG: x_i8 = 11 : i8
206            x_idx=10,  # CHECK-DAG: x_idx = 10 : index
207            # CHECK-DAG: x_idxelems = dense<[11, 12]> : tensor<2xindex>
208            x_idxelems=[11, 12],
209            # CHECK-DAG: x_idxlistarr = [{{\[}}13], [14, 15]]
210            x_idxlistarr=[[13], [14, 15]],
211            x_si1=-1,  # CHECK-DAG: x_si1 = -1 : si1
212            x_si16=-2,  # CHECK-DAG: x_si16 = -2 : si16
213            x_si32=-3,  # CHECK-DAG: x_si32 = -3 : si32
214            x_si64=-123,  # CHECK-DAG: x_si64 = -123 : si64
215            x_si8=-4,  # CHECK-DAG: x_si8 = -4 : si8
216            x_strarr=["hello", "world"],  # CHECK-DAG: x_strarr = ["hello", "world"]
217            x_str="hello world!",  # CHECK-DAG: x_str = "hello world!"
218            # CHECK-DAG: x_symrefarr = [@flatsym, @deep::@sym]
219            x_symrefarr=["flatsym", ["deep", "sym"]],
220            x_symref=["deep", "sym2"],  # CHECK-DAG: x_symref = @deep::@sym2
221            x_sym="symbol",  # CHECK-DAG: x_sym = "symbol"
222            x_typearr=[F32Type.get()],  # CHECK-DAG: x_typearr = [f32]
223            x_type=F64Type.get(),  # CHECK-DAG: x_type = f64
224            x_ui1=1,  # CHECK-DAG: x_ui1 = 1 : ui1
225            x_ui16=2,  # CHECK-DAG: x_ui16 = 2 : ui16
226            x_ui32=3,  # CHECK-DAG: x_ui32 = 3 : ui32
227            x_ui64=4,  # CHECK-DAG: x_ui64 = 4 : ui64
228            x_ui8=5,  # CHECK-DAG: x_ui8 = 5 : ui8
229            x_unit=True,  # CHECK-DAG: x_unit
230        )
231        op.verify()
232        op.print(use_local_scope=True)
233
234
235# CHECK-LABEL: TEST: inferReturnTypes
236@run
237def inferReturnTypes():
238    with Context() as ctx, Location.unknown(ctx):
239        module = Module.create()
240        with InsertionPoint(module.body):
241            op = test.InferResultsOp()
242            dummy = test.DummyOp()
243
244        # CHECK: [Type(i32), Type(i64)]
245        iface = InferTypeOpInterface(op)
246        print(iface.inferReturnTypes())
247
248        # CHECK: [Type(i32), Type(i64)]
249        iface_static = InferTypeOpInterface(test.InferResultsOp)
250        print(iface.inferReturnTypes())
251
252        assert isinstance(iface.opview, test.InferResultsOp)
253        assert iface.opview == iface.operation.opview
254
255        try:
256            iface_static.opview
257        except TypeError:
258            pass
259        else:
260            assert False, (
261                "not expected to be able to obtain an opview from a static" " interface"
262            )
263
264        try:
265            InferTypeOpInterface(dummy)
266        except ValueError:
267            pass
268        else:
269            assert False, "not expected dummy op to implement the interface"
270
271        try:
272            InferTypeOpInterface(test.DummyOp)
273        except ValueError:
274            pass
275        else:
276            assert False, "not expected dummy op class to implement the interface"
277
278
279# CHECK-LABEL: TEST: resultTypesDefinedByTraits
280@run
281def resultTypesDefinedByTraits():
282    with Context() as ctx, Location.unknown(ctx):
283        module = Module.create()
284        with InsertionPoint(module.body):
285            inferred = test.InferResultsOp()
286            same = test.SameOperandAndResultTypeOp([inferred.results[0]])
287            # CHECK-COUNT-2: i32
288            print(same.one.type)
289            print(same.two.type)
290
291            first_type_attr = test.FirstAttrDeriveTypeAttrOp(
292                inferred.results[1], TypeAttr.get(IndexType.get())
293            )
294            # CHECK-COUNT-2: index
295            print(first_type_attr.one.type)
296            print(first_type_attr.two.type)
297
298            first_attr = test.FirstAttrDeriveAttrOp(FloatAttr.get(F32Type.get(), 3.14))
299            # CHECK-COUNT-3: f32
300            print(first_attr.one.type)
301            print(first_attr.two.type)
302            print(first_attr.three.type)
303
304            implied = test.InferResultsImpliedOp()
305            # CHECK: i32
306            print(implied.integer.type)
307            # CHECK: f64
308            print(implied.flt.type)
309            # CHECK: index
310            print(implied.index.type)
311
312
313# CHECK-LABEL: TEST: testOptionalOperandOp
314@run
315def testOptionalOperandOp():
316    with Context() as ctx, Location.unknown():
317        module = Module.create()
318        with InsertionPoint(module.body):
319            op1 = test.OptionalOperandOp()
320            # CHECK: op1.input is None: True
321            print(f"op1.input is None: {op1.input is None}")
322
323            op2 = test.OptionalOperandOp(input=op1)
324            # CHECK: op2.input is None: False
325            print(f"op2.input is None: {op2.input is None}")
326
327
328# CHECK-LABEL: TEST: testCustomAttribute
329@run
330def testCustomAttribute():
331    with Context() as ctx, Location.unknown():
332        a = TestAttr.get()
333        # CHECK: #python_test.test_attr
334        print(a)
335
336        # CHECK: python_test.custom_attributed_op  {
337        # CHECK: #python_test.test_attr
338        # CHECK: }
339        op2 = test.CustomAttributedOp(a)
340        print(f"{op2}")
341
342        # CHECK: #python_test.test_attr
343        print(f"{op2.test_attr}")
344
345        # CHECK: TestAttr(#python_test.test_attr)
346        print(repr(op2.test_attr))
347
348        # The following cast must not assert.
349        b = TestAttr(a)
350
351        unit = UnitAttr.get()
352        try:
353            TestAttr(unit)
354        except ValueError as e:
355            assert "Cannot cast attribute to TestAttr" in str(e)
356        else:
357            raise
358
359        # The following must trigger a TypeError from our adaptors and must not
360        # crash.
361        try:
362            TestAttr(42)
363        except TypeError as e:
364            assert "Expected an MLIR object" in str(e)
365        else:
366            raise
367
368        # The following must trigger a TypeError from pybind (therefore, not
369        # checking its message) and must not crash.
370        try:
371            TestAttr(42, 56)
372        except TypeError:
373            pass
374        else:
375            raise
376
377
378@run
379def testCustomType():
380    with Context() as ctx:
381        a = TestType.get()
382        # CHECK: !python_test.test_type
383        print(a)
384
385        # The following cast must not assert.
386        b = TestType(a)
387        # Instance custom types should have typeids
388        assert isinstance(b.typeid, TypeID)
389        # Subclasses of ir.Type should not have a static_typeid
390        # CHECK: 'TestType' object has no attribute 'static_typeid'
391        try:
392            b.static_typeid
393        except AttributeError as e:
394            print(e)
395
396        i8 = IntegerType.get_signless(8)
397        try:
398            TestType(i8)
399        except ValueError as e:
400            assert "Cannot cast type to TestType" in str(e)
401        else:
402            raise
403
404        # The following must trigger a TypeError from our adaptors and must not
405        # crash.
406        try:
407            TestType(42)
408        except TypeError as e:
409            assert "Expected an MLIR object" in str(e)
410        else:
411            raise
412
413        # The following must trigger a TypeError from pybind (therefore, not
414        # checking its message) and must not crash.
415        try:
416            TestType(42, 56)
417        except TypeError:
418            pass
419        else:
420            raise
421
422
423@run
424# CHECK-LABEL: TEST: testTensorValue
425def testTensorValue():
426    with Context() as ctx, Location.unknown():
427        i8 = IntegerType.get_signless(8)
428
429        class Tensor(TestTensorValue):
430            def __str__(self):
431                return super().__str__().replace("Value", "Tensor")
432
433        module = Module.create()
434        with InsertionPoint(module.body):
435            t = tensor.EmptyOp([10, 10], i8).result
436
437            # CHECK: Value(%{{.*}} = tensor.empty() : tensor<10x10xi8>)
438            print(Value(t))
439
440            tt = Tensor(t)
441            # CHECK: Tensor(%{{.*}} = tensor.empty() : tensor<10x10xi8>)
442            print(tt)
443
444            # CHECK: False
445            print(tt.is_null())
446
447            # Classes of custom types that inherit from concrete types should have
448            # static_typeid
449            assert isinstance(TestIntegerRankedTensorType.static_typeid, TypeID)
450            # And it should be equal to the in-tree concrete type
451            assert TestIntegerRankedTensorType.static_typeid == t.type.typeid
452
453            d = tensor.EmptyOp([1, 2, 3], IntegerType.get_signless(5)).result
454            # CHECK: Value(%{{.*}} = tensor.empty() : tensor<1x2x3xi5>)
455            print(d)
456            # CHECK: TestTensorValue
457            print(repr(d))
458
459
460# CHECK-LABEL: TEST: inferReturnTypeComponents
461@run
462def inferReturnTypeComponents():
463    with Context() as ctx, Location.unknown(ctx):
464        module = Module.create()
465        i32 = IntegerType.get_signless(32)
466        with InsertionPoint(module.body):
467            resultType = UnrankedTensorType.get(i32)
468            operandTypes = [
469                RankedTensorType.get([1, 3, 10, 10], i32),
470                UnrankedTensorType.get(i32),
471            ]
472            f = func.FuncOp(
473                "test_inferReturnTypeComponents", (operandTypes, [resultType])
474            )
475            entry_block = Block.create_at_start(f.operation.regions[0], operandTypes)
476            with InsertionPoint(entry_block):
477                ranked_op = test.InferShapedTypeComponentsOp(
478                    resultType, entry_block.arguments[0]
479                )
480                unranked_op = test.InferShapedTypeComponentsOp(
481                    resultType, entry_block.arguments[1]
482                )
483
484        # CHECK: has rank: True
485        # CHECK: rank: 4
486        # CHECK: element type: i32
487        # CHECK: shape: [1, 3, 10, 10]
488        iface = InferShapedTypeOpInterface(ranked_op)
489        shaped_type_components = iface.inferReturnTypeComponents(
490            operands=[ranked_op.operand]
491        )[0]
492        print("has rank:", shaped_type_components.has_rank)
493        print("rank:", shaped_type_components.rank)
494        print("element type:", shaped_type_components.element_type)
495        print("shape:", shaped_type_components.shape)
496
497        # CHECK: has rank: False
498        # CHECK: rank: None
499        # CHECK: element type: i32
500        # CHECK: shape: None
501        iface = InferShapedTypeOpInterface(unranked_op)
502        shaped_type_components = iface.inferReturnTypeComponents(
503            operands=[unranked_op.operand]
504        )[0]
505        print("has rank:", shaped_type_components.has_rank)
506        print("rank:", shaped_type_components.rank)
507        print("element type:", shaped_type_components.element_type)
508        print("shape:", shaped_type_components.shape)
509
510
511# CHECK-LABEL: TEST: testCustomTypeTypeCaster
512@run
513def testCustomTypeTypeCaster():
514    with Context() as ctx, Location.unknown():
515        a = TestType.get()
516        assert a.typeid is not None
517
518        b = Type.parse("!python_test.test_type")
519        # CHECK: !python_test.test_type
520        print(b)
521        # CHECK: TestType(!python_test.test_type)
522        print(repr(b))
523
524        c = TestIntegerRankedTensorType.get([10, 10], 5)
525        # CHECK: tensor<10x10xi5>
526        print(c)
527        # CHECK: TestIntegerRankedTensorType(tensor<10x10xi5>)
528        print(repr(c))
529
530        # CHECK: Type caster is already registered
531        try:
532
533            @register_type_caster(c.typeid)
534            def type_caster(pytype):
535                return TestIntegerRankedTensorType(pytype)
536
537        except RuntimeError as e:
538            print(e)
539
540        # python_test dialect registers a caster for RankedTensorType in its extension (pybind) module.
541        # So this one replaces that one (successfully). And then just to be sure we restore the original caster below.
542        @register_type_caster(c.typeid, replace=True)
543        def type_caster(pytype):
544            return RankedTensorType(pytype)
545
546        d = tensor.EmptyOp([10, 10], IntegerType.get_signless(5)).result
547        # CHECK: tensor<10x10xi5>
548        print(d.type)
549        # CHECK: ranked tensor type RankedTensorType(tensor<10x10xi5>)
550        print("ranked tensor type", repr(d.type))
551
552        @register_type_caster(c.typeid, replace=True)
553        def type_caster(pytype):
554            return TestIntegerRankedTensorType(pytype)
555
556        d = tensor.EmptyOp([10, 10], IntegerType.get_signless(5)).result
557        # CHECK: tensor<10x10xi5>
558        print(d.type)
559        # CHECK: TestIntegerRankedTensorType(tensor<10x10xi5>)
560        print(repr(d.type))
561
562
563# CHECK-LABEL: TEST: testInferTypeOpInterface
564@run
565def testInferTypeOpInterface():
566    with Context() as ctx, Location.unknown(ctx):
567        module = Module.create()
568        with InsertionPoint(module.body):
569            i64 = IntegerType.get_signless(64)
570            zero = arith.ConstantOp(i64, 0)
571
572            one_operand = test.InferResultsVariadicInputsOp(single=zero, doubled=None)
573            # CHECK: i32
574            print(one_operand.result.type)
575
576            two_operands = test.InferResultsVariadicInputsOp(single=zero, doubled=zero)
577            # CHECK: f32
578            print(two_operands.result.type)
579
580
581# CHECK-LABEL: TEST: testVariadicOperandAccess
582@run
583def testVariadicOperandAccess():
584    def values(lst):
585        return [str(e) for e in lst]
586
587    with Context() as ctx, Location.unknown(ctx):
588        module = Module.create()
589        with InsertionPoint(module.body):
590            i32 = IntegerType.get_signless(32)
591            zero = arith.ConstantOp(i32, 0)
592            one = arith.ConstantOp(i32, 1)
593            two = arith.ConstantOp(i32, 2)
594            three = arith.ConstantOp(i32, 3)
595            four = arith.ConstantOp(i32, 4)
596
597            variadic_operands = test.SameVariadicOperandSizeOp(
598                [zero, one], two, [three, four]
599            )
600            # CHECK: Value(%{{.*}} = arith.constant 2 : i32)
601            print(variadic_operands.non_variadic)
602            # CHECK: ['Value(%{{.*}} = arith.constant 0 : i32)', 'Value(%{{.*}} = arith.constant 1 : i32)']
603            print(values(variadic_operands.variadic1))
604            # CHECK: ['Value(%{{.*}} = arith.constant 3 : i32)', 'Value(%{{.*}} = arith.constant 4 : i32)']
605            print(values(variadic_operands.variadic2))
606
607
608# CHECK-LABEL: TEST: testVariadicResultAccess
609@run
610def testVariadicResultAccess():
611    def types(lst):
612        return [e.type for e in lst]
613
614    with Context() as ctx, Location.unknown(ctx):
615        module = Module.create()
616        with InsertionPoint(module.body):
617            i = [IntegerType.get_signless(k) for k in range(7)]
618
619            # Test Variadic-Fixed-Variadic
620            op = test.SameVariadicResultSizeOpVFV([i[0], i[1]], i[2], [i[3], i[4]])
621            # CHECK: i2
622            print(op.non_variadic.type)
623            # CHECK: [IntegerType(i0), IntegerType(i1)]
624            print(types(op.variadic1))
625            # CHECK: [IntegerType(i3), IntegerType(i4)]
626            print(types(op.variadic2))
627
628            #  Test Variadic-Variadic-Variadic
629            op = test.SameVariadicResultSizeOpVVV(
630                [i[0], i[1]], [i[2], i[3]], [i[4], i[5]]
631            )
632            # CHECK: [IntegerType(i0), IntegerType(i1)]
633            print(types(op.variadic1))
634            # CHECK: [IntegerType(i2), IntegerType(i3)]
635            print(types(op.variadic2))
636            # CHECK: [IntegerType(i4), IntegerType(i5)]
637            print(types(op.variadic3))
638
639            #  Test Fixed-Fixed-Variadic
640            op = test.SameVariadicResultSizeOpFFV(i[0], i[1], [i[2], i[3], i[4]])
641            # CHECK: i0
642            print(op.non_variadic1.type)
643            # CHECK: i1
644            print(op.non_variadic2.type)
645            # CHECK: [IntegerType(i2), IntegerType(i3), IntegerType(i4)]
646            print(types(op.variadic))
647
648            #  Test Variadic-Variadic-Fixed
649            op = test.SameVariadicResultSizeOpVVF(
650                [i[0], i[1], i[2]], [i[3], i[4], i[5]], i[6]
651            )
652            # CHECK: [IntegerType(i0), IntegerType(i1), IntegerType(i2)]
653            print(types(op.variadic1))
654            # CHECK: [IntegerType(i3), IntegerType(i4), IntegerType(i5)]
655            print(types(op.variadic2))
656            # CHECK: i6
657            print(op.non_variadic.type)
658
659            # Test Fixed-Variadic-Fixed-Variadic-Fixed
660            op = test.SameVariadicResultSizeOpFVFVF(
661                i[0], [i[1], i[2]], i[3], [i[4], i[5]], i[6]
662            )
663            # CHECK: i0
664            print(op.non_variadic1.type)
665            # CHECK: [IntegerType(i1), IntegerType(i2)]
666            print(types(op.variadic1))
667            # CHECK: i3
668            print(op.non_variadic2.type)
669            # CHECK: [IntegerType(i4), IntegerType(i5)]
670            print(types(op.variadic2))
671            # CHECK: i6
672            print(op.non_variadic3.type)
673
674            # Test Fixed-Variadic-Fixed-Variadic-Fixed - Variadic group size 0
675            op = test.SameVariadicResultSizeOpFVFVF(i[0], [], i[1], [], i[2])
676            # CHECK: i0
677            print(op.non_variadic1.type)
678            # CHECK: []
679            print(types(op.variadic1))
680            # CHECK: i1
681            print(op.non_variadic2.type)
682            # CHECK: []
683            print(types(op.variadic2))
684            # CHECK: i2
685            print(op.non_variadic3.type)
686
687            # Test Fixed-Variadic-Fixed-Variadic-Fixed - Variadic group size 1
688            op = test.SameVariadicResultSizeOpFVFVF(i[0], [i[1]], i[2], [i[3]], i[4])
689            # CHECK: i0
690            print(op.non_variadic1.type)
691            # CHECK: [IntegerType(i1)]
692            print(types(op.variadic1))
693            # CHECK: i2
694            print(op.non_variadic2.type)
695            # CHECK: [IntegerType(i3)]
696            print(types(op.variadic2))
697            # CHECK: i4
698            print(op.non_variadic3.type)
699