1# RUN: %PYTHON %s | FileCheck %s
2
3from mlir.ir import *
4from mlir.dialects import builtin
5from mlir.dialects import func
6from mlir.dialects import linalg
7
8from mlir.dialects.linalg.opdsl.lang import *
9
10# This tests miscellaneous features of the emitter that are not tested by the
11# fill, matmul, convolution, or pooling tests. The features include:
12# - constant defined in the body
13# - fix/predefined types
14# - some math/arith functions, including abs, ceil, exp, floor, log, and negf
15# - custom op names.
16
17
18@linalg_structured_op
19def test_const(O=TensorDef(F32, S.M, S.N, output=True)):
20  O[D.m, D.n] = TypeFn.cast_unsigned(F32, const(42)) + TypeFn.cast_unsigned(
21      F32, const(2.3283064e-10))
22
23
24@linalg_structured_op
25def test_index(O=TensorDef(I32, S.M, S.N, output=True)):
26  O[D.m, D.n] = TypeFn.cast_signed(I32, index(D.m)) + TypeFn.cast_signed(
27      I32, index(D.n))
28
29
30@linalg_structured_op
31def elemwise_unary_poly(
32    I=TensorDef(T),
33    O=TensorDef(U, output=True),
34    fun=UnaryFnAttrDef(default=UnaryFn.exp),
35    cast=TypeFnAttrDef(default=TypeFn.cast_signed)):
36  O[None] = fun(cast(U, I[None]))
37
38
39@linalg_structured_op(op_name="custom_op_name")
40def non_default_op_name(I=TensorDef(T, S.N), O=TensorDef(T, S.N, output=True)):
41  O[D.n] = I[D.n]
42
43
44with Context() as ctx, Location.unknown():
45  module = Module.create()
46  f32 = F32Type.get()
47  i32 = IntegerType.get_signless(32)
48  with InsertionPoint(module.body):
49
50    # CHECK-LABEL: @test_f32_const
51    # CHECK-DAG:    %[[CST0:.+]] = arith.constant 42 : i64
52    # CHECK-DAG:    %[[CST0_CAST:.+]] = arith.uitofp %[[CST0]] : i64 to f32
53    # CHECK-DAG:    %[[CST1:.+]] = arith.constant 2.3283063999999999E-10 : f64
54    # CHECK-DAG:    %[[CST1_CAST:.+]] = arith.truncf %[[CST1]] : f64 to f32
55    # CHECK-DAG:    %[[SUM:.+]] = arith.addf %[[CST0_CAST]], %[[CST1_CAST]] : f32
56    # CHECK-NEXT:   linalg.yield %[[SUM]] : f32
57    @builtin.FuncOp.from_py_func(RankedTensorType.get((4, 16), f32))
58    def test_f32_const(init_result):
59      return test_const(outs=[init_result])
60
61    # CHECK-LABEL: @test_i32_index
62    # CHECK-DAG:    %[[IDX0:.+]] = linalg.index 0 : index
63    # CHECK-DAG:    %[[IDX1:.+]] = linalg.index 1 : index
64    # CHECK-DAG:    %[[IDX0_CAST:.+]] = arith.index_cast %[[IDX0]] : index to i32
65    # CHECK-DAG:    %[[IDX1_CAST:.+]] = arith.index_cast %[[IDX1]] : index to i32
66    # CHECK-DAG:    %[[SUM:.+]] = arith.addi %[[IDX0_CAST]], %[[IDX1_CAST]] : i32
67    # CHECK-NEXT:   linalg.yield %[[SUM]] : i32
68    @builtin.FuncOp.from_py_func(RankedTensorType.get((4, 16), i32))
69    def test_i32_index(init_result):
70      return test_index(outs=[init_result])
71
72    # CHECK-LABEL: @test_f32_elemwise_exp
73    # CHECK:      ^{{.*}}(%[[IN:.+]]: f32, %[[OUT:.+]]: f32)
74    # CHECK-NEXT:   %[[EXP:.+]] = math.exp %[[IN]] : f32
75    # CHECK-NEXT:   linalg.yield %[[EXP]] : f32
76    # CHECK-NEXT: -> tensor<4x16xf32>
77    @builtin.FuncOp.from_py_func(
78        RankedTensorType.get((4, 16), f32), RankedTensorType.get((4, 16), f32))
79    def test_f32_elemwise_exp(input, init_result):
80      return elemwise_unary_poly(input, outs=[init_result], fun=UnaryFn.exp)
81
82    # CHECK-LABEL: @test_f32_elemwise_log
83    # CHECK:      ^{{.*}}(%[[IN:.+]]: f32, %[[OUT:.+]]: f32)
84    # CHECK-NEXT:   %[[LOG:.+]] = math.log %[[IN]] : f32
85    # CHECK-NEXT:   linalg.yield %[[LOG]] : f32
86    # CHECK-NEXT: -> tensor<4x16xf32>
87    @builtin.FuncOp.from_py_func(
88        RankedTensorType.get((4, 16), f32), RankedTensorType.get((4, 16), f32))
89    def test_f32_elemwise_log(input, init_result):
90      return elemwise_unary_poly(input, outs=[init_result], fun=UnaryFn.log)
91
92    # CHECK-LABEL: @test_f32_elemwise_abs
93    # CHECK:      ^{{.*}}(%[[IN:.+]]: f32, %[[OUT:.+]]: f32)
94    # CHECK-NEXT:   %[[EXP:.+]] = math.abs %[[IN]] : f32
95    # CHECK-NEXT:   linalg.yield %[[EXP]] : f32
96    # CHECK-NEXT: -> tensor<4x16xf32>
97    @builtin.FuncOp.from_py_func(
98        RankedTensorType.get((4, 16), f32), RankedTensorType.get((4, 16), f32))
99    def test_f32_elemwise_abs(input, init_result):
100      return elemwise_unary_poly(input, outs=[init_result], fun=UnaryFn.abs)
101
102    # CHECK-LABEL: @test_f32_elemwise_ceil
103    # CHECK:      ^{{.*}}(%[[IN:.+]]: f32, %[[OUT:.+]]: f32)
104    # CHECK-NEXT:   %[[EXP:.+]] = math.ceil %[[IN]] : f32
105    # CHECK-NEXT:   linalg.yield %[[EXP]] : f32
106    # CHECK-NEXT: -> tensor<4x16xf32>
107    @builtin.FuncOp.from_py_func(
108        RankedTensorType.get((4, 16), f32), RankedTensorType.get((4, 16), f32))
109    def test_f32_elemwise_ceil(input, init_result):
110      return elemwise_unary_poly(input, outs=[init_result], fun=UnaryFn.ceil)
111
112    # CHECK-LABEL: @test_f32_elemwise_floor
113    # CHECK:      ^{{.*}}(%[[IN:.+]]: f32, %[[OUT:.+]]: f32)
114    # CHECK-NEXT:   %[[EXP:.+]] = math.floor %[[IN]] : f32
115    # CHECK-NEXT:   linalg.yield %[[EXP]] : f32
116    # CHECK-NEXT: -> tensor<4x16xf32>
117    @builtin.FuncOp.from_py_func(
118        RankedTensorType.get((4, 16), f32), RankedTensorType.get((4, 16), f32))
119    def test_f32_elemwise_floor(input, init_result):
120      return elemwise_unary_poly(input, outs=[init_result], fun=UnaryFn.floor)
121
122    # CHECK-LABEL: @test_f32_elemwise_neg
123    # CHECK:      ^{{.*}}(%[[IN:.+]]: f32, %[[OUT:.+]]: f32)
124    # CHECK-NEXT:   %[[EXP:.+]] = arith.negf %[[IN]] : f32
125    # CHECK-NEXT:   linalg.yield %[[EXP]] : f32
126    # CHECK-NEXT: -> tensor<4x16xf32>
127    @builtin.FuncOp.from_py_func(
128        RankedTensorType.get((4, 16), f32), RankedTensorType.get((4, 16), f32))
129    def test_f32_elemwise_neg(input, init_result):
130      return elemwise_unary_poly(input, outs=[init_result], fun=UnaryFn.negf)
131
132    # Just check that we don't assert out on name mismatch.
133    # CHECK-LABEL: @test_non_default_op_name
134    @builtin.FuncOp.from_py_func(
135        RankedTensorType.get((42,), f32), RankedTensorType.get((42,), f32))
136    def test_non_default_op_name(input, init_result):
137      return non_default_op_name(input, outs=[init_result])
138
139
140print(module)
141