xref: /llvm-project/mlir/test/Conversion/ControlFlowToSCF/test.mlir (revision 30fe8762446ca91a34174ab9c5dde34bde4d4394)
1// RUN: mlir-opt --lift-cf-to-scf -split-input-file %s | FileCheck %s
2
3func.func @simple_if() {
4  %cond = "test.test1"() : () -> i1
5  cf.cond_br %cond, ^bb1, ^bb2
6^bb1:
7  "test.test2"() : () -> ()
8  cf.br ^bb3
9^bb2:
10  "test.test3"() : () -> ()
11  cf.br ^bb3
12^bb3:
13  "test.test4"() : () -> ()
14  return
15}
16
17// CHECK-LABEL: func @simple_if
18// CHECK:      %[[COND:.*]] = "test.test1"()
19// CHECK-NEXT: scf.if %[[COND]]
20// CHECK-NEXT:   "test.test2"()
21// CHECK-NEXT: else
22// CHECK-NEXT:   "test.test3"()
23// CHECK-NEXT: }
24// CHECK-NEXT: "test.test4"()
25// CHECK-NEXT: return
26
27// -----
28
29func.func @if_with_block_args() -> index {
30  %cond = "test.test1"() : () -> i1
31  cf.cond_br %cond, ^bb1, ^bb2
32^bb1:
33  %1 = "test.test2"() : () -> (index)
34  cf.br ^bb3(%1: index)
35^bb2:
36  %2 = "test.test3"() : () -> (index)
37  cf.br ^bb3(%2: index)
38^bb3(%3: index):
39  "test.test4"() : () -> ()
40  return %3 : index
41}
42
43// CHECK-LABEL: func @if_with_block_args
44// CHECK:      %[[COND:.*]] = "test.test1"()
45// CHECK-NEXT: %[[RES:.*]] = scf.if %[[COND]]
46// CHECK-NEXT:   %[[VAL1:.*]]  = "test.test2"()
47// CHECK-NEXT:   scf.yield %[[VAL1]]
48// CHECK-NEXT: else
49// CHECK-NEXT:   %[[VAL2:.*]]  = "test.test3"()
50// CHECK-NEXT:   scf.yield %[[VAL2]]
51// CHECK:      "test.test4"()
52// CHECK-NEXT: return %[[RES]]
53
54// -----
55
56func.func @empty_else() {
57  %cond = "test.test1"() : () -> i1
58  cf.cond_br %cond, ^bb1, ^bb3
59^bb1:
60  "test.test2"() : () -> ()
61  cf.br ^bb3
62^bb3:
63  "test.test4"() : () -> ()
64  return
65}
66
67// CHECK-LABEL: func @empty_else
68// CHECK:      %[[COND:.*]] = "test.test1"()
69// CHECK-NEXT: scf.if %[[COND]]
70// CHECK-NEXT:   "test.test2"()
71// CHECK:      else
72// CHECK-NEXT:      }
73// CHECK-NEXT: "test.test4"()
74// CHECK-NEXT: return
75
76// -----
77
78func.func @while_loop() {
79  "test.test1"() : () -> ()
80  cf.br ^bb1
81^bb1:
82  %cond = "test.test2"() : () -> i1
83  cf.cond_br %cond, ^bb2, ^bb3
84^bb2:
85  "test.test3"() : () -> ()
86  cf.br ^bb1
87^bb3:
88  "test.test4"() : () -> ()
89  return
90}
91
92// CHECK-LABEL: func @while_loop
93// CHECK-DAG: %[[C0:.*]] = arith.constant 0
94// CHECK-DAG: %[[C1:.*]] = arith.constant 1
95// CHECK-NEXT: "test.test1"()
96// CHECK-NEXT: scf.while
97// CHECK-NEXT:   %[[COND:.*]] = "test.test2"()
98// CHECK-NEXT:   %[[RES:.*]]:2 = scf.if %[[COND]]
99// CHECK-NEXT:     "test.test3"()
100// CHECK-NEXT:     scf.yield %[[C0]], %[[C1]]
101// CHECK-NEXT:   else
102// CHECK-NEXT:     scf.yield %[[C1]], %[[C0]]
103// CHECK:        %[[COND:.*]] = arith.trunci %[[RES]]#1
104// CHECK-NEXT:   scf.condition(%[[COND]])
105// CHECK-NEXT: do
106// CHECK-NEXT:   scf.yield
107// CHECK:      "test.test4"()
108// CHECK-NEXT: return
109
110// -----
111
112func.func @while_loop_with_block_args() -> i64{
113  %1 = "test.test1"() : () -> index
114  cf.br ^bb1(%1: index)
115^bb1(%2: index):
116  %cond:2 = "test.test2"() : () -> (i1, i64)
117  cf.cond_br %cond#0, ^bb2(%cond#1: i64), ^bb3(%cond#1: i64)
118^bb2(%3: i64):
119  %4 = "test.test3"(%3) : (i64) -> index
120  cf.br ^bb1(%4: index)
121^bb3(%5: i64):
122  "test.test4"() : () -> ()
123  return %5 : i64
124}
125
126// CHECK-LABEL: func @while_loop_with_block_args
127// CHECK-DAG: %[[C0:.*]] = arith.constant 0
128// CHECK-DAG: %[[C1:.*]] = arith.constant 1
129// CHECK-DAG: %[[POISON_i64:.*]] = ub.poison : i64
130// CHECK-DAG: %[[POISON_index:.*]] = ub.poison : index
131// CHECK-NEXT: %[[VAL1:.*]] = "test.test1"()
132// CHECK-NEXT: %[[RES:.*]]:2 = scf.while (%[[ARG0:.*]] = %[[VAL1]], %[[ARG1:.*]] = %[[POISON_i64]])
133// CHECK-NEXT:   %[[COND:.*]]:2 = "test.test2"()
134// CHECK-NEXT:   %[[IF_VALS:.*]]:4 = scf.if %[[COND]]#0
135// CHECK-NEXT:     %[[VAL:.*]] = "test.test3"(%[[COND]]#1)
136// CHECK-NEXT:     scf.yield %[[VAL]], %[[POISON_i64]], %[[C0]], %[[C1]]
137// CHECK-NEXT:   else
138// CHECK-NEXT:     scf.yield %[[POISON_index]], %[[COND]]#1, %[[C1]], %[[C0]]
139// CHECK:        %[[TRUNC:.*]] = arith.trunci %[[IF_VALS]]#3
140// CHECK-NEXT:   scf.condition(%[[TRUNC]]) %[[IF_VALS]]#0, %[[IF_VALS]]#1
141// CHECK-NEXT: do
142// CHECK-NEXT:   ^{{.+}}(
143// CHECK-SAME: [[ARG0:[[:alnum:]]+]]:
144// CHECK-SAME: [[ARG1:[[:alnum:]]+]]:
145// CHECK-NEXT:   scf.yield %[[ARG0]], %[[ARG1]]
146// CHECK:      "test.test4"() : () -> ()
147// CHECK-NEXT: return %[[RES]]#1 : i64
148
149// -----
150
151func.func @multi_exit_loop() {
152  "test.test1"() : () -> ()
153  cf.br ^bb1
154^bb1:
155  %cond = "test.test2"() : () -> i1
156  cf.cond_br %cond, ^bb2, ^bb3
157^bb2:
158  %cond2 = "test.test3"() : () -> i1
159  cf.cond_br %cond2, ^bb3, ^bb1
160^bb3:
161  "test.test4"() : () -> ()
162  return
163}
164
165// CHECK-LABEL: func @multi_exit_loop
166// CHECK-DAG: %[[C0:.*]] = arith.constant 0
167// CHECK-DAG: %[[C1:.*]] = arith.constant 1
168// CHECK-NEXT: "test.test1"()
169// CHECK-NEXT: scf.while
170// CHECK-NEXT:   %[[COND:.*]] = "test.test2"()
171// CHECK-NEXT:   %[[IF_PAIR:.*]]:2 = scf.if %[[COND]]
172// CHECK-NEXT:     %[[COND2:.*]] = "test.test3"()
173// CHECK-NEXT:     %[[IF_PAIR2:.*]]:2 = scf.if %[[COND2]]
174// CHECK-NEXT:       scf.yield %[[C1]], %[[C0]]
175// CHECK-NEXT:     else
176// CHECK-NEXT:       scf.yield %[[C0]], %[[C1]]
177// CHECK:          scf.yield %[[IF_PAIR2]]#0, %[[IF_PAIR2]]#1
178// CHECK:        %[[TRUNC:.*]] = arith.trunci %[[IF_PAIR]]#1
179// CHECK-NEXT:   scf.condition(%[[TRUNC]])
180// CHECK-NEXT: do
181// CHECK-NEXT:   scf.yield
182// CHECK:      "test.test4"()
183// CHECK-NEXT: return
184
185// -----
186
187func.func private @foo(%arg: f32) -> f32
188func.func private @bar(%arg: f32)
189
190func.func @switch_with_fallthrough(%flag: i32, %arg1 : f32, %arg2 : f32) {
191  cf.switch %flag : i32, [
192    default: ^bb1(%arg1 : f32),
193    0: ^bb2(%arg2 : f32),
194    1: ^bb3
195  ]
196
197^bb1(%arg3 : f32):
198  %0 = call @foo(%arg3) : (f32) -> f32
199  cf.br ^bb2(%0 : f32)
200
201^bb2(%arg4 : f32):
202  call @bar(%arg4) : (f32) -> ()
203  cf.br ^bb3
204
205^bb3:
206  return
207}
208
209// CHECK-LABEL: func @switch_with_fallthrough
210// CHECK-SAME: %[[ARG0:[[:alnum:]]+]]
211// CHECK-SAME: %[[ARG1:[[:alnum:]]+]]
212// CHECK-SAME: %[[ARG2:[[:alnum:]]+]]
213// CHECK-DAG: %[[C0:.*]] = arith.constant 0
214// CHECK-DAG: %[[C1:.*]] = arith.constant 1
215// CHECK-DAG: %[[POISON:.*]] = ub.poison
216// CHECK-NEXT: %[[INDEX_CAST:.*]] = arith.index_castui %[[ARG0]]
217// CHECK-NEXT: %[[SWITCH_PAIR:.*]]:2 = scf.index_switch %[[INDEX_CAST]]
218// CHECK-NEXT: case 0
219// CHECK-NEXT:   scf.yield %[[ARG2]], %[[C0]]
220// CHECK:      case 1
221// CHECK-NEXT:   scf.yield %[[POISON]], %[[C1]]
222// CHECK:      default
223// CHECK-NEXT:   %[[RES:.*]] = func.call @foo(%[[ARG1]])
224// CHECK-NEXT:   scf.yield %[[RES]], %[[C0]]
225// CHECK:      %[[INDEX_CAST:.*]] = arith.index_castui %[[SWITCH_PAIR]]#1
226// CHECK-NEXT: scf.index_switch %[[INDEX_CAST]]
227// CHECK-NEXT: case 0
228// CHECK-NEXT:   call @bar(%[[SWITCH_PAIR]]#0)
229// CHECK-NEXT:   scf.yield
230// CHECK:      default {
231// CHECK-NEXT: }
232// CHECK-NEXT: return
233
234// -----
235
236func.func private @bar(%arg: f32) -> (i1, f32)
237
238func.func @already_structured_loop(%arg: f32) -> f32 {
239  cf.br ^bb0
240
241^bb0:
242  %cond, %value = call @bar(%arg) : (f32) -> (i1, f32)
243  cf.cond_br %cond, ^bb1, ^bb0
244
245^bb1:
246  return %value : f32
247}
248
249// CHECK-LABEL: @already_structured_loop
250// CHECK-SAME: %[[ARG:.*]]: f32
251// CHECK-DAG: %[[C0:.*]] = arith.constant 0
252// CHECK-DAG: %[[C1:.*]] = arith.constant 1
253// CHECK-DAG: %[[POISON:.*]] = ub.poison
254// CHECK-NEXT: %[[RES:.*]] = scf.while (%[[ARG1:.*]] = %[[POISON]])
255// CHECK-NEXT:   %[[CALL_PAIR:.*]]:2 = func.call @bar(%[[ARG]])
256// CHECK-NEXT:   %[[IF_PAIR:.*]]:2 = scf.if %[[CALL_PAIR]]#0
257// CHECK-NEXT:     scf.yield %[[C1]], %[[C0]]
258// CHECK-NEXT:   else
259// CHECK-NEXT:     scf.yield %[[C0]], %[[C1]]
260// CHECK:        %[[TRUNC:.*]] = arith.trunci %[[IF_PAIR]]#1
261// CHECK-NEXT:   scf.condition(%[[TRUNC]]) %[[CALL_PAIR]]#1
262// CHECK: return %[[RES]]
263
264// -----
265
266func.func private @bar(%arg: f32) -> (i1, f32)
267
268// This test makes sure that the exit block using an iteration variable works
269// correctly.
270
271func.func @exit_loop_iter_use(%arg: f32) -> f32 {
272  cf.br ^bb0(%arg : f32)
273
274^bb0(%arg1: f32):
275  %cond, %value = call @bar(%arg1) : (f32) -> (i1, f32)
276  cf.cond_br %cond, ^bb1, ^bb0(%value : f32)
277
278^bb1:
279  return %arg1 : f32
280}
281
282// CHECK-LABEL: @exit_loop_iter_use
283// CHECK-SAME: %[[ARG:.*]]:
284// CHECK-DAG: %[[C0:.*]] = arith.constant 0
285// CHECK-DAG: %[[C1:.*]] = arith.constant 1
286// CHECK-DAG: %[[POISON:.*]] = ub.poison
287// CHECK-NEXT: %[[RES:.*]]:2 = scf.while
288// CHECK-SAME:   %[[ARG1:.*]] = %[[ARG]]
289// CHECK-SAME:   %[[ARG2:.*]] = %[[POISON]]
290// CHECK-NEXT:   %[[CALL_PAIR:.*]]:2 = func.call @bar(%[[ARG1]])
291// CHECK-NEXT:   %[[IF_RES:.*]]:3 = scf.if %[[CALL_PAIR]]#0
292// CHECK-NEXT:     scf.yield %[[POISON]], %[[C1]], %[[C0]]
293// CHECK-NEXT:   else
294// CHECK-NEXT:     scf.yield %[[CALL_PAIR]]#1, %[[C0]], %[[C1]]
295// CHECK:        %[[TRUNC:.*]] = arith.trunci %[[IF_RES]]#2
296// CHECK-NEXT:   scf.condition(%[[TRUNC]]) %[[IF_RES]]#0, %[[ARG1]]
297// CHECK: return %[[RES]]#1
298
299// -----
300
301func.func private @bar(%arg: f32) -> f32
302
303func.func @infinite_loop(%arg: f32) -> f32 {
304  cf.br ^bb1(%arg: f32)
305
306^bb1(%arg1: f32):
307  %0 = call @bar(%arg1) : (f32) -> f32
308  cf.br ^bb1(%0 : f32)
309}
310
311// CHECK-LABEL: @infinite_loop
312// CHECK-SAME: %[[ARG:.*]]:
313// CHECK-DAG: %[[C0:.*]] = arith.constant 0
314// CHECK-DAG: %[[C1:.*]] = arith.constant 1
315// CHECK-NEXT: scf.while
316// CHECK-SAME:   %[[ARG1:.*]] = %[[ARG]]
317// CHECK-NEXT:   %[[CALL:.*]] = func.call @bar(%[[ARG1]])
318// CHECK-NEXT:   %[[TRUNC:.*]] = arith.trunci %[[C1]]
319// CHECK-NEXT:   scf.condition(%[[TRUNC]]) %[[CALL]]
320// CHECK: %[[POISON:.*]] = ub.poison
321// CHECK: return %[[POISON]]
322
323// -----
324
325func.func @multi_return() -> i32 {
326  %cond = "test.test1"() : () -> i1
327  cf.cond_br %cond, ^bb1, ^bb3
328^bb1:
329  %0 = "test.test2"() : () -> i32
330  return %0 : i32
331^bb3:
332  %1 = "test.test4"() : () -> i32
333  return %1 : i32
334}
335
336// CHECK-LABEL: func @multi_return
337// CHECK:      %[[COND:.*]] = "test.test1"()
338// CHECK-NEXT: %[[RES:.*]] = scf.if %[[COND]]
339// CHECK-NEXT:   %[[VAL2:.*]] = "test.test2"()
340// CHECK:        scf.yield %[[VAL2]]
341// CHECK-NEXT: else
342// CHECK-NEXT:   %[[VAL4:.*]] = "test.test4"()
343// CHECK:        scf.yield %[[VAL4]]
344// CHECK:      return %[[RES]]
345
346// -----
347
348func.func private @bar(%arg: f32) -> f32
349
350func.func @conditional_infinite_loop(%arg: f32, %cond: i1) -> f32 {
351  cf.cond_br %cond, ^bb1(%arg: f32), ^bb2
352
353^bb1(%arg1: f32):
354  %0 = call @bar(%arg1) : (f32) -> f32
355  cf.br ^bb1(%0 : f32)
356
357^bb2:
358  return %arg : f32
359}
360
361// CHECK-LABEL: @conditional_infinite_loop
362// CHECK-SAME: %[[ARG0:[[:alnum:]]+]]:
363// CHECK-SAME: %[[ARG1:[[:alnum:]]+]]:
364// CHECK-DAG: %[[C0:.*]] = arith.constant 0
365// CHECK-DAG: %[[C1:.*]] = arith.constant 1
366// CHECK-NEXT: %[[RES:.*]] = scf.if %[[ARG1]]
367// CHECK-NEXT:   scf.while
368// CHECK-SAME:     %[[ARG2:.*]] = %[[ARG0]]
369// CHECK-NEXT:     %[[CALL:.*]] = func.call @bar(%[[ARG2]])
370// CHECK-NEXT:     %[[TRUNC:.*]] = arith.trunci %[[C1]]
371// CHECK-NEXT:     scf.condition(%[[TRUNC]]) %[[CALL]]
372// CHECK:      else
373// CHECK:        scf.yield %[[ARG0]]
374// CHECK:      return %[[RES]]
375
376// -----
377
378// Different return-like terminators lead one control flow op remaining in the top level region.
379// Each of the blocks the control flow op leads to are transformed into regions nevertheless.
380
381func.func private @bar(%arg: i32)
382
383func.func @mixing_return_like(%cond: i1, %cond2: i1, %cond3: i1) {
384  %0 = arith.constant 0 : i32
385  %1 = arith.constant 1 : i32
386  cf.cond_br %cond, ^bb1, ^bb3
387
388^bb1:
389  cf.cond_br %cond2, ^bb2(%0 : i32), ^bb2(%1 : i32)
390^bb2(%arg: i32):
391  call @bar(%arg) : (i32) -> ()
392  "test.returnLike"() : () -> ()
393
394^bb3:
395  cf.cond_br %cond3, ^bb4(%1 : i32), ^bb4(%0 : i32)
396^bb4(%arg2: i32):
397  call @bar(%arg2) : (i32) -> ()
398  return
399}
400
401// CHECK-LABEL: @mixing_return_like
402// CHECK-SAME: %[[COND1:[[:alnum:]]+]]:
403// CHECK-SAME: %[[COND2:[[:alnum:]]+]]:
404// CHECK-SAME: %[[COND3:[[:alnum:]]+]]:
405// CHECK-DAG: %[[C0:.*]] = arith.constant 0
406// CHECK-DAG: %[[C1:.*]] = arith.constant 1
407// CHECK: cf.cond_br %[[COND1]], ^[[BB1:.*]], ^[[BB2:[[:alnum:]]+]]
408
409// CHECK: ^[[BB1]]:
410// CHECK: scf.if
411// CHECK-NOT: cf.{{(switch|(cond_)?br)}}
412// CHECK: call @bar
413// CHECK: "test.returnLike"
414
415// CHECK: ^[[BB2]]:
416// CHECK: scf.if
417// CHECK-NOT: cf.{{(switch|(cond_)?br)}}
418// CHECK: call @bar
419// CHECK: return
420
421// -----
422
423// cf.switch here only has some successors with different return-like ops.
424// This test makes sure that if there are at least two successors branching to
425// the same region, that this region gets properly turned to structured control
426// flow.
427
428func.func @some_successors_with_different_return(%flag: i32) -> i32 {
429  %0 = arith.constant 5 : i32
430  %1 = arith.constant 6 : i32
431  cf.switch %flag : i32, [
432    default: ^bb1,
433    0: ^bb3(%0 : i32),
434    1: ^bb3(%1 : i32)
435  ]
436
437^bb1:
438  "test.returnLike"() : () -> ()
439
440^bb3(%arg: i32):
441  cf.br ^bb3(%arg : i32)
442}
443
444// CHECK-LABEL: @some_successors_with_different_return
445// CHECK-SAME: %[[FLAG:[[:alnum:]]+]]:
446// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : i32
447// CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i32
448// CHECK-DAG: %[[POISON:.*]] = ub.poison
449// CHECK-DAG: %[[C5:.*]] = arith.constant 5 : i32
450// CHECK-DAG: %[[C6:.*]] = arith.constant 6 : i32
451// CHECK:      %[[INDEX_CAST:.*]] = arith.index_castui %[[FLAG]]
452// CHECK-NEXT: %[[INDEX_SWITCH:.*]]:2 = scf.index_switch %[[INDEX_CAST]]
453// CHECK:      case 0
454// CHECK-NEXT:   scf.yield %[[C5]], %[[C1]]
455// CHECK:      case 1
456// CHECK-NEXT:   scf.yield %[[C6]], %[[C1]]
457// CHECK:      default
458// CHECK-NEXT:   scf.yield %[[POISON]], %[[C0]]
459// CHECK:      cf.switch %[[INDEX_SWITCH]]#1
460// CHECK-NEXT: default: ^[[BB2:[[:alnum:]]+]]
461// CHECK-SAME: %[[INDEX_SWITCH]]#0
462// CHECK-NEXT: 0: ^[[BB1:[[:alnum:]]+]]
463// CHECK-NEXT: ]
464
465// CHECK: ^[[BB2]]{{.*}}:
466// CHECK: scf.while
467// CHECK-NOT: cf.{{(switch|(cond_)?br)}}
468// CHECK: return
469
470// CHECK: ^[[BB1]]:
471// CHECK-NEXT: "test.returnLike"
472
473// -----
474
475func.func @select_like(%cond: i1) -> i32 {
476  %0 = arith.constant 0 : i32
477  %1 = arith.constant 1 : i32
478  cf.cond_br %cond, ^bb0(%0 : i32), ^bb0(%1 : i32)
479^bb0(%arg: i32):
480  return %arg : i32
481}
482
483// CHECK-LABEL: func @select_like
484// CHECK-SAME: %[[COND:.*]]: i1
485// CHECK-DAG: %[[C0:.*]] = arith.constant 0
486// CHECK-DAG: %[[C1:.*]] = arith.constant 1
487// CHECK-NEXT: %[[RES:.*]] = scf.if %[[COND]]
488// CHECK-NEXT:   scf.yield %[[C0]]
489// CHECK-NEXT: else
490// CHECK-NEXT:   scf.yield %[[C1]]
491// CHECK:      return %[[RES]]
492
493// -----
494
495func.func @return_like_dominated_by_condition(%cond1: i1, %cond2: i1, %cond3: i1) {
496  cf.cond_br %cond1, ^bb1, ^bb2
497
498^bb1:
499  return
500
501^bb2:
502  cf.cond_br %cond2, ^bb3, ^bb4
503
504^bb3:
505  "test.unreachable"() : () -> ()
506
507^bb4:
508  cf.cond_br %cond3, ^bb3, ^bb5
509
510^bb5:
511  return
512}
513
514// CHECK-LABEL: func @return_like_dominated_by_condition
515// CHECK-SAME: %[[COND1:[[:alnum:]]+]]
516// CHECK-SAME: %[[COND2:[[:alnum:]]+]]
517// CHECK-SAME: %[[COND3:[[:alnum:]]+]]
518// CHECK-DAG: %[[C0:.*]] = arith.constant 0
519// CHECK-DAG: %[[C1:.*]] = arith.constant 1
520// CHECK: %[[IF:.*]] = scf.if %[[COND1]]
521// CHECK-NEXT:   scf.yield
522// CHECK: else
523// CHECK:   scf.if %[[COND2]]
524// CHECK-NEXT:   scf.yield
525// CHECK:   else
526// CHECK:      scf.if %[[COND3]]
527// CHECK-NEXT:    scf.yield
528// CHECK-NEXT: else
529// CHECK-NEXT:    scf.yield
530
531// CHECK: cf.switch %[[IF]]
532// CHECK-NEXT: default: ^[[BB1:.*]],
533// CHECK-NEXT: 0: ^[[BB2:[[:alnum:]]+]]
534
535// CHECK: ^[[BB2]]:
536// CHECK-NEXT: return
537
538// CHECK: ^[[BB1]]:
539// CHECK-NEXT: "test.unreachable"
540
541// -----
542
543func.func @dominator_issue(%cond: i1, %cond2: i1) -> i32 {
544  cf.cond_br %cond, ^bb1, ^bb2
545
546^bb1:
547  "test.unreachable"() : () -> ()
548
549^bb2:
550  %value = "test.def"() : () -> i32
551  cf.cond_br %cond2, ^bb1, ^bb4
552
553^bb4:
554  return %value : i32
555}
556
557// CHECK-LABEL: func @dominator_issue
558// CHECK-SAME: %[[COND1:[[:alnum:]]+]]
559// CHECK-SAME: %[[COND2:[[:alnum:]]+]]
560// CHECK: %[[IF:.*]]:2 = scf.if %[[COND1]]
561// CHECK: else
562// CHECK:   %[[VALUE:.*]] = "test.def"
563// CHECK:   %[[IF_RES:.*]]:2 = scf.if %[[COND2]]
564// CHECK:   else
565// CHECK-NEXT: scf.yield %[[VALUE]]
566// CHECK:   scf.yield %[[IF_RES]]#0
567// CHECK: cf.switch %[[IF]]#1
568// CHECK-NEXT: default: ^[[BB2:[[:alnum:]]+]](
569// CHECK-SAME: %[[IF]]#0
570// CHECK-NEXT: 0: ^[[BB1:[[:alnum:]]+]]
571// CHECK: ^[[BB1]]:
572// CHECK-NEXT: "test.unreachable"
573// CHECK: ^[[BB2]]
574// CHECK-SAME: %[[ARG:[[:alnum:]]+]]
575// CHECK-NEXT: return %[[ARG]]
576
577// -----
578
579// Test that %value gets properly passed to ^bb4.
580
581func.func private @bar(i32)
582
583func.func @dominator_issue_loop(%cond: i1, %cond2: i1) -> i32 {
584  %0 = arith.constant 5 : i32
585  cf.br ^bb0
586
587^bb0:
588  cf.cond_br %cond, ^bb1, ^bb3
589
590^bb1:
591  %value = "test.def"() : () -> i32
592  cf.cond_br %cond2, ^bb0, ^bb4
593
594^bb3:
595  return %0 : i32
596
597^bb4:
598  return %value : i32
599}
600
601// CHECK-LABEL: func @dominator_issue_loop
602// CHECK-SAME: %[[COND1:[[:alnum:]]+]]
603// CHECK-SAME: %[[COND2:[[:alnum:]]+]]
604// CHECK: %[[WHILE:.*]]:2 = scf.while
605// CHECK:   %[[IF:.*]]:3 = scf.if %[[COND1]]
606// CHECK:     %[[DEF:.*]] = "test.def"
607// CHECK:     %[[IF2:.*]]:3 = scf.if %[[COND2]]
608// CHECK:       scf.yield
609// CHECK-SAME:   %[[DEF]]
610// CHECK:     else
611// CHECK:       scf.yield %{{.*}}, %{{.*}}, %[[DEF]]
612// CHECK:     scf.yield %[[IF2]]#0, %[[IF2]]#1, %[[IF2]]#2
613// CHECK:   scf.condition(%{{.*}}) %[[IF]]#2, %[[IF]]#0
614
615// CHECK: %[[SWITCH:.*]] = scf.index_switch
616// CHECK:   scf.yield %[[WHILE]]#0
617// CHECK: return %[[SWITCH]]
618
619// -----
620
621// Multi entry loops generally produce code in dire need of canonicalization.
622
623func.func private @comp1(%arg: i32) -> i1
624func.func private @comp2(%arg: i32) -> i1
625func.func private @foo(%arg: i32)
626
627func.func @multi_entry_loop(%cond: i1) {
628  %0 = arith.constant 6 : i32
629  %1 = arith.constant 5 : i32
630  cf.cond_br %cond, ^bb0, ^bb1
631
632^bb0:
633  %exit = call @comp1(%0) : (i32) -> i1
634  cf.cond_br %exit, ^bb2(%0 : i32), ^bb1
635
636^bb1:
637  %exit2 = call @comp2(%1) : (i32) -> i1
638  cf.cond_br %exit2, ^bb2(%1 : i32), ^bb0
639
640^bb2(%arg3 : i32):
641  call @foo(%arg3) : (i32) -> ()
642  return
643}
644
645// CHECK-LABEL: func @multi_entry_loop
646// CHECK-SAME: %[[ARG0:[[:alnum:]]+]]
647// CHECK-DAG: %[[C0:.*]] = arith.constant 0
648// CHECK-DAG: %[[UB:.*]] = ub.poison
649// CHECK-DAG: %[[C1:.*]] = arith.constant 1
650// CHECK-DAG: %[[C6:.*]] = arith.constant 6
651// CHECK-DAG: %[[C5:.*]] = arith.constant 5
652// CHECK:      %[[IF:.*]]:{{.*}} = scf.if %[[ARG0]]
653// CHECK-NEXT:   scf.yield %[[C1]], %[[UB]]
654// CHECK-NEXT: else
655// CHECK-NEXT:   scf.yield %[[C0]], %[[UB]]
656// CHECK:      %[[WHILE:.*]]:{{.*}} = scf.while
657// CHECK-SAME: %[[ARG1:.*]] = %[[IF]]#0
658// CHECK-SAME: %[[ARG2:.*]] = %[[IF]]#1
659// CHECK-NEXT:   %[[FLAG:.*]] = arith.index_castui %[[ARG1]]
660// CHECK-NEXT:   %[[SWITCH:.*]]:{{.*}} = scf.index_switch %[[FLAG]]
661// CHECK-NEXT:   case 0
662// CHECK-NEXT:     %[[EXIT:.*]] = func.call @comp2(%[[C5]])
663// CHECK-NEXT:     %[[IF_RES:.*]]:{{.*}} = scf.if %[[EXIT]]
664// CHECK-NEXT:       scf.yield %[[UB]], %[[C5]], %[[C1]], %[[C0]]
665// CHECK-NEXT:     else
666// CHECK-NEXT:       scf.yield %[[C1]], %[[UB]], %[[C0]], %[[C1]]
667// CHECK:          scf.yield %[[IF_RES]]#0, %[[IF_RES]]#1, %[[IF_RES]]#2, %[[IF_RES]]#3
668// CHECK:        default
669// CHECK-NEXT:     %[[EXIT:.*]] = func.call @comp1(%[[C6]])
670// CHECK-NEXT:     %[[IF_RES:.*]]:{{.*}} = scf.if %[[EXIT]]
671// CHECK-NEXT:       scf.yield %[[UB]], %[[C6]], %[[C1]], %[[C0]]
672// CHECK-NEXT:     else
673// CHECK-NEXT:       scf.yield %[[C0]], %[[UB]], %[[C0]], %[[C1]]
674// CHECK:          scf.yield %[[IF_RES]]#0, %[[IF_RES]]#1, %[[IF_RES]]#2, %[[IF_RES]]#3
675// CHECK:        %[[COND:.*]] = arith.trunci %[[SWITCH]]#3
676// CHECK-NEXT:   scf.condition(%[[COND]]) %[[SWITCH]]#0, %[[SWITCH]]#1
677// CHECK:      do
678// CHECK:        scf.yield
679// CHECK:      call @foo(%[[WHILE]]#1)
680// CHECK-NEXT: return
681
682// -----
683
684func.func @nested_region() {
685  scf.execute_region {
686    %cond = "test.test1"() : () -> i1
687    cf.cond_br %cond, ^bb1, ^bb2
688  ^bb1:
689    "test.test2"() : () -> ()
690    cf.br ^bb3
691  ^bb2:
692    "test.test3"() : () -> ()
693    cf.br ^bb3
694  ^bb3:
695    "test.test4"() : () -> ()
696    scf.yield
697  }
698  return
699}
700
701// CHECK-LABEL: func @nested_region
702// CHECK:      scf.execute_region {
703// CHECK:      %[[COND:.*]] = "test.test1"()
704// CHECK-NEXT: scf.if %[[COND]]
705// CHECK-NEXT:   "test.test2"()
706// CHECK-NEXT: else
707// CHECK-NEXT:   "test.test3"()
708// CHECK-NEXT: }
709// CHECK-NEXT: "test.test4"()
710// CHECK-NEXT: scf.yield
711// CHECK-NEXT: }
712// CHECK-NEXT: return
713
714// -----
715
716func.func @nested_region_inside_loop_use() {
717  cf.br ^bb1
718
719^bb1:
720  %3 = "test.test1"() : () -> i32
721  scf.execute_region {
722    "test.foo"(%3) : (i32) -> ()
723    scf.yield
724  }
725  cf.br ^bb1
726}
727
728// CHECK-LABEL: func @nested_region_inside_loop_use
729// CHECK: scf.while
730// CHECK-NEXT: %[[DEF:.*]] = "test.test1"()
731// CHECK-NEXT: scf.execute_region
732// CHECK-NEXT: "test.foo"(%[[DEF]])
733
734// -----
735
736func.func @nested_region_outside_loop_use() {
737  cf.br ^bb1
738
739^bb1:
740  %3 = "test.test1"() : () -> i32
741  %cond = "test.test2"() : () -> i1
742  cf.cond_br %cond, ^bb1, ^bb2
743
744^bb2:
745  scf.execute_region {
746    "test.foo"(%3) : (i32) -> ()
747    scf.yield
748  }
749  return
750}
751
752// CHECK-LABEL: func @nested_region_outside_loop_use
753// CHECK: %[[RES:.*]] = scf.while
754// CHECK: %[[DEF:.*]] = "test.test1"()
755// CHECK: scf.condition(%{{.*}}) %[[DEF]]
756
757// CHECK: scf.execute_region
758// CHECK-NEXT: "test.foo"(%[[RES]])
759