321 lines · plain
1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='builtin.module(func.func(canonicalize{region-simplify=aggressive}))' -split-input-file | FileCheck %s2 3// Check the simple case of single operation blocks with a return.4 5// CHECK-LABEL: func @return_blocks(6func.func @return_blocks() {7 // CHECK: "foo.cond_br"()[^bb1, ^bb1]8 // CHECK: ^bb1:9 // CHECK-NEXT: return10 // CHECK-NOT: ^bb211 12 "foo.cond_br"() [^bb1, ^bb2] : () -> ()13 14^bb1:15 return16^bb2:17 return18}19 20// Check the case of identical blocks with matching arguments.21 22// CHECK-LABEL: func @matching_arguments(23func.func @matching_arguments() -> i32 {24 // CHECK: "foo.cond_br"()[^bb1, ^bb1]25 // CHECK: ^bb1(%{{.*}}: i32):26 // CHECK-NEXT: return27 // CHECK-NOT: ^bb228 29 "foo.cond_br"() [^bb1, ^bb2] : () -> ()30 31^bb1(%arg0 : i32):32 return %arg0 : i3233^bb2(%arg1 : i32):34 return %arg1 : i3235}36 37// Check that no merging occurs if there is an operand mismatch and we can't38// update th predecessor.39 40// CHECK-LABEL: func @mismatch_unknown_terminator41func.func @mismatch_unknown_terminator(%arg0 : i32, %arg1 : i32) -> i32 {42 // CHECK: "foo.cond_br"()[^bb1, ^bb2]43 44 "foo.cond_br"() [^bb1, ^bb2] : () -> ()45 46^bb1:47 return %arg0 : i3248^bb2:49 return %arg1 : i3250}51 52// Check that merging does occurs if there is an operand mismatch and we can53// update th predecessor.54 55// CHECK-LABEL: func @mismatch_operands56// CHECK-SAME: %[[COND:.*]]: i1, %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i3257func.func @mismatch_operands(%cond : i1, %arg0 : i32, %arg1 : i32) -> i32 {58 // CHECK: %[[RES:.*]] = arith.select %[[COND]], %[[ARG0]], %[[ARG1]]59 // CHECK: return %[[RES]]60 61 cf.cond_br %cond, ^bb1, ^bb262 63^bb1:64 return %arg0 : i3265^bb2:66 return %arg1 : i3267}68 69// Check the same as above, but with pre-existing arguments.70 71// CHECK-LABEL: func @mismatch_operands_matching_arguments(72// CHECK-SAME: %[[COND:.*]]: i1, %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i3273func.func @mismatch_operands_matching_arguments(%cond : i1, %arg0 : i32, %arg1 : i32) -> (i32, i32) {74 // CHECK: %[[RES0:.*]] = arith.select %[[COND]], %[[ARG1]], %[[ARG0]]75 // CHECK: %[[RES1:.*]] = arith.select %[[COND]], %[[ARG0]], %[[ARG1]]76 // CHECK: return %[[RES1]], %[[RES0]]77 78 cf.cond_br %cond, ^bb1(%arg1 : i32), ^bb2(%arg0 : i32)79 80^bb1(%arg2 : i32):81 return %arg0, %arg2 : i32, i3282^bb2(%arg3 : i32):83 return %arg1, %arg3 : i32, i3284}85 86// Check that merging does not occur if the uses of the arguments differ.87 88// CHECK-LABEL: func @mismatch_argument_uses(89func.func @mismatch_argument_uses(%cond : i1, %arg0 : i32, %arg1 : i32) -> (i32, i32) {90 // CHECK: return {{.*}}, {{.*}}91 92 cf.cond_br %cond, ^bb1(%arg1 : i32), ^bb2(%arg0 : i32)93 94^bb1(%arg2 : i32):95 return %arg0, %arg2 : i32, i3296^bb2(%arg3 : i32):97 return %arg3, %arg1 : i32, i3298}99 100// Check that merging does not occur if the types of the arguments differ.101 102// CHECK-LABEL: func @mismatch_argument_types(103func.func @mismatch_argument_types(%cond : i1, %arg0 : i32, %arg1 : i16) {104 // CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2105 106 cf.cond_br %cond, ^bb1(%arg0 : i32), ^bb2(%arg1 : i16)107 108^bb1(%arg2 : i32):109 "foo.return"(%arg2) : (i32) -> ()110^bb2(%arg3 : i16):111 "foo.return"(%arg3) : (i16) -> ()112}113 114// Check that merging does not occur if the number of the arguments differ.115 116// CHECK-LABEL: func @mismatch_argument_count(117func.func @mismatch_argument_count(%cond : i1, %arg0 : i32) {118 // CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2119 120 cf.cond_br %cond, ^bb1(%arg0 : i32), ^bb2121 122^bb1(%arg2 : i32):123 "foo.return"(%arg2) : (i32) -> ()124^bb2:125 "foo.return"() : () -> ()126}127 128// Check that merging does not occur if the operations differ.129 130// CHECK-LABEL: func @mismatch_operations(131func.func @mismatch_operations(%cond : i1) {132 // CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2133 134 cf.cond_br %cond, ^bb1, ^bb2135 136^bb1:137 "foo.return"() : () -> ()138^bb2:139 return140}141 142// Check that merging does not occur if the number of operations differ.143 144// CHECK-LABEL: func @mismatch_operation_count(145func.func @mismatch_operation_count(%cond : i1) {146 // CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2147 148 cf.cond_br %cond, ^bb1, ^bb2149 150^bb1:151 "foo.op"() : () -> ()152 return153^bb2:154 return155}156 157// Check that merging does not occur if the blocks contain regions.158 159// CHECK-LABEL: func @contains_regions(160func.func @contains_regions(%cond : i1) {161 // CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2162 163 cf.cond_br %cond, ^bb1, ^bb2164 165^bb1:166 scf.if %cond {167 "foo.op"() : () -> ()168 }169 return170^bb2:171 scf.if %cond {172 "foo.op"() : () -> ()173 }174 return175}176 177// Check that properly handles back edges.178 179// CHECK-LABEL: func @mismatch_loop(180// CHECK-SAME: %[[ARG:.*]]: i1, %[[ARG2:.*]]: i1181func.func @mismatch_loop(%cond : i1, %cond2 : i1) {182 // CHECK-NEXT: %[[LOOP_CARRY:.*]] = "foo.op"183 // CHECK: cf.cond_br %{{.*}}, ^bb1(%[[ARG2]] : i1), ^bb2184 185 %cond3 = "foo.op"() : () -> (i1)186 cf.cond_br %cond, ^bb2, ^bb3187 188^bb1:189 // CHECK: ^bb1(%[[ARG3:.*]]: i1):190 // CHECK-NEXT: cf.cond_br %[[ARG3]], ^bb1(%[[LOOP_CARRY]] : i1), ^bb2191 192 cf.cond_br %cond3, ^bb1, ^bb3193 194^bb2:195 cf.cond_br %cond2, ^bb1, ^bb3196 197^bb3:198 // CHECK: ^bb2:199 // CHECK-NEXT: return200 201 return202}203 204// Check that blocks are not merged if the types of the operands differ.205 206// CHECK-LABEL: func @mismatch_operand_types(207func.func @mismatch_operand_types(%arg0 : i1, %arg1 : memref<i32>, %arg2 : memref<i1>) {208 %c0_i32 = arith.constant 0 : i32209 %true = arith.constant true210 cf.br ^bb1211 212^bb1:213 cf.cond_br %arg0, ^bb2, ^bb3214 215^bb2:216 // CHECK: memref.store %{{.*}}, %{{.*}} : memref<i32>217 memref.store %c0_i32, %arg1[] : memref<i32>218 cf.br ^bb1219 220^bb3:221 // CHECK: memref.store %{{.*}}, %{{.*}} : memref<i1>222 memref.store %true, %arg2[] : memref<i1>223 cf.br ^bb1224}225 226// Check that it is illegal to merge blocks containing an operand227// with an external user. Incorrectly performing the optimization228// anyways will result in print(merged, merged) rather than229// distinct operands.230func.func private @print(%arg0: i32, %arg1: i32)231// CHECK-LABEL: @nomerge232func.func @nomerge(%arg0: i32, %i: i32) {233 %c1_i32 = arith.constant 1 : i32234 %icmp = arith.cmpi slt, %i, %arg0 : i32235 cf.cond_br %icmp, ^bb2, ^bb3236 237^bb2: // pred: ^bb1238 %ip1 = arith.addi %i, %c1_i32 : i32239 cf.br ^bb4(%ip1 : i32)240 241^bb7: // pred: ^bb5242 %jp1 = arith.addi %j, %c1_i32 : i32243 cf.br ^bb4(%jp1 : i32)244 245^bb4(%j: i32): // 2 preds: ^bb2, ^bb7246 %jcmp = arith.cmpi slt, %j, %arg0 : i32247// CHECK-NOT: call @print(%[[arg1:.+]], %[[arg1]])248 call @print(%j, %ip1) : (i32, i32) -> ()249 cf.cond_br %jcmp, ^bb7, ^bb3250 251^bb3: // pred: ^bb1252 return253}254 255 256// CHECK-LABEL: func @mismatch_dominance(257func.func @mismatch_dominance() -> i32 {258 // CHECK: %[[RES:.*]] = "test.producing_br"()259 %0 = "test.producing_br"()[^bb1, ^bb2] {260 operandSegmentSizes = array<i32: 0, 0>261 } : () -> i32262 263^bb1:264 // CHECK: "test.br"(%[[RES]])[^[[MERGE_BLOCK:.*]]]265 "test.br"(%0)[^bb4] : (i32) -> ()266 267^bb2:268 %1 = "foo.def"() : () -> i32269 "test.br"()[^bb3] : () -> ()270 271^bb3:272 // CHECK: "test.br"(%{{.*}})[^[[MERGE_BLOCK]]]273 "test.br"(%1)[^bb4] : (i32) -> ()274 275^bb4(%3: i32):276 return %3 : i32277}278 279// CHECK-LABEL: func @dead_dealloc_fold_multi_use280func.func @dead_dealloc_fold_multi_use(%cond : i1) {281 // CHECK-NEXT: return282 %a = memref.alloc() : memref<4xf32>283 cf.cond_br %cond, ^bb1, ^bb2284 285^bb1:286 memref.dealloc %a: memref<4xf32>287 return288 289^bb2:290 memref.dealloc %a: memref<4xf32>291 return292}293 294// CHECK-LABEL: func @nested_loop295func.func @nested_loop(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32, %arg4: i32, %arg5: i1) {296// Irreducible control-flow: enter the middle of the loop in LoopBody_entry here.297 "test.foo_br"(%arg0, %arg4)[^LoopBody_entry] : (i32, i32) -> ()298 299// Loop exit condition: jump to exit or LoobBody blocks300^Loop_header: // 2 preds: ^bb2, ^bb3301 // Consumes the block arg from LoopBody_entry302 // Because of this use here, we can't merge the two blocks below.303 "test.foo_br2"(%0)[^EXIT, ^LoopBody_entry, ^LoopBody_other] : (i32) -> ()304 305// LoopBody_entry is jumped in from the entry block (bb0) and Loop_header306// It **dominates** the Loop_header.307^LoopBody_entry(%0: i32): // 2 preds: ^bb0, ^Loop_header308 // CHECK: test.bar309 %1 = "test.bar"(%0) : (i32) -> i32310 cf.br ^Loop_header311 312// Other block inside the loop, not dominating the header313^LoopBody_other(%2: i32): // pred: ^Loop_header314 // CHECK: test.bar315 %3 = "test.bar"(%2) : (i32) -> i32316 cf.br ^Loop_header317 318^EXIT: // pred: ^Loop_header319 return320}321