1579 lines · plain
1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='builtin.module(func.func(affine-loop-fusion))' -split-input-file | FileCheck %s2 3// Part II of fusion tests in mlir/test/Transforms/loop-fusion=2.mlir.4// Part III of fusion tests in mlir/test/Transforms/loop-fusion-3.mlir5// Part IV of fusion tests in mlir/test/Transforms/loop-fusion-4.mlir6 7// TODO: Add more tests:8// *) Add nested fusion test cases when non-constant loop bound support is9// added to iteration domain in dependence check.10// *) Add a test w/ floordiv/ceildiv/mod when supported in dependence check.11// *) Add tests which check fused computation slice indexing and loop bounds.12// TODO: Test clean up: move memref allocs to func args.13 14// -----15 16// CHECK-LABEL: func @should_fuse_raw_dep_for_locality() {17func.func @should_fuse_raw_dep_for_locality() {18 %m = memref.alloc() : memref<10xf32>19 %cf7 = arith.constant 7.0 : f3220 21 affine.for %i0 = 0 to 10 {22 affine.store %cf7, %m[%i0] : memref<10xf32>23 }24 affine.for %i1 = 0 to 10 {25 %v0 = affine.load %m[%i1] : memref<10xf32>26 }27 // CHECK: affine.for %{{.*}} = 0 to 10 {28 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>29 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>30 // CHECK-NEXT: }31 // CHECK-NEXT: return32 return33}34 35// -----36 37// CHECK-LABEL: func @should_fuse_reduction_to_pointwise() {38func.func @should_fuse_reduction_to_pointwise() {39 %a = memref.alloc() : memref<10x10xf32>40 %b = memref.alloc() : memref<10xf32>41 %c = memref.alloc() : memref<10xf32>42 43 %cf7 = arith.constant 7.0 : f3244 45 affine.for %i0 = 0 to 10 {46 affine.for %i1 = 0 to 10 {47 %v0 = affine.load %b[%i0] : memref<10xf32>48 %v1 = affine.load %a[%i0, %i1] : memref<10x10xf32>49 %v3 = arith.addf %v0, %v1 : f3250 affine.store %v3, %b[%i0] : memref<10xf32>51 }52 }53 affine.for %i2 = 0 to 10 {54 %v4 = affine.load %b[%i2] : memref<10xf32>55 affine.store %v4, %c[%i2] : memref<10xf32>56 }57 58 // Should fuse in entire inner loop on %i1 from source loop nest, as %i159 // is not used in the access function of the store/load on %b.60 // CHECK: affine.for %{{.*}} = 0 to 10 {61 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {62 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>63 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x10xf32>64 // CHECK-NEXT: arith.addf %{{.*}}, %{{.*}} : f3265 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>66 // CHECK-NEXT: }67 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>68 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>69 // CHECK-NEXT: }70 // CHECK-NEXT: return71 return72}73 74// -----75 76// CHECK-DAG: [[$MAP_SHIFT_MINUS_ONE_R1:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 - 1)>77// CHECK-DAG: [[$MAP_SHIFT_D0_BY_ONE:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (d0 + 1)>78// CHECK-DAG: [[$MAP_SHIFT_D1_BY_ONE:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (d1 + 1)>79 80// CHECK-LABEL: func @should_fuse_loop_nests_with_shifts() {81func.func @should_fuse_loop_nests_with_shifts() {82 %a = memref.alloc() : memref<10x10xf32>83 %cf7 = arith.constant 7.0 : f3284 85 affine.for %i0 = 0 to 9 {86 affine.for %i1 = 0 to 9 {87 affine.store %cf7, %a[%i0 + 1, %i1 + 1] : memref<10x10xf32>88 }89 }90 affine.for %i2 = 1 to 10 {91 affine.for %i3 = 1 to 10 {92 %v0 = affine.load %a[%i2, %i3] : memref<10x10xf32>93 }94 }95 96 // Source slice affine apply sequence:97 // *) First two affine apply's map from the dst to src iteration space.98 // *) Third affine apply is access function around src store.99 // *) Fourth affine apply shifts the stores access function by '-1', because100 // of the offset induced by reducing the memref shape from 10x10 to 9x9.101 // *) Fifth affine apply shifts the loads access function by '-1', because102 // of the offset induced by reducing the memref shape from 10x10 to 9x9.103 // NOTE: Should create a private memref with reduced shape 9x9xf32.104 // CHECK: affine.for %{{.*}} = 1 to 10 {105 // CHECK-NEXT: affine.for %{{.*}} = 1 to 10 {106 // CHECK-NEXT: %[[I:.*]] = affine.apply [[$MAP_SHIFT_MINUS_ONE_R1]](%{{.*}})107 // CHECK-NEXT: %[[J:.*]] = affine.apply [[$MAP_SHIFT_MINUS_ONE_R1]](%{{.*}})108 // CHECK-NEXT: affine.apply [[$MAP_SHIFT_D0_BY_ONE]](%[[I]], %[[J]])109 // CHECK-NEXT: affine.apply [[$MAP_SHIFT_D1_BY_ONE]](%[[I]], %[[J]])110 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0] : memref<1x1xf32>111 // CHECK-NEXT: affine.load %{{.*}}[0, 0] : memref<1x1xf32>112 // CHECK-NEXT: }113 // CHECK-NEXT: }114 // CHECK-NEXT: return115 return116}117 118// -----119 120// CHECK-LABEL: func @should_fuse_loop_nest() {121func.func @should_fuse_loop_nest() {122 %a = memref.alloc() : memref<10x10xf32>123 %b = memref.alloc() : memref<10x10xf32>124 %cf7 = arith.constant 7.0 : f32125 126 affine.for %i0 = 0 to 10 {127 affine.for %i1 = 0 to 10 {128 affine.store %cf7, %a[%i0, %i1] : memref<10x10xf32>129 }130 }131 affine.for %i2 = 0 to 10 {132 affine.for %i3 = 0 to 10 {133 %v0 = affine.load %a[%i3, %i2] : memref<10x10xf32>134 affine.store %v0, %b[%i2, %i3] : memref<10x10xf32>135 }136 }137 affine.for %i4 = 0 to 10 {138 affine.for %i5 = 0 to 10 {139 %v1 = affine.load %b[%i4, %i5] : memref<10x10xf32>140 }141 }142 // Expecting private memref for '%a' first, then private memref for '%b'.143 // CHECK-DAG: [[NEWA:%[0-9a-zA-Z_]+]] = memref.alloc() : memref<1x1xf32>144 // CHECK-DAG: [[NEWB:%[0-9a-zA-Z_]+]] = memref.alloc() : memref<1x1xf32>145 // CHECK: affine.for %{{.*}} = 0 to 10 {146 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {147 // CHECK-NEXT: affine.store %{{.*}}, [[NEWA]][0, 0] : memref<1x1xf32>148 // CHECK-NEXT: affine.load [[NEWA]][0, 0] : memref<1x1xf32>149 // CHECK-NEXT: affine.store %{{.*}}, [[NEWB]][0, 0] : memref<1x1xf32>150 // CHECK-NEXT: affine.load [[NEWB]][0, 0] : memref<1x1xf32>151 // CHECK-NEXT: }152 // CHECK-NEXT: }153 // CHECK-NEXT: return154 return155}156 157// -----158 159// CHECK-LABEL: func @should_fuse_across_intermediate_loop_with_no_deps() {160func.func @should_fuse_across_intermediate_loop_with_no_deps() {161 %a = memref.alloc() : memref<10xf32>162 %b = memref.alloc() : memref<10xf32>163 %c = memref.alloc() : memref<10xf32>164 165 %cf7 = arith.constant 7.0 : f32166 167 affine.for %i0 = 0 to 10 {168 %v0 = affine.load %a[%i0] : memref<10xf32>169 affine.store %v0, %b[%i0] : memref<10xf32>170 }171 affine.for %i1 = 0 to 10 {172 affine.store %cf7, %c[%i1] : memref<10xf32>173 }174 affine.for %i2 = 0 to 10 {175 %v1 = affine.load %b[%i2] : memref<10xf32>176 }177 178 // Should fuse first loop (past second loop with no dependences) into third.179 // Note that fusion creates a private memref '%2' for the fused loop nest.180 // CHECK: affine.for %{{.*}} = 0 to 10 {181 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>182 // CHECK-NEXT: }183 // CHECK: affine.for %{{.*}} = 0 to 10 {184 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>185 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>186 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>187 // CHECK-NEXT: }188 // CHECK-NEXT: return189 return190}191 192// -----193 194// CHECK-LABEL: func @should_fuse_all_loops() {195func.func @should_fuse_all_loops() {196 %a = memref.alloc() : memref<10xf32>197 %b = memref.alloc() : memref<10xf32>198 %cf7 = arith.constant 7.0 : f32199 200 // Set up flow dependences from first and second loops to third.201 affine.for %i0 = 0 to 10 {202 affine.store %cf7, %a[%i0] : memref<10xf32>203 }204 affine.for %i1 = 0 to 10 {205 affine.store %cf7, %b[%i1] : memref<10xf32>206 }207 affine.for %i2 = 0 to 10 {208 %v0 = affine.load %a[%i2] : memref<10xf32>209 %v1 = affine.load %b[%i2] : memref<10xf32>210 }211 212 // Should fuse first and second loops into third.213 // Expecting private memref for '%a' first, then private memref for '%b'.214 // CHECK-DAG: [[NEWA:%[0-9a-zA-Z_]+]] = memref.alloc() : memref<1xf32>215 // CHECK-DAG: [[NEWB:%[0-9a-zA-Z_]+]] = memref.alloc() : memref<1xf32>216 // CHECK: affine.for %{{.*}} = 0 to 10 {217 // CHECK-NEXT: affine.store %{{.*}}, [[NEWA]][0] : memref<1xf32>218 // CHECK-NEXT: affine.store %{{.*}}, [[NEWB]][0] : memref<1xf32>219 // CHECK-NEXT: affine.load [[NEWA]][0] : memref<1xf32>220 // CHECK-NEXT: affine.load [[NEWB]][0] : memref<1xf32>221 // CHECK-NEXT: }222 // CHECK-NEXT: return223 return224}225 226// -----227 228// CHECK-LABEL: func @should_fuse_first_and_second_loops() {229func.func @should_fuse_first_and_second_loops() {230 %a = memref.alloc() : memref<10xf32>231 %b = memref.alloc() : memref<10xf32>232 %c = memref.alloc() : memref<10xf32>233 234 %cf7 = arith.constant 7.0 : f32235 236 affine.for %i0 = 0 to 10 {237 affine.store %cf7, %a[%i0] : memref<10xf32>238 }239 affine.for %i1 = 0 to 10 {240 %v0 = affine.load %a[%i1] : memref<10xf32>241 affine.store %cf7, %b[%i1] : memref<10xf32>242 }243 affine.for %i2 = 0 to 10 {244 %v1 = affine.load %c[%i2] : memref<10xf32>245 }246 247 // Should fuse first loop into the second (last loop should not be fused).248 // Should create private memref '%2' for fused scf.249 // CHECK: affine.for %{{.*}} = 0 to 10 {250 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>251 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>252 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>253 // CHECK-NEXT: }254 // CHECK: affine.for %{{.*}} = 0 to 10 {255 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>256 // CHECK-NEXT: }257 // CHECK-NEXT: return258 259 return260}261 262// -----263 264// CHECK-LABEL: func @should_not_fuse_would_create_cycle() {265func.func @should_not_fuse_would_create_cycle() {266 %a = memref.alloc() : memref<10xf32>267 %b = memref.alloc() : memref<10xf32>268 %c = memref.alloc() : memref<10xf32>269 270 %cf7 = arith.constant 7.0 : f32271 272 // Set up the following dependences:273 // 1) loop0 -> loop1 on memref '%{{.*}}'274 // 2) loop0 -> loop2 on memref '%{{.*}}'275 // 3) loop1 -> loop2 on memref '%{{.*}}'276 affine.for %i0 = 0 to 10 {277 %v0 = affine.load %a[%i0] : memref<10xf32>278 affine.store %cf7, %b[%i0] : memref<10xf32>279 }280 affine.for %i1 = 0 to 10 {281 affine.store %cf7, %a[%i1] : memref<10xf32>282 %v1 = affine.load %c[%i1] : memref<10xf32>283 }284 affine.for %i2 = 0 to 10 {285 %v2 = affine.load %b[%i2] : memref<10xf32>286 affine.store %cf7, %c[%i2] : memref<10xf32>287 }288 // Should not fuse: fusing loop first loop into last would create a cycle.289 // CHECK: affine.for %{{.*}} = 0 to 10 {290 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>291 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>292 // CHECK-NEXT: }293 // CHECK: affine.for %{{.*}} = 0 to 10 {294 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>295 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>296 // CHECK-NEXT: }297 // CHECK: affine.for %{{.*}} = 0 to 10 {298 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>299 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>300 // CHECK-NEXT: }301 // CHECK-NEXT: return302 return303}304 305// -----306 307// CHECK-LABEL: func @should_fuse_producer_consumer() {308func.func @should_fuse_producer_consumer() {309 %m = memref.alloc() : memref<10xf32>310 %cf7 = arith.constant 7.0 : f32311 312 affine.for %i0 = 0 to 10 {313 affine.store %cf7, %m[%i0] : memref<10xf32>314 }315 affine.for %i1 = 0 to 10 {316 affine.store %cf7, %m[%i1] : memref<10xf32>317 }318 affine.for %i2 = 0 to 10 {319 %v1 = affine.load %m[%i2] : memref<10xf32>320 }321 // Fusing loop %i0 to %i2 would violate the WAW dependence between %i0 and322 // %i1, but OK to fuse %i1 into %i2.323 // TODO: When the fusion pass is run to a fixed-point, it should324 // fuse all three of these loop nests.325 // CHECK: memref.alloc() : memref<1xf32>326 // CHECK: affine.for %{{.*}} = 0 to 10 {327 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>328 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>329 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>330 // CHECK-NEXT: }331 // CHECK-NEXT: return332 return333}334 335// -----336 337// CHECK-LABEL: func @should_fuse_and_move_to_preserve_war_dep() {338func.func @should_fuse_and_move_to_preserve_war_dep() {339 %a = memref.alloc() : memref<10xf32>340 %b = memref.alloc() : memref<10xf32>341 %cf7 = arith.constant 7.0 : f32342 343 affine.for %i0 = 0 to 10 {344 %v0 = affine.load %a[%i0] : memref<10xf32>345 affine.store %v0, %b[%i0] : memref<10xf32>346 }347 affine.for %i1 = 0 to 10 {348 affine.store %cf7, %a[%i1] : memref<10xf32>349 }350 affine.for %i2 = 0 to 10 {351 %v1 = affine.load %b[%i2] : memref<10xf32>352 }353 // Loops '%i1' and '%i2' have no dependences. We can fuse a slice of '%i0'354 // into '%i2' if we move the fused loop nest before '%i1', which preserves355 // the WAR dependence from load '%a' in '%i0' to the store '%a' in loop '%i1'.356 // CHECK: affine.for %{{.*}} = 0 to 10 {357 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>358 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>359 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>360 // CHECK-NEXT: }361 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {362 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>363 // CHECK-NEXT: }364 // CHECK-NEXT: return365 return366}367 368// -----369 370// CHECK-LABEL: func @should_fuse_if_top_level_access() {371func.func @should_fuse_if_top_level_access() {372 %m = memref.alloc() : memref<10xf32>373 %cf7 = arith.constant 7.0 : f32374 375 affine.for %i0 = 0 to 10 {376 affine.store %cf7, %m[%i0] : memref<10xf32>377 }378 affine.for %i1 = 0 to 10 {379 %v0 = affine.load %m[%i1] : memref<10xf32>380 }381 382 %c0 = arith.constant 4 : index383 %v1 = affine.load %m[%c0] : memref<10xf32>384 // Top-level load to '%m' should prevent creating a private memref but385 // loop nests should be fused and '%i0' should be removed.386 // CHECK: %[[m:.*]] = memref.alloc() : memref<10xf32>387 // CHECK-NOT: memref.alloc388 389 // CHECK: affine.for %[[i1:.*]] = 0 to 10 {390 // CHECK-NEXT: affine.store %{{.*}}, %[[m]][%[[i1]]] : memref<10xf32>391 // CHECK-NEXT: affine.load %[[m]][%[[i1]]] : memref<10xf32>392 // CHECK-NEXT: }393 // CHECK: affine.load %[[m]][%{{.*}}] : memref<10xf32>394 return395}396 397// -----398 399// CHECK-LABEL: func @should_fuse_but_not_remove_src() {400func.func @should_fuse_but_not_remove_src() {401 %m = memref.alloc() : memref<100xf32>402 %cf7 = arith.constant 7.0 : f32403 404 affine.for %i0 = 0 to 100 {405 affine.store %cf7, %m[%i0] : memref<100xf32>406 }407 affine.for %i1 = 0 to 17 {408 %v0 = affine.load %m[%i1] : memref<100xf32>409 }410 %v1 = affine.load %m[99] : memref<100xf32>411 412 // Loop '%i0' and '%i1' should be fused but '%i0' shouldn't be removed to413 // preserve the dependence with the top-level access.414 // CHECK: affine.for %{{.*}} = 0 to 100 {415 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<100xf32>416 // CHECK-NEXT: }417 // CHECK-NEXT: affine.for %{{.*}} = 0 to 17 {418 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>419 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>420 // CHECK-NEXT: }421 // CHECK-NEXT: affine.load %{{.*}}[99] : memref<100xf32>422 // CHECK-NEXT: return423 return424}425 426// -----427 428// CHECK-LABEL: func @should_fuse_no_top_level_access() {429func.func @should_fuse_no_top_level_access() {430 %m = memref.alloc() : memref<10xf32>431 %cf7 = arith.constant 7.0 : f32432 433 affine.for %i0 = 0 to 10 {434 affine.store %cf7, %m[%i0] : memref<10xf32>435 }436 affine.for %i1 = 0 to 10 {437 %v0 = affine.load %m[%i1] : memref<10xf32>438 }439 // CHECK: affine.for %{{.*}} = 0 to 10 {440 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>441 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>442 // CHECK-NEXT: }443 // CHECK-NEXT: return444 return445}446 447// -----448 449#set0 = affine_set<(d0) : (1 == 0)>450 451// CHECK-LABEL: func @should_fuse_despite_affine_if() {452func.func @should_fuse_despite_affine_if() {453 %m = memref.alloc() : memref<10xf32>454 %cf7 = arith.constant 7.0 : f32455 456 affine.for %i0 = 0 to 10 {457 affine.store %cf7, %m[%i0] : memref<10xf32>458 }459 affine.for %i1 = 0 to 10 {460 %v0 = affine.load %m[%i1] : memref<10xf32>461 }462 %c0 = arith.constant 4 : index463 affine.if #set0(%c0) {464 }465 // An unrelated affine.if op doesn't prevent fusion.466 // CHECK: affine.for %{{.*}} = 0 to 10 {467 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>468 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>469 // CHECK-NEXT: }470 return471}472 473// -----474 475#set0 = affine_set<(d0) : (1 == 0)>476 477// CHECK-LABEL: func @should_not_fuse_if_op_in_loop_nest() {478func.func @should_not_fuse_if_op_in_loop_nest() {479 %m = memref.alloc() : memref<10xf32>480 %cf7 = arith.constant 7.0 : f32481 %c4 = arith.constant 4 : index482 483 affine.for %i0 = 0 to 10 {484 affine.store %cf7, %m[%i0] : memref<10xf32>485 }486 affine.for %i1 = 0 to 10 {487 affine.if #set0(%c4) {488 }489 %v0 = affine.load %m[%i1] : memref<10xf32>490 }491 492 // IfOp in ForOp should prevent fusion.493 // CHECK: affine.for %{{.*}} = 0 to 10 {494 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>495 // CHECK-NEXT: }496 // CHECK: affine.for %{{.*}} = 0 to 10 {497 // CHECK-NEXT: affine.if #set(%{{.*}}) {498 // CHECK-NEXT: }499 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>500 // CHECK-NEXT: }501 return502}503 504// -----505 506#set = affine_set<(d0) : (d0 - 1 >= 0)>507 508// CHECK-LABEL: func @should_fuse_if_op_in_loop_nest_not_sandwiched() -> memref<10xf32> {509func.func @should_fuse_if_op_in_loop_nest_not_sandwiched() -> memref<10xf32> {510 %a = memref.alloc() : memref<10xf32>511 %b = memref.alloc() : memref<10xf32>512 %cf7 = arith.constant 7.0 : f32513 514 affine.for %i0 = 0 to 10 {515 affine.store %cf7, %a[%i0] : memref<10xf32>516 }517 affine.for %i1 = 0 to 10 {518 %v0 = affine.load %a[%i1] : memref<10xf32>519 affine.store %v0, %b[%i1] : memref<10xf32>520 }521 affine.for %i2 = 0 to 10 {522 affine.if #set(%i2) {523 %v0 = affine.load %b[%i2] : memref<10xf32>524 }525 }526 527 // IfOp in ForOp should not prevent fusion if it does not in between the528 // source and dest ForOp ops.529 530 // CHECK: affine.for531 // CHECK-NEXT: affine.store532 // CHECK-NEXT: affine.load533 // CHECK-NEXT: affine.store534 // CHECK: affine.for535 // CHECK-NEXT: affine.if536 // CHECK-NEXT: affine.load537 // CHECK-NOT: affine.for538 // CHECK: return539 540 return %a : memref<10xf32>541}542 543// -----544 545#set = affine_set<(d0) : (d0 - 1 >= 0)>546 547// CHECK-LABEL: func @should_not_fuse_if_op_in_loop_nest_between_src_and_dest() -> memref<10xf32> {548func.func @should_not_fuse_if_op_in_loop_nest_between_src_and_dest() -> memref<10xf32> {549 %a = memref.alloc() : memref<10xf32>550 %b = memref.alloc() : memref<10xf32>551 %cf7 = arith.constant 7.0 : f32552 553 affine.for %i0 = 0 to 10 {554 affine.store %cf7, %a[%i0] : memref<10xf32>555 }556 affine.for %i1 = 0 to 10 {557 affine.if #set(%i1) {558 affine.store %cf7, %a[%i1] : memref<10xf32>559 }560 }561 affine.for %i3 = 0 to 10 {562 %v0 = affine.load %a[%i3] : memref<10xf32>563 affine.store %v0, %b[%i3] : memref<10xf32>564 }565 return %b : memref<10xf32>566 567 // IfOp in ForOp which modifies the memref should prevent fusion if it is in568 // between the source and dest ForOp.569 570 // CHECK: affine.for571 // CHECK-NEXT: affine.store572 // CHECK: affine.for573 // CHECK-NEXT: affine.if574 // CHECK-NEXT: affine.store575 // CHECK: affine.for576 // CHECK-NEXT: affine.load577 // CHECK-NEXT: affine.store578 // CHECK: return579}580 581// -----582 583// CHECK-LABEL: func @permute_and_fuse() {584func.func @permute_and_fuse() {585 %m = memref.alloc() : memref<10x20x30xf32>586 587 %cf7 = arith.constant 7.0 : f32588 affine.for %i0 = 0 to 10 {589 affine.for %i1 = 0 to 20 {590 affine.for %i2 = 0 to 30 {591 affine.store %cf7, %m[%i0, %i1, %i2] : memref<10x20x30xf32>592 }593 }594 }595 affine.for %i3 = 0 to 30 {596 affine.for %i4 = 0 to 10 {597 affine.for %i5 = 0 to 20 {598 %v0 = affine.load %m[%i4, %i5, %i3] : memref<10x20x30xf32>599 "foo"(%v0) : (f32) -> ()600 }601 }602 }603// CHECK: affine.for %{{.*}} = 0 to 30 {604// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {605// CHECK-NEXT: affine.for %{{.*}} = 0 to 20 {606// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0, 0] : memref<1x1x1xf32>607// CHECK-NEXT: affine.load %{{.*}}[0, 0, 0] : memref<1x1x1xf32>608// CHECK-NEXT: "foo"(%{{.*}}) : (f32) -> ()609// CHECK-NEXT: }610// CHECK-NEXT: }611// CHECK-NEXT: }612// CHECK-NEXT: return613 614 return615}616 617// -----618 619// CHECK-DAG: [[$MAP0:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (d0 * 4 + d1)>620// CHECK-DAG: [[$MAP1:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 floordiv 4)>621// CHECK-DAG: [[$MAP2:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 mod 4)>622 623// Reshape from a 64 x f32 to 16 x 4 x f32.624// CHECK-LABEL: func @fuse_reshape_64_16_4625func.func @fuse_reshape_64_16_4(%in : memref<64xf32>) {626 %out = memref.alloc() : memref<16x4xf32>627 628 affine.for %i0 = 0 to 64 {629 %v = affine.load %in[%i0] : memref<64xf32>630 affine.store %v, %out[%i0 floordiv 4, %i0 mod 4] : memref<16x4xf32>631 }632 633 affine.for %i1 = 0 to 16 {634 affine.for %i2 = 0 to 4 {635 %w = affine.load %out[%i1, %i2] : memref<16x4xf32>636 "foo"(%w) : (f32) -> ()637 }638 }639 return640 // CHECK: affine.for %{{.*}} =641 // CHECK-NEXT: affine.for %{{.*}} =642 // CHECK-NOT: for643 // CHECK: }644 // CHECK-NEXT: }645 // CHECK-NEXT: return646}647 648// -----649// CHECK-DAG: [[$MAP0:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 floordiv 4)>650// CHECK-DAG: [[$MAP1:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 mod 4)>651// CHECK-DAG: [[$MAP2:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (d0 * 4 + d1)>652 653// Reshape a 16x4xf32 to 64xf32.654// CHECK-LABEL: func @fuse_reshape_16_4_64655func.func @fuse_reshape_16_4_64() {656 %in = memref.alloc() : memref<16x4xf32>657 %out = memref.alloc() : memref<64xf32>658 659 affine.for %i0 = 0 to 16 {660 affine.for %i1 = 0 to 4 {661 %v = affine.load %in[%i0, %i1] : memref<16x4xf32>662 affine.store %v, %out[4*%i0 + %i1] : memref<64xf32>663 }664 }665 666 affine.for %i2 = 0 to 64 {667 %w = affine.load %out[%i2] : memref<64xf32>668 "foo"(%w) : (f32) -> ()669 }670// CHECK: affine.for %{{.*}} = 0 to 64 {671// CHECK-NEXT: affine.apply [[$MAP0]](%{{.*}})672// CHECK-NEXT: affine.apply [[$MAP1]](%{{.*}})673// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<16x4xf32>674// CHECK-NEXT: affine.apply [[$MAP2]](%{{.*}}, %{{.*}})675// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>676// CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>677// CHECK-NEXT: "foo"(%{{.*}}) : (f32) -> ()678// CHECK-NEXT: }679// CHECK-NEXT: return680 return681}682 683 684// -----685 686// All three loop nests below (6-d one, 2-d one, 2-d one is fused into a single687// 2-d loop nest).688func.func @R6_to_R2_reshape_square() -> memref<64x9xi32> {689 %in = memref.alloc() : memref<2x2x3x3x16x1xi32>690 %out = memref.alloc() : memref<64x9xi32>691 %live_out = memref.alloc() : memref<64x9xi32>692 693 // Initialize input.694 affine.for %i0 = 0 to 2 {695 affine.for %i1 = 0 to 2 {696 affine.for %i2 = 0 to 3 {697 affine.for %i3 = 0 to 3 {698 affine.for %i4 = 0 to 16 {699 affine.for %i5 = 0 to 1 {700 %val = "foo"(%i0, %i1, %i2, %i3, %i4, %i5) : (index, index, index, index, index, index) -> i32701 affine.store %val, %in[%i0, %i1, %i2, %i3, %i4, %i5] : memref<2x2x3x3x16x1xi32>702 }703 }704 }705 }706 }707 }708 709 affine.for %ii = 0 to 64 {710 affine.for %jj = 0 to 9 {711 // Convert output coordinates to linear index.712 %a0 = affine.apply affine_map<(d0, d1) -> (d0 * 9 + d1)> (%ii, %jj)713 %0 = affine.apply affine_map<(d0) -> (d0 floordiv (2 * 3 * 3 * 16 * 1))>(%a0)714 %1 = affine.apply affine_map<(d0) -> ((d0 mod 288) floordiv (3 * 3 * 16 * 1))>(%a0)715 %2 = affine.apply affine_map<(d0) -> (((d0 mod 288) mod 144) floordiv (3 * 16 * 1))>(%a0)716 %3 = affine.apply affine_map<(d0) -> ((((d0 mod 288) mod 144) mod 48) floordiv (16 * 1))>(%a0)717 %4 = affine.apply affine_map<(d0) -> ((((d0 mod 288) mod 144) mod 48) mod 16)>(%a0)718 %5 = affine.apply affine_map<(d0) -> (((((d0 mod 144) mod 144) mod 48) mod 16) mod 1)>(%a0)719 %v = affine.load %in[%0, %1, %2, %3, %4, %5] : memref<2x2x3x3x16x1xi32>720 affine.store %v, %out[%ii, %jj] : memref<64x9xi32>721 }722 }723 724 affine.for %i = 0 to 64 {725 affine.for %j = 0 to 9 {726 %a = affine.load %out[%i, %j] : memref<64x9xi32>727 %b = arith.muli %a, %a : i32728 affine.store %b, %live_out[%i, %j] : memref<64x9xi32>729 }730 }731 return %live_out : memref<64x9xi32>732}733// Everything above is fused to a single 2-d loop nest, and the 6-d tensor %in734// is eliminated if -memref-dataflow-opt is also supplied.735//736// CHECK-DAG: [[$MAP0:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> ((d0 * 9 + d1) floordiv 288)>737// CHECK-DAG: [[$MAP1:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (((d0 * 9 + d1) mod 288) floordiv 144)>738// CHECK-DAG: [[$MAP2:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (((d0 * 9 + d1) mod 144) floordiv 48)>739// CHECK-DAG: [[$MAP3:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (((d0 * 9 + d1) mod 48) floordiv 16)>740// CHECK-DAG: [[$MAP4:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> ((d0 * 9 + d1) mod 16)>741// CHECK-DAG: [[$MAP11:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (d0 * 9 + d1)>742// CHECK-DAG: [[$MAP12:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 floordiv 288)>743// CHECK-DAG: [[$MAP13:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> ((d0 mod 288) floordiv 144)>744// CHECK-DAG: [[$MAP14:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> ((d0 mod 144) floordiv 48)>745// CHECK-DAG: [[$MAP15:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> ((d0 mod 48) floordiv 16)>746// CHECK-DAG: [[$MAP16:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 mod 16)>747// CHECK-DAG: [[$MAP17:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (0)>748 749//750// CHECK-LABEL: func @R6_to_R2_reshape751// CHECK: memref.alloc() : memref<1x1x1x1x1x1xi32>752// CHECK: memref.alloc() : memref<1x1xi32>753// CHECK: memref.alloc() : memref<64x9xi32>754// CHECK-NEXT: affine.for %{{.*}} = 0 to 64 {755// CHECK-NEXT: affine.for %{{.*}} = 0 to 9 {756// CHECK-NEXT: affine.apply [[$MAP0]](%{{.*}}, %{{.*}})757// CHECK-NEXT: affine.apply [[$MAP1]](%{{.*}}, %{{.*}})758// CHECK-NEXT: affine.apply [[$MAP2]](%{{.*}}, %{{.*}})759// CHECK-NEXT: affine.apply [[$MAP3]](%{{.*}}, %{{.*}})760// CHECK-NEXT: affine.apply [[$MAP4]](%{{.*}}, %{{.*}})761// CHECK-NEXT: "foo"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (index, index, index, index, index, index) -> i32762// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0, 0, 0, 0, 0] : memref<1x1x1x1x1x1xi32>763// CHECK-NEXT: affine.apply [[$MAP11]](%{{.*}}, %{{.*}})764// CHECK-NEXT: affine.apply [[$MAP12]](%{{.*}})765// CHECK-NEXT: affine.apply [[$MAP13]](%{{.*}})766// CHECK-NEXT: affine.apply [[$MAP14]](%{{.*}})767// CHECK-NEXT: affine.apply [[$MAP15]](%{{.*}})768// CHECK-NEXT: affine.apply [[$MAP16]](%{{.*}})769// CHECK-NEXT: affine.apply [[$MAP17]](%{{.*}})770// CHECK-NEXT: affine.load %{{.*}}[0, 0, 0, 0, 0, 0] : memref<1x1x1x1x1x1xi32>771// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0] : memref<1x1xi32>772// CHECK-NEXT: affine.load %{{.*}}[0, 0] : memref<1x1xi32>773// CHECK-NEXT: arith.muli %{{.*}}, %{{.*}} : i32774// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}] : memref<64x9xi32>775// CHECK-NEXT: }776// CHECK-NEXT: }777// CHECK-NEXT: return %{{.*}} : memref<64x9xi32>778 779// -----780 781// CHECK-LABEL: func @fuse_symbolic_bounds782func.func @fuse_symbolic_bounds(%M : index, %N : index) {783 %N_plus_5 = affine.apply affine_map<(d0) -> (d0 + 5)>(%N)784 %m = memref.alloc(%M, %N_plus_5) : memref<? x ? x f32>785 786 %c0 = arith.constant 0.0 : f32787 %s = arith.constant 5 : index788 789 affine.for %i0 = 0 to %M {790 affine.for %i1 = 0 to affine_map<(d0) -> (d0 + 5)> (%N) {791 affine.store %c0, %m[%i0, %i1] : memref<? x ? x f32>792 }793 }794 795 affine.for %i2 = 0 to %M {796 affine.for %i3 = 0 to %N {797 %v = affine.load %m[%i2, %i3 + symbol(%s)] : memref<? x ? x f32>798 }799 }800 801 return802}803 804// -----805 806// CHECK-LABEL: func @should_fuse_reduction_at_depth_of_one807func.func @should_fuse_reduction_at_depth_of_one() {808 %a = memref.alloc() : memref<10x100xf32>809 %b = memref.alloc() : memref<10xf32>810 811 affine.for %i0 = 0 to 10 {812 affine.for %i1 = 0 to 100 {813 %v0 = affine.load %b[%i0] : memref<10xf32>814 %v1 = affine.load %a[%i0, %i1] : memref<10x100xf32>815 %v2 = "maxf"(%v0, %v1) : (f32, f32) -> f32816 affine.store %v2, %b[%i0] : memref<10xf32>817 }818 }819 affine.for %i2 = 0 to 10 {820 affine.for %i3 = 0 to 100 {821 %v3 = affine.load %b[%i2] : memref<10xf32>822 %v4 = affine.load %a[%i2, %i3] : memref<10x100xf32>823 %v5 = arith.subf %v4, %v3 : f32824 affine.store %v5, %b[%i2] : memref<10xf32>825 }826 }827 // This test should fuse the src reduction loop at depth 1 in the destination828 // loop nest, which improves locality and enables subsequence passes to829 // decrease the reduction memref size and possibly place it in a faster830 // memory space.831 // CHECK: affine.for %{{.*}} = 0 to 10 {832 // CHECK-NEXT: affine.for %{{.*}} = 0 to 100 {833 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>834 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x100xf32>835 // CHECK-NEXT: "maxf"(%{{.*}}, %{{.*}}) : (f32, f32) -> f32836 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>837 // CHECK-NEXT: }838 // CHECK-NEXT: affine.for %{{.*}} = 0 to 100 {839 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>840 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<10x100xf32>841 // CHECK-NEXT: arith.subf %{{.*}}, %{{.*}} : f32842 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>843 // CHECK-NEXT: }844 // CHECK-NEXT: }845 // CHECK-NEXT: return846 return847}848 849// -----850 851// CHECK-LABEL: func @should_fuse_at_src_depth1_and_dst_depth1852func.func @should_fuse_at_src_depth1_and_dst_depth1() {853 %a = memref.alloc() : memref<100x16xf32>854 %b = memref.alloc() : memref<100x16xf32>855 856 affine.for %i0 = 0 to 100 {857 affine.for %i1 = 0 to 16 {858 %v0 = affine.load %a[%i0, %i1] : memref<100x16xf32>859 "op0"(%v0) : (f32) -> ()860 }861 affine.for %i2 = 0 to 16 {862 %v1 = "op1"() : () -> (f32)863 affine.store %v1, %b[%i0, %i2] : memref<100x16xf32>864 }865 }866 867 affine.for %i3 = 0 to 100 {868 affine.for %i4 = 0 to 16 {869 %v2 = affine.load %b[%i3, %i4] : memref<100x16xf32>870 "op2"(%v2) : (f32) -> ()871 }872 }873 // We can slice iterations of the '%i0' and '%i1' loops in the source874 // loop nest, but slicing at depth 2 and inserting the slice in the875 // destination loop nest at depth2 causes extra computation. Instead,876 // the fusion algorithm should detect that the source loop should be sliced877 // at depth 1 and the slice should be inserted at depth 1.878 // CHECK: affine.for %{{.*}} = 0 to 100 {879 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {880 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<100x16xf32>881 // CHECK-NEXT: "op0"(%{{.*}}) : (f32) -> ()882 // CHECK-NEXT: }883 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {884 // CHECK-NEXT: %{{.*}} = "op1"() : () -> f32885 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, %{{.*}}] : memref<1x16xf32>886 // CHECK-NEXT: }887 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {888 // CHECK-NEXT: affine.load %{{.*}}[0, %{{.*}}] : memref<1x16xf32>889 // CHECK-NEXT: "op2"(%{{.*}}) : (f32) -> ()890 // CHECK-NEXT: }891 // CHECK-NEXT: }892 // CHECK-NEXT: return893 return894}895 896// -----897// CHECK: [[$MAP0:#map[0-9]*]] = affine_map<(d0, d1) -> (d0 * 10 + d1)>898 899// CHECK-LABEL: func @should_fuse_src_depth1_at_dst_depth2900func.func @should_fuse_src_depth1_at_dst_depth2() {901 %a = memref.alloc() : memref<100xf32>902 %c0 = arith.constant 0.0 : f32903 904 affine.for %i0 = 0 to 100 {905 affine.store %c0, %a[%i0] : memref<100xf32>906 }907 908 affine.for %i1 = 0 to 10 {909 affine.for %i2 = 0 to 10 {910 %a0 = affine.apply affine_map<(d0, d1) -> (d0 * 10 + d1)> (%i1, %i2)911 %v0 = affine.load %a[%a0] : memref<100xf32>912 }913 }914 // The source loop nest slice loop bound is a function of both destination915 // loop IVs, so we should slice at depth 1 and insert the slice at depth 2.916 // CHECK: affine.for %{{.*}} = 0 to 10 {917 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {918 // CHECK-NEXT: affine.apply [[$MAP0]](%{{.*}}, %{{.*}})919 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>920 // CHECK-NEXT: affine.apply [[$MAP0]](%{{.*}}, %{{.*}})921 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>922 // CHECK-NEXT: }923 // CHECK-NEXT: }924 // CHECK-NEXT: return925 return926}927 928// -----929 930// CHECK-LABEL: func @fusion_at_depth0_not_currently_supported931func.func @fusion_at_depth0_not_currently_supported() {932 %0 = memref.alloc() : memref<10xf32>933 %c0 = arith.constant 0 : index934 %cst = arith.constant 0.000000e+00 : f32935 affine.for %i0 = 0 to 10 {936 affine.store %cst, %0[%i0] : memref<10xf32>937 }938 affine.for %i1 = 0 to 10 {939 %1 = affine.load %0[%c0] : memref<10xf32>940 }941 // NOTE: Should shrink memref size to 1 element access by load in dst loop942 // nest, and make the store in the slice store to the same element.943 // CHECK-DAG: memref.alloc() : memref<1xf32>944 // CHECK: affine.for %{{.*}} = 0 to 10 {945 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>946 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>947 // CHECK-NEXT: }948 // CHECK-NEXT: return949 return950}951 952// -----953 954// CHECK-LABEL: func @should_fuse_deep_loop_nests955func.func @should_fuse_deep_loop_nests() {956 %0 = memref.alloc() : memref<2x2x3x3x16x10xf32, 2>957 %1 = memref.alloc() : memref<2x2x3x3x16x10xf32, 2>958 %2 = memref.alloc() : memref<3x3x3x3x16x10xf32, 2>959 %c0 = arith.constant 0 : index960 %c1 = arith.constant 1 : index961 %c1_0 = arith.constant 1 : index962 %cst = arith.constant 0.000000e+00 : f32963 affine.for %i0 = 0 to 2 {964 affine.for %i1 = 0 to 2 {965 affine.for %i2 = 0 to 3 {966 affine.for %i3 = 0 to 3 {967 affine.for %i4 = 0 to 16 {968 affine.for %i5 = 0 to 10 {969 %3 = affine.load %0[%i0, %i1, %i2, %i3, %i4, %i5]970 : memref<2x2x3x3x16x10xf32, 2>971 }972 }973 affine.for %i6 = 0 to 16 {974 affine.for %i7 = 0 to 10 {975 affine.store %cst, %1[%i0, %i1, %i2, %i3, %i6, %i7]976 : memref<2x2x3x3x16x10xf32, 2>977 }978 }979 }980 }981 }982 }983 affine.for %i8 = 0 to 3 {984 affine.for %i9 = 0 to 3 {985 affine.for %i10 = 0 to 2 {986 affine.for %i11 = 0 to 2 {987 affine.for %i12 = 0 to 3 {988 affine.for %i13 = 0 to 3 {989 affine.for %i14 = 0 to 2 {990 affine.for %i15 = 0 to 2 {991 affine.for %i16 = 0 to 16 {992 affine.for %i17 = 0 to 10 {993 %5 = affine.load %0[%i14, %i15, %i12, %i13, %i16, %i17]994 : memref<2x2x3x3x16x10xf32, 2>995 }996 }997 affine.for %i18 = 0 to 16 {998 affine.for %i19 = 0 to 10 {999 %6 = affine.load %1[%i10, %i11, %i8, %i9, %i18, %i19]1000 : memref<2x2x3x3x16x10xf32, 2>1001 }1002 }1003 }1004 }1005 }1006 }1007 }1008 }1009 }1010 }1011// The first four loops of the source loop nest can be sliced with iteration1012// bounds which are a function of the first four loops of destination loop nest,1013// where the destination loops nests have been interchanged.1014 1015// CHECK-DAG: memref.alloc() : memref<1x1x1x1x16x10xf32, 2>1016// CHECK: affine.for %{{.*}} = 0 to 3 {1017// CHECK-NEXT: affine.for %{{.*}} = 0 to 3 {1018// CHECK-NEXT: affine.for %{{.*}} = 0 to 2 {1019// CHECK-NEXT: affine.for %{{.*}} = 0 to 2 {1020// CHECK-NEXT: affine.for %{{.*}} = 0 to 3 {1021// CHECK-NEXT: affine.for %{{.*}} = 0 to 3 {1022// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {1023// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1024// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref<2x2x3x3x16x10xf32, 2>1025// CHECK-NEXT: }1026// CHECK-NEXT: }1027// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {1028// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1029// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0, 0, 0, %{{.*}}, %{{.*}}] : memref<1x1x1x1x16x10xf32, 2>1030// CHECK-NEXT: }1031// CHECK-NEXT: }1032// CHECK-NEXT: affine.for %{{.*}} = 0 to 2 {1033// CHECK-NEXT: affine.for %{{.*}} = 0 to 2 {1034// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {1035// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1036// CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref<2x2x3x3x16x10xf32, 2>1037// CHECK-NEXT: }1038// CHECK-NEXT: }1039// CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {1040// CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1041// CHECK-NEXT: affine.load %{{.*}}[0, 0, 0, 0, %{{.*}}, %{{.*}}] : memref<1x1x1x1x16x10xf32, 2>1042// CHECK-NEXT: }1043// CHECK-NEXT: }1044// CHECK-NEXT: }1045// CHECK-NEXT: }1046// CHECK-NEXT: }1047// CHECK-NEXT: }1048// CHECK-NEXT: }1049// CHECK-NEXT: }1050// CHECK-NEXT: }1051// CHECK-NEXT: }1052// CHECK-NEXT: return1053 return1054}1055 1056// -----1057 1058// CHECK-LABEL: func @should_fuse_at_depth1_and_reduce_slice_trip_count1059func.func @should_fuse_at_depth1_and_reduce_slice_trip_count() {1060 %a = memref.alloc() : memref<4x256xf32>1061 %b = memref.alloc() : memref<4x256xf32>1062 1063 %c0 = arith.constant 0 : index1064 %cf0 = arith.constant 0.0 : f321065 1066 affine.for %i0 = 0 to 4 {1067 affine.for %i1 = 0 to 256 {1068 %v0 = affine.load %b[%i0, %i1] : memref<4x256xf32>1069 }1070 affine.for %i2 = 0 to 256 {1071 affine.store %cf0, %a[%i0, %i2] : memref<4x256xf32>1072 }1073 }1074 1075 affine.for %d0 = 0 to 4 {1076 affine.for %d1 = 0 to 16 {1077 %v1 = affine.load %a[%d0, %d1] : memref<4x256xf32>1078 }1079 }1080 // The cost of fusing at depth 2 is greater than the cost of fusing at depth 11081 // for two reasons:1082 // 1) Inserting the unsliceable src loop %i1 to a higher depth removes1083 // redundant computation and reduces costs.1084 // 2) Inserting the sliceable src loop %i2 at depth 1, we can still reduce1085 // its trip count to 16 (from 256) reducing costs.1086 // NOTE: the size of the private memref created for the fused loop nest1087 // is reduced from the original shape from 4x256 to 4x16 because of the1088 // data accessed by the load.1089 // CHECK-DAG: memref.alloc() : memref<1x16xf32>1090 // CHECK: affine.for %{{.*}} = 0 to 4 {1091 // CHECK-NEXT: affine.for %{{.*}} = 0 to 256 {1092 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<4x256xf32>1093 // CHECK-NEXT: }1094 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {1095 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, %{{.*}}] : memref<1x16xf32>1096 // CHECK-NEXT: }1097 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 {1098 // CHECK-NEXT: affine.load %{{.*}}[0, %{{.*}}] : memref<1x16xf32>1099 // CHECK-NEXT: }1100 // CHECK-NEXT: }1101 // CHECK-NEXT: return1102 return1103}1104 1105// -----1106 1107// CHECK-LABEL: func @should_fuse_at_depth1_with_trip_count_201108func.func @should_fuse_at_depth1_with_trip_count_20() {1109 %a = memref.alloc() : memref<100xf32>1110 %c0 = arith.constant 0 : index1111 %cf0 = arith.constant 0.0 : f321112 1113 affine.for %i0 = 0 to 100 {1114 affine.store %cf0, %a[%i0]: memref<100xf32>1115 }1116 1117 affine.for %i1 = 0 to 5 {1118 affine.for %i2 = 0 to 10 {1119 %v0 = affine.load %a[%i2]: memref<100xf32>1120 }1121 affine.for %i3 = 0 to 10 {1122 affine.for %i4 = 0 to 20 {1123 %v1 = affine.load %a[%i4]: memref<100xf32>1124 }1125 }1126 }1127 // NOTE: The size of the private memref created for fusion is shrunk to 20xf321128 // CHECK-DAG: memref.alloc() : memref<20xf32>1129 // CHECK: affine.for %{{.*}} = 0 to 5 {1130 // CHECK-NEXT: affine.for %{{.*}} = 0 to 20 {1131 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<20xf32>1132 // CHECK-NEXT: }1133 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1134 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<20xf32>1135 // CHECK-NEXT: }1136 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1137 // CHECK-NEXT: affine.for %{{.*}} = 0 to 20 {1138 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<20xf32>1139 // CHECK-NEXT: }1140 // CHECK-NEXT: }1141 // CHECK-NEXT: }1142 // CHECK-NEXT: return1143 return1144}1145 1146// -----1147 1148// CHECK-LABEL: func @should_fuse_at_depth1_with_trip_count_191149func.func @should_fuse_at_depth1_with_trip_count_19() {1150 %a = memref.alloc() : memref<100xf32>1151 %c0 = arith.constant 0 : index1152 %cf0 = arith.constant 0.0 : f321153 1154 affine.for %i0 = 0 to 100 {1155 affine.store %cf0, %a[%i0]: memref<100xf32>1156 }1157 1158 affine.for %i1 = 0 to 5 {1159 affine.for %i2 = 0 to 19 {1160 %v0 = affine.load %a[%i2]: memref<100xf32>1161 }1162 affine.for %i3 = 0 to 10 {1163 affine.for %i4 = 0 to 10 {1164 %v1 = affine.load %a[%i4]: memref<100xf32>1165 }1166 }1167 }1168 // NOTE: The size of the private memref created for fusion is shrunk to 19xf321169 // CHECK-DAG: memref.alloc() : memref<19xf32>1170 // CHECK: affine.for %{{.*}} = 0 to 5 {1171 // CHECK-NEXT: affine.for %{{.*}} = 0 to 19 {1172 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<19xf32>1173 // CHECK-NEXT: }1174 // CHECK-NEXT: affine.for %{{.*}} = 0 to 19 {1175 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<19xf32>1176 // CHECK-NEXT: }1177 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1178 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1179 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<19xf32>1180 // CHECK-NEXT: }1181 // CHECK-NEXT: }1182 // CHECK-NEXT: }1183 // CHECK-NEXT: return1184 return1185}1186 1187 1188// -----1189 1190// CHECK-LABEL: func @should_fuse_with_private_memref() {1191func.func @should_fuse_with_private_memref() {1192 %m = memref.alloc() : memref<100xf32>1193 %cf7 = arith.constant 7.0 : f321194 1195 affine.for %i0 = 0 to 100 {1196 affine.store %cf7, %m[%i0] : memref<100xf32>1197 }1198 affine.for %i1 = 0 to 17 {1199 %v0 = affine.load %m[%i1] : memref<100xf32>1200 }1201 affine.for %i2 = 0 to 82 {1202 %v1 = affine.load %m[%i2] : memref<100xf32>1203 }1204 // Should create a new private memref.1205 // CHECK-DAG: memref.alloc() : memref<1xf32>1206 // CHECK: affine.for %{{.*}} = 0 to 17 {1207 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>1208 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>1209 // CHECK-NEXT: }1210 // CHECK: affine.for %{{.*}} = 0 to 82 {1211 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>1212 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>1213 // CHECK-NEXT: }1214 // CHECK-NEXT: return1215 return1216}1217 1218// -----1219 1220// CHECK-LABEL: func @should_fuse_live_out_arg_but_preserve_src_loop(%{{.*}}: memref<10xf32>) {1221func.func @should_fuse_live_out_arg_but_preserve_src_loop(%arg0: memref<10xf32>) {1222 %cf7 = arith.constant 7.0 : f321223 1224 affine.for %i0 = 0 to 10 {1225 affine.store %cf7, %arg0[%i0] : memref<10xf32>1226 }1227 affine.for %i1 = 0 to 9 {1228 %v0 = affine.load %arg0[%i1] : memref<10xf32>1229 }1230 // This tests that the loop nest '%i0' should not be removed after fusion1231 // because it writes to memref argument '%arg0', and its read region1232 // does not cover its write region (so fusion would shrink the write region1233 // in the fused loop nest, so complete live out data region would not1234 // be written).1235 // CHECK: affine.for %{{.*}} = 0 to 10 {1236 // CHECK-NEXT: affine.store %{{.*}} : memref<10xf32>1237 // CHECK-NEXT: }1238 // CHECK-NEXT: affine.for %{{.*}} = 0 to 9 {1239 // CHECK-NEXT: affine.store %{{.*}} : memref<1xf32>1240 // CHECK-NEXT: affine.load %{{.*}} : memref<1xf32>1241 // CHECK-NEXT: }1242 // CHECK-NEXT: return1243 return1244}1245 1246// -----1247 1248// CHECK-LABEL: func @should_fuse_live_out_arg(%{{.*}}: memref<10xf32>) {1249func.func @should_fuse_live_out_arg(%arg0: memref<10xf32>) {1250 %cf7 = arith.constant 7.0 : f321251 1252 affine.for %i0 = 0 to 10 {1253 affine.store %cf7, %arg0[%i0] : memref<10xf32>1254 }1255 affine.for %i1 = 0 to 10 {1256 %v0 = affine.load %arg0[%i1] : memref<10xf32>1257 }1258 // The read/write regions for memref '%{{.*}}' are the same for both1259 // loops, so they should fuse.1260 1261 // CHECK: affine.for %{{.*}} = 0 to 10 {1262 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1263 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1264 // CHECK-NEXT: }1265 // CHECK-NEXT: return1266 return1267}1268 1269// -----1270 1271// CHECK-LABEL: func @should_fuse_escaping_memref_but_preserve_src_loop() -> memref<10xf32>1272func.func @should_fuse_escaping_memref_but_preserve_src_loop() -> memref<10xf32> {1273 %cf7 = arith.constant 7.0 : f321274 %m = memref.alloc() : memref<10xf32>1275 affine.for %i0 = 0 to 10 {1276 affine.store %cf7, %m[%i0] : memref<10xf32>1277 }1278 affine.for %i1 = 0 to 9 {1279 %v0 = affine.load %m[%i1] : memref<10xf32>1280 }1281 // This tests that the loop nest '%i0' should not be removed after fusion1282 // because it writes to memref '%m', which is returned by the function, and1283 // the '%i1' memory region does not cover '%i0' memory region.1284 1285 // CHECK-DAG: memref.alloc() : memref<1xf32>1286 // CHECK: affine.for %{{.*}} = 0 to 10 {1287 // CHECK-NEXT: affine.store %{{.*}} : memref<10xf32>1288 // CHECK-NEXT: }1289 // CHECK-NEXT: affine.for %{{.*}} = 0 to 9 {1290 // CHECK-NEXT: affine.store %{{.*}} : memref<1xf32>1291 // CHECK-NEXT: affine.load %{{.*}} : memref<1xf32>1292 // CHECK-NEXT: }1293 // CHECK-NEXT: return %{{.*}} : memref<10xf32>1294 return %m : memref<10xf32>1295}1296// -----1297 1298// This should fuse with the %in becoming a 1x1x1.1299func.func @R3_to_R2_reshape() {1300 %in = memref.alloc() : memref<2x3x16xi32>1301 1302 %c0 = arith.constant 0 : index1303 1304 affine.for %i0 = 0 to 2 {1305 affine.for %i1 = 0 to 3 {1306 affine.for %i2 = 0 to 16 {1307 %val = "foo"(%i0, %i1, %i2) : (index, index, index) -> i321308 affine.store %val, %in[%i0, %i1, %i2] : memref<2x3x16xi32>1309 }1310 }1311 }1312 1313 affine.for %ii = 0 to 32 {1314 affine.for %jj = 0 to 3 {1315 %a0 = affine.apply affine_map<(d0, d1) -> (d0 * 3 + d1)> (%ii, %jj)1316 %idx = affine.apply affine_map<(d0) -> (d0 floordiv (3 * 16))> (%a0)1317 %v = affine.load %in[%idx, %jj, %c0]1318 : memref<2x3x16xi32>1319 }1320 }1321 return1322}1323// CHECK-DAG: [[$MAP0:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> ((d0 * 3 + d1) floordiv 48)>1324// CHECK-DAG: [[$MAP1:#map[0-9a-zA-Z_]*]] = affine_map<(d0, d1) -> (d0 * 3 + d1)>1325// CHECK-DAG: [[$MAP2:#map[0-9a-zA-Z_]*]] = affine_map<(d0) -> (d0 floordiv 48)>1326 1327// CHECK-LABEL: func @R3_to_R2_reshape()1328// CHECK-DAG: memref.alloc() : memref<1x1x1xi32>1329// CHECK: affine.for %{{.*}} = 0 to 32 {1330// CHECK-NEXT: affine.for %{{.*}} = 0 to 3 {1331// CHECK-NEXT: affine.apply [[$MAP0]](%{{.*}}, %{{.*}})1332// CHECK-NEXT: "foo"(%{{.*}}, %{{.*}}, %{{.*}}) : (index, index, index) -> i321333// CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0, 0, 0] : memref<1x1x1xi32>1334// CHECK-NEXT: affine.apply [[$MAP1]](%{{.*}}, %{{.*}})1335// CHECK-NEXT: affine.apply [[$MAP2]](%{{.*}})1336// CHECK-NEXT: affine.load %{{.*}}[0, 0, 0] : memref<1x1x1xi32>1337// CHECK-NEXT: }1338// CHECK-NEXT: }1339// CHECK-NEXT: return1340 1341// -----1342 1343func.func @should_fuse_multi_output_producer() {1344 %a = memref.alloc() : memref<10xf32>1345 %b = memref.alloc() : memref<10xf32>1346 1347 %cf7 = arith.constant 7.0 : f321348 1349 affine.for %i0 = 0 to 10 {1350 affine.store %cf7, %a[%i0] : memref<10xf32>1351 affine.store %cf7, %b[%i0] : memref<10xf32>1352 }1353 affine.for %i1 = 0 to 10 {1354 %v0 = affine.load %a[%i1] : memref<10xf32>1355 %v1 = affine.load %b[%i1] : memref<10xf32>1356 }1357 1358 // CHECK: affine.for %{{.*}} = 0 to 10 {1359 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>1360 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>1361 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>1362 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>1363 // CHECK-NEXT: }1364 // CHECK-NEXT: return1365 return1366}1367 1368// -----1369 1370// CHECK-LABEL: func @fusion_preventing_deps_on_middle_loop() {1371func.func @fusion_preventing_deps_on_middle_loop() {1372 %a = memref.alloc() : memref<10xf32>1373 %b = memref.alloc() : memref<10xf32>1374 %c = memref.alloc() : memref<10xf32>1375 1376 %cf7 = arith.constant 7.0 : f321377 1378 affine.for %i0 = 0 to 10 {1379 %v0 = affine.load %a[%i0] : memref<10xf32>1380 affine.store %v0, %b[%i0] : memref<10xf32>1381 }1382 affine.for %i1 = 0 to 10 {1383 affine.store %cf7, %a[%i1] : memref<10xf32>1384 %v1 = affine.load %c[%i1] : memref<10xf32>1385 }1386 affine.for %i2 = 0 to 10 {1387 %v2 = affine.load %b[%i2] : memref<10xf32>1388 affine.store %v2, %c[%i2] : memref<10xf32>1389 }1390 // Loops '%i0' and '%i2' cannot fuse along producer/consumer edge on memref1391 // '%b', because of the WAR dep from '%i0' to '%i1' on memref '%a' and1392 // because of the WAR dep from '%i1' to '%i2' on memref '%c'.1393 // CHECK: affine.for %{{.*}} = 0 to 10 {1394 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1395 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1396 // CHECK-NEXT: }1397 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1398 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1399 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1400 // CHECK-NEXT: }1401 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1402 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1403 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1404 // CHECK-NEXT: }1405 // CHECK-NEXT: return1406 return1407}1408 1409// -----1410 1411// CHECK-LABEL: func @should_fuse_and_move_to_preserve_war_dep() {1412func.func @should_fuse_and_move_to_preserve_war_dep() {1413 %a = memref.alloc() : memref<10xf32>1414 %b = memref.alloc() : memref<10xf32>1415 %c = memref.alloc() : memref<10xf32>1416 1417 %cf7 = arith.constant 7.0 : f321418 1419 affine.for %i0 = 0 to 10 {1420 %v0 = affine.load %b[%i0] : memref<10xf32>1421 affine.store %v0, %a[%i0] : memref<10xf32>1422 }1423 affine.for %i1 = 0 to 3 {1424 %v2 = affine.load %c[%i1] : memref<10xf32>1425 }1426 affine.for %i2 = 0 to 5 {1427 affine.store %cf7, %b[%i2] : memref<10xf32>1428 }1429 affine.for %i3 = 0 to 10 {1430 %v1 = affine.load %a[%i3] : memref<10xf32>1431 affine.store %cf7, %c[%i3] : memref<10xf32>1432 }1433 1434 // Dependence graph:1435 //1436 // %i0 ---------1437 // | |1438 // --- %i1 | %b | %a1439 // | | |1440 // %c | %i2 <-- |1441 // | |1442 // --> %i3 <--------1443 //1444 // It is possible to fuse loop '%i0' into '%i3' and preserve dependences1445 // if the fused loop nest is inserted between loops '%i1' and '%i2'.1446 1447 // CHECK-DAG: memref.alloc() : memref<1xf32>1448 // CHECK: affine.for %{{.*}} = 0 to 3 {1449 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1450 // CHECK-NEXT: }1451 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1452 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1453 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>1454 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>1455 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1456 // CHECK-NEXT: }1457 // CHECK-NEXT: affine.for %{{.*}} = 0 to 5 {1458 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1459 // CHECK-NEXT: }1460 // CHECK-NEXT: return1461 return1462}1463 1464// -----1465 1466// CHECK-LABEL: func @fusion_preventing_dep_on_constant() {1467func.func @fusion_preventing_dep_on_constant() {1468 %a = memref.alloc() : memref<10xf32>1469 %b = memref.alloc() : memref<10xf32>1470 %c = memref.alloc() : memref<10xf32>1471 1472 %cf7 = arith.constant 7.0 : f321473 1474 affine.for %i0 = 0 to 10 {1475 %v0 = affine.load %b[%i0] : memref<10xf32>1476 affine.store %cf7, %a[%i0] : memref<10xf32>1477 }1478 affine.for %i1 = 0 to 10 {1479 affine.store %cf7, %b[%i1] : memref<10xf32>1480 }1481 %cf11 = arith.constant 11.0 : f321482 affine.for %i2 = 0 to 10 {1483 %v2 = affine.load %a[%i2] : memref<10xf32>1484 affine.store %cf11, %c[%i2] : memref<10xf32>1485 }1486 // Loops '%i0' and '%i2' cannot fuse along producer/consumer edge on memref1487 // '%a', because of the WAR dep from '%i0' to '%i1' on memref '%b' and1488 // because of the SSA value dep from '%cf11' def to use in '%i2'.1489 // CHECK: affine.for %{{.*}} = 0 to 10 {1490 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1491 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1492 // CHECK-NEXT: }1493 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1494 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1495 // CHECK-NEXT: }1496 // CHECK-NEXT: %{{.*}} = arith.constant 1.100000e+01 : f321497 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1498 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1499 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1500 // CHECK-NEXT: }1501 // CHECK-NEXT: return1502 return1503}1504 1505// -----1506 1507// CHECK-LABEL: func @should_fuse_and_preserve_dep_on_constant() {1508func.func @should_fuse_and_preserve_dep_on_constant() {1509 %a = memref.alloc() : memref<10xf32>1510 %b = memref.alloc() : memref<10xf32>1511 %c = memref.alloc() : memref<10xf32>1512 1513 %cf7 = arith.constant 7.0 : f321514 %cf11 = arith.constant 11.0 : f321515 affine.for %i0 = 0 to 10 {1516 %v0 = affine.load %b[%i0] : memref<10xf32>1517 affine.store %cf7, %a[%i0] : memref<10xf32>1518 }1519 affine.for %i1 = 0 to 10 {1520 affine.store %cf7, %b[%i1] : memref<10xf32>1521 }1522 affine.for %i2 = 0 to 10 {1523 %v2 = affine.load %a[%i2] : memref<10xf32>1524 affine.store %cf11, %c[%i2] : memref<10xf32>1525 }1526 1527 // Loops '%i0' and '%i2' can fuse along producer/consumer edge on memref1528 // '%a', and preserve the WAR dep from '%i0' to '%i1' on memref '%b', and1529 // the SSA value dep from '%cf11' def to use in '%i2'.1530 1531 // CHECK: arith.constant 1.100000e+01 : f321532 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1533 // CHECK-NEXT: affine.load %{{.*}}[%{{.*}}] : memref<10xf32>1534 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[0] : memref<1xf32>1535 // CHECK-NEXT: affine.load %{{.*}}[0] : memref<1xf32>1536 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1537 // CHECK-NEXT: }1538 // CHECK-NEXT: affine.for %{{.*}} = 0 to 10 {1539 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}}] : memref<10xf32>1540 // CHECK-NEXT: }1541 // CHECK-NEXT: return1542 return1543}1544 1545// -----1546 1547// CHECK-LABEL: @producer_consumer_with_outmost_user1548func.func @producer_consumer_with_outmost_user(%arg0 : f16) {1549 %c0 = arith.constant 0 : index1550 %src = memref.alloc() : memref<f16, 1>1551 %dst = memref.alloc() : memref<f16>1552 %tag = memref.alloc() : memref<1xi32>1553 affine.for %arg1 = 4 to 6 {1554 affine.for %arg2 = 0 to 1 {1555 %0 = arith.addf %arg0, %arg0 : f161556 affine.store %0, %src[] : memref<f16, 1>1557 }1558 affine.for %arg3 = 0 to 1 {1559 %0 = affine.load %src[] : memref<f16, 1>1560 }1561 }1562 affine.dma_start %src[], %dst[], %tag[%c0], %c0 : memref<f16, 1>, memref<f16>, memref<1xi32>1563 // CHECK: %[[CST_INDEX:.*]] = arith.constant 0 : index1564 // CHECK: %[[DMA_SRC:.*]] = memref.alloc() : memref<f16, 1>1565 // CHECK: %[[DMA_DST:.*]] = memref.alloc() : memref<f16>1566 // CHECK: %[[DMA_TAG:.*]] = memref.alloc() : memref<1xi32>1567 // CHECK: affine.for %arg1 = 4 to 61568 // CHECK-NEXT: affine.for %arg2 = 0 to 11569 // CHECK-NEXT: %[[RESULT_ADD:.*]] = arith.addf %arg0, %arg0 : f161570 // CHECK-NEXT: affine.store %[[RESULT_ADD]], %[[DMA_SRC]][] : memref<f16, 1>1571 // CHECK-NEXT: affine.load %[[DMA_SRC]][] : memref<f16, 1>1572 // CHECK: affine.dma_start %[[DMA_SRC]][], %[[DMA_DST]][], %[[DMA_TAG]][%[[CST_INDEX]]], %[[CST_INDEX]] : memref<f16, 1>, memref<f16>, memref<1xi32>1573 // CHECK-NEXT: return1574 return1575}1576 1577// Add further tests in mlir/test/Transforms/loop-fusion-4.mlir1578 1579