792 lines · plain
1// RUN: mlir-opt -buffer-hoisting -split-input-file %s | FileCheck %s2 3// This file checks the behaviour of BufferHoisting pass for moving Alloc4// operations to their correct positions.5 6// Test Case:7// bb08// / \9// bb1 bb2 <- Initial position of AllocOp10// \ /11// bb312// BufferHoisting expected behavior: It should move the existing AllocOp to13// the entry block.14 15// CHECK-LABEL: func @condBranch16func.func @condBranch(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {17 cf.cond_br %arg0, ^bb1, ^bb218^bb1:19 cf.br ^bb3(%arg1 : memref<2xf32>)20^bb2:21 %0 = memref.alloc() : memref<2xf32>22 test.buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>)23 cf.br ^bb3(%0 : memref<2xf32>)24^bb3(%1: memref<2xf32>):25 test.copy(%1, %arg2) : (memref<2xf32>, memref<2xf32>)26 return27}28 29// CHECK-NEXT: %[[ALLOC:.*]] = memref.alloc()30// CHECK-NEXT: cf.cond_br31 32// -----33 34// Test Case:35// bb036// / \37// bb1 bb2 <- Initial position of AllocOp38// \ /39// bb340// BufferHoisting expected behavior: It should not move the existing AllocOp41// to any other block since the alloc has a dynamic dependency to block argument42// %0 in bb2.43 44// CHECK-LABEL: func @condBranchDynamicType45func.func @condBranchDynamicType(46 %arg0: i1,47 %arg1: memref<?xf32>,48 %arg2: memref<?xf32>,49 %arg3: index) {50 cf.cond_br %arg0, ^bb1, ^bb2(%arg3: index)51^bb1:52 cf.br ^bb3(%arg1 : memref<?xf32>)53^bb2(%0: index):54 %1 = memref.alloc(%0) : memref<?xf32>55 test.buffer_based in(%arg1: memref<?xf32>) out(%1: memref<?xf32>)56 cf.br ^bb3(%1 : memref<?xf32>)57^bb3(%2: memref<?xf32>):58 test.copy(%2, %arg2) : (memref<?xf32>, memref<?xf32>)59 return60}61 62// CHECK-NEXT: cf.cond_br63// CHECK: ^bb264// CHECK: ^bb2(%[[IDX:.*]]:{{.*}})65// CHECK-NEXT: %[[ALLOC0:.*]] = memref.alloc(%[[IDX]])66// CHECK-NEXT: test.buffer_based67 68// -----69 70// Test Case:71// bb072// / \73// bb1 bb2 <- Initial position of AllocOp74// | / \75// | bb3 bb476// | \ /77// \ bb578// \ /79// bb680// |81// bb782// BufferHoisting expected behavior: It should not move the existing AllocOp83// to any other block since the alloc has a dynamic dependency to block argument84// %0 in bb2.85 86// CHECK-LABEL: func @condBranchDynamicTypeNested87func.func @condBranchDynamicTypeNested(88 %arg0: i1,89 %arg1: memref<?xf32>,90 %arg2: memref<?xf32>,91 %arg3: index) {92 cf.cond_br %arg0, ^bb1, ^bb2(%arg3: index)93^bb1:94 cf.br ^bb6(%arg1 : memref<?xf32>)95^bb2(%0: index):96 %1 = memref.alloc(%0) : memref<?xf32>97 test.buffer_based in(%arg1: memref<?xf32>) out(%1: memref<?xf32>)98 cf.cond_br %arg0, ^bb3, ^bb499^bb3:100 cf.br ^bb5(%1 : memref<?xf32>)101^bb4:102 cf.br ^bb5(%1 : memref<?xf32>)103^bb5(%2: memref<?xf32>):104 cf.br ^bb6(%2 : memref<?xf32>)105^bb6(%3: memref<?xf32>):106 cf.br ^bb7(%3 : memref<?xf32>)107^bb7(%4: memref<?xf32>):108 test.copy(%4, %arg2) : (memref<?xf32>, memref<?xf32>)109 return110}111 112// CHECK-NEXT: cf.cond_br113// CHECK: ^bb2114// CHECK: ^bb2(%[[IDX:.*]]:{{.*}})115// CHECK-NEXT: %[[ALLOC0:.*]] = memref.alloc(%[[IDX]])116// CHECK-NEXT: test.buffer_based117 118// -----119 120// Test Case:121// bb0122// / \123// | bb1 <- Initial position of AllocOp124// \ /125// bb2126// BufferHoisting expected behavior: It should move the existing AllocOp to127// the entry block.128 129// CHECK-LABEL: func @criticalEdge130func.func @criticalEdge(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {131 cf.cond_br %arg0, ^bb1, ^bb2(%arg1 : memref<2xf32>)132^bb1:133 %0 = memref.alloc() : memref<2xf32>134 test.buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>)135 cf.br ^bb2(%0 : memref<2xf32>)136^bb2(%1: memref<2xf32>):137 test.copy(%1, %arg2) : (memref<2xf32>, memref<2xf32>)138 return139}140 141// CHECK-NEXT: %[[ALLOC:.*]] = memref.alloc()142// CHECK-NEXT: cf.cond_br143 144// -----145 146// Test Case:147// bb0 <- Initial position of the first AllocOp148// / \149// bb1 bb2150// \ /151// bb3 <- Initial position of the second AllocOp152// BufferHoisting expected behavior: It shouldn't move the AllocOps.153 154// CHECK-LABEL: func @ifElse155func.func @ifElse(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {156 %0 = memref.alloc() : memref<2xf32>157 test.buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>)158 cf.cond_br %arg0,159 ^bb1(%arg1, %0 : memref<2xf32>, memref<2xf32>),160 ^bb2(%0, %arg1 : memref<2xf32>, memref<2xf32>)161^bb1(%1: memref<2xf32>, %2: memref<2xf32>):162 cf.br ^bb3(%1, %2 : memref<2xf32>, memref<2xf32>)163^bb2(%3: memref<2xf32>, %4: memref<2xf32>):164 cf.br ^bb3(%3, %4 : memref<2xf32>, memref<2xf32>)165^bb3(%5: memref<2xf32>, %6: memref<2xf32>):166 %7 = memref.alloc() : memref<2xf32>167 test.buffer_based in(%7: memref<2xf32>) out(%7: memref<2xf32>)168 test.copy(%7, %arg2) : (memref<2xf32>, memref<2xf32>)169 return170}171 172// CHECK-NEXT: %[[ALLOC0:.*]] = memref.alloc()173// CHECK-NEXT: test.buffer_based174// CHECK: cf.br ^bb3175// CHECK: cf.br ^bb3176// CHECK-NEXT: ^bb3177// CHECK: %[[ALLOC1:.*]] = memref.alloc()178// CHECK-NEXT: test.buffer_based179// CHECK: test.copy(%[[ALLOC1]]180// CHECK-NEXT: return181 182// -----183 184// Test Case: No users for buffer in if-else CFG185// bb0 <- Initial position of AllocOp186// / \187// bb1 bb2188// \ /189// bb3190// BufferHoisting expected behavior: It shouldn't move the AllocOp.191 192// CHECK-LABEL: func @ifElseNoUsers193func.func @ifElseNoUsers(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {194 %0 = memref.alloc() : memref<2xf32>195 test.buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>)196 cf.cond_br %arg0,197 ^bb1(%arg1, %0 : memref<2xf32>, memref<2xf32>),198 ^bb2(%0, %arg1 : memref<2xf32>, memref<2xf32>)199^bb1(%1: memref<2xf32>, %2: memref<2xf32>):200 cf.br ^bb3(%1, %2 : memref<2xf32>, memref<2xf32>)201^bb2(%3: memref<2xf32>, %4: memref<2xf32>):202 cf.br ^bb3(%3, %4 : memref<2xf32>, memref<2xf32>)203^bb3(%5: memref<2xf32>, %6: memref<2xf32>):204 test.copy(%arg1, %arg2) : (memref<2xf32>, memref<2xf32>)205 return206}207 208// CHECK-NEXT: %[[ALLOC0:.*]] = memref.alloc()209// CHECK-NEXT: test.buffer_based210 211// -----212 213// Test Case:214// bb0 <- Initial position of the first AllocOp215// / \216// bb1 bb2217// | / \218// | bb3 bb4219// \ \ /220// \ /221// bb5 <- Initial position of the second AllocOp222// BufferHoisting expected behavior: AllocOps shouldn't be moved.223 224// CHECK-LABEL: func @ifElseNested225func.func @ifElseNested(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {226 %0 = memref.alloc() : memref<2xf32>227 test.buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>)228 cf.cond_br %arg0,229 ^bb1(%arg1, %0 : memref<2xf32>, memref<2xf32>),230 ^bb2(%0, %arg1 : memref<2xf32>, memref<2xf32>)231^bb1(%1: memref<2xf32>, %2: memref<2xf32>):232 cf.br ^bb5(%1, %2 : memref<2xf32>, memref<2xf32>)233^bb2(%3: memref<2xf32>, %4: memref<2xf32>):234 cf.cond_br %arg0, ^bb3(%3 : memref<2xf32>), ^bb4(%4 : memref<2xf32>)235^bb3(%5: memref<2xf32>):236 cf.br ^bb5(%5, %3 : memref<2xf32>, memref<2xf32>)237^bb4(%6: memref<2xf32>):238 cf.br ^bb5(%3, %6 : memref<2xf32>, memref<2xf32>)239^bb5(%7: memref<2xf32>, %8: memref<2xf32>):240 %9 = memref.alloc() : memref<2xf32>241 test.buffer_based in(%7: memref<2xf32>) out(%9: memref<2xf32>)242 test.copy(%9, %arg2) : (memref<2xf32>, memref<2xf32>)243 return244}245 246// CHECK-NEXT: %[[ALLOC0:.*]] = memref.alloc()247// CHECK-NEXT: test.buffer_based248// CHECK: cf.br ^bb5249// CHECK: cf.br ^bb5250// CHECK: cf.br ^bb5251// CHECK-NEXT: ^bb5252// CHECK: %[[ALLOC1:.*]] = memref.alloc()253// CHECK-NEXT: test.buffer_based254 255// -----256 257// Test Case: Dead operations in a single block.258// BufferHoisting expected behavior: It shouldn't move the AllocOps.259 260// CHECK-LABEL: func @redundantOperations261func.func @redundantOperations(%arg0: memref<2xf32>) {262 %0 = memref.alloc() : memref<2xf32>263 test.buffer_based in(%arg0: memref<2xf32>) out(%0: memref<2xf32>)264 %1 = memref.alloc() : memref<2xf32>265 test.buffer_based in(%0: memref<2xf32>) out(%1: memref<2xf32>)266 return267}268 269// CHECK-NEXT: %[[ALLOC0:.*]] = memref.alloc()270// CHECK-NEXT: test.buffer_based271// CHECK: %[[ALLOC1:.*]] = memref.alloc()272// CHECK-NEXT: test.buffer_based273 274// -----275 276// Test Case:277// bb0278// / \279// Initial pos of the 1st AllocOp -> bb1 bb2 <- Initial pos of the 2nd AllocOp280// \ /281// bb3282// BufferHoisting expected behavior: Both AllocOps should be moved to the283// entry block.284 285// CHECK-LABEL: func @moving_alloc_and_inserting_missing_dealloc286func.func @moving_alloc_and_inserting_missing_dealloc(287 %cond: i1,288 %arg0: memref<2xf32>,289 %arg1: memref<2xf32>) {290 cf.cond_br %cond, ^bb1, ^bb2291^bb1:292 %0 = memref.alloc() : memref<2xf32>293 test.buffer_based in(%arg0: memref<2xf32>) out(%0: memref<2xf32>)294 cf.br ^exit(%0 : memref<2xf32>)295^bb2:296 %1 = memref.alloc() : memref<2xf32>297 test.buffer_based in(%arg0: memref<2xf32>) out(%1: memref<2xf32>)298 cf.br ^exit(%1 : memref<2xf32>)299^exit(%arg2: memref<2xf32>):300 test.copy(%arg2, %arg1) : (memref<2xf32>, memref<2xf32>)301 return302}303 304// CHECK-NEXT: %{{.*}} = memref.alloc()305// CHECK-NEXT: %{{.*}} = memref.alloc()306// CHECK-NEXT: cf.cond_br307 308// -----309 310// Test Case: Invalid position of the DeallocOp. There is a user after311// deallocation.312// bb0313// / \314// bb1 bb2 <- Initial position of AllocOp315// \ /316// bb3317// BufferHoisting expected behavior: It should move the AllocOp to the entry318// block.319 320// CHECK-LABEL: func @moving_invalid_dealloc_op_complex321func.func @moving_invalid_dealloc_op_complex(322 %cond: i1,323 %arg0: memref<2xf32>,324 %arg1: memref<2xf32>) {325 cf.cond_br %cond, ^bb1, ^bb2326^bb1:327 cf.br ^exit(%arg0 : memref<2xf32>)328^bb2:329 %1 = memref.alloc() : memref<2xf32>330 test.buffer_based in(%arg0: memref<2xf32>) out(%1: memref<2xf32>)331 memref.dealloc %1 : memref<2xf32>332 cf.br ^exit(%1 : memref<2xf32>)333^exit(%arg2: memref<2xf32>):334 test.copy(%arg2, %arg1) : (memref<2xf32>, memref<2xf32>)335 return336}337 338// CHECK-NEXT: %{{.*}} = memref.alloc()339// CHECK-NEXT: cf.cond_br340 341// -----342 343// Test Case: Nested regions - This test defines a BufferBasedOp inside the344// region of a RegionBufferBasedOp.345// BufferHoisting expected behavior: The AllocOp for the BufferBasedOp should346// remain inside the region of the RegiobBufferBasedOp. The AllocOp of the347// RegionBufferBasedOp should be moved to the entry block.348 349// CHECK-LABEL: func @nested_regions_and_cond_branch350func.func @nested_regions_and_cond_branch(351 %arg0: i1,352 %arg1: memref<2xf32>,353 %arg2: memref<2xf32>) {354 cf.cond_br %arg0, ^bb1, ^bb2355^bb1:356 cf.br ^bb3(%arg1 : memref<2xf32>)357^bb2:358 %0 = memref.alloc() : memref<2xf32>359 test.region_buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>) {360 ^bb0(%gen1_arg0: f32, %gen1_arg1: f32):361 %1 = memref.alloc() : memref<2xf32>362 test.buffer_based in(%arg1: memref<2xf32>) out(%1: memref<2xf32>)363 %tmp1 = math.exp %gen1_arg0 : f32364 test.region_yield %tmp1 : f32365 }366 cf.br ^bb3(%0 : memref<2xf32>)367^bb3(%1: memref<2xf32>):368 test.copy(%1, %arg2) : (memref<2xf32>, memref<2xf32>)369 return370}371// CHECK-NEXT: %[[ALLOC0:.*]] = memref.alloc()372// CHECK-NEXT: cf.cond_br373// CHECK: test.region_buffer_based374// CHECK: %[[ALLOC1:.*]] = memref.alloc()375// CHECK-NEXT: test.buffer_based376 377// -----378 379// Test Case: nested region control flow380// The alloc position of %1 does not need to be changed and flows through381// both if branches until it is finally returned.382 383// CHECK-LABEL: func @nested_region_control_flow384func.func @nested_region_control_flow(385 %arg0 : index,386 %arg1 : index) -> memref<?x?xf32> {387 %0 = arith.cmpi eq, %arg0, %arg1 : index388 %1 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>389 %2 = scf.if %0 -> (memref<?x?xf32>) {390 scf.yield %1 : memref<?x?xf32>391 } else {392 %3 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>393 scf.yield %1 : memref<?x?xf32>394 }395 return %2 : memref<?x?xf32>396}397 398// CHECK: %[[ALLOC0:.*]] = memref.alloc(%arg0, %arg0)399// CHECK-NEXT: %{{.*}} = scf.if400// CHECK: else401// CHECK-NEXT: %[[ALLOC1:.*]] = memref.alloc(%arg0, %arg1)402 403// -----404 405// Test Case: nested region control flow with a nested buffer allocation in a406// divergent branch.407// The alloc positions of %1 does not need to be changed. %3 is moved upwards.408 409// CHECK-LABEL: func @nested_region_control_flow_div410func.func @nested_region_control_flow_div(411 %arg0 : index,412 %arg1 : index) -> memref<?x?xf32> {413 %0 = arith.cmpi eq, %arg0, %arg1 : index414 %1 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>415 %2 = scf.if %0 -> (memref<?x?xf32>) {416 scf.yield %1 : memref<?x?xf32>417 } else {418 %3 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>419 scf.yield %3 : memref<?x?xf32>420 }421 return %2 : memref<?x?xf32>422}423 424// CHECK: %[[ALLOC0:.*]] = memref.alloc(%arg0, %arg0)425// CHECK-NEXT: %[[ALLOC1:.*]] = memref.alloc(%arg0, %arg1)426// CHECK-NEXT: %{{.*}} = scf.if427 428// -----429 430// Test Case: deeply nested region control flow with a nested buffer allocation431// in a divergent branch.432// The alloc position of %1 does not need to be changed. Allocs %4 and %5 are433// moved upwards.434 435// CHECK-LABEL: func @nested_region_control_flow_div_nested436func.func @nested_region_control_flow_div_nested(437 %arg0 : index,438 %arg1 : index) -> memref<?x?xf32> {439 %0 = arith.cmpi eq, %arg0, %arg1 : index440 %1 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>441 %2 = scf.if %0 -> (memref<?x?xf32>) {442 %3 = scf.if %0 -> (memref<?x?xf32>) {443 scf.yield %1 : memref<?x?xf32>444 } else {445 %4 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>446 scf.yield %4 : memref<?x?xf32>447 }448 scf.yield %3 : memref<?x?xf32>449 } else {450 %5 = memref.alloc(%arg1, %arg1) : memref<?x?xf32>451 scf.yield %5 : memref<?x?xf32>452 }453 return %2 : memref<?x?xf32>454}455// CHECK: %[[ALLOC0:.*]] = memref.alloc(%arg0, %arg0)456// CHECK-NEXT: %[[ALLOC1:.*]] = memref.alloc(%arg0, %arg1)457// CHECK-NEXT: %[[ALLOC2:.*]] = memref.alloc(%arg1, %arg1)458// CHECK-NEXT: %{{.*}} = scf.if459 460// -----461 462// Test Case: deeply nested region control flow with a nested buffer allocation463// that has dependency within a nested region should not be moved outside of464// this region.465 466// CHECK-LABEL: func @nested_region_control_flow_div_nested_dependencies467func.func @nested_region_control_flow_div_nested_dependencies(468 %arg0: i32,469 %arg1: i1,470 %arg2: index) -> memref<?x?xf32> {471 %0 = scf.if %arg1 -> (memref<?x?xf32>) {472 %1 = arith.constant 1 : i32473 %2 = arith.addi %arg0, %1 : i32474 %3 = arith.index_cast %2 : i32 to index475 %4 = memref.alloc(%arg2, %3) : memref<?x?xf32>476 scf.yield %4 : memref<?x?xf32>477 } else {478 %1 = arith.constant 2 : i32479 %2 = arith.addi %arg0, %1 : i32480 %3 = arith.index_cast %2 : i32 to index481 %4 = memref.alloc(%arg2, %3) : memref<?x?xf32>482 scf.yield %4 : memref<?x?xf32>483 }484 return %0 : memref<?x?xf32>485}486 487// CHECK: (%[[ARG0:.*]]: {{.*}}488// CHECK-NEXT: %{{.*}} = scf.if489// CHECK-NEXT: %{{.*}} = arith.constant490// CHECK-NEXT: %{{.*}} = arith.addi491// CHECK-NEXT: %[[FUNC:.*]] = arith.index_cast492// CHECK-NEXT: alloc(%arg2, %[[FUNC]])493// CHECK-NEXT: scf.yield494// CHECK-NEXT: } else {495// CHECK-NEXT: %{{.*}} = arith.constant496// CHECK-NEXT: %{{.*}} = arith.addi497// CHECK-NEXT: %[[FUNC:.*]] = arith.index_cast498// CHECK-NEXT: alloc(%arg2, %[[FUNC]])499 500// -----501 502// Test Case: nested region control flow within a region interface.503// The alloc positions of %0 does not need to be changed.504 505// CHECK-LABEL: func @inner_region_control_flow506func.func @inner_region_control_flow(%arg0 : index) -> memref<?x?xf32> {507 %0 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>508 %1 = test.region_if %0 : memref<?x?xf32> -> (memref<?x?xf32>) then {509 ^bb0(%arg1 : memref<?x?xf32>):510 test.region_if_yield %arg1 : memref<?x?xf32>511 } else {512 ^bb0(%arg1 : memref<?x?xf32>):513 test.region_if_yield %arg1 : memref<?x?xf32>514 } join {515 ^bb0(%arg1 : memref<?x?xf32>):516 test.region_if_yield %arg1 : memref<?x?xf32>517 }518 return %1 : memref<?x?xf32>519}520 521// CHECK: %[[ALLOC0:.*]] = memref.alloc(%arg0, %arg0)522// CHECK-NEXT: {{.*}} test.region_if523 524// -----525 526// Test Case: nested region control flow within a region interface including an527// allocation in a divergent branch.528// The alloc positions of %0 does not need to be changed. %2 is moved upwards.529 530// CHECK-LABEL: func @inner_region_control_flow_div531func.func @inner_region_control_flow_div(532 %arg0 : index,533 %arg1 : index) -> memref<?x?xf32> {534 %0 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>535 %1 = test.region_if %0 : memref<?x?xf32> -> (memref<?x?xf32>) then {536 ^bb0(%arg2 : memref<?x?xf32>):537 test.region_if_yield %arg2 : memref<?x?xf32>538 } else {539 ^bb0(%arg2 : memref<?x?xf32>):540 %2 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>541 test.region_if_yield %2 : memref<?x?xf32>542 } join {543 ^bb0(%arg2 : memref<?x?xf32>):544 test.region_if_yield %arg2 : memref<?x?xf32>545 }546 return %1 : memref<?x?xf32>547}548 549// CHECK: %[[ALLOC0:.*]] = memref.alloc(%arg0, %arg0)550// CHECK-NEXT: %[[ALLOC1:.*]] = memref.alloc(%arg0, %arg1)551// CHECK-NEXT: {{.*}} test.region_if552 553// -----554 555// Test Case: Alloca operations shouldn't be moved.556 557// CHECK-LABEL: func @condBranchAlloca558func.func @condBranchAlloca(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {559 cf.cond_br %arg0, ^bb1, ^bb2560^bb1:561 cf.br ^bb3(%arg1 : memref<2xf32>)562^bb2:563 %0 = memref.alloca() : memref<2xf32>564 test.buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>)565 cf.br ^bb3(%0 : memref<2xf32>)566^bb3(%1: memref<2xf32>):567 test.copy(%1, %arg2) : (memref<2xf32>, memref<2xf32>)568 return569}570 571// CHECK-NEXT: cf.cond_br572// CHECK: ^bb2573// CHECK: ^bb2574// CHECK-NEXT: %[[ALLOCA:.*]] = memref.alloca()575// CHECK-NEXT: test.buffer_based576 577// -----578 579// Test Case: Alloca operations shouldn't be moved. The alloc operation also580// shouldn't be moved analogously to the ifElseNested test.581 582// CHECK-LABEL: func @ifElseNestedAlloca583func.func @ifElseNestedAlloca(584 %arg0: i1,585 %arg1: memref<2xf32>,586 %arg2: memref<2xf32>) {587 %0 = memref.alloca() : memref<2xf32>588 test.buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>)589 cf.cond_br %arg0,590 ^bb1(%arg1, %0 : memref<2xf32>, memref<2xf32>),591 ^bb2(%0, %arg1 : memref<2xf32>, memref<2xf32>)592^bb1(%1: memref<2xf32>, %2: memref<2xf32>):593 cf.br ^bb5(%1, %2 : memref<2xf32>, memref<2xf32>)594^bb2(%3: memref<2xf32>, %4: memref<2xf32>):595 cf.cond_br %arg0, ^bb3(%3 : memref<2xf32>), ^bb4(%4 : memref<2xf32>)596^bb3(%5: memref<2xf32>):597 cf.br ^bb5(%5, %3 : memref<2xf32>, memref<2xf32>)598^bb4(%6: memref<2xf32>):599 cf.br ^bb5(%3, %6 : memref<2xf32>, memref<2xf32>)600^bb5(%7: memref<2xf32>, %8: memref<2xf32>):601 %9 = memref.alloc() : memref<2xf32>602 test.buffer_based in(%7: memref<2xf32>) out(%9: memref<2xf32>)603 test.copy(%9, %arg2) : (memref<2xf32>, memref<2xf32>)604 return605}606 607// CHECK-NEXT: %[[ALLOCA:.*]] = memref.alloca()608// CHECK-NEXT: test.buffer_based609// CHECK: ^bb5610// CHECK: ^bb5611// CHECK: ^bb5612// CHECK-NEXT: ^bb5613// CHECK-NEXT: %[[ALLOC:.*]] = memref.alloc()614// CHECK-NEXT: test.buffer_based615 616// -----617 618// Test Case: Alloca operations shouldn't be moved. The alloc operation should619// be moved in the beginning analogous to the nestedRegionsAndCondBranch test.620 621// CHECK-LABEL: func @nestedRegionsAndCondBranchAlloca622func.func @nestedRegionsAndCondBranchAlloca(623 %arg0: i1,624 %arg1: memref<2xf32>,625 %arg2: memref<2xf32>) {626 cf.cond_br %arg0, ^bb1, ^bb2627^bb1:628 cf.br ^bb3(%arg1 : memref<2xf32>)629^bb2:630 %0 = memref.alloc() : memref<2xf32>631 test.region_buffer_based in(%arg1: memref<2xf32>) out(%0: memref<2xf32>) {632 ^bb0(%gen1_arg0: f32, %gen1_arg1: f32):633 %1 = memref.alloca() : memref<2xf32>634 test.buffer_based in(%arg1: memref<2xf32>) out(%1: memref<2xf32>)635 %tmp1 = math.exp %gen1_arg0 : f32636 test.region_yield %tmp1 : f32637 }638 cf.br ^bb3(%0 : memref<2xf32>)639^bb3(%1: memref<2xf32>):640 test.copy(%1, %arg2) : (memref<2xf32>, memref<2xf32>)641 return642}643// CHECK-NEXT: %[[ALLOC:.*]] = memref.alloc()644// CHECK-NEXT: cf.cond_br645// CHECK: test.region_buffer_based646// CHECK: %[[ALLOCA:.*]] = memref.alloca()647// CHECK-NEXT: test.buffer_based648 649// -----650 651// Test Case: structured control-flow loop using a nested alloc.652// The alloc positions of %3 will be moved upwards.653 654// CHECK-LABEL: func @loop_alloc655func.func @loop_alloc(656 %lb: index,657 %ub: index,658 %step: index,659 %buf: memref<2xf32>,660 %res: memref<2xf32>) {661 %0 = memref.alloc() : memref<2xf32>662 %1 = scf.for %i = %lb to %ub step %step663 iter_args(%iterBuf = %buf) -> memref<2xf32> {664 %2 = arith.cmpi eq, %i, %ub : index665 %3 = memref.alloc() : memref<2xf32>666 scf.yield %3 : memref<2xf32>667 }668 test.copy(%1, %res) : (memref<2xf32>, memref<2xf32>)669 return670}671 672// CHECK: %[[ALLOC0:.*]] = memref.alloc()673// CHECK-NEXT: {{.*}} scf.for674// CHECK: %[[ALLOC1:.*]] = memref.alloc()675 676// -----677 678// Test Case: structured control-flow loop with a nested if operation using679// a deeply nested buffer allocation.680// The allocation %4 is not moved upwards.681 682// CHECK-LABEL: func @loop_nested_if_alloc683func.func @loop_nested_if_alloc(684 %lb: index,685 %ub: index,686 %step: index,687 %buf: memref<2xf32>) -> memref<2xf32> {688 %0 = memref.alloc() : memref<2xf32>689 %1 = scf.for %i = %lb to %ub step %step690 iter_args(%iterBuf = %buf) -> memref<2xf32> {691 %2 = arith.cmpi eq, %i, %ub : index692 %3 = scf.if %2 -> (memref<2xf32>) {693 %4 = memref.alloc() : memref<2xf32>694 scf.yield %4 : memref<2xf32>695 } else {696 scf.yield %0 : memref<2xf32>697 }698 scf.yield %3 : memref<2xf32>699 }700 return %1 : memref<2xf32>701}702 703// CHECK: %[[ALLOC0:.*]] = memref.alloc()704// CHECK-NEXT: {{.*}} scf.for705// CHECK: %[[ALLOC1:.*]] = memref.alloc()706 707// -----708 709// Test Case: several nested structured control-flow loops with a deeply nested710// buffer allocation inside an if operation.711// Same behavior is an loop_nested_if_alloc: The allocs are not moved upwards.712 713// CHECK-LABEL: func @loop_nested_alloc714func.func @loop_nested_alloc(715 %lb: index,716 %ub: index,717 %step: index,718 %buf: memref<2xf32>,719 %res: memref<2xf32>) {720 %0 = memref.alloc() : memref<2xf32>721 %1 = scf.for %i = %lb to %ub step %step722 iter_args(%iterBuf = %buf) -> memref<2xf32> {723 %2 = scf.for %i2 = %lb to %ub step %step724 iter_args(%iterBuf2 = %iterBuf) -> memref<2xf32> {725 %3 = scf.for %i3 = %lb to %ub step %step726 iter_args(%iterBuf3 = %iterBuf2) -> memref<2xf32> {727 %4 = memref.alloc() : memref<2xf32>728 %5 = arith.cmpi eq, %i, %ub : index729 %6 = scf.if %5 -> (memref<2xf32>) {730 %7 = memref.alloc() : memref<2xf32>731 scf.yield %7 : memref<2xf32>732 } else {733 scf.yield %iterBuf3 : memref<2xf32>734 }735 scf.yield %6 : memref<2xf32>736 }737 scf.yield %3 : memref<2xf32>738 }739 scf.yield %2 : memref<2xf32>740 }741 test.copy(%1, %res) : (memref<2xf32>, memref<2xf32>)742 return743}744 745// CHECK: %[[ALLOC0:.*]] = memref.alloc()746// CHECK-NEXT: {{.*}} = scf.for747// CHECK-NEXT: {{.*}} = scf.for748// CHECK-NEXT: {{.*}} = scf.for749// CHECK-NEXT: %[[ALLOC1:.*]] = memref.alloc()750// CHECK: %[[ALLOC2:.*]] = memref.alloc()751 752// -----753 754// CHECK-LABEL: func @loop_nested_alloc_dyn_dependency755func.func @loop_nested_alloc_dyn_dependency(756 %lb: index,757 %ub: index,758 %step: index,759 %arg0: index,760 %buf: memref<?xf32>,761 %res: memref<?xf32>) {762 %0 = memref.alloc(%arg0) : memref<?xf32>763 %1 = scf.for %i = %lb to %ub step %step764 iter_args(%iterBuf = %buf) -> memref<?xf32> {765 %2 = scf.for %i2 = %lb to %ub step %step766 iter_args(%iterBuf2 = %iterBuf) -> memref<?xf32> {767 %3 = scf.for %i3 = %lb to %ub step %step768 iter_args(%iterBuf3 = %iterBuf2) -> memref<?xf32> {769 %5 = arith.cmpi eq, %i, %ub : index770 %6 = scf.if %5 -> (memref<?xf32>) {771 %7 = memref.alloc(%i3) : memref<?xf32>772 scf.yield %7 : memref<?xf32>773 } else {774 scf.yield %iterBuf3 : memref<?xf32>775 }776 scf.yield %6 : memref<?xf32>777 }778 scf.yield %3 : memref<?xf32>779 }780 scf.yield %0 : memref<?xf32>781 }782 test.copy(%1, %res) : (memref<?xf32>, memref<?xf32>)783 return784}785 786 787// CHECK: %[[ALLOC0:.*]] = memref.alloc({{.*}})788// CHECK-NEXT: {{.*}} = scf.for789// CHECK-NEXT: {{.*}} = scf.for790// CHECK-NEXT: {{.*}} = scf.for791// CHECK: %[[ALLOC1:.*]] = memref.alloc({{.*}})792