1// RUN: mlir-opt -split-input-file -verify-diagnostics %s
2
3func.func @test_conv_op_not_linalg_op(%arg0 : tensor<?xf32>, %arg1 : tensor<?xf32>,
4    %arg2 : tensor<?xf32>) -> tensor<?xf32> {
5  // expected-error @+1 {{expected a LinalgOp}}
6  %0 = "test.conv_op_not_linalg_op"(%arg0, %arg1, %arg2)
7      : (tensor<?xf32>, tensor<?xf32>, tensor<?xf32>) -> tensor<?xf32>
8  return %0 : tensor<?xf32>
9}
10
11// -----
12
13// Check for number of operands being >= 2.
14#map = affine_map<(d0) -> (d0)>
15func.func @test_conv_op_wrong_num_operands(%arg0 : tensor<?xf32>,
16    %arg1 : tensor<?xf32>) -> tensor<?xf32> {
17  // expected-error @+1 {{expected op with 2 inputs and 1 output}}
18  %0 = test.linalg_conv_op {
19      indexing_maps = [#map, #map],
20      iterator_types = ["parallel"]}
21      ins(%arg0 : tensor<?xf32>) outs(%arg1 : tensor<?xf32>) {
22      ^bb0(%arg2 : f32, %arg3 : f32):
23         linalg.yield  %arg3 : f32
24      } -> tensor<?xf32>
25  return %0 : tensor<?xf32>
26}
27
28// -----
29
30func.func @test_conv_op_wrong_input_indexing_map1(%arg0 : tensor<?xf32>,
31    %arg1 : tensor<?xf32>, %arg2 : tensor<?xf32>) -> tensor<?xf32> {
32  // expected-error @+1 {{unexpected input index map for convolution}}
33  %0 = test.linalg_conv_op {
34      indexing_maps = [affine_map<(d0, d1) -> (d0 * 2)>,
35                       affine_map<(d0, d1) -> (d1)>,
36                       affine_map<(d0, d1) -> (d0)>],
37      iterator_types = ["parallel", "reduction"]}
38      ins(%arg0, %arg1 : tensor<?xf32>, tensor<?xf32>)
39      outs(%arg2 : tensor<?xf32>) {
40      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
41         linalg.yield %arg5 : f32
42      } -> tensor<?xf32>
43  return %0 : tensor<?xf32>
44}
45
46// -----
47
48func.func @test_conv_op_wrong_input_indexing_map2(%arg0 : tensor<?x?xf32>,
49    %arg1 : tensor<?xf32>, %arg2 : tensor<?xf32>) -> tensor<?xf32> {
50  // expected-error @+1 {{unexpected input index map for convolution}}
51  %0 = test.linalg_conv_op {
52      indexing_maps = [affine_map<(d0, d1) -> (d0 + d1, d0)>,
53                       affine_map<(d0, d1) -> (d1)>,
54                       affine_map<(d0, d1) -> (d0)>],
55      iterator_types = ["parallel", "reduction"]}
56      ins(%arg0, %arg1 : tensor<?x?xf32>, tensor<?xf32>)
57      outs(%arg2 : tensor<?xf32>) {
58      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
59         linalg.yield %arg5 : f32
60      } -> tensor<?xf32>
61  return %0 : tensor<?xf32>
62}
63
64// -----
65
66func.func @test_conv_op_filter_index_map_not_projection(%arg0 : tensor<?xf32>,
67    %arg1 : tensor<?xf32>, %arg2 : tensor<?xf32>) -> tensor<?xf32> {
68  // expected-error @+1 {{expected output/filter indexing maps to be projected permutations}}
69  %0 = test.linalg_conv_op {
70      indexing_maps = [affine_map<(d0, d1) -> (d1)>,
71                       affine_map<(d0, d1) -> (d1 + d0)>,
72                       affine_map<(d0, d1) -> (d0)>],
73      iterator_types = ["parallel", "reduction"]}
74      ins(%arg0, %arg1 : tensor<?xf32>, tensor<?xf32>)
75      outs(%arg2 : tensor<?xf32>) {
76      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
77         linalg.yield %arg5 : f32
78      } -> tensor<?xf32>
79  return %0 : tensor<?xf32>
80}
81
82// -----
83
84func.func @test_conv_op_output_index_map_not_projection(%arg0 : tensor<?xf32>,
85    %arg1 : tensor<?xf32>, %arg2 : tensor<?xf32>) -> tensor<?xf32> {
86  // expected-error @+1 {{expected output/filter indexing maps to be projected permutations}}
87  %0 = test.linalg_conv_op {
88      indexing_maps = [affine_map<(d0, d1) -> (d0)>,
89                       affine_map<(d0, d1) -> (d1)>,
90                       affine_map<(d0, d1) -> (d0 + d1)>],
91      iterator_types = ["parallel", "parallel"]}
92      ins(%arg0, %arg1 : tensor<?xf32>, tensor<?xf32>)
93      outs(%arg2 : tensor<?xf32>) {
94      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
95         linalg.yield %arg5 : f32
96      } -> tensor<?xf32>
97  return %0 : tensor<?xf32>
98}
99
100// -----
101
102// Convolution op illegal if a loop dimension is used to access
103// output, filter and is convolved.
104func.func @test_conv_op_output_filter_convolved(%arg0 : tensor<?xf32>,
105    %arg1 : tensor<?xf32>, %arg2 : tensor<?x?xf32>) -> tensor<?x?xf32> {
106  // expected-error @+1 {{unexpected loop dimension for convolution op}}
107  %0 = test.linalg_conv_op {
108      indexing_maps = [affine_map<(d0, d1) -> (d0 + d1)>,
109                       affine_map<(d0, d1) -> (d1)>,
110                       affine_map<(d0, d1) -> (d0, d1)>],
111      iterator_types = ["parallel", "parallel"]}
112      ins(%arg0, %arg1 : tensor<?xf32>, tensor<?xf32>)
113      outs(%arg2 : tensor<?x?xf32>) {
114      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
115         linalg.yield %arg5 : f32
116      } -> tensor<?x?xf32>
117  return %0 : tensor<?x?xf32>
118}
119
120// -----
121
122// Convolution op illegal if a loop dimension is used only in the output.
123func.func @test_conv_op_output_only_dim(%arg0 : tensor<?xf32>,
124    %arg1 : tensor<?xf32>, %arg2 : tensor<?x?xf32>) -> tensor<?x?xf32> {
125  // expected-error @+1 {{unexpected loop dimension for convolution op}}
126  %0 = test.linalg_conv_op {
127      indexing_maps = [affine_map<(d0, d1, d2) -> (d0 + d1)>,
128                       affine_map<(d0, d1, d2) -> (d1)>,
129                       affine_map<(d0, d1, d2) -> (d0, d2)>],
130      iterator_types = ["parallel", "reduction", "parallel"]}
131      ins(%arg0, %arg1 : tensor<?xf32>, tensor<?xf32>)
132      outs(%arg2 : tensor<?x?xf32>) {
133      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
134         linalg.yield %arg5 : f32
135      } -> tensor<?x?xf32>
136  return %0 : tensor<?x?xf32>
137}
138
139// -----
140
141// Convolution op illegal if a loop dimension is used only in the filter.
142func.func @test_conv_op_filter_only_dim(%arg0 : tensor<?xf32>,
143    %arg1 : tensor<?x?xf32>, %arg2 : tensor<?xf32>) -> tensor<?xf32> {
144  // expected-error @+1 {{unexpected loop dimension for convolution op}}
145  %0 = test.linalg_conv_op {
146      indexing_maps = [affine_map<(d0, d1, d2) -> (d0 + d1)>,
147                       affine_map<(d0, d1, d2) -> (d1, d2)>,
148                       affine_map<(d0, d1, d2) -> (d0)>],
149      iterator_types = ["parallel", "reduction", "reduction"]}
150      ins(%arg0, %arg1 : tensor<?xf32>, tensor<?x?xf32>)
151      outs(%arg2 : tensor<?xf32>) {
152      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
153         linalg.yield %arg5 : f32
154      } -> tensor<?xf32>
155  return %0 : tensor<?xf32>
156}
157
158// -----
159
160// Convolution op illegal if a loop dimension is used only in the input.
161func.func @test_conv_op_input_only_dim(%arg0 : tensor<?x?xf32>,
162    %arg1 : tensor<?xf32>, %arg2 : tensor<?xf32>) -> tensor<?xf32> {
163  // expected-error @+1 {{unexpected loop dimension for convolution op}}
164  %0 = test.linalg_conv_op {
165      indexing_maps = [affine_map<(d0, d1, d2) -> (d0 + d1, d2)>,
166                       affine_map<(d0, d1, d2) -> (d1)>,
167                       affine_map<(d0, d1, d2) -> (d0)>],
168      iterator_types = ["parallel", "reduction", "reduction"]}
169      ins(%arg0, %arg1 : tensor<?x?xf32>, tensor<?xf32>)
170      outs(%arg2 : tensor<?xf32>) {
171      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
172         linalg.yield %arg5 : f32
173      } -> tensor<?xf32>
174  return %0 : tensor<?xf32>
175}
176
177// -----
178
179// Convolution op illegal if a loop dimension accessing output is not parallel.
180func.func @test_conv_op_non_output_access_loop_parallel(%arg0 : tensor<?xf32>,
181    %arg1 : tensor<?xf32>, %arg2 : tensor<?xf32>) -> tensor<?xf32> {
182  // expected-error @+1 {{expected all iterators not used to access outputs to be reduction}}
183  %0 = test.linalg_conv_op  {
184      indexing_maps = [affine_map<(d0, d1) -> (d0 + d1)>,
185                       affine_map<(d0, d1) -> (d1)>,
186                       affine_map<(d0, d1) -> (d0)>],
187      iterator_types = ["parallel", "parallel"]}
188      ins(%arg0, %arg1 : tensor<?xf32>, tensor<?xf32>)
189      outs(%arg2 : tensor<?xf32>) {
190      ^bb0(%arg3 : f32, %arg4 : f32, %arg5 : f32):
191         linalg.yield %arg5 : f32
192      } -> tensor<?xf32>
193  return %0 : tensor<?xf32>
194}
195