1// RUN: mlir-opt %s -test-linalg-transform-patterns | FileCheck %s
2
3// CHECK-DAG: #[[STRIDED_1D:.*]] = affine_map<(d0)[s0] -> (d0 + s0)>
4// CHECK-DAG: #[[STRIDED_2D:.*]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)>
5// CHECK-DAG: #[[mk:.*]] = affine_map<(d0, d1, d2) -> (d0, d2)>
6// CHECK-DAG: #[[kn:.*]] = affine_map<(d0, d1, d2) -> (d2, d1)>
7// CHECK-DAG: #[[mn:.*]] = affine_map<(d0, d1, d2) -> (d0, d1)>
8// CHECK-DAG: #[[nm:.*]] = affine_map<(d0, d1, d2) -> (d1, d0)>
9// CHECK-DAG: #[[km:.*]] = affine_map<(d0, d1, d2) -> (d2, d0)>
10
11func @dot(%x: memref<?xf32, offset: ?, strides: [1]>,
12          %y: memref<?xf32, offset: ?, strides: [1]>,
13          %v: memref<f32>) {
14  linalg.dot(%x, %y, %v) : memref<?xf32, offset: ?, strides: [1]>,
15                           memref<?xf32, offset: ?, strides: [1]>,
16                           memref<f32>
17  return
18}
19// CHECK-LABEL: func @dot
20// CHECK-DAG  :   %[[c0:.*]] = constant 0 : index
21// CHECK-DAG  :   %[[c8:.*]] = constant 8 : index
22// CHECK-DAG  :   %[[c8000:.*]] = constant 8000 : index
23// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c8000]] {
24// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c8]] {
25// CHECK      :       loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c1]] {
26// CHECK      :         load
27// CHECK      :         load
28// CHECK      :         mulf
29// CHECK      :         load
30// CHECK      :         addf
31// CHECK      :         store
32
33func @matvec(%A: memref<?x?xf32, offset: ?, strides: [?, 1]>,
34             %x: memref<?xf32, offset: ?, strides: [1]>,
35             %y: memref<?xf32, offset: ?, strides: [1]>) {
36  linalg.matvec(%A, %x, %y) : memref<?x?xf32, offset: ?, strides: [?, 1]>,
37                              memref<?xf32, offset: ?, strides: [1]>,
38                              memref<?xf32, offset: ?, strides: [1]>
39  return
40}
41// CHECK-LABEL: func @matvec
42// CHECK-DAG  :   %[[c0:.*]] = constant 0 : index
43// CHECK-DAG  :   %[[c5:.*]] = constant 5 : index
44// CHECK-DAG  :   %[[c6:.*]] = constant 6 : index
45// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c5]]
46// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c6]]
47// CHECK      :       linalg.matvec({{.*}}, {{.*}}, {{.*}}) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?xf32, #[[STRIDED_1D]]>, memref<?xf32, #[[STRIDED_1D]]>
48
49func @matmul(%A: memref<?x?xf32, offset: ?, strides: [?, 1]>,
50             %B: memref<?x?xf32, offset: ?, strides: [?, 1]>,
51             %C: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
52  linalg.matmul(%A, %B, %C) : memref<?x?xf32, offset: ?, strides: [?, 1]>,
53                              memref<?x?xf32, offset: ?, strides: [?, 1]>,
54                              memref<?x?xf32, offset: ?, strides: [?, 1]>
55  return
56}
57// CHECK-LABEL: func @matmul
58// CHECK-DAG  :   %[[c0:.*]] = constant 0 : index
59// CHECK-DAG  :   %[[c2:.*]] = constant 2 : index
60// CHECK-DAG  :   %[[c3:.*]] = constant 3 : index
61// CHECK-DAG  :   %[[c4:.*]] = constant 4 : index
62// CHECK-DAG  :   %[[c20:.*]] = constant 20 : index
63// CHECK-DAG  :   %[[c30:.*]] = constant 30 : index
64// CHECK-DAG  :   %[[c40:.*]] = constant 40 : index
65// CHECK-DAG  :   %[[c200:.*]] = constant 200 : index
66// CHECK-DAG  :   %[[c300:.*]] = constant 300 : index
67// CHECK-DAG  :   %[[c400:.*]] = constant 400 : index
68// CHECK-DAG  :   %[[c2000:.*]] = constant 2000 : index
69// CHECK-DAG  :   %[[c3000:.*]] = constant 3000 : index
70// CHECK-DAG  :   %[[c4000:.*]] = constant 4000 : index
71// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c2000]] {
72// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c3000]] {
73// CHECK      :       loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c4000]] {
74// CHECK      :         loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c200]] {
75// CHECK      :           loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c300]] {
76// CHECK      :             loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c400]] {
77// CHECK      :               loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c20]] {
78// CHECK      :                 loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c30]] {
79// CHECK      :                   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c40]] {
80// CHECK      :                     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c2]] {
81// CHECK      :                       loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c3]] {
82// CHECK      :                         loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c4]] {
83// CHECK      :                           linalg.matmul({{.*}}, {{.*}}, {{.*}}) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>
84
85#some_generic_trait = {
86  args_in = 1,
87  args_out = 1,
88  indexing_maps = [
89    affine_map<(i, j) -> (i, j)>,
90    affine_map<(i, j) -> (i, j)>
91  ],
92  iterator_types = ["parallel", "parallel"]
93}
94func @fusion_test(%A: memref<?x?xf32, offset: ?, strides: [?, 1]>,
95                  %B: memref<?x?xf32, offset: ?, strides: [?, 1]>,
96                  %C: memref<?x?xf32, offset: ?, strides: [?, 1]>,
97                  %D: memref<?x?xf32, offset: ?, strides: [?, 1]>,
98                  %E: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
99  // This should not be fused as it would violate dependencies. It will get
100  // tiled for all levels of the memory hierarchy.
101  linalg.matmul(%A, %A, %C) : memref<?x?xf32, offset: ?, strides: [?, 1]>,
102                              memref<?x?xf32, offset: ?, strides: [?, 1]>,
103                              memref<?x?xf32, offset: ?, strides: [?, 1]>
104
105  // This should be fused.
106  linalg.matmul(%A, %B, %C) : memref<?x?xf32, offset: ?, strides: [?, 1]>,
107                              memref<?x?xf32, offset: ?, strides: [?, 1]>,
108                              memref<?x?xf32, offset: ?, strides: [?, 1]>
109
110  // This should not be fused or transformed at all since there are no patterns
111  // on it. However it will be reordered because there are no dependencies.
112  linalg.generic #some_generic_trait %A, %D {
113    ^bb(%a: f32, %b: f32) :
114      linalg.yield %a : f32
115  } : memref<?x?xf32, offset: ?, strides: [?, 1]>,
116      memref<?x?xf32, offset: ?, strides: [?, 1]>
117
118  linalg.matmul(%C, %D, %E) : memref<?x?xf32, offset: ?, strides: [?, 1]>,
119                              memref<?x?xf32, offset: ?, strides: [?, 1]>,
120                              memref<?x?xf32, offset: ?, strides: [?, 1]>
121
122  return
123}
124// CHECK-LABEL: func @fusion_test
125// CHECK-DAG  :   %[[c0:.*]] = constant 0 : index
126// CHECK-DAG  :   %[[c2:.*]] = constant 2 : index
127// CHECK-DAG  :   %[[c3:.*]] = constant 3 : index
128// CHECK-DAG  :   %[[c4:.*]] = constant 4 : index
129// CHECK-DAG  :   %[[c20:.*]] = constant 20 : index
130// CHECK-DAG  :   %[[c30:.*]] = constant 30 : index
131// CHECK-DAG  :   %[[c40:.*]] = constant 40 : index
132// CHECK-DAG  :   %[[c100:.*]] = constant 100 : index
133// CHECK-DAG  :   %[[c150:.*]] = constant 150 : index
134// CHECK-DAG  :   %[[c200:.*]] = constant 200 : index
135// CHECK-DAG  :   %[[c300:.*]] = constant 300 : index
136// CHECK-DAG  :   %[[c400:.*]] = constant 400 : index
137// CHECK-DAG  :   %[[c2000:.*]] = constant 2000 : index
138// CHECK-DAG  :   %[[c3000:.*]] = constant 3000 : index
139// CHECK-DAG  :   %[[c4000:.*]] = constant 4000 : index
140// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c2000]] {
141// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c3000]] {
142// CHECK      :       loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c4000]] {
143// CHECK      :         loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c200]] {
144// CHECK      :           loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c300]] {
145// CHECK      :             loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c400]] {
146// CHECK      :               loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c20]] {
147// CHECK      :                 loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c30]] {
148// CHECK      :                   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c40]] {
149// CHECK      :                     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c2]] {
150// CHECK      :                       loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c3]] {
151// CHECK      :                         loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c4]] {
152// CHECK      :                           linalg.matmul({{.*}}, {{.*}}, {{.*}}) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>
153//
154// CHECK      :   linalg.generic
155//
156// CHECK      :   loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c100]] {
157// CHECK      :     loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c150]] {
158// CHECK      :       loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c2]] {
159// CHECK      :         loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c3]] {
160// CHECK      :           loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c4]] {
161// CHECK      :             linalg.matmul(%{{.*}}, %{{.*}}, %{{.*}}) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>
162// CHECK      :       loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c2]] {
163// CHECK      :         loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c3]] {
164// CHECK      :           loop.for %{{.*}} = %[[c0]] to %{{.*}} step %[[c4]] {
165// CHECK      :             linalg.matmul(%{{.*}}, %{{.*}}, %{{.*}}) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>
166
167#matmul_trait = {
168  args_in = 2,
169  args_out = 1,
170  indexing_maps = [
171    affine_map<(m, n, k) -> (m, k)>,
172    affine_map<(m, n, k) -> (k, n)>,
173    affine_map<(m, n, k) -> (m, n)>
174  ],
175  iterator_types = ["parallel", "parallel", "reduction"],
176  __internal_linalg_transform__ = "VECTORIZE"
177}
178func @vectorization_test(%A: memref<8x16xf32>, %B: memref<16x32xf32>,
179                         %C: memref<8x32xf32>) {
180  linalg.generic #matmul_trait %A, %B, %C {
181    ^bb(%a: f32, %b: f32, %c: f32) :
182      %d = mulf %a, %b: f32
183      %e = addf %c, %d: f32
184      linalg.yield %e : f32
185  } : memref<8x16xf32>, memref<16x32xf32>, memref<8x32xf32>
186  return
187}
188// CHECK-LABEL: func @vectorization_test
189//       CHECK: vector.type_cast %{{.*}} : memref<8x16xf32> to memref<vector<8x16xf32>>
190//       CHECK: load %{{.*}}[] : memref<vector<8x16xf32>>
191//       CHECK: vector.type_cast %{{.*}} : memref<16x32xf32> to memref<vector<16x32xf32>>
192//       CHECK: load %{{.*}}[] : memref<vector<16x32xf32>>
193//       CHECK: vector.type_cast %{{.*}} : memref<8x32xf32> to memref<vector<8x32xf32>>
194//       CHECK: load %{{.*}}[] : memref<vector<8x32xf32>>
195//       CHECK: vector.contract {indexing_maps = [#[[mk]], #[[kn]], #[[mn]]], iterator_types = ["parallel", "parallel", "reduction"]} %{{.*}}, %{{.*}}, %{{.*}} : vector<8x16xf32>, vector<16x32xf32> into vector<8x32xf32>
196//       CHECK: store %{{.*}}, %{{.*}}[] : memref<vector<8x32xf32>>
197
198func @vectorization_test_2(%A: memref<8x16xf32>, %B: memref<16x32xf32>,
199                         %C: memref<8x32xf32>) {
200  linalg.matmul(%A, %B, %C) { __internal_linalg_transform__ = "VECTORIZE"} :
201    memref<8x16xf32>, memref<16x32xf32>, memref<8x32xf32>
202  return
203}
204// CHECK-LABEL: func @vectorization_test_2
205//       CHECK: vector.contract {{.*}} :
206//                vector<8x16xf32>, vector<16x32xf32> into vector<8x32xf32>
207
208func @test_vectorize_fill(%A : memref<8x16xf32>, %arg0 : f32) {
209  linalg.fill(%A, %arg0) { __internal_linalg_transform__ = "VECTORIZE"} :  memref<8x16xf32>, f32
210  return
211}
212// CHECK-LABEL: func @test_vectorize_fill
213//       CHECK: vector.broadcast {{.*}} : f32 to vector<8x16xf32>
214
215#matmul_accesses = [
216  affine_map<(m, n, k) -> (m, k)>,
217  affine_map<(m, n, k) -> (k, n)>,
218  affine_map<(m, n, k) -> (m, n)>
219]
220#generic_matmul_trait = {
221  args_in = 2,
222  args_out = 1,
223  indexing_maps = #matmul_accesses,
224  library_call = "linalg_matmul",
225  iterator_types = ["parallel", "parallel", "reduction"]
226}
227func @permute_generic(%A: memref<?x?xf32, offset: ?, strides: [?, 1]>,
228           %B: memref<?x?xf32, offset: ?, strides: [?, 1]>,
229           %C: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
230  linalg.generic #generic_matmul_trait %A, %B, %C {
231    ^bb(%a: f32, %b: f32, %c: f32):
232      %d = mulf %a, %b: f32
233      %e = addf %c, %d: f32
234      linalg.yield %e: f32
235  }: memref<?x?xf32, offset: ?, strides: [?, 1]>,
236     memref<?x?xf32, offset: ?, strides: [?, 1]>,
237     memref<?x?xf32, offset: ?, strides: [?, 1]>
238  return
239}
240// CHECK-LABEL : func @fma
241// CHECK-LABEL : func @permute_generic
242// CHECK       : linalg.generic {args_in = 2, args_out = 1,
243// CHECK-SAME  : indexing_maps = [#[[kn]], #[[nm]], #[[km]]],
244// CHECK-SAME  : iterator_types = ["parallel", "reduction", "parallel"],
245// CHECK-SAME  : library_call = "linalg_matmul"} %{{.*}}, %{{.*}}, %{{.*}}
246// CHECK       :   memref<?x?xf32, #[[STRIDED_2D]]>,
247// CHECK-SAME  :   memref<?x?xf32, #[[STRIDED_2D]]>,
248// CHECK-SAME  :   memref<?x?xf32, #[[STRIDED_2D]]>
249
250#indexed_matmul_trait = {
251  args_in = 2,
252  args_out = 1,
253  indexing_maps = #matmul_accesses,
254  library_call = "linalg_matmul_indexed",
255  iterator_types = ["parallel", "parallel", "reduction"]
256}
257func @permute_generic_indexed(
258    %A: memref<?x?xf32, offset: ?, strides: [?, 1]>,
259    %B: memref<?x?xf32, offset: ?, strides: [?, 1]>,
260    %C: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
261  linalg.indexed_generic #indexed_matmul_trait %A, %B, %C {
262    ^bb(%i: index, %j: index, %k: index, %a: f32, %b: f32, %c: f32):
263      %d = mulf %a, %b: f32
264      %e = addf %c, %d: f32
265      linalg.yield %e: f32
266  } : memref<?x?xf32, offset: ?, strides: [?, 1]>,
267      memref<?x?xf32, offset: ?, strides: [?, 1]>,
268      memref<?x?xf32, offset: ?, strides: [?, 1]>
269  return
270}
271// CHECK-LABEL : func @fma_indexed
272// CHECK-LABEL : func @permute_generic_indexed
273// CHECK       : linalg.indexed_generic {args_in = 2, args_out = 1,
274// CHECK-SAME  :   indexing_maps = [#[[kn]], #[[nm]], #[[km]]],
275// CHECK-SAME  :   iterator_types = ["parallel", "reduction", "parallel"],
276// CHECK-SAME  :   library_call = "linalg_matmul_indexed"} %{{.*}}, %{{.*}}, %{{.*}} :
277// CHECK       :     memref<?x?xf32, #[[STRIDED_2D]]>,
278// CHECK-SAME  :     memref<?x?xf32, #[[STRIDED_2D]]>,
279// CHECK-SAME  :     memref<?x?xf32, #[[STRIDED_2D]]>
280
281func @dot_perm(%x: memref<?xf32, offset: ?, strides: [1]>,
282          %y: memref<?xf32, offset: ?, strides: [1]>,
283          %v: memref<f32>) {
284  linalg.dot(%x, %y, %v) {__internal_linalg_transform__ = "__with_perm__"} :
285            memref<?xf32, offset: ?, strides: [1]>,
286            memref<?xf32, offset: ?, strides: [1]>,
287            memref<f32>
288  return
289}
290// CHECK-LABEL: func @dot_perm
291// CHECK-DAG  :   %[[c0:.*]] = constant 0 : index
292// CHECK-DAG  :   %[[c8:.*]] = constant 8 : index
293// CHECK-DAG  :   %[[c8000:.*]] = constant 8000 : index
294// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c8000]] {
295// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c8]] {
296// CHECK      :       linalg.dot({{.*}}, {{.*}}, {{.*}}) : memref<?xf32, #[[STRIDED_1D]]>, memref<?xf32, #[[STRIDED_1D]]>, memref<f32>
297
298func @matvec_perm(%A: memref<?x?xf32, offset: ?, strides: [?, 1]>,
299             %x: memref<?xf32, offset: ?, strides: [1]>,
300             %y: memref<?xf32, offset: ?, strides: [1]>) {
301  linalg.matvec(%A, %x, %y) {__internal_linalg_transform__ = "__with_perm__"} :
302               memref<?x?xf32, offset: ?, strides: [?, 1]>,
303               memref<?xf32, offset: ?, strides: [1]>,
304               memref<?xf32, offset: ?, strides: [1]>
305  return
306}
307// CHECK-LABEL: func @matvec_perm
308// CHECK-DAG  :   %[[c0:.*]] = constant 0 : index
309// CHECK-DAG  :   %[[c5:.*]] = constant 5 : index
310// CHECK-DAG  :   %[[c6:.*]] = constant 6 : index
311// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c6]]
312// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c5]]
313// CHECK      :       linalg.matvec({{.*}}, {{.*}}, {{.*}}) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?xf32, #[[STRIDED_1D]]>, memref<?xf32, #[[STRIDED_1D]]>
314
315func @matmul_perm(%A: memref<?x?xf32, offset: ?, strides: [?, 1]>,
316             %B: memref<?x?xf32, offset: ?, strides: [?, 1]>,
317             %C: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
318  linalg.matmul(%A, %B, %C) {__internal_linalg_transform__ = "__with_perm__"} :
319               memref<?x?xf32, offset: ?, strides: [?, 1]>,
320               memref<?x?xf32, offset: ?, strides: [?, 1]>,
321               memref<?x?xf32, offset: ?, strides: [?, 1]>
322  return
323}
324// CHECK-LABEL: func @matmul_perm
325// CHECK-DAG  :   %[[c0:.*]] = constant 0 : index
326// CHECK-DAG  :   %[[c2:.*]] = constant 2 : index
327// CHECK-DAG  :   %[[c3:.*]] = constant 3 : index
328// CHECK-DAG  :   %[[c4:.*]] = constant 4 : index
329// CHECK-DAG  :   %[[c20:.*]] = constant 20 : index
330// CHECK-DAG  :   %[[c30:.*]] = constant 30 : index
331// CHECK-DAG  :   %[[c40:.*]] = constant 40 : index
332// CHECK-DAG  :   %[[c200:.*]] = constant 200 : index
333// CHECK-DAG  :   %[[c300:.*]] = constant 300 : index
334// CHECK-DAG  :   %[[c400:.*]] = constant 400 : index
335// CHECK-DAG  :   %[[c2000:.*]] = constant 2000 : index
336// CHECK-DAG  :   %[[c3000:.*]] = constant 3000 : index
337// CHECK-DAG  :   %[[c4000:.*]] = constant 4000 : index
338// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c3000]] {
339// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c4000]] {
340// CHECK      :       loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c2000]] {
341// CHECK      :         loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c300]] {
342// CHECK      :           loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c200]] {
343// CHECK      :             loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c400]] {
344// CHECK      :               loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c20]] {
345// CHECK      :                 loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c30]] {
346// CHECK      :                   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c40]] {
347// CHECK      :                           linalg.matmul({{.*}}, {{.*}}, {{.*}}) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>
348
349func @promote_subview_matmul(%arg0: memref<?x?xf32, offset: ?, strides: [?, 1]>,
350                             %arg1: memref<?x?xf32, offset: ?, strides: [?, 1]>,
351                             %arg2: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
352  %c2000 = constant 2000 : index
353  %c3000 = constant 3000 : index
354  %c4000 = constant 4000 : index
355  %c0 = constant 0 : index
356  %c1 = constant 1 : index
357  %0 = dim %arg0, 0 : memref<?x?xf32, offset: ?, strides: [?, 1]>
358  %1 = dim %arg0, 1 : memref<?x?xf32, offset: ?, strides: [?, 1]>
359  %2 = dim %arg1, 1 : memref<?x?xf32, offset: ?, strides: [?, 1]>
360  loop.for %arg3 = %c0 to %0 step %c2000 {
361    loop.for %arg4 = %c0 to %2 step %c3000 {
362      loop.for %arg5 = %c0 to %1 step %c4000 {
363        %3 = std.subview %arg0[%arg3, %arg5][%c2000, %c4000][%c1, %c1] :
364             memref<?x?xf32, offset: ?, strides: [?, 1]> to memref<?x?xf32, offset: ?, strides: [?, ?]>
365        %4 = std.subview %arg1[%arg5, %arg4][%c4000, %c3000][%c1, %c1] :
366             memref<?x?xf32, offset: ?, strides: [?, 1]> to memref<?x?xf32, offset: ?, strides: [?, ?]>
367        %5 = std.subview %arg2[%arg3, %arg4][%c2000, %c3000][%c1, %c1] :
368             memref<?x?xf32, offset: ?, strides: [?, 1]> to memref<?x?xf32, offset: ?, strides: [?, ?]>
369        linalg.matmul(%3, %4, %5) {__internal_linalg_transform__ = "_promote_views_"} :
370                      memref<?x?xf32, offset: ?, strides: [?, ?]>,
371                      memref<?x?xf32, offset: ?, strides: [?, ?]>,
372                      memref<?x?xf32, offset: ?, strides: [?, ?]>
373      }
374    }
375  }
376  return
377}
378// CHECK-LABEL: func @promote_subview_matmul
379// CHECK      :   loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c2000]] {
380// CHECK      :     loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c3000]] {
381// CHECK      :       loop.for {{.*}} = %[[c0]] to {{.*}} step %[[c4000]] {
382// CHECK      :         %[[s0:.*]] = std.subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
383// CHECK      :         %[[s1:.*]] = std.subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
384// CHECK      :         %[[s2:.*]] = std.subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
385// CHECK      :         %[[a0:.*]] = alloc({{%.*}}) : memref<?xi8>
386// CHECK      :         %[[v0:.*]] = std.view %[[a0]][][{{%.*}}, {{%.*}}]: memref<?xi8> to memref<?x?xf32>
387// CHECK      :         %[[l0:.*]] = linalg.slice %[[v0]][{{%.*}}, {{%.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, memref<?x?xf32, #map{{.*}}>
388// CHECK      :         %[[a1:.*]] = alloc({{%.*}}) : memref<?xi8>
389// CHECK      :         %[[v1:.*]] = std.view %[[a1]][][{{%.*}}, {{%.*}}]: memref<?xi8> to memref<?x?xf32>
390// CHECK      :         %[[l1:.*]] = linalg.slice %[[v1]][{{%.*}}, {{%.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, memref<?x?xf32, #map{{.*}}>
391// CHECK      :         %[[a2:.*]] = alloc({{%.*}}) : memref<?xi8>
392// CHECK      :         %[[v2:.*]] = std.view %[[a2]][][{{%.*}}, {{%.*}}]: memref<?xi8> to memref<?x?xf32>
393// CHECK      :         %[[l2:.*]] = linalg.slice %[[v2]][{{%.*}}, {{%.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, memref<?x?xf32, #map{{.*}}>
394// CHECK      :         linalg.copy(%[[s0]], %[[l0]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>
395// CHECK      :         linalg.copy(%[[s1]], %[[l1]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>
396// CHECK      :         linalg.copy(%[[s2]], %[[l2]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>
397// CHECK      :         linalg.matmul(%[[v0]], %[[v1]], %[[v2]]) : memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>, memref<?x?xf32, #[[STRIDED_2D]]>
398