Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / UnifyLoopExits / integer_guards.ll
blob803f14b24a97675bde3e1223db72bdefa1c394db
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=unify-loop-exits -max-booleans-in-control-flow-hub=1 -S | FileCheck %s
3 ; RUN: opt < %s -passes=unify-loop-exits -S | FileCheck --check-prefix=BOOLEAN %s
5 ; A loop with multiple exit blocks.
7 define void @loop_two_exits(i1 %PredEntry, i1 %PredA) {
8 ; CHECK-LABEL: @loop_two_exits(
9 ; CHECK-NEXT:  entry:
10 ; CHECK-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[E:%.*]]
11 ; CHECK:       A:
12 ; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ]
13 ; CHECK-NEXT:    br i1 [[PREDA:%.*]], label [[LOOP_EXIT_GUARD:%.*]], label [[C]]
14 ; CHECK:       B:
15 ; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0:[0-9]+]]
16 ; CHECK-NEXT:    br label [[D:%.*]]
17 ; CHECK:       C:
18 ; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1
19 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
20 ; CHECK-NEXT:    br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
21 ; CHECK:       D:
22 ; CHECK-NEXT:    unreachable
23 ; CHECK:       E:
24 ; CHECK-NEXT:    ret void
25 ; CHECK:       loop.exit.guard:
26 ; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A]] ], [ 1, [[C]] ]
27 ; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
28 ; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[E]]
30 ; BOOLEAN-LABEL: @loop_two_exits(
31 ; BOOLEAN-NEXT:  entry:
32 ; BOOLEAN-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[E:%.*]]
33 ; BOOLEAN:       A:
34 ; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ]
35 ; BOOLEAN-NEXT:    br i1 [[PREDA:%.*]], label [[LOOP_EXIT_GUARD:%.*]], label [[C]]
36 ; BOOLEAN:       B:
37 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0:[0-9]+]]
38 ; BOOLEAN-NEXT:    br label [[D:%.*]]
39 ; BOOLEAN:       C:
40 ; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1
41 ; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
42 ; BOOLEAN-NEXT:    br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
43 ; BOOLEAN:       D:
44 ; BOOLEAN-NEXT:    unreachable
45 ; BOOLEAN:       E:
46 ; BOOLEAN-NEXT:    ret void
47 ; BOOLEAN:       loop.exit.guard:
48 ; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ]
49 ; BOOLEAN-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[E]]
51 entry:
52   br i1 %PredEntry, label %A, label %E
55   %inc1 = phi i32 [ 0, %entry ], [ %inc2, %C ]
56   br i1 %PredA, label %B, label %C
59   tail call fastcc void @check(i32 1) #0
60   br label %D
63   %inc2 = add i32 %inc1, 1
64   %cmp = icmp ult i32 %inc2, 10
65   br i1 %cmp, label %A, label %E
68   unreachable
71   ret void
74 ; The loop exit blocks appear in an inner loop.
76 define void @inner_loop(i1 %PredEntry, i1 %PredA, i1 %PredB) {
77 ; CHECK-LABEL: @inner_loop(
78 ; CHECK-NEXT:  entry:
79 ; CHECK-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[I:%.*]]
80 ; CHECK:       A:
81 ; CHECK-NEXT:    [[OUTER1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[OUTER2:%.*]], [[G:%.*]] ]
82 ; CHECK-NEXT:    br label [[B:%.*]]
83 ; CHECK:       B:
84 ; CHECK-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ]
85 ; CHECK-NEXT:    br i1 [[PREDA:%.*]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]]
86 ; CHECK:       C:
87 ; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
88 ; CHECK-NEXT:    br label [[H:%.*]]
89 ; CHECK:       D:
90 ; CHECK-NEXT:    br i1 [[PREDB:%.*]], label [[LOOP_EXIT_GUARD2]], label [[F]]
91 ; CHECK:       E:
92 ; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
93 ; CHECK-NEXT:    br label [[H]]
94 ; CHECK:       F:
95 ; CHECK-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1
96 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20
97 ; CHECK-NEXT:    br i1 [[CMP1]], label [[B]], label [[LOOP_EXIT_GUARD2]]
98 ; CHECK:       G:
99 ; CHECK-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1
100 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10
101 ; CHECK-NEXT:    br i1 [[CMP2]], label [[A]], label [[LOOP_EXIT_GUARD:%.*]]
102 ; CHECK:       H:
103 ; CHECK-NEXT:    unreachable
104 ; CHECK:       I:
105 ; CHECK-NEXT:    ret void
106 ; CHECK:       loop.exit.guard:
107 ; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 2, [[G]] ], [ [[MERGED_BB_IDX_MOVED:%.*]], [[LOOP_EXIT_GUARD2]] ]
108 ; CHECK-NEXT:    [[C_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
109 ; CHECK-NEXT:    br i1 [[C_PREDICATE]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
110 ; CHECK:       loop.exit.guard1:
111 ; CHECK-NEXT:    [[E_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 1
112 ; CHECK-NEXT:    br i1 [[E_PREDICATE]], label [[E:%.*]], label [[I]]
113 ; CHECK:       loop.exit.guard2:
114 ; CHECK-NEXT:    [[MERGED_BB_IDX_MOVED]] = phi i32 [ 0, [[B]] ], [ 1, [[D]] ], [ undef, [[F]] ]
115 ; CHECK-NEXT:    [[MERGED_BB_IDX3:%.*]] = phi i32 [ 0, [[B]] ], [ 0, [[D]] ], [ 1, [[F]] ]
116 ; CHECK-NEXT:    [[LOOP_EXIT_GUARD_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX3]], 0
117 ; CHECK-NEXT:    br i1 [[LOOP_EXIT_GUARD_PREDICATE]], label [[LOOP_EXIT_GUARD]], label [[G]]
119 ; BOOLEAN-LABEL: @inner_loop(
120 ; BOOLEAN-NEXT:  entry:
121 ; BOOLEAN-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[I:%.*]]
122 ; BOOLEAN:       A:
123 ; BOOLEAN-NEXT:    [[OUTER1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[OUTER2:%.*]], [[G:%.*]] ]
124 ; BOOLEAN-NEXT:    br label [[B:%.*]]
125 ; BOOLEAN:       B:
126 ; BOOLEAN-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ]
127 ; BOOLEAN-NEXT:    br i1 [[PREDA:%.*]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]]
128 ; BOOLEAN:       C:
129 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
130 ; BOOLEAN-NEXT:    br label [[H:%.*]]
131 ; BOOLEAN:       D:
132 ; BOOLEAN-NEXT:    br i1 [[PREDB:%.*]], label [[LOOP_EXIT_GUARD2]], label [[F]]
133 ; BOOLEAN:       E:
134 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
135 ; BOOLEAN-NEXT:    br label [[H]]
136 ; BOOLEAN:       F:
137 ; BOOLEAN-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1
138 ; BOOLEAN-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20
139 ; BOOLEAN-NEXT:    br i1 [[CMP1]], label [[B]], label [[LOOP_EXIT_GUARD2]]
140 ; BOOLEAN:       G:
141 ; BOOLEAN-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1
142 ; BOOLEAN-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10
143 ; BOOLEAN-NEXT:    br i1 [[CMP2]], label [[A]], label [[LOOP_EXIT_GUARD:%.*]]
144 ; BOOLEAN:       H:
145 ; BOOLEAN-NEXT:    unreachable
146 ; BOOLEAN:       I:
147 ; BOOLEAN-NEXT:    ret void
148 ; BOOLEAN:       loop.exit.guard:
149 ; BOOLEAN-NEXT:    [[GUARD_C:%.*]] = phi i1 [ false, [[G]] ], [ [[GUARD_C_MOVED:%.*]], [[LOOP_EXIT_GUARD2]] ]
150 ; BOOLEAN-NEXT:    [[GUARD_E:%.*]] = phi i1 [ false, [[G]] ], [ [[GUARD_E_MOVED:%.*]], [[LOOP_EXIT_GUARD2]] ]
151 ; BOOLEAN-NEXT:    br i1 [[GUARD_C]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
152 ; BOOLEAN:       loop.exit.guard1:
153 ; BOOLEAN-NEXT:    br i1 [[GUARD_E]], label [[E:%.*]], label [[I]]
154 ; BOOLEAN:       loop.exit.guard2:
155 ; BOOLEAN-NEXT:    [[GUARD_E_MOVED]] = phi i1 [ false, [[B]] ], [ true, [[D]] ], [ undef, [[F]] ]
156 ; BOOLEAN-NEXT:    [[GUARD_C_MOVED]] = phi i1 [ true, [[B]] ], [ false, [[D]] ], [ undef, [[F]] ]
157 ; BOOLEAN-NEXT:    [[GUARD_LOOP_EXIT_GUARD:%.*]] = phi i1 [ true, [[B]] ], [ true, [[D]] ], [ false, [[F]] ]
158 ; BOOLEAN-NEXT:    br i1 [[GUARD_LOOP_EXIT_GUARD]], label [[LOOP_EXIT_GUARD]], label [[G]]
160 entry:
161   br i1 %PredEntry, label %A, label %I
164   %outer1 = phi i32 [ 0, %entry ], [ %outer2, %G ]
165   br label %B
168   %inner1 = phi i32 [ 0, %A ], [ %inner2, %F ]
169   br i1 %PredA, label %D, label %C
172   tail call fastcc void @check(i32 1) #0
173   br label %H
176   br i1 %PredB, label %E, label %F
179   tail call fastcc void @check(i32 2) #0
180   br label %H
183   %inner2 = add i32 %inner1, 1
184   %cmp1 = icmp ult i32 %inner2, 20
185   br i1 %cmp1, label %B, label %G
188   %outer2 = add i32 %outer1, 1
189   %cmp2 = icmp ult i32 %outer2, 10
190   br i1 %cmp2, label %A, label %I
193   unreachable
196   ret void
199 ; A loop with more exit blocks.
201 define void @loop_five_exits(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %PredC, i1 %PredD) {
202 ; CHECK-LABEL: @loop_five_exits(
203 ; CHECK-NEXT:  entry:
204 ; CHECK-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[L:%.*]]
205 ; CHECK:       A:
206 ; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ]
207 ; CHECK-NEXT:    br i1 [[PREDA:%.*]], label [[LOOP_EXIT_GUARD:%.*]], label [[C:%.*]]
208 ; CHECK:       B:
209 ; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
210 ; CHECK-NEXT:    br label [[J:%.*]]
211 ; CHECK:       C:
212 ; CHECK-NEXT:    br i1 [[PREDB:%.*]], label [[LOOP_EXIT_GUARD]], label [[E:%.*]]
213 ; CHECK:       D:
214 ; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
215 ; CHECK-NEXT:    br label [[J]]
216 ; CHECK:       E:
217 ; CHECK-NEXT:    br i1 [[PREDC:%.*]], label [[LOOP_EXIT_GUARD]], label [[G:%.*]]
218 ; CHECK:       F:
219 ; CHECK-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]]
220 ; CHECK-NEXT:    br label [[K:%.*]]
221 ; CHECK:       G:
222 ; CHECK-NEXT:    br i1 [[PREDD:%.*]], label [[LOOP_EXIT_GUARD]], label [[I]]
223 ; CHECK:       H:
224 ; CHECK-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]]
225 ; CHECK-NEXT:    br label [[K]]
226 ; CHECK:       I:
227 ; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1
228 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
229 ; CHECK-NEXT:    br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
230 ; CHECK:       J:
231 ; CHECK-NEXT:    br label [[L]]
232 ; CHECK:       K:
233 ; CHECK-NEXT:    br label [[L]]
234 ; CHECK:       L:
235 ; CHECK-NEXT:    ret void
236 ; CHECK:       loop.exit.guard:
237 ; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A]] ], [ 1, [[C]] ], [ 2, [[E]] ], [ 3, [[G]] ], [ 4, [[I]] ]
238 ; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
239 ; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
240 ; CHECK:       loop.exit.guard1:
241 ; CHECK-NEXT:    [[D_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 1
242 ; CHECK-NEXT:    br i1 [[D_PREDICATE]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]]
243 ; CHECK:       loop.exit.guard2:
244 ; CHECK-NEXT:    [[F_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 2
245 ; CHECK-NEXT:    br i1 [[F_PREDICATE]], label [[F:%.*]], label [[LOOP_EXIT_GUARD3:%.*]]
246 ; CHECK:       loop.exit.guard3:
247 ; CHECK-NEXT:    [[H_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 3
248 ; CHECK-NEXT:    br i1 [[H_PREDICATE]], label [[H:%.*]], label [[L]]
250 ; BOOLEAN-LABEL: @loop_five_exits(
251 ; BOOLEAN-NEXT:  entry:
252 ; BOOLEAN-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[L:%.*]]
253 ; BOOLEAN:       A:
254 ; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ]
255 ; BOOLEAN-NEXT:    br i1 [[PREDA:%.*]], label [[LOOP_EXIT_GUARD:%.*]], label [[C:%.*]]
256 ; BOOLEAN:       B:
257 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
258 ; BOOLEAN-NEXT:    br label [[J:%.*]]
259 ; BOOLEAN:       C:
260 ; BOOLEAN-NEXT:    br i1 [[PREDB:%.*]], label [[LOOP_EXIT_GUARD]], label [[E:%.*]]
261 ; BOOLEAN:       D:
262 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
263 ; BOOLEAN-NEXT:    br label [[J]]
264 ; BOOLEAN:       E:
265 ; BOOLEAN-NEXT:    br i1 [[PREDC:%.*]], label [[LOOP_EXIT_GUARD]], label [[G:%.*]]
266 ; BOOLEAN:       F:
267 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]]
268 ; BOOLEAN-NEXT:    br label [[K:%.*]]
269 ; BOOLEAN:       G:
270 ; BOOLEAN-NEXT:    br i1 [[PREDD:%.*]], label [[LOOP_EXIT_GUARD]], label [[I]]
271 ; BOOLEAN:       H:
272 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]]
273 ; BOOLEAN-NEXT:    br label [[K]]
274 ; BOOLEAN:       I:
275 ; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1
276 ; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
277 ; BOOLEAN-NEXT:    br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
278 ; BOOLEAN:       J:
279 ; BOOLEAN-NEXT:    br label [[L]]
280 ; BOOLEAN:       K:
281 ; BOOLEAN-NEXT:    br label [[L]]
282 ; BOOLEAN:       L:
283 ; BOOLEAN-NEXT:    ret void
284 ; BOOLEAN:       loop.exit.guard:
285 ; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ], [ false, [[E]] ], [ false, [[G]] ], [ false, [[I]] ]
286 ; BOOLEAN-NEXT:    [[GUARD_D:%.*]] = phi i1 [ false, [[A]] ], [ true, [[C]] ], [ false, [[E]] ], [ false, [[G]] ], [ false, [[I]] ]
287 ; BOOLEAN-NEXT:    [[GUARD_F:%.*]] = phi i1 [ false, [[A]] ], [ false, [[C]] ], [ true, [[E]] ], [ false, [[G]] ], [ false, [[I]] ]
288 ; BOOLEAN-NEXT:    [[GUARD_H:%.*]] = phi i1 [ false, [[A]] ], [ false, [[C]] ], [ false, [[E]] ], [ true, [[G]] ], [ false, [[I]] ]
289 ; BOOLEAN-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
290 ; BOOLEAN:       loop.exit.guard1:
291 ; BOOLEAN-NEXT:    br i1 [[GUARD_D]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]]
292 ; BOOLEAN:       loop.exit.guard2:
293 ; BOOLEAN-NEXT:    br i1 [[GUARD_F]], label [[F:%.*]], label [[LOOP_EXIT_GUARD3:%.*]]
294 ; BOOLEAN:       loop.exit.guard3:
295 ; BOOLEAN-NEXT:    br i1 [[GUARD_H]], label [[H:%.*]], label [[L]]
297 entry:
298   br i1 %PredEntry, label %A, label %L
301   %inc1 = phi i32 [ 0, %entry ], [ %inc2, %I ]
302   br i1 %PredA, label %B, label %C
305   tail call fastcc void @check(i32 1) #0
306   br label %J
309   br i1 %PredB, label %D, label %E
312   tail call fastcc void @check(i32 2) #0
313   br label %J
316   br i1 %PredC, label %F, label %G
319   tail call fastcc void @check(i32 3) #0
320   br label %K
323   br i1 %PredD, label %H, label %I
326   tail call fastcc void @check(i32 4) #0
327   br label %K
330   %inc2 = add i32 %inc1, 1
331   %cmp = icmp ult i32 %inc2, 10
332   br i1 %cmp, label %A, label %L
335   br label %L
338   br label %L
341   ret void
345 declare void @check(i32 noundef %i) #0
347 attributes #0 = { noreturn nounwind }