19f3f6d7bSStella Laurenzo# RUN: %PYTHON %s | FileCheck %s
29f3f6d7bSStella Laurenzo
39f3f6d7bSStella Laurenzofrom mlir.ir import *
49f3f6d7bSStella Laurenzoimport mlir.dialects.builtin as builtin
59f3f6d7bSStella Laurenzoimport mlir.dialects.std as std
69f3f6d7bSStella Laurenzo
79f3f6d7bSStella Laurenzo
89f3f6d7bSStella Laurenzodef run(f):
99f3f6d7bSStella Laurenzo  print("\nTEST:", f.__name__)
109f3f6d7bSStella Laurenzo  f()
119f3f6d7bSStella Laurenzo  return f
129f3f6d7bSStella Laurenzo
139f3f6d7bSStella Laurenzo
149f3f6d7bSStella Laurenzo# CHECK-LABEL: TEST: testFromPyFunc
159f3f6d7bSStella Laurenzo@run
169f3f6d7bSStella Laurenzodef testFromPyFunc():
179f3f6d7bSStella Laurenzo  with Context() as ctx, Location.unknown() as loc:
18f431d387SMehdi Amini    ctx.allow_unregistered_dialects = True
199f3f6d7bSStella Laurenzo    m = builtin.ModuleOp()
209f3f6d7bSStella Laurenzo    f32 = F32Type.get()
219f3f6d7bSStella Laurenzo    f64 = F64Type.get()
229f3f6d7bSStella Laurenzo    with InsertionPoint(m.body):
239f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @unary_return(%arg0: f64) -> f64
249f3f6d7bSStella Laurenzo      # CHECK: return %arg0 : f64
259f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f64)
269f3f6d7bSStella Laurenzo      def unary_return(a):
279f3f6d7bSStella Laurenzo        return a
289f3f6d7bSStella Laurenzo
299f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @binary_return(%arg0: f32, %arg1: f64) -> (f32, f64)
309f3f6d7bSStella Laurenzo      # CHECK: return %arg0, %arg1 : f32, f64
319f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
329f3f6d7bSStella Laurenzo      def binary_return(a, b):
339f3f6d7bSStella Laurenzo        return a, b
349f3f6d7bSStella Laurenzo
359f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @none_return(%arg0: f32, %arg1: f64)
369f3f6d7bSStella Laurenzo      # CHECK: return
379f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
389f3f6d7bSStella Laurenzo      def none_return(a, b):
399f3f6d7bSStella Laurenzo        pass
409f3f6d7bSStella Laurenzo
419f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @call_unary
429f3f6d7bSStella Laurenzo      # CHECK: %0 = call @unary_return(%arg0) : (f64) -> f64
439f3f6d7bSStella Laurenzo      # CHECK: return %0 : f64
449f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f64)
459f3f6d7bSStella Laurenzo      def call_unary(a):
469f3f6d7bSStella Laurenzo        return unary_return(a)
479f3f6d7bSStella Laurenzo
489f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @call_binary
499f3f6d7bSStella Laurenzo      # CHECK: %0:2 = call @binary_return(%arg0, %arg1) : (f32, f64) -> (f32, f64)
509f3f6d7bSStella Laurenzo      # CHECK: return %0#0, %0#1 : f32, f64
519f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
529f3f6d7bSStella Laurenzo      def call_binary(a, b):
539f3f6d7bSStella Laurenzo        return binary_return(a, b)
549f3f6d7bSStella Laurenzo
55f431d387SMehdi Amini      # We expect coercion of a single result operation to a returned value.
56f431d387SMehdi Amini      # CHECK-LABEL: func @single_result_op
57f431d387SMehdi Amini      # CHECK: %0 = "custom.op1"() : () -> f32
58f431d387SMehdi Amini      # CHECK: return %0 : f32
59f431d387SMehdi Amini      @builtin.FuncOp.from_py_func()
60f431d387SMehdi Amini      def single_result_op():
61f431d387SMehdi Amini        return Operation.create("custom.op1", results=[f32])
62f431d387SMehdi Amini
639f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @call_none
649f3f6d7bSStella Laurenzo      # CHECK: call @none_return(%arg0, %arg1) : (f32, f64) -> ()
659f3f6d7bSStella Laurenzo      # CHECK: return
669f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
679f3f6d7bSStella Laurenzo      def call_none(a, b):
689f3f6d7bSStella Laurenzo        return none_return(a, b)
699f3f6d7bSStella Laurenzo
709f3f6d7bSStella Laurenzo      ## Variants and optional feature tests.
719f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @from_name_arg
729f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64, name="from_name_arg")
739f3f6d7bSStella Laurenzo      def explicit_name(a, b):
749f3f6d7bSStella Laurenzo        return b
759f3f6d7bSStella Laurenzo
769f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
779f3f6d7bSStella Laurenzo      def positional_func_op(a, b, func_op):
789f3f6d7bSStella Laurenzo        assert isinstance(func_op, builtin.FuncOp)
799f3f6d7bSStella Laurenzo        return b
809f3f6d7bSStella Laurenzo
819f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
829f3f6d7bSStella Laurenzo      def kw_func_op(a, b=None, func_op=None):
839f3f6d7bSStella Laurenzo        assert isinstance(func_op, builtin.FuncOp)
849f3f6d7bSStella Laurenzo        return b
859f3f6d7bSStella Laurenzo
869f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
879f3f6d7bSStella Laurenzo      def kwargs_func_op(a, b=None, **kwargs):
889f3f6d7bSStella Laurenzo        assert isinstance(kwargs["func_op"], builtin.FuncOp)
899f3f6d7bSStella Laurenzo        return b
909f3f6d7bSStella Laurenzo
919f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @explicit_results(%arg0: f32, %arg1: f64) -> f64
929f3f6d7bSStella Laurenzo      # CHECK: return %arg1 : f64
939f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64, results=[f64])
949f3f6d7bSStella Laurenzo      def explicit_results(a, b):
959f3f6d7bSStella Laurenzo        std.ReturnOp([b])
969f3f6d7bSStella Laurenzo
979f3f6d7bSStella Laurenzo  print(m)
989f3f6d7bSStella Laurenzo
999f3f6d7bSStella Laurenzo
1009f3f6d7bSStella Laurenzo# CHECK-LABEL: TEST: testFromPyFuncErrors
1019f3f6d7bSStella Laurenzo@run
1029f3f6d7bSStella Laurenzodef testFromPyFuncErrors():
1039f3f6d7bSStella Laurenzo  with Context() as ctx, Location.unknown() as loc:
1049f3f6d7bSStella Laurenzo    m = builtin.ModuleOp()
1059f3f6d7bSStella Laurenzo    f32 = F32Type.get()
1069f3f6d7bSStella Laurenzo    f64 = F64Type.get()
1079f3f6d7bSStella Laurenzo    with InsertionPoint(m.body):
1089f3f6d7bSStella Laurenzo      try:
1099f3f6d7bSStella Laurenzo
1109f3f6d7bSStella Laurenzo        @builtin.FuncOp.from_py_func(f64, results=[f64])
1119f3f6d7bSStella Laurenzo        def unary_return(a):
1129f3f6d7bSStella Laurenzo          return a
1139f3f6d7bSStella Laurenzo      except AssertionError as e:
1149f3f6d7bSStella Laurenzo        # CHECK: Capturing a python function with explicit `results=` requires that the wrapped function returns None.
1159f3f6d7bSStella Laurenzo        print(e)
1169f3f6d7bSStella Laurenzo
1179f3f6d7bSStella Laurenzo
1189f3f6d7bSStella Laurenzo# CHECK-LABEL: TEST: testBuildFuncOp
1199f3f6d7bSStella Laurenzo@run
1209f3f6d7bSStella Laurenzodef testBuildFuncOp():
1219f3f6d7bSStella Laurenzo  ctx = Context()
1229f3f6d7bSStella Laurenzo  with Location.unknown(ctx) as loc:
1239f3f6d7bSStella Laurenzo    m = builtin.ModuleOp()
1249f3f6d7bSStella Laurenzo
1259f3f6d7bSStella Laurenzo    f32 = F32Type.get()
1269f3f6d7bSStella Laurenzo    tensor_type = RankedTensorType.get((2, 3, 4), f32)
1279f3f6d7bSStella Laurenzo    with InsertionPoint.at_block_begin(m.body):
1289f3f6d7bSStella Laurenzo      func = builtin.FuncOp(name="some_func",
1299f3f6d7bSStella Laurenzo                            type=FunctionType.get(
1309f3f6d7bSStella Laurenzo                                inputs=[tensor_type, tensor_type],
1319f3f6d7bSStella Laurenzo                                results=[tensor_type]),
1329f3f6d7bSStella Laurenzo                            visibility="nested")
1339f3f6d7bSStella Laurenzo      # CHECK: Name is: "some_func"
1349f3f6d7bSStella Laurenzo      print("Name is: ", func.name)
1359f3f6d7bSStella Laurenzo
1369f3f6d7bSStella Laurenzo      # CHECK: Type is: (tensor<2x3x4xf32>, tensor<2x3x4xf32>) -> tensor<2x3x4xf32>
1379f3f6d7bSStella Laurenzo      print("Type is: ", func.type)
1389f3f6d7bSStella Laurenzo
1399f3f6d7bSStella Laurenzo      # CHECK: Visibility is: "nested"
1409f3f6d7bSStella Laurenzo      print("Visibility is: ", func.visibility)
1419f3f6d7bSStella Laurenzo
1429f3f6d7bSStella Laurenzo      try:
1439f3f6d7bSStella Laurenzo        entry_block = func.entry_block
1449f3f6d7bSStella Laurenzo      except IndexError as e:
1459f3f6d7bSStella Laurenzo        # CHECK: External function does not have a body
1469f3f6d7bSStella Laurenzo        print(e)
1479f3f6d7bSStella Laurenzo
1489f3f6d7bSStella Laurenzo      with InsertionPoint(func.add_entry_block()):
1499f3f6d7bSStella Laurenzo        std.ReturnOp([func.entry_block.arguments[0]])
1509f3f6d7bSStella Laurenzo        pass
1519f3f6d7bSStella Laurenzo
1529f3f6d7bSStella Laurenzo      try:
1539f3f6d7bSStella Laurenzo        func.add_entry_block()
1549f3f6d7bSStella Laurenzo      except IndexError as e:
1559f3f6d7bSStella Laurenzo        # CHECK: The function already has an entry block!
1569f3f6d7bSStella Laurenzo        print(e)
1579f3f6d7bSStella Laurenzo
1589f3f6d7bSStella Laurenzo      # Try the callback builder and passing type as tuple.
1599f3f6d7bSStella Laurenzo      func = builtin.FuncOp(name="some_other_func",
1609f3f6d7bSStella Laurenzo                            type=([tensor_type, tensor_type], [tensor_type]),
1619f3f6d7bSStella Laurenzo                            visibility="nested",
1629f3f6d7bSStella Laurenzo                            body_builder=lambda func: std.ReturnOp(
1639f3f6d7bSStella Laurenzo                                [func.entry_block.arguments[0]]))
1649f3f6d7bSStella Laurenzo
1659f3f6d7bSStella Laurenzo  # CHECK: module  {
1669f3f6d7bSStella Laurenzo  # CHECK:  func nested @some_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
1679f3f6d7bSStella Laurenzo  # CHECK:   return %arg0 : tensor<2x3x4xf32>
1689f3f6d7bSStella Laurenzo  # CHECK:  }
1699f3f6d7bSStella Laurenzo  # CHECK:  func nested @some_other_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
1709f3f6d7bSStella Laurenzo  # CHECK:   return %arg0 : tensor<2x3x4xf32>
1719f3f6d7bSStella Laurenzo  # CHECK:  }
1729f3f6d7bSStella Laurenzo  print(m)
173afeda4b9SAlex Zinenko
174afeda4b9SAlex Zinenko
175afeda4b9SAlex Zinenko# CHECK-LABEL: TEST: testFuncArgumentAccess
176afeda4b9SAlex Zinenko@run
177afeda4b9SAlex Zinenkodef testFuncArgumentAccess():
178*ace1d0adSStella Laurenzo  with Context() as ctx, Location.unknown():
179*ace1d0adSStella Laurenzo    ctx.allow_unregistered_dialects = True
180afeda4b9SAlex Zinenko    module = Module.create()
181afeda4b9SAlex Zinenko    f32 = F32Type.get()
182afeda4b9SAlex Zinenko    f64 = F64Type.get()
183afeda4b9SAlex Zinenko    with InsertionPoint(module.body):
184255a6909SAlex Zinenko      func = builtin.FuncOp("some_func", ([f32, f32], [f32, f32]))
185afeda4b9SAlex Zinenko      with InsertionPoint(func.add_entry_block()):
186afeda4b9SAlex Zinenko        std.ReturnOp(func.arguments)
187afeda4b9SAlex Zinenko      func.arg_attrs = ArrayAttr.get([
188afeda4b9SAlex Zinenko          DictAttr.get({
189*ace1d0adSStella Laurenzo              "custom_dialect.foo": StringAttr.get("bar"),
190*ace1d0adSStella Laurenzo              "custom_dialect.baz": UnitAttr.get()
191afeda4b9SAlex Zinenko          }),
192*ace1d0adSStella Laurenzo          DictAttr.get({"custom_dialect.qux": ArrayAttr.get([])})
193afeda4b9SAlex Zinenko      ])
194afeda4b9SAlex Zinenko      func.result_attrs = ArrayAttr.get([
195*ace1d0adSStella Laurenzo          DictAttr.get({"custom_dialect.res1": FloatAttr.get(f32, 42.0)}),
196*ace1d0adSStella Laurenzo          DictAttr.get({"custom_dialect.res2": FloatAttr.get(f64, 256.0)})
197afeda4b9SAlex Zinenko      ])
198afeda4b9SAlex Zinenko
199255a6909SAlex Zinenko      other = builtin.FuncOp("other_func", ([f32, f32], []))
200255a6909SAlex Zinenko      with InsertionPoint(other.add_entry_block()):
201255a6909SAlex Zinenko        std.ReturnOp([])
202255a6909SAlex Zinenko      other.arg_attrs = [
203*ace1d0adSStella Laurenzo          DictAttr.get({"custom_dialect.foo": StringAttr.get("qux")}),
204255a6909SAlex Zinenko          DictAttr.get()
205255a6909SAlex Zinenko      ]
206255a6909SAlex Zinenko
207*ace1d0adSStella Laurenzo  # CHECK: [{custom_dialect.baz, custom_dialect.foo = "bar"}, {custom_dialect.qux = []}]
208afeda4b9SAlex Zinenko  print(func.arg_attrs)
209afeda4b9SAlex Zinenko
210*ace1d0adSStella Laurenzo  # CHECK: [{custom_dialect.res1 = 4.200000e+01 : f32}, {custom_dialect.res2 = 2.560000e+02 : f64}]
211afeda4b9SAlex Zinenko  print(func.result_attrs)
212afeda4b9SAlex Zinenko
213afeda4b9SAlex Zinenko  # CHECK: func @some_func(
214*ace1d0adSStella Laurenzo  # CHECK: %[[ARG0:.*]]: f32 {custom_dialect.baz, custom_dialect.foo = "bar"},
215*ace1d0adSStella Laurenzo  # CHECK: %[[ARG1:.*]]: f32 {custom_dialect.qux = []}) ->
216*ace1d0adSStella Laurenzo  # CHECK: f32 {custom_dialect.res1 = 4.200000e+01 : f32},
217*ace1d0adSStella Laurenzo  # CHECK: f32 {custom_dialect.res2 = 2.560000e+02 : f64})
218afeda4b9SAlex Zinenko  # CHECK: return %[[ARG0]], %[[ARG1]] : f32, f32
219255a6909SAlex Zinenko  #
220255a6909SAlex Zinenko  # CHECK: func @other_func(
221*ace1d0adSStella Laurenzo  # CHECK: %{{.*}}: f32 {custom_dialect.foo = "qux"},
222255a6909SAlex Zinenko  # CHECK: %{{.*}}: f32)
223afeda4b9SAlex Zinenko  print(module)
224