901 lines · plain
1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='builtin.module(func.func(affine-loop-fusion))' -split-input-file | FileCheck %s2// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='builtin.module(func.func(affine-loop-fusion{maximal}))' -split-input-file | FileCheck %s --check-prefix=MAXIMAL3 4// Part I of fusion tests in mlir/test/Transforms/loop-fusion.mlir.5// Part III of fusion tests in mlir/test/Transforms/loop-fusion-3.mlir6// Part IV of fusion tests in mlir/test/Transforms/loop-fusion-4.mlir7 8// -----9 10// CHECK-LABEL: func @should_fuse_at_depth_above_loop_carried_dependence(%{{.*}}: memref<64x4xf32>, %{{.*}}: memref<64x4xf32>) {11func.func @should_fuse_at_depth_above_loop_carried_dependence(%arg0: memref<64x4xf32>, %arg1: memref<64x4xf32>) {12 %out = memref.alloc() : memref<64x4xf32>13 %0 = arith.constant 0.0 : f3214 affine.for %i0 = 0 to 64 {15 affine.for %i1 = 0 to 4 {16 affine.store %0, %out[%i0, %i1] : memref<64x4xf32>17 }18 }19 affine.for %i2 = 0 to 4 {20 affine.for %i3 = 0 to 4 {21 affine.for %i4 = 0 to 16 {22 %v = affine.load %arg1[16 * %i3 - %i4 + 15, %i2] : memref<64x4xf32>23 "op0"(%v) : (f32) -> ()24 }25 affine.for %i5 = 0 to 4 {26 affine.for %i6 = 0 to 16 {27 %v = affine.load %arg0[16 * %i5 - %i6 + 15, %i3] : memref<64x4xf32>28 "op1"(%v) : (f32) -> ()29 }30 affine.for %i7 = 0 to 16 {31 %r = "op2"() : () -> (f32)32 %v = affine.load %out[16 * %i5 + %i7, %i2] : memref<64x4xf32>33 %s = arith.addf %v, %r : f3234 affine.store %s, %out[16 * %i5 + %i7, %i2] : memref<64x4xf32>35 }36 }37 }38 }39 40 // We can fuse source loop nest '%i0' into dst loop nest '%i2', but the41 // depth at which we can insert the src loop nest slice into the dst loop42 // nest must be decreased because of a loop carried dependence on loop '%i3'.43 // As a result, the source loop nest is inserted at dst loop nest depth 1,44 // just above the loop with the carried dependence. In addition, the source45 // loop nest iteration bounds on its loop '%i1' are reduced to 1, so the46 // memref size can be reduced to 64x1xf32.47 48 // In this case, since we have multiple producer stores (for %out) with49 // different access functions and we don't yet support private memref50 // computation in such cases, a 64x1 private memref isn't created.51 52 // CHECK: memref.alloc() : memref<64x4xf32>53 // CHECK: affine.for %{{.*}} = 0 to 4 {54 // CHECK-NEXT: affine.for %{{.*}} = 0 to 64 {55 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<64x4xf32>56 // CHECK-NEXT: }57 // CHECK-NEXT: affine.for %{{.*}} = 0 to 4 {58 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {59 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}} * 16 - %{{.*}} + 15, %{{.*}}] : memref<64x4xf32>60 // CHECK-NEXT: "op0"(%{{.*}}) : (f32) -> ()61 // CHECK-NEXT: }62 // CHECK-NEXT: affine.for %{{.*}} = 0 to 4 {63 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {64 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}} * 16 - %{{.*}} + 15, %{{.*}}] : memref<64x4xf32>65 // CHECK-NEXT: "op1"(%{{.*}}) : (f32) -> ()66 // CHECK-NEXT: }67 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {68 // CHECK-NEXT: %{{.*}} = "op2"() : () -> f3269 // CHECK: affine.load %{{.*}}[%{{.*}} * 16 + %{{.*}}, %{{.*}}] : memref<64x4xf32>70 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f3271 // CHECK: affine.store %{{.*}}, %{{.*}}[%{{.*}} * 16 + %{{.*}}, %{{.*}}] : memref<64x4xf32>72 // CHECK-NEXT: }73 // CHECK-NEXT: }74 // CHECK-NEXT: }75 // CHECK-NEXT: }76 // CHECK-NEXT: return77 return78}79 80// -----81 82// CHECK-LABEL: func @should_fuse_only_two_loops_and_remove_producer() {83func.func @should_fuse_only_two_loops_and_remove_producer() {84 %a = memref.alloc() : memref<10xf32>85 %b = memref.alloc() : memref<10xf32>86 87 %cf7 = arith.constant 7.0 : f3288 89 affine.for %i0 = 0 to 10 {90 affine.store %cf7, %a[%i0] : memref<10xf32>91 }92 affine.for %i1 = 0 to 10 {93 %v0 = affine.load %a[%i1] : memref<10xf32>94 affine.store %v0, %b[%i1] : memref<10xf32>95 }96 affine.for %i2 = 0 to 10 {97 %v1 = affine.load %a[%i2] : memref<10xf32>98 affine.store %v1, %b[%i2] : memref<10xf32>99 }100 101 // On the first visit to '%i2', the fusion algorithm can not fuse loop nest102 // '%i0' into '%i2' because of the dependences '%i0' and '%i2' each have on103 // '%i1'. Then, '%i0' is fused into '%i1' and no private memref is created for104 // memref '%a' to be able to remove '%i0' and still preserve the depencence on105 // '%a' with '%i2'.106 // TODO: Alternatively, we could fuse '%i0' into '%i1' with a private memref,107 // the dependence between '%i0' and '%i1' on memref '%a' would no longer exist,108 // and '%i0' could be fused into '%i2' as well. Note that this approach would109 // duplicate the computation in loop nest '%i0' to loop nests '%i1' and '%i2',110 // which would limit its profitability.111 // CHECK: affine.for %{{.*}} = 0 to 10 {112 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>113 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>114 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>115 // CHECK-NEXT: }116 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {117 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>118 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>119 // CHECK-NEXT: }120 // CHECK-NEXT: return121 return122}123 124// -----125 126// CHECK-LABEL: func @should_fuse_after_one_loop_interchange() {127func.func @should_fuse_after_one_loop_interchange() {128 %a = memref.alloc() : memref<10xf32>129 130 %cf0 = arith.constant 0.0 : f32131 affine.for %i0 = 0 to 10 {132 affine.store %cf0, %a[%i0] : memref<10xf32>133 }134 135 affine.for %i1 = 0 to 5 {136 affine.for %i2 = 0 to 10 {137 %v0 = affine.load %a[%i2] : memref<10xf32>138 affine.store %v0, %a[%i2] : memref<10xf32>139 }140 }141 142 // The dependence between the load and affine.store is carried on loop '%i1', and143 // cannot be fused with loop '%i0' without violating this dependence.144 // Once loops '%i1' and %i2' are interchanged, loop '%i0' can be fused145 // at loop depth 1, because the loop carrying the dependence has been146 // interchanged and is now at depth 2.147 148 // CHECK: affine.for %{{.*}} = 0 to 10 {149 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>150 // CHECK-NEXT: affine.for %{{.*}} = 0 to 5 {151 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>152 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>153 // CHECK-NEXT: }154 // CHECK-NEXT: }155 // CHECK-NEXT: return156 return157}158 159// -----160// CHECK-LABEL: func @should_fuse_after_two_loop_interchanges() {161func.func @should_fuse_after_two_loop_interchanges() {162 %a = memref.alloc() : memref<6x8xf32>163 164 %cf0 = arith.constant 0.0 : f32165 affine.for %i0 = 0 to 6 {166 affine.for %i1 = 0 to 8 {167 affine.store %cf0, %a[%i0, %i1] : memref<6x8xf32>168 }169 }170 171 affine.for %i2 = 0 to 4 {172 affine.for %i3 = 0 to 6 {173 affine.for %i4 = 0 to 2 {174 affine.for %i5 = 0 to 8 {175 %v0 = affine.load %a[%i3, %i5] : memref<6x8xf32>176 %v1 = arith.addf %v0, %v0 : f32177 affine.store %v1, %a[%i3, %i5] : memref<6x8xf32>178 }179 }180 }181 }182 183 // The dependence between the load and affine.store is carried on loops '%i2' and184 // '%i4', and cannot be fused with loop '%i0' without violating this185 // dependence.186 // Once loop '%i2' is interchanged with loop '%i3', and again with loop187 // '%i5', then loop '%i0' can be fused at loop depth 2, because the loop188 // carrying the dependences have been interchanged with loops at depth > 2.189 190 // CHECK: affine.for %{{.*}} = 0 to 6 {191 // CHECK-NEXT: affine.for %{{.*}} = 0 to 8 {192 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0] : memref<1x1xf32>193 // CHECK-NEXT: affine.for %{{.*}} = 0 to 4 {194 // CHECK-NEXT: affine.for %{{.*}} = 0 to 2 {195 // CHECK-NEXT: affine.load %{{.*}}[0, 0] : memref<1x1xf32>196 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32197 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0] : memref<1x1xf32>198 // CHECK-NEXT: }199 // CHECK-NEXT: }200 // CHECK-NEXT: }201 // CHECK-NEXT: }202 // CHECK-NEXT: return203 return204}205 206// -----207 208func.func @should_fuse_live_out_writer(%arg0 : memref<10xf32>) -> memref<10xf32> {209 %cst = arith.constant 0.000000e+00 : f32210 affine.for %i0 = 0 to 10 {211 affine.store %cst, %arg0[%i0] : memref<10xf32>212 }213 affine.for %i1 = 0 to 10 {214 %1 = affine.load %arg0[%i1] : memref<10xf32>215 affine.store %1, %arg0[%i1] : memref<10xf32>216 }217 return %arg0 : memref<10xf32>218 219 // CHECK: %{{.*}} = arith.constant 0.000000e+00 : f32220 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {221 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>222 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>223 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>224 // CHECK-NEXT: }225 // CHECK-NEXT: return %{{.*}} : memref<10xf32>226}227 228// -----229 230// The fused slice has 16 iterations from along %i0.231 232// CHECK-DAG: [[$MAP_LB:#map[0-9]*]] = affine_map<(d0) -> (d0 * 16)>233// CHECK-DAG: [[$MAP_UB:#map[0-9]*]] = affine_map<(d0) -> (d0 * 16 + 16)>234 235// CHECK-LABEL: slice_tile236func.func @slice_tile(%arg0: memref<128x8xf32>, %arg1: memref<32x8xf32>, %0 : f32) -> memref<32x8xf32> {237 affine.for %i0 = 0 to 32 {238 affine.for %i1 = 0 to 8 {239 affine.store %0, %arg1[%i0, %i1] : memref<32x8xf32>240 }241 }242 affine.for %i = 0 to 2 {243 affine.for %j = 0 to 8 {244 affine.for %k = 0 to 8 {245 affine.for %kk = 0 to 16 {246 %v = affine.load %arg0[16 * %k + %kk, %j] : memref<128x8xf32>247 %r = "foo"(%v) : (f32) -> f32248 }249 affine.for %ii = 0 to 16 {250 %v = affine.load %arg1[16 * %i + %ii, %j] : memref<32x8xf32>251 %s = arith.addf %v, %v : f32252 affine.store %s, %arg1[16 * %i + %ii, %j] : memref<32x8xf32>253 }254 }255 }256 }257 return %arg1 : memref<32x8xf32>258}259// CHECK: affine.for %{{.*}} = 0 to 2 {260// CHECK-NEXT: affine.for %{{.*}} = 0 to 8 {261// CHECK-NEXT: affine.for %{{.*}} = [[$MAP_LB]](%{{.*}}) to [[$MAP_UB]](%{{.*}}) {262// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<32x8xf32>263// CHECK-NEXT: }264// CHECK-NEXT: affine.for %{{.*}} = 0 to 8 {265// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {266// CHECK-NEXT: affine.load %{{.*}}[%{{.*}} * 16 + %{{.*}}, %{{.*}}] : memref<128x8xf32>267// CHECK-NEXT: "foo"(%{{.*}}) : (f32) -> f32268// CHECK-NEXT: }269// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {270// CHECK-NEXT: affine.load %{{.*}}[%{{.*}} * 16 + %{{.*}}, %{{.*}}] : memref<32x8xf32>271// CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32272// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}} * 16 + %{{.*}}, %{{.*}}] : memref<32x8xf32>273// CHECK-NEXT: }274// CHECK-NEXT: }275// CHECK-NEXT: }276// CHECK-NEXT: }277// CHECK-NEXT: return %{{.*}} : memref<32x8xf32>278// CHECK-NEXT:}279 280// -----281 282// Test case which illustrates fix for b/126454413283func.func @test_add_slice_bounds() {284 %a = memref.alloc() : memref<10xf32>285 %b = memref.alloc() : memref<10xf32>286 %cf7 = arith.constant 7.0 : f32287 %c0 = arith.constant 0 : index288 289 affine.for %i0 = 0 to 10 {290 affine.for %i1 = 0 to 10 {291 affine.for %i2 = 0 to 10 {292 %a0 = affine.apply affine_map<(d0) -> (d0)> (%i0)293 %a1 = affine.apply affine_map<(d0) -> (d0)> (%i0)294 %a2 = affine.apply affine_map<(d0, d1) -> (d0 - d1)> (%a0, %a1)295 affine.store %cf7, %a[%a2] : memref<10xf32>296 }297 }298 }299 affine.for %i3 = 0 to 10 {300 affine.for %i4 = 0 to 10 {301 affine.for %i5 = 0 to 10 {302 %v0 = affine.load %a[%c0] : memref<10xf32>303 }304 }305 }306 307// CHECK: affine.for %{{.*}} = 0 to 10 {308// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {309// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {310// CHECK-NEXT: affine.apply #map(%{{.*}})311// CHECK-NEXT: affine.apply #map(%{{.*}})312// CHECK-NEXT: affine.apply #map1(%{{.*}}, %{{.*}})313// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>314// CHECK-NEXT: }315// CHECK-NEXT: }316// CHECK-NEXT: }317// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {318// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {319// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {320// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>321// CHECK-NEXT: }322// CHECK-NEXT: }323// CHECK-NEXT: }324 return325}326 327// -----328 329func.func @should_fuse_init_loops_siblings_then_shared_producer(%arg0: memref<10x10xf32>, %arg1: memref<10x10xf32>) {330 %0 = memref.alloc() : memref<10x10xf32>331 %cst = arith.constant 0.000000e+00 : f32332 %cst_0 = arith.constant 1.000000e+00 : f32333 %cst_1 = arith.constant 7.000000e+00 : f32334 affine.for %i0 = 0 to 10 {335 affine.for %i1 = 0 to 10 {336 affine.store %cst_1, %0[%i0, %i1] : memref<10x10xf32>337 }338 }339 affine.for %i2 = 0 to 3 {340 affine.for %i3 = 0 to 3 {341 affine.store %cst, %arg0[%i2, %i3] : memref<10x10xf32>342 }343 }344 affine.for %i4 = 0 to 3 {345 affine.for %i5 = 0 to 3 {346 %1 = affine.load %0[%i4, %i5] : memref<10x10xf32>347 %2 = affine.load %arg0[%i4, %i5] : memref<10x10xf32>348 %3 = arith.mulf %1, %2 : f32349 affine.store %3, %arg0[%i4, %i5] : memref<10x10xf32>350 }351 }352 affine.for %i6 = 0 to 3 {353 affine.for %i7 = 0 to 3 {354 affine.store %cst_0, %arg1[%i6, %i7] : memref<10x10xf32>355 }356 }357 affine.for %i8 = 0 to 3 {358 affine.for %i9 = 0 to 3 {359 %4 = affine.load %0[%i8, %i9] : memref<10x10xf32>360 %5 = affine.load %arg1[%i8, %i9] : memref<10x10xf32>361 %6 = arith.addf %4, %5 : f32362 affine.store %6, %arg1[%i8, %i9] : memref<10x10xf32>363 }364 }365 366 // Pass 1: should fuse single-use producer loop nests into their unique user,367 // so '%i2' will fuse into '%i4' and '%i6' will fuse into '%i8'.368 // Pass 2: should fuse sibling loop nests which share no dependence edges,369 // so should fuse '%i4' into '%i8'.370 // Pass 3: should fuse single-use producer loop nest '%i0' into '%i8'. Note371 // that loop nest '%i0' now has a single user after Pass 2 fused its372 // two users together).373 374// CHECK: affine.for %{{.*}} = 0 to 3 {375// CHECK-NEXT: affine.for %{{.*}} = 0 to 3 {376// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0] : memref<1x1xf32>377// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x10xf32>378// CHECK-NEXT: affine.load %{{.*}}[0, 0] : memref<1x1xf32>379// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x10xf32>380// CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32381// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x10xf32>382// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x10xf32>383// CHECK-NEXT: affine.load %{{.*}}[0, 0] : memref<1x1xf32>384// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x10xf32>385// CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32386// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x10xf32>387// CHECK-NEXT: }388// CHECK-NEXT: }389// CHECK-NEXT: return390 391 return392}393 394// -----395 396// Test sibling fusion of two matrix-vector products sharing the input matrix.397 398func.func @two_matrix_vector_products() {399 %in_matrix = memref.alloc() : memref<10x10xf32>400 %in_vec0 = memref.alloc() : memref<10xf32>401 %in_vec1 = memref.alloc() : memref<10xf32>402 %out_vec0 = memref.alloc() : memref<10xf32>403 %out_vec1 = memref.alloc() : memref<10xf32>404 %cf7 = arith.constant 7.0 : f32405 406 // Populate input matrix.407 affine.for %i0 = 0 to 10 {408 affine.for %i1 = 0 to 10 {409 affine.store %cf7, %in_matrix[%i0, %i1] : memref<10x10xf32>410 }411 }412 // out_vec0 = in_matrix x in_vec0413 affine.for %i2 = 0 to 10 {414 affine.for %i3 = 0 to 10 {415 %v0 = affine.load %in_matrix[%i2, %i3] : memref<10x10xf32>416 %v1 = affine.load %in_vec0[%i3] : memref<10xf32>417 %v2 = arith.mulf %v0, %v1 : f32418 %v3 = affine.load %out_vec0[%i3] : memref<10xf32>419 %v4 = arith.addf %v2, %v3 : f32420 affine.store %v4, %out_vec0[%i3] : memref<10xf32>421 }422 }423 // out_vec1 = in_matrix x in_vec1424 affine.for %i4 = 0 to 10 {425 affine.for %i5 = 0 to 10 {426 %v5 = affine.load %in_matrix[%i4, %i5] : memref<10x10xf32>427 %v6 = affine.load %in_vec1[%i5] : memref<10xf32>428 %v7 = arith.mulf %v5, %v6 : f32429 %v8 = affine.load %out_vec1[%i5] : memref<10xf32>430 %v9 = arith.addf %v7, %v8 : f32431 affine.store %v9, %out_vec1[%i5] : memref<10xf32>432 }433 }434 435// CHECK: affine.for %{{.*}} = 0 to 10 {436// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {437// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, 0] : memref<10x1xf32>438// CHECK-NEXT: }439// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {440// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, 0] : memref<10x1xf32>441// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>442// CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32443// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>444// CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32445// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>446// CHECK-NEXT: }447// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {448// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, 0] : memref<10x1xf32>449// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>450// CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32451// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>452// CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32453// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>454// CHECK-NEXT: }455// CHECK-NEXT: }456// CHECK-NEXT: return457 return458}459 460// -----461 462func.func @should_not_slice_past_slice_barrier() {463 %0 = memref.alloc() : memref<100x16xf32>464 affine.for %i0 = 0 to 100 {465 affine.for %i1 = 0 to 16 {466 %1 = "op1"() : () -> f32467 affine.store %1, %0[%i0, %i1] : memref<100x16xf32>468 } {slice_fusion_barrier = true}469 }470 affine.for %i2 = 0 to 100 {471 affine.for %i3 = 0 to 16 {472 %2 = affine.load %0[%i2, %i3] : memref<100x16xf32>473 "op2"(%2) : (f32) -> ()474 }475 }476 // The 'slice_fusion_barrier' attribute on '%i1' prevents slicing the477 // iteration space of '%i1' and any enclosing loop nests.478// CHECK: affine.for %{{.*}} = 0 to 100 {479// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {480// CHECK-NEXT: %{{.*}} = "op1"() : () -> f32481// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, %{{.*}}] : memref<1x16xf32>482// CHECK-NEXT: } {slice_fusion_barrier = true}483// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {484// CHECK-NEXT: affine.load %{{.*}}[0, %{{.*}}] : memref<1x16xf32>485// CHECK-NEXT: "op2"(%{{.*}}) : (f32) -> ()486// CHECK-NEXT: }487// CHECK-NEXT: }488 return489}490 491// -----492 493#map = affine_map<(d0, d1) -> (d0 * 16 + d1)>494func.func @fuse_across_dim_mismatch(%arg0: memref<4x4x16x1xf32>, %arg1: memref<144x9xf32>, %arg2: memref<9xf32>) {495 %1 = memref.alloc() : memref<144x4xf32>496 %2 = arith.constant 0.0 : f32497 affine.for %i2 = 0 to 9 {498 affine.for %i3 = 0 to 4 {499 affine.for %i5 = 0 to 16 {500 %7 = affine.apply #map(%i2, %i5)501 affine.store %2, %1[%7, %i3] : memref<144x4xf32>502 }503 }504 }505 affine.for %i6 = 0 to 9 {506 affine.for %i7 = 0 to 9 {507 affine.for %i8 = 0 to 4 {508 affine.for %i10 = 0 to 16 {509 %10 = affine.apply #map(%i6, %i10)510 %11 = affine.load %1[%10, %i8] : memref<144x4xf32>511 }512 }513 }514 }515 return516}517// MAXIMAL: #[[$MAP:.*]] = affine_map<(d0, d1) -> (d0 * 16 + d1)>518// MAXIMAL-LABEL: func @fuse_across_dim_mismatch519// MAXIMAL: memref.alloc() : memref<1x1xf32>520// MAXIMAL: affine.for %{{.*}} = 0 to 9 {521// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 9 {522// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 4 {523// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 16 {524// MAXIMAL-NEXT: affine.apply #[[$MAP]](%{{.*}}, %{{.*}})525// MAXIMAL-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0] : memref<1x1xf32>526// MAXIMAL-NEXT: affine.apply #[[$MAP]](%{{.*}}, %{{.*}})527// MAXIMAL-NEXT: affine.load %{{.*}}[0, 0] : memref<1x1xf32>528// MAXIMAL-NEXT: }529// MAXIMAL-NEXT: }530// MAXIMAL-NEXT: }531// MAXIMAL-NEXT: }532 533// -----534 535#map3 = affine_map<(d0, d1) -> ((d0 * 72 + d1) floordiv 2304)>536#map4 = affine_map<(d0, d1) -> (((d0 * 72 + d1) mod 2304) floordiv 1152)>537#map5 = affine_map<(d0, d1) -> (((((d0 * 72 + d1) mod 2304) mod 1152) floordiv 9) floordiv 8)>538#map6 = affine_map<(d0, d1) -> (((((d0 * 72 + d1) mod 2304) mod 1152) mod 9) floordiv 3)>539#map7 = affine_map<(d0, d1) -> (((((d0 * 72 + d1) mod 2304) mod 1152) mod 9) mod 3)>540#map10 = affine_map<(d0, d1) -> (d0 * 16 + d1)>541#map11 = affine_map<(d0, d1) -> (d0 * 16 + d1)>542#map12 = affine_map<(d0, d1) -> (d0 * 16 - d1 + 15)>543func.func @fuse_across_varying_dims_complex(%arg0: f32) {544 %c0 = arith.constant 0 : index545 %0 = memref.alloc() : memref<2x2x3x3x16x1xf32>546 %1 = memref.alloc() : memref<64x9xf32>547 %2 = memref.alloc() : memref<144x4xf32>548 affine.for %i0 = 0 to 64 {549 affine.for %i1 = 0 to 9 {550 %4 = affine.apply #map3(%i0, %i1)551 %5 = affine.apply #map4(%i0, %i1)552 %6 = affine.apply #map5(%i0, %i1)553 %7 = affine.apply #map6(%i0, %i1)554 %8 = affine.apply #map7(%i0, %i1)555 %9 = affine.load %0[%4, %5, %7, %8, %6, %c0] : memref<2x2x3x3x16x1xf32>556 affine.store %9, %1[%i0, %i1] : memref<64x9xf32>557 }558 }559 affine.for %i2 = 0 to 9 {560 affine.for %i3 = 0 to 4 {561 affine.for %i4 = 0 to 16 {562 %10 = affine.apply #map10(%i3, %i4)563 %11 = affine.load %1[%10, %i2] : memref<64x9xf32>564 }565 affine.for %i5 = 0 to 16 {566 %14 = affine.apply #map11(%i2, %i5)567 affine.store %arg0, %2[%14, %i3] : memref<144x4xf32>568 }569 }570 }571 affine.for %i6 = 0 to 9 {572 affine.for %i7 = 0 to 9 {573 affine.for %i8 = 0 to 4 {574 affine.for %i9 = 0 to 16 {575 %15 = affine.apply #map12(%i8, %i9)576 %16 = affine.load %1[%15, %i7] : memref<64x9xf32>577 }578 }579 }580 }581 return582}583// MAXIMAL-DAG: [[$MAP0:#map[0-9]*]] = affine_map<(d0, d1) -> ((d0 * 72 + d1) floordiv 2304)>584// MAXIMAL-DAG: [[$MAP1:#map[0-9]*]] = affine_map<(d0, d1) -> (((d0 * 72 + d1) mod 2304) floordiv 1152)>585// MAXIMAL-DAG: [[$MAP2:#map[0-9]*]] = affine_map<(d0, d1) -> ((((d0 * 72 + d1) mod 1152) floordiv 9) floordiv 8)>586// MAXIMAL-DAG: [[$MAP3:#map[0-9]*]] = affine_map<(d0, d1) -> ((d1 mod 9) floordiv 3)>587// MAXIMAL-DAG: [[$MAP4:#map[0-9]*]] = affine_map<(d0, d1) -> (d1 mod 3)>588// MAXIMAL-DAG: [[$MAP7:#map[0-9]*]] = affine_map<(d0, d1) -> (d0 * 16 + d1)>589// MAXIMAL-DAG: [[$MAP8:#map[0-9]*]] = affine_map<(d0, d1) -> (d0 * 16 - d1 + 15)>590// MAXIMAL-LABEL: func @fuse_across_varying_dims_complex591// MAXIMAL-NEXT: memref.alloc() : memref<64x1xf32>592// MAXIMAL-NEXT: arith.constant 0 : index593// MAXIMAL-NEXT: memref.alloc() : memref<2x2x3x3x16x1xf32>594// MAXIMAL-NEXT: memref.alloc() : memref<144x4xf32>595// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 9 {596// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 4 {597// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 16 {598// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 64 {599// MAXIMAL-NEXT: affine.apply [[$MAP0]](%{{.*}}, %{{.*}})600// MAXIMAL-NEXT: affine.apply [[$MAP1]](%{{.*}}, %{{.*}})601// MAXIMAL-NEXT: affine.apply [[$MAP2]](%{{.*}}, %{{.*}})602// MAXIMAL-NEXT: affine.apply [[$MAP3]](%{{.*}}, %{{.*}})603// MAXIMAL-NEXT: affine.apply [[$MAP4]](%{{.*}}, %{{.*}})604// MAXIMAL-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref<2x2x3x3x16x1xf32>605// MAXIMAL-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, 0] : memref<64x1xf32>606// MAXIMAL-NEXT: }607// MAXIMAL-NEXT: affine.apply [[$MAP7]](%{{.*}}, %{{.*}})608// MAXIMAL-NEXT: affine.load %{{.*}}[%{{.*}} * 16 + %{{.*}}, 0] : memref<64x1xf32>609// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 9 {610// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 4 {611// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 16 {612// MAXIMAL-NEXT: affine.apply [[$MAP8]](%{{.*}}, %{{.*}})613// MAXIMAL-NEXT: affine.load %{{.*}}[%{{.*}} * 16 - %{{.*}} + 15, 0] : memref<64x1xf32>614// MAXIMAL-NEXT: }615// MAXIMAL-NEXT: }616// MAXIMAL-NEXT: }617// MAXIMAL-NEXT: }618// MAXIMAL-NEXT: affine.for %{{.*}} = 0 to 16 {619// MAXIMAL-NEXT: affine.apply [[$MAP7]](%{{.*}}, %{{.*}})620// MAXIMAL-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<144x4xf32>621// MAXIMAL-NEXT: }622// MAXIMAL-NEXT: }623// MAXIMAL-NEXT: }624 625// -----626 627func.func @should_fuse_with_slice_union() {628 %a = memref.alloc() : memref<100xf32>629 %c0 = arith.constant 0 : index630 %cf0 = arith.constant 0.0 : f32631 632 affine.for %i0 = 0 to 100 {633 affine.store %cf0, %a[%i0]: memref<100xf32>634 }635 636 affine.for %i1 = 10 to 20 {637 %v0 = affine.load %a[%i1]: memref<100xf32>638 affine.for %i2 = 15 to 25 {639 %v1 = affine.load %a[%i2]: memref<100xf32>640 }641 }642 // The union of two slice bounds (calculated between the store and each of643 // the loads) is computed and used in the fusion cost calculation, index644 // remapping, and private memref size. The result is that the temporary645 // memref is reduced from 100xf32 to 15xf32 and properly indexed by646 // the fused loops based on the union calculation.647// CHECK: affine.for %{{.*}} = 10 to 20 {648// CHECK-NEXT: affine.for %{{.*}} = 10 to 25 {649// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}} - 10] : memref<15xf32>650// CHECK-NEXT: }651// CHECK-NEXT: affine.load %{{.*}}[%{{.*}} - 10] : memref<15xf32>652// CHECK-NEXT: affine.for %{{.*}} = 15 to 25 {653// CHECK-NEXT: affine.load %{{.*}}[%{{.*}} - 10] : memref<15xf32>654// CHECK-NEXT: }655// CHECK-NEXT: }656// CHECK-NEXT: return657 return658}659 660// -----661 662func.func @affine_add_mm_fused(%arg0: memref<1024x1024xf32>, %arg1: memref<1024x1024xf32>, %arg2: memref<1024x1024xf32>, %arg3: memref<1024x1024xf32>) {663 affine.for %i2 = 0 to 1024 {664 affine.for %i3 = 0 to 1024 {665 %0 = affine.load %arg3[%i2, %i3] : memref<1024x1024xf32>666 %1 = affine.load %arg2[%i2, %i3] : memref<1024x1024xf32>667 %2 = arith.addf %1, %0 : f32668 affine.store %2, %arg2[%i2, %i3] : memref<1024x1024xf32>669 }670 }671 affine.for %i4 = 0 to 1024 {672 affine.for %i5 = 0 to 1024 {673 affine.for %i6 = 0 to 1024 {674 %3 = affine.load %arg1[%i6, %i5] : memref<1024x1024xf32>675 %4 = affine.load %arg0[%i4, %i6] : memref<1024x1024xf32>676 %5 = arith.mulf %4, %3 : f32677 %6 = affine.load %arg2[%i4, %i5] : memref<1024x1024xf32>678 %7 = arith.addf %6, %5 : f32679 affine.store %7, %arg2[%i4, %i5] : memref<1024x1024xf32>680 }681 }682 }683 // Should fuse elementwise add loop at loop depth 2, above loop-carried684 // dependence between load/store on '%arg2', carried on reduction loop %i6.685 // CHECK: affine.for %{{.*}} = 0 to 1024 {686 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {687 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>688 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>689 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32690 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>691 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {692 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>693 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>694 // CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32695 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>696 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32697 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>698 // CHECK-NEXT: }699 // CHECK-NEXT: }700 // CHECK-NEXT: }701 return702}703 704// -----705 706func.func @affine_2mm_fused(%arg0: memref<1024x1024xf32>, %arg1: memref<1024x1024xf32>, %arg2: memref<1024x1024xf32>, %arg3: memref<1024x1024xf32>, %arg4: memref<1024x1024xf32>) {707 %cst = arith.constant 0.000000e+00 : f32708 affine.for %i0 = 0 to 1024 {709 affine.for %i1 = 0 to 1024 {710 affine.store %cst, %arg2[%i0, %i1] : memref<1024x1024xf32>711 }712 }713 affine.for %i2 = 0 to 1024 {714 affine.for %i3 = 0 to 1024 {715 affine.store %cst, %arg4[%i2, %i3] : memref<1024x1024xf32>716 }717 }718 affine.for %i4 = 0 to 1024 {719 affine.for %i5 = 0 to 1024 {720 affine.for %i6 = 0 to 1024 {721 %0 = affine.load %arg1[%i6, %i5] : memref<1024x1024xf32>722 %1 = affine.load %arg0[%i4, %i6] : memref<1024x1024xf32>723 %2 = arith.mulf %1, %0 : f32724 %3 = affine.load %arg2[%i4, %i5] : memref<1024x1024xf32>725 %4 = arith.addf %3, %2 : f32726 affine.store %4, %arg2[%i4, %i5] : memref<1024x1024xf32>727 }728 }729 }730 affine.for %i7 = 0 to 1024 {731 affine.for %i8 = 0 to 1024 {732 affine.for %i9 = 0 to 1024 {733 %5 = affine.load %arg1[%i9, %i8] : memref<1024x1024xf32>734 %6 = affine.load %arg0[%i7, %i9] : memref<1024x1024xf32>735 %7 = arith.mulf %6, %5 : f32736 %8 = affine.load %arg4[%i7, %i8] : memref<1024x1024xf32>737 %9 = arith.addf %8, %7 : f32738 affine.store %9, %arg4[%i7, %i8] : memref<1024x1024xf32>739 }740 }741 }742 743 // Should fuse MM initialization loops into their consumers, then fuse the744 // two matmul loops together for input reuse on '%arg0/%arg1'.745 746 // CHECK: affine.for %{{.*}} = 0 to 1024 {747 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {748 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>749 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {750 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>751 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>752 // CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32753 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>754 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32755 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>756 // CHECK-NEXT: }757 // CHECK-NEXT: }758 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {759 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>760 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {761 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>762 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>763 // CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32764 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>765 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32766 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>767 // CHECK-NEXT: }768 // CHECK-NEXT: }769 // CHECK-NEXT: }770 771 return772}773 774// -----775 776func.func @affine_2_dependent_mm_fused(%arg0: memref<1024x1024xf32>, %arg1: memref<1024x1024xf32>, %arg2: memref<1024x1024xf32>, %arg3: memref<1024x1024xf32>, %arg4: memref<1024x1024xf32>) {777 affine.for %i0 = 0 to 1024 {778 affine.for %i1 = 0 to 1024 {779 affine.for %i2 = 0 to 1024 {780 %0 = affine.load %arg1[%i2, %i1] : memref<1024x1024xf32>781 %1 = affine.load %arg0[%i0, %i2] : memref<1024x1024xf32>782 %2 = arith.mulf %1, %0 : f32783 %3 = affine.load %arg2[%i0, %i1] : memref<1024x1024xf32>784 %4 = arith.addf %3, %2 : f32785 affine.store %4, %arg2[%i0, %i1] : memref<1024x1024xf32>786 }787 }788 }789 affine.for %i3 = 0 to 1024 {790 affine.for %i4 = 0 to 1024 {791 affine.for %i5 = 0 to 1024 {792 %5 = affine.load %arg3[%i5, %i4] : memref<1024x1024xf32>793 %6 = affine.load %arg2[%i3, %i5] : memref<1024x1024xf32>794 %7 = arith.mulf %6, %5 : f32795 %8 = affine.load %arg4[%i3, %i4] : memref<1024x1024xf32>796 %9 = arith.addf %8, %7 : f32797 affine.store %9, %arg4[%i3, %i4] : memref<1024x1024xf32>798 }799 }800 }801 802 // CHECK: affine.for %{{.*}} = 0 to 1024 {803 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {804 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {805 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>806 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>807 // CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32808 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>809 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32810 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>811 // CHECK-NEXT: }812 // CHECK-NEXT: }813 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {814 // CHECK-NEXT: affine.for %{{.*}} = 0 to 1024 {815 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>816 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>817 // CHECK-NEXT: arith.mulf %{{.*}}, %{{.*}} : f32818 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>819 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f32820 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<1024x1024xf32>821 // CHECK-NEXT: }822 // CHECK-NEXT: }823 // CHECK-NEXT: }824 return825}826 827// -----828 829// CHECK-LABEL: func @should_fuse_self_dependence_multi_store_producer() {830func.func @should_fuse_self_dependence_multi_store_producer() {831 %m = memref.alloc() : memref<10xf32>832 %local_m = memref.alloc() : memref<10xf32>833 %cf7 = arith.constant 7.0 : f32834 835 affine.for %i0 = 0 to 10 {836 affine.store %cf7, %local_m[%i0] : memref<10xf32>837 %v0 = affine.load %local_m[%i0] : memref<10xf32>838 affine.store %v0, %m[%i0] : memref<10xf32>839 }840 affine.for %i1 = 0 to 10 {841 %v1 = affine.load %m[%i1] : memref<10xf32>842 }843 // CHECK: affine.for %[[i0:.*]] = 0 to 10 {844 // CHECK-NEXT: affine.store %{{.*}}, [[LOCAL_M:%.*]][%[[i0]]] : memref<10xf32>845 // CHECK-NEXT: [[v0:%.*]] = affine.load [[LOCAL_M]][%[[i0]]] : memref<10xf32>846 // CHECK-NEXT: affine.store [[v0]], %{{.*}}[0] : memref<1xf32>847 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>848 // CHECK-NEXT: }849 // CHECK-NEXT: return850 return851}852 853// -----854 855// CHECK-LABEL: func @should_fuse_dead_multi_store_producer() {856func.func @should_fuse_dead_multi_store_producer() {857 %m = memref.alloc() : memref<10xf32>858 %dead_m = memref.alloc() : memref<10xf32>859 %cf7 = arith.constant 7.0 : f32860 861 affine.for %i0 = 0 to 10 {862 affine.store %cf7, %dead_m[%i0] : memref<10xf32>863 affine.store %cf7, %m[%i0] : memref<10xf32>864 }865 affine.for %i1 = 0 to 10 {866 %v0 = affine.load %m[%i1] : memref<10xf32>867 }868 // CHECK: affine.for %[[i0:.*]] = 0 to 10 {869 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%[[i0]]] : memref<10xf32>870 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>871 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>872 // CHECK-NEXT: }873 // CHECK-NEXT: return874 return875}876 877// -----878 879// CHECK-LABEL: func @should_fuse_function_live_out_multi_store_producer880func.func @should_fuse_function_live_out_multi_store_producer(%live_in_out_m : memref<10xf32>) {881 %m = memref.alloc() : memref<10xf32>882 %cf7 = arith.constant 7.0 : f32883 884 affine.for %i0 = 0 to 10 {885 affine.store %cf7, %live_in_out_m[%i0] : memref<10xf32>886 affine.store %cf7, %m[%i0] : memref<10xf32>887 }888 affine.for %i1 = 0 to 10 {889 %v0 = affine.load %m[%i1] : memref<10xf32>890 }891 // CHECK: affine.for %[[i0:.*]] = 0 to 10 {892 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%[[i0]]] : memref<10xf32>893 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>894 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>895 // CHECK-NEXT: }896 // CHECK-NEXT: return897 return898}899 900// Add further tests in mlir/test/Transforms/loop-fusion-4.mlir901