1*9f3f6d7bSStella Laurenzo# RUN: %PYTHON %s | FileCheck %s
2*9f3f6d7bSStella Laurenzo
3*9f3f6d7bSStella Laurenzofrom mlir.ir import *
4*9f3f6d7bSStella Laurenzoimport mlir.dialects.builtin as builtin
5*9f3f6d7bSStella Laurenzoimport mlir.dialects.std as std
6*9f3f6d7bSStella Laurenzo
7*9f3f6d7bSStella Laurenzo
8*9f3f6d7bSStella Laurenzodef run(f):
9*9f3f6d7bSStella Laurenzo  print("\nTEST:", f.__name__)
10*9f3f6d7bSStella Laurenzo  f()
11*9f3f6d7bSStella Laurenzo  return f
12*9f3f6d7bSStella Laurenzo
13*9f3f6d7bSStella Laurenzo
14*9f3f6d7bSStella Laurenzo# CHECK-LABEL: TEST: testFromPyFunc
15*9f3f6d7bSStella Laurenzo@run
16*9f3f6d7bSStella Laurenzodef testFromPyFunc():
17*9f3f6d7bSStella Laurenzo  with Context() as ctx, Location.unknown() as loc:
18*9f3f6d7bSStella Laurenzo    m = builtin.ModuleOp()
19*9f3f6d7bSStella Laurenzo    f32 = F32Type.get()
20*9f3f6d7bSStella Laurenzo    f64 = F64Type.get()
21*9f3f6d7bSStella Laurenzo    with InsertionPoint(m.body):
22*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @unary_return(%arg0: f64) -> f64
23*9f3f6d7bSStella Laurenzo      # CHECK: return %arg0 : f64
24*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f64)
25*9f3f6d7bSStella Laurenzo      def unary_return(a):
26*9f3f6d7bSStella Laurenzo        return a
27*9f3f6d7bSStella Laurenzo
28*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @binary_return(%arg0: f32, %arg1: f64) -> (f32, f64)
29*9f3f6d7bSStella Laurenzo      # CHECK: return %arg0, %arg1 : f32, f64
30*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
31*9f3f6d7bSStella Laurenzo      def binary_return(a, b):
32*9f3f6d7bSStella Laurenzo        return a, b
33*9f3f6d7bSStella Laurenzo
34*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @none_return(%arg0: f32, %arg1: f64)
35*9f3f6d7bSStella Laurenzo      # CHECK: return
36*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
37*9f3f6d7bSStella Laurenzo      def none_return(a, b):
38*9f3f6d7bSStella Laurenzo        pass
39*9f3f6d7bSStella Laurenzo
40*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @call_unary
41*9f3f6d7bSStella Laurenzo      # CHECK: %0 = call @unary_return(%arg0) : (f64) -> f64
42*9f3f6d7bSStella Laurenzo      # CHECK: return %0 : f64
43*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f64)
44*9f3f6d7bSStella Laurenzo      def call_unary(a):
45*9f3f6d7bSStella Laurenzo        return unary_return(a)
46*9f3f6d7bSStella Laurenzo
47*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @call_binary
48*9f3f6d7bSStella Laurenzo      # CHECK: %0:2 = call @binary_return(%arg0, %arg1) : (f32, f64) -> (f32, f64)
49*9f3f6d7bSStella Laurenzo      # CHECK: return %0#0, %0#1 : f32, f64
50*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
51*9f3f6d7bSStella Laurenzo      def call_binary(a, b):
52*9f3f6d7bSStella Laurenzo        return binary_return(a, b)
53*9f3f6d7bSStella Laurenzo
54*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @call_none
55*9f3f6d7bSStella Laurenzo      # CHECK: call @none_return(%arg0, %arg1) : (f32, f64) -> ()
56*9f3f6d7bSStella Laurenzo      # CHECK: return
57*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
58*9f3f6d7bSStella Laurenzo      def call_none(a, b):
59*9f3f6d7bSStella Laurenzo        return none_return(a, b)
60*9f3f6d7bSStella Laurenzo
61*9f3f6d7bSStella Laurenzo      ## Variants and optional feature tests.
62*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @from_name_arg
63*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64, name="from_name_arg")
64*9f3f6d7bSStella Laurenzo      def explicit_name(a, b):
65*9f3f6d7bSStella Laurenzo        return b
66*9f3f6d7bSStella Laurenzo
67*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
68*9f3f6d7bSStella Laurenzo      def positional_func_op(a, b, func_op):
69*9f3f6d7bSStella Laurenzo        assert isinstance(func_op, builtin.FuncOp)
70*9f3f6d7bSStella Laurenzo        return b
71*9f3f6d7bSStella Laurenzo
72*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
73*9f3f6d7bSStella Laurenzo      def kw_func_op(a, b=None, func_op=None):
74*9f3f6d7bSStella Laurenzo        assert isinstance(func_op, builtin.FuncOp)
75*9f3f6d7bSStella Laurenzo        return b
76*9f3f6d7bSStella Laurenzo
77*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64)
78*9f3f6d7bSStella Laurenzo      def kwargs_func_op(a, b=None, **kwargs):
79*9f3f6d7bSStella Laurenzo        assert isinstance(kwargs["func_op"], builtin.FuncOp)
80*9f3f6d7bSStella Laurenzo        return b
81*9f3f6d7bSStella Laurenzo
82*9f3f6d7bSStella Laurenzo      # CHECK-LABEL: func @explicit_results(%arg0: f32, %arg1: f64) -> f64
83*9f3f6d7bSStella Laurenzo      # CHECK: return %arg1 : f64
84*9f3f6d7bSStella Laurenzo      @builtin.FuncOp.from_py_func(f32, f64, results=[f64])
85*9f3f6d7bSStella Laurenzo      def explicit_results(a, b):
86*9f3f6d7bSStella Laurenzo        std.ReturnOp([b])
87*9f3f6d7bSStella Laurenzo
88*9f3f6d7bSStella Laurenzo  print(m)
89*9f3f6d7bSStella Laurenzo
90*9f3f6d7bSStella Laurenzo
91*9f3f6d7bSStella Laurenzo# CHECK-LABEL: TEST: testFromPyFuncErrors
92*9f3f6d7bSStella Laurenzo@run
93*9f3f6d7bSStella Laurenzodef testFromPyFuncErrors():
94*9f3f6d7bSStella Laurenzo  with Context() as ctx, Location.unknown() as loc:
95*9f3f6d7bSStella Laurenzo    m = builtin.ModuleOp()
96*9f3f6d7bSStella Laurenzo    f32 = F32Type.get()
97*9f3f6d7bSStella Laurenzo    f64 = F64Type.get()
98*9f3f6d7bSStella Laurenzo    with InsertionPoint(m.body):
99*9f3f6d7bSStella Laurenzo      try:
100*9f3f6d7bSStella Laurenzo
101*9f3f6d7bSStella Laurenzo        @builtin.FuncOp.from_py_func(f64, results=[f64])
102*9f3f6d7bSStella Laurenzo        def unary_return(a):
103*9f3f6d7bSStella Laurenzo          return a
104*9f3f6d7bSStella Laurenzo      except AssertionError as e:
105*9f3f6d7bSStella Laurenzo        # CHECK: Capturing a python function with explicit `results=` requires that the wrapped function returns None.
106*9f3f6d7bSStella Laurenzo        print(e)
107*9f3f6d7bSStella Laurenzo
108*9f3f6d7bSStella Laurenzo
109*9f3f6d7bSStella Laurenzo# CHECK-LABEL: TEST: testBuildFuncOp
110*9f3f6d7bSStella Laurenzo@run
111*9f3f6d7bSStella Laurenzodef testBuildFuncOp():
112*9f3f6d7bSStella Laurenzo  ctx = Context()
113*9f3f6d7bSStella Laurenzo  with Location.unknown(ctx) as loc:
114*9f3f6d7bSStella Laurenzo    m = builtin.ModuleOp()
115*9f3f6d7bSStella Laurenzo
116*9f3f6d7bSStella Laurenzo    f32 = F32Type.get()
117*9f3f6d7bSStella Laurenzo    tensor_type = RankedTensorType.get((2, 3, 4), f32)
118*9f3f6d7bSStella Laurenzo    with InsertionPoint.at_block_begin(m.body):
119*9f3f6d7bSStella Laurenzo      func = builtin.FuncOp(name="some_func",
120*9f3f6d7bSStella Laurenzo                            type=FunctionType.get(
121*9f3f6d7bSStella Laurenzo                                inputs=[tensor_type, tensor_type],
122*9f3f6d7bSStella Laurenzo                                results=[tensor_type]),
123*9f3f6d7bSStella Laurenzo                            visibility="nested")
124*9f3f6d7bSStella Laurenzo      # CHECK: Name is: "some_func"
125*9f3f6d7bSStella Laurenzo      print("Name is: ", func.name)
126*9f3f6d7bSStella Laurenzo
127*9f3f6d7bSStella Laurenzo      # CHECK: Type is: (tensor<2x3x4xf32>, tensor<2x3x4xf32>) -> tensor<2x3x4xf32>
128*9f3f6d7bSStella Laurenzo      print("Type is: ", func.type)
129*9f3f6d7bSStella Laurenzo
130*9f3f6d7bSStella Laurenzo      # CHECK: Visibility is: "nested"
131*9f3f6d7bSStella Laurenzo      print("Visibility is: ", func.visibility)
132*9f3f6d7bSStella Laurenzo
133*9f3f6d7bSStella Laurenzo      try:
134*9f3f6d7bSStella Laurenzo        entry_block = func.entry_block
135*9f3f6d7bSStella Laurenzo      except IndexError as e:
136*9f3f6d7bSStella Laurenzo        # CHECK: External function does not have a body
137*9f3f6d7bSStella Laurenzo        print(e)
138*9f3f6d7bSStella Laurenzo
139*9f3f6d7bSStella Laurenzo      with InsertionPoint(func.add_entry_block()):
140*9f3f6d7bSStella Laurenzo        std.ReturnOp([func.entry_block.arguments[0]])
141*9f3f6d7bSStella Laurenzo        pass
142*9f3f6d7bSStella Laurenzo
143*9f3f6d7bSStella Laurenzo      try:
144*9f3f6d7bSStella Laurenzo        func.add_entry_block()
145*9f3f6d7bSStella Laurenzo      except IndexError as e:
146*9f3f6d7bSStella Laurenzo        # CHECK: The function already has an entry block!
147*9f3f6d7bSStella Laurenzo        print(e)
148*9f3f6d7bSStella Laurenzo
149*9f3f6d7bSStella Laurenzo      # Try the callback builder and passing type as tuple.
150*9f3f6d7bSStella Laurenzo      func = builtin.FuncOp(name="some_other_func",
151*9f3f6d7bSStella Laurenzo                            type=([tensor_type, tensor_type], [tensor_type]),
152*9f3f6d7bSStella Laurenzo                            visibility="nested",
153*9f3f6d7bSStella Laurenzo                            body_builder=lambda func: std.ReturnOp(
154*9f3f6d7bSStella Laurenzo                                [func.entry_block.arguments[0]]))
155*9f3f6d7bSStella Laurenzo
156*9f3f6d7bSStella Laurenzo  # CHECK: module  {
157*9f3f6d7bSStella Laurenzo  # CHECK:  func nested @some_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
158*9f3f6d7bSStella Laurenzo  # CHECK:   return %arg0 : tensor<2x3x4xf32>
159*9f3f6d7bSStella Laurenzo  # CHECK:  }
160*9f3f6d7bSStella Laurenzo  # CHECK:  func nested @some_other_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
161*9f3f6d7bSStella Laurenzo  # CHECK:   return %arg0 : tensor<2x3x4xf32>
162*9f3f6d7bSStella Laurenzo  # CHECK:  }
163*9f3f6d7bSStella Laurenzo  print(m)
164