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