1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='func(canonicalize)' -split-input-file | FileCheck %s 2 3// Check the simple case of single operation blocks with a return. 4 5// CHECK-LABEL: func @return_blocks( 6func @return_blocks() { 7 // CHECK: "foo.cond_br"()[^bb1, ^bb1] 8 // CHECK: ^bb1: 9 // CHECK-NEXT: return 10 // CHECK-NOT: ^bb2 11 12 "foo.cond_br"() [^bb1, ^bb2] : () -> () 13 14^bb1: 15 return 16^bb2: 17 return 18} 19 20// Check the case of identical blocks with matching arguments. 21 22// CHECK-LABEL: func @matching_arguments( 23func @matching_arguments() -> i32 { 24 // CHECK: "foo.cond_br"()[^bb1, ^bb1] 25 // CHECK: ^bb1(%{{.*}}: i32): 26 // CHECK-NEXT: return 27 // CHECK-NOT: ^bb2 28 29 "foo.cond_br"() [^bb1, ^bb2] : () -> () 30 31^bb1(%arg0 : i32): 32 return %arg0 : i32 33^bb2(%arg1 : i32): 34 return %arg1 : i32 35} 36 37// Check that no merging occurs if there is an operand mismatch and we can't 38// update th predecessor. 39 40// CHECK-LABEL: func @mismatch_unknown_terminator 41func @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 : i32 48^bb2: 49 return %arg1 : i32 50} 51 52// Check that merging does occurs if there is an operand mismatch and we can 53// update th predecessor. 54 55// CHECK-LABEL: func @mismatch_operands 56// CHECK-SAME: %[[COND:.*]]: i1, %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32 57func @mismatch_operands(%cond : i1, %arg0 : i32, %arg1 : i32) -> i32 { 58 // CHECK: %[[RES:.*]] = select %[[COND]], %[[ARG0]], %[[ARG1]] 59 // CHECK: return %[[RES]] 60 61 cond_br %cond, ^bb1, ^bb2 62 63^bb1: 64 return %arg0 : i32 65^bb2: 66 return %arg1 : i32 67} 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:.*]]: i32 73func @mismatch_operands_matching_arguments(%cond : i1, %arg0 : i32, %arg1 : i32) -> (i32, i32) { 74 // CHECK: %[[RES0:.*]] = select %[[COND]], %[[ARG1]], %[[ARG0]] 75 // CHECK: %[[RES1:.*]] = select %[[COND]], %[[ARG0]], %[[ARG1]] 76 // CHECK: return %[[RES1]], %[[RES0]] 77 78 cond_br %cond, ^bb1(%arg1 : i32), ^bb2(%arg0 : i32) 79 80^bb1(%arg2 : i32): 81 return %arg0, %arg2 : i32, i32 82^bb2(%arg3 : i32): 83 return %arg1, %arg3 : i32, i32 84} 85 86// Check that merging does not occur if the uses of the arguments differ. 87 88// CHECK-LABEL: func @mismatch_argument_uses( 89func @mismatch_argument_uses(%cond : i1, %arg0 : i32, %arg1 : i32) -> (i32, i32) { 90 // CHECK: cond_br %{{.*}}, ^bb1(%{{.*}}), ^bb2 91 92 cond_br %cond, ^bb1(%arg1 : i32), ^bb2(%arg0 : i32) 93 94^bb1(%arg2 : i32): 95 return %arg0, %arg2 : i32, i32 96^bb2(%arg3 : i32): 97 return %arg3, %arg1 : i32, i32 98} 99 100// Check that merging does not occur if the types of the arguments differ. 101 102// CHECK-LABEL: func @mismatch_argument_types( 103func @mismatch_argument_types(%cond : i1, %arg0 : i32, %arg1 : i16) { 104 // CHECK: cond_br %{{.*}}, ^bb1(%{{.*}}), ^bb2 105 106 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 @mismatch_argument_count(%cond : i1, %arg0 : i32) { 118 // CHECK: cond_br %{{.*}}, ^bb1(%{{.*}}), ^bb2 119 120 cond_br %cond, ^bb1(%arg0 : i32), ^bb2 121 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 @mismatch_operations(%cond : i1) { 132 // CHECK: cond_br %{{.*}}, ^bb1, ^bb2 133 134 cond_br %cond, ^bb1, ^bb2 135 136^bb1: 137 "foo.return"() : () -> () 138^bb2: 139 return 140} 141 142// Check that merging does not occur if the number of operations differ. 143 144// CHECK-LABEL: func @mismatch_operation_count( 145func @mismatch_operation_count(%cond : i1) { 146 // CHECK: cond_br %{{.*}}, ^bb1, ^bb2 147 148 cond_br %cond, ^bb1, ^bb2 149 150^bb1: 151 "foo.op"() : () -> () 152 return 153^bb2: 154 return 155} 156 157// Check that merging does not occur if the blocks contain regions. 158 159// CHECK-LABEL: func @contains_regions( 160func @contains_regions(%cond : i1) { 161 // CHECK: cond_br %{{.*}}, ^bb1, ^bb2 162 163 cond_br %cond, ^bb1, ^bb2 164 165^bb1: 166 scf.if %cond { 167 "foo.op"() : () -> () 168 } 169 return 170^bb2: 171 scf.if %cond { 172 "foo.op"() : () -> () 173 } 174 return 175} 176 177// Check that properly handles back edges. 178 179// CHECK-LABEL: func @mismatch_loop( 180// CHECK-SAME: %[[ARG:.*]]: i1, %[[ARG2:.*]]: i1 181func @mismatch_loop(%cond : i1, %cond2 : i1) { 182 // CHECK-NEXT: %[[LOOP_CARRY:.*]] = "foo.op" 183 // CHECK: cond_br %{{.*}}, ^bb1(%[[ARG2]] : i1), ^bb2 184 185 %cond3 = "foo.op"() : () -> (i1) 186 cond_br %cond, ^bb2, ^bb3 187 188^bb1: 189 // CHECK: ^bb1(%[[ARG3:.*]]: i1): 190 // CHECK-NEXT: cond_br %[[ARG3]], ^bb1(%[[LOOP_CARRY]] : i1), ^bb2 191 192 cond_br %cond3, ^bb1, ^bb3 193 194^bb2: 195 cond_br %cond2, ^bb1, ^bb3 196 197^bb3: 198 // CHECK: ^bb2: 199 // CHECK-NEXT: return 200 201 return 202} 203 204// Check that blocks are not merged if the types of the operands differ. 205 206// CHECK-LABEL: func @mismatch_operand_types( 207func @mismatch_operand_types(%arg0 : i1, %arg1 : memref<i32>, %arg2 : memref<i1>) { 208 %c0_i32 = constant 0 : i32 209 %true = constant true 210 br ^bb1 211 212^bb1: 213 cond_br %arg0, ^bb2, ^bb3 214 215^bb2: 216 // CHECK: store %{{.*}}, %{{.*}} : memref<i32> 217 store %c0_i32, %arg1[] : memref<i32> 218 br ^bb1 219 220^bb3: 221 // CHECK: store %{{.*}}, %{{.*}} : memref<i1> 222 store %true, %arg2[] : memref<i1> 223 br ^bb1 224} 225 226// Check that it is illegal to merge blocks containing an operand 227// with an external user. Incorrectly performing the optimization 228// anyways will result in print(merged, merged) rather than 229// distinct operands. 230func private @print(%arg0: i32, %arg1: i32) 231// CHECK-LABEL: @nomerge 232func @nomerge(%arg0: i32, %i: i32) { 233 %c1_i32 = constant 1 : i32 234 %icmp = cmpi "slt", %i, %arg0 : i32 235 cond_br %icmp, ^bb2, ^bb3 236 237^bb2: // pred: ^bb1 238 %ip1 = addi %i, %c1_i32 : i32 239 br ^bb4(%ip1 : i32) 240 241^bb7: // pred: ^bb5 242 %jp1 = addi %j, %c1_i32 : i32 243 br ^bb4(%jp1 : i32) 244 245^bb4(%j: i32): // 2 preds: ^bb2, ^bb7 246 %jcmp = cmpi "slt", %j, %arg0 : i32 247// CHECK-NOT: call @print(%[[arg1:.+]], %[[arg1]]) 248 call @print(%j, %ip1) : (i32, i32) -> () 249 cond_br %jcmp, ^bb7, ^bb3 250 251^bb3: // pred: ^bb1 252 return 253} 254