1 // RUN: mlir-opt %s -allow-unregistered-dialect -pass-pipeline='builtin.module(func.func(canonicalize{test-convergence}))' -split-input-file | FileCheck --dump-input-context 20 %s
3 /// Test the folding of BranchOp.
5 // CHECK-LABEL: func @br_folding(
6 func.func @br_folding() -> i32 {
7 // CHECK-NEXT: %[[CST:.*]] = arith.constant 0 : i32
8 // CHECK-NEXT: return %[[CST]] : i32
9 %c0_i32 = arith.constant 0 : i32
10 cf.br ^bb1(%c0_i32 : i32)
15 /// Test that pass-through successors of BranchOp get folded.
17 // CHECK-LABEL: func @br_passthrough(
18 // CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32
19 func.func @br_passthrough(%arg0 : i32, %arg1 : i32) -> (i32, i32) {
20 "foo.switch"() [^bb1, ^bb2, ^bb3] : () -> ()
24 // CHECK-NEXT: cf.br ^bb3(%[[ARG0]], %[[ARG1]] : i32, i32)
26 cf.br ^bb2(%arg0 : i32)
29 cf.br ^bb3(%arg2, %arg1 : i32, i32)
31 ^bb3(%arg4 : i32, %arg5 : i32):
32 return %arg4, %arg5 : i32, i32
35 /// Test the folding of CondBranchOp with a constant condition.
37 // CHECK-LABEL: func @cond_br_folding(
38 func.func @cond_br_folding(%cond : i1, %a : i32) {
41 %false_cond = arith.constant false
42 %true_cond = arith.constant true
43 cf.cond_br %cond, ^bb1, ^bb2(%a : i32)
46 cf.cond_br %true_cond, ^bb3, ^bb2(%a : i32)
49 cf.cond_br %false_cond, ^bb2(%x : i32), ^bb3
55 /// Test the folding of CondBranchOp when the successors are identical.
57 // CHECK-LABEL: func @cond_br_same_successor(
58 func.func @cond_br_same_successor(%cond : i1, %a : i32) {
61 cf.cond_br %cond, ^bb1(%a : i32), ^bb1(%a : i32)
67 /// Test the folding of CondBranchOp when the successors are identical, but the
68 /// arguments are different.
70 // CHECK-LABEL: func @cond_br_same_successor_insert_select(
71 // CHECK-SAME: %[[COND:.*]]: i1, %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32
72 // CHECK-SAME: %[[ARG2:.*]]: tensor<2xi32>, %[[ARG3:.*]]: tensor<2xi32>
73 func.func @cond_br_same_successor_insert_select(
74 %cond : i1, %a : i32, %b : i32, %c : tensor<2xi32>, %d : tensor<2xi32>
75 ) -> (i32, tensor<2xi32>) {
76 // CHECK: %[[RES:.*]] = arith.select %[[COND]], %[[ARG0]], %[[ARG1]]
77 // CHECK: %[[RES2:.*]] = arith.select %[[COND]], %[[ARG2]], %[[ARG3]]
78 // CHECK: return %[[RES]], %[[RES2]]
80 cf.cond_br %cond, ^bb1(%a, %c : i32, tensor<2xi32>), ^bb1(%b, %d : i32, tensor<2xi32>)
82 ^bb1(%result : i32, %result2 : tensor<2xi32>):
83 return %result, %result2 : i32, tensor<2xi32>
86 /// Test the compound folding of BranchOp and CondBranchOp.
88 // CHECK-LABEL: func @cond_br_and_br_folding(
89 func.func @cond_br_and_br_folding(%a : i32) {
92 %false_cond = arith.constant false
93 %true_cond = arith.constant true
94 cf.cond_br %true_cond, ^bb2, ^bb1(%a : i32)
97 cf.cond_br %false_cond, ^bb1(%x : i32), ^bb2
103 /// Test that pass-through successors of CondBranchOp get folded.
105 // CHECK-LABEL: func @cond_br_passthrough(
106 // CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32, %[[ARG2:.*]]: i32, %[[COND:.*]]: i1
107 func.func @cond_br_passthrough(%arg0 : i32, %arg1 : i32, %arg2 : i32, %cond : i1) -> (i32, i32) {
108 // CHECK: %[[RES:.*]] = arith.select %[[COND]], %[[ARG0]], %[[ARG2]]
109 // CHECK: %[[RES2:.*]] = arith.select %[[COND]], %[[ARG1]], %[[ARG2]]
110 // CHECK: return %[[RES]], %[[RES2]]
112 cf.cond_br %cond, ^bb1(%arg0 : i32), ^bb2(%arg2, %arg2 : i32, i32)
115 cf.br ^bb2(%arg3, %arg1 : i32, i32)
117 ^bb2(%arg4: i32, %arg5: i32):
118 return %arg4, %arg5 : i32, i32
121 /// Test the failure modes of collapsing CondBranchOp pass-throughs successors.
123 // CHECK-LABEL: func @cond_br_pass_through_fail(
124 func.func @cond_br_pass_through_fail(%cond : i1) {
125 // CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2
127 cf.cond_br %cond, ^bb1, ^bb2
134 // Successors can't be collapsed if they contain other operations.
135 "foo.op"() : () -> ()
143 /// Test the folding of SwitchOp
145 // CHECK-LABEL: func @switch_only_default(
146 // CHECK-SAME: %[[FLAG:[a-zA-Z0-9_]+]]
147 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
148 func.func @switch_only_default(%flag : i32, %caseOperand0 : f32) {
149 // add predecessors for all blocks to avoid other canonicalizations.
150 "foo.pred"() [^bb1, ^bb2] : () -> ()
152 // CHECK-NOT: cf.switch
153 // CHECK: cf.br ^[[BB2:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_0]]
154 cf.switch %flag : i32, [
155 default: ^bb2(%caseOperand0 : f32)
157 // CHECK: ^[[BB2]]({{.*}}):
159 // CHECK-NEXT: "foo.bb2Terminator"
160 "foo.bb2Terminator"(%bb2Arg) : (f32) -> ()
164 // CHECK-LABEL: func @switch_case_matching_default(
165 // CHECK-SAME: %[[FLAG:[a-zA-Z0-9_]+]]
166 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
167 // CHECK-SAME: %[[CASE_OPERAND_1:[a-zA-Z0-9_]+]]
168 func.func @switch_case_matching_default(%flag : i32, %caseOperand0 : f32, %caseOperand1 : f32) {
169 // add predecessors for all blocks to avoid other canonicalizations.
170 "foo.pred"() [^bb1, ^bb2, ^bb3] : () -> ()
172 // CHECK: cf.switch %[[FLAG]]
173 // CHECK-NEXT: default: ^[[BB1:.+]](%[[CASE_OPERAND_0]] : f32)
174 // CHECK-NEXT: 10: ^[[BB2:.+]](%[[CASE_OPERAND_1]] : f32)
176 cf.switch %flag : i32, [
177 default: ^bb2(%caseOperand0 : f32),
178 42: ^bb2(%caseOperand0 : f32),
179 10: ^bb3(%caseOperand1 : f32),
180 17: ^bb2(%caseOperand0 : f32)
183 "foo.bb2Terminator"(%bb2Arg) : (f32) -> ()
185 "foo.bb3Terminator"(%bb3Arg) : (f32) -> ()
189 // CHECK-LABEL: func @switch_on_const_no_match(
190 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
191 // CHECK-SAME: %[[CASE_OPERAND_1:[a-zA-Z0-9_]+]]
192 // CHECK-SAME: %[[CASE_OPERAND_2:[a-zA-Z0-9_]+]]
193 func.func @switch_on_const_no_match(%caseOperand0 : f32, %caseOperand1 : f32, %caseOperand2 : f32) {
194 // add predecessors for all blocks to avoid other canonicalizations.
195 "foo.pred"() [^bb1, ^bb2, ^bb3, ^bb4] : () -> ()
197 // CHECK-NOT: cf.switch
198 // CHECK: cf.br ^[[BB2:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_0]]
199 %c0_i32 = arith.constant 0 : i32
200 cf.switch %c0_i32 : i32, [
201 default: ^bb2(%caseOperand0 : f32),
202 -1: ^bb3(%caseOperand1 : f32),
203 1: ^bb4(%caseOperand2 : f32)
205 // CHECK: ^[[BB2]]({{.*}}):
206 // CHECK-NEXT: "foo.bb2Terminator"
208 "foo.bb2Terminator"(%bb2Arg) : (f32) -> ()
210 "foo.bb3Terminator"(%bb3Arg) : (f32) -> ()
212 "foo.bb4Terminator"(%bb4Arg) : (f32) -> ()
215 // CHECK-LABEL: func @switch_on_const_with_match(
216 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
217 // CHECK-SAME: %[[CASE_OPERAND_1:[a-zA-Z0-9_]+]]
218 // CHECK-SAME: %[[CASE_OPERAND_2:[a-zA-Z0-9_]+]]
219 func.func @switch_on_const_with_match(%caseOperand0 : f32, %caseOperand1 : f32, %caseOperand2 : f32) {
220 // add predecessors for all blocks to avoid other canonicalizations.
221 "foo.pred"() [^bb1, ^bb2, ^bb3, ^bb4] : () -> ()
223 // CHECK-NOT: cf.switch
224 // CHECK: cf.br ^[[BB4:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_2]]
225 %c0_i32 = arith.constant 1 : i32
226 cf.switch %c0_i32 : i32, [
227 default: ^bb2(%caseOperand0 : f32),
228 -1: ^bb3(%caseOperand1 : f32),
229 1: ^bb4(%caseOperand2 : f32)
232 "foo.bb2Terminator"(%bb2Arg) : (f32) -> ()
234 "foo.bb3Terminator"(%bb3Arg) : (f32) -> ()
235 // CHECK: ^[[BB4]]({{.*}}):
236 // CHECK-NEXT: "foo.bb4Terminator"
238 "foo.bb4Terminator"(%bb4Arg) : (f32) -> ()
241 // CHECK-LABEL: func @switch_passthrough(
242 // CHECK-SAME: %[[FLAG:[a-zA-Z0-9_]+]]
243 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
244 // CHECK-SAME: %[[CASE_OPERAND_1:[a-zA-Z0-9_]+]]
245 // CHECK-SAME: %[[CASE_OPERAND_2:[a-zA-Z0-9_]+]]
246 // CHECK-SAME: %[[CASE_OPERAND_3:[a-zA-Z0-9_]+]]
247 func.func @switch_passthrough(%flag : i32,
251 %caseOperand3 : f32) {
252 // add predecessors for all blocks to avoid other canonicalizations.
253 "foo.pred"() [^bb1, ^bb2, ^bb3, ^bb4, ^bb5, ^bb6] : () -> ()
256 // CHECK: cf.switch %[[FLAG]]
257 // CHECK-NEXT: default: ^[[BB5:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_0]]
258 // CHECK-NEXT: 43: ^[[BB6:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_1]]
259 // CHECK-NEXT: 44: ^[[BB4:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_2]]
261 cf.switch %flag : i32, [
262 default: ^bb2(%caseOperand0 : f32),
263 43: ^bb3(%caseOperand1 : f32),
264 44: ^bb4(%caseOperand2 : f32)
267 cf.br ^bb5(%bb2Arg : f32)
269 cf.br ^bb6(%bb3Arg : f32)
271 "foo.bb4Terminator"(%bb4Arg) : (f32) -> ()
273 // CHECK: ^[[BB5]]({{.*}}):
274 // CHECK-NEXT: "foo.bb5Terminator"
276 "foo.bb5Terminator"(%bb5Arg) : (f32) -> ()
278 // CHECK: ^[[BB6]]({{.*}}):
279 // CHECK-NEXT: "foo.bb6Terminator"
281 "foo.bb6Terminator"(%bb6Arg) : (f32) -> ()
284 // CHECK-LABEL: func @switch_from_switch_with_same_value_with_match(
285 // CHECK-SAME: %[[FLAG:[a-zA-Z0-9_]+]]
286 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
287 // CHECK-SAME: %[[CASE_OPERAND_1:[a-zA-Z0-9_]+]]
288 func.func @switch_from_switch_with_same_value_with_match(%flag : i32, %caseOperand0 : f32, %caseOperand1 : f32) {
289 // add predecessors for all blocks except ^bb3 to avoid other canonicalizations.
290 "foo.pred"() [^bb1, ^bb2, ^bb4, ^bb5] : () -> ()
293 // CHECK: cf.switch %[[FLAG]]
294 cf.switch %flag : i32, [
300 "foo.bb2Terminator"() : () -> ()
302 // prevent this block from being simplified away
303 "foo.op"() : () -> ()
304 // CHECK-NOT: cf.switch %[[FLAG]]
305 // CHECK: cf.br ^[[BB5:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_1]]
306 cf.switch %flag : i32, [
307 default: ^bb4(%caseOperand0 : f32),
308 42: ^bb5(%caseOperand1 : f32)
312 "foo.bb4Terminator"(%bb4Arg) : (f32) -> ()
314 // CHECK: ^[[BB5]]({{.*}}):
315 // CHECK-NEXT: "foo.bb5Terminator"
317 "foo.bb5Terminator"(%bb5Arg) : (f32) -> ()
320 // CHECK-LABEL: func @switch_from_switch_with_same_value_no_match(
321 // CHECK-SAME: %[[FLAG:[a-zA-Z0-9_]+]]
322 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
323 // CHECK-SAME: %[[CASE_OPERAND_1:[a-zA-Z0-9_]+]]
324 // CHECK-SAME: %[[CASE_OPERAND_2:[a-zA-Z0-9_]+]]
325 func.func @switch_from_switch_with_same_value_no_match(%flag : i32, %caseOperand0 : f32, %caseOperand1 : f32, %caseOperand2 : f32) {
326 // add predecessors for all blocks except ^bb3 to avoid other canonicalizations.
327 "foo.pred"() [^bb1, ^bb2, ^bb4, ^bb5, ^bb6] : () -> ()
330 // CHECK: cf.switch %[[FLAG]]
331 cf.switch %flag : i32, [
337 "foo.bb2Terminator"() : () -> ()
339 "foo.op"() : () -> ()
340 // CHECK-NOT: cf.switch %[[FLAG]]
341 // CHECK: cf.br ^[[BB4:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_0]]
342 cf.switch %flag : i32, [
343 default: ^bb4(%caseOperand0 : f32),
344 0: ^bb5(%caseOperand1 : f32),
345 43: ^bb6(%caseOperand2 : f32)
348 // CHECK: ^[[BB4]]({{.*}})
349 // CHECK-NEXT: "foo.bb4Terminator"
351 "foo.bb4Terminator"(%bb4Arg) : (f32) -> ()
354 "foo.bb5Terminator"(%bb5Arg) : (f32) -> ()
357 "foo.bb6Terminator"(%bb6Arg) : (f32) -> ()
360 // CHECK-LABEL: func @switch_from_switch_default_with_same_value(
361 // CHECK-SAME: %[[FLAG:[a-zA-Z0-9_]+]]
362 // CHECK-SAME: %[[CASE_OPERAND_0:[a-zA-Z0-9_]+]]
363 // CHECK-SAME: %[[CASE_OPERAND_1:[a-zA-Z0-9_]+]]
364 // CHECK-SAME: %[[CASE_OPERAND_2:[a-zA-Z0-9_]+]]
365 func.func @switch_from_switch_default_with_same_value(%flag : i32, %caseOperand0 : f32, %caseOperand1 : f32, %caseOperand2 : f32) {
366 // add predecessors for all blocks except ^bb3 to avoid other canonicalizations.
367 "foo.pred"() [^bb1, ^bb2, ^bb4, ^bb5, ^bb6] : () -> ()
370 // CHECK: cf.switch %[[FLAG]]
371 cf.switch %flag : i32, [
377 "foo.bb2Terminator"() : () -> ()
379 "foo.op"() : () -> ()
380 // CHECK: cf.switch %[[FLAG]]
381 // CHECK-NEXT: default: ^[[BB4:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_0]]
382 // CHECK-NEXT: 43: ^[[BB6:[a-zA-Z0-9_]+]](%[[CASE_OPERAND_2]]
384 cf.switch %flag : i32, [
385 default: ^bb4(%caseOperand0 : f32),
386 42: ^bb5(%caseOperand1 : f32),
387 43: ^bb6(%caseOperand2 : f32)
390 // CHECK: ^[[BB4]]({{.*}}):
391 // CHECK-NEXT: "foo.bb4Terminator"
393 "foo.bb4Terminator"(%bb4Arg) : (f32) -> ()
396 "foo.bb5Terminator"(%bb5Arg) : (f32) -> ()
398 // CHECK: ^[[BB6]]({{.*}}):
399 // CHECK-NEXT: "foo.bb6Terminator"
401 "foo.bb6Terminator"(%bb6Arg) : (f32) -> ()
404 /// Test folding conditional branches that are successors of conditional
405 /// branches with the same condition.
407 // CHECK-LABEL: func @cond_br_from_cond_br_with_same_condition
408 func.func @cond_br_from_cond_br_with_same_condition(%cond : i1) {
409 // CHECK: cf.cond_br %{{.*}}, ^bb1, ^bb2
413 cf.cond_br %cond, ^bb1, ^bb2
416 cf.cond_br %cond, ^bb3, ^bb2
419 "foo.terminator"() : () -> ()
427 // Erase assertion if condition is known to be true at compile time.
428 // CHECK-LABEL: @assert_true
429 func.func @assert_true() {
430 // CHECK-NOT: cf.assert
431 %true = arith.constant true
432 cf.assert %true, "Computer says no"
438 // Keep assertion if condition unknown at compile time.
439 // CHECK-LABEL: @cf.assert
440 // CHECK-SAME: (%[[ARG:.*]]: i1)
441 func.func @cf.assert(%arg : i1) {
442 // CHECK: cf.assert %[[ARG]], "Computer says no"
443 cf.assert %arg, "Computer says no"
449 // CHECK-LABEL: @branchCondProp
450 // CHECK: %[[trueval:.+]] = arith.constant true
451 // CHECK: %[[falseval:.+]] = arith.constant false
452 // CHECK: "test.consumer1"(%[[trueval]]) : (i1) -> ()
453 // CHECK: "test.consumer2"(%[[falseval]]) : (i1) -> ()
454 func.func @branchCondProp(%arg0: i1) {
455 cf.cond_br %arg0, ^trueB, ^falseB
458 "test.consumer1"(%arg0) : (i1) -> ()
462 "test.consumer2"(%arg0) : (i1) -> ()