1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S %s -passes='loop-mssa(licm)' -verify-memoryssa | FileCheck %s
4 ; turn to %iv <u umin(inv_1, inv_2) and hoist it out of loop.
5 define i32 @test_ult(i32 %start, i32 %inv_1, i32 %inv_2) {
6 ; CHECK-LABEL: @test_ult(
8 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
9 ; CHECK-NEXT: br label [[LOOP:%.*]]
11 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
12 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]]
13 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
14 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
16 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
17 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
23 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
24 %cmp_1 = icmp ult i32 %iv, %inv_1
25 %cmp_2 = icmp ult i32 %iv, %inv_2
26 %loop_cond = and i1 %cmp_1, %cmp_2
27 %iv.next = add i32 %iv, 1
28 br i1 %loop_cond, label %loop, label %exit
34 ; Do not optimize: pointer types.
35 define ptr @test_ult_ptr_neg(ptr %start, ptr %inv_1, ptr %inv_2) {
36 ; CHECK-LABEL: @test_ult_ptr_neg(
38 ; CHECK-NEXT: br label [[LOOP:%.*]]
40 ; CHECK-NEXT: [[IV:%.*]] = phi ptr [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
41 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult ptr [[IV]], [[INV_1:%.*]]
42 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult ptr [[IV]], [[INV_2:%.*]]
43 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
44 ; CHECK-NEXT: [[IV_NEXT]] = getelementptr i32, ptr [[IV]], i64 4
45 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
47 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi ptr [ [[IV]], [[LOOP]] ]
48 ; CHECK-NEXT: ret ptr [[IV_LCSSA]]
54 %iv = phi ptr [%start, %entry], [%iv.next, %loop]
55 %cmp_1 = icmp ult ptr %iv, %inv_1
56 %cmp_2 = icmp ult ptr %iv, %inv_2
57 %loop_cond = and i1 %cmp_1, %cmp_2
58 %iv.next = getelementptr i32, ptr %iv, i64 4
59 br i1 %loop_cond, label %loop, label %exit
65 ; turn to %iv <=u umin(inv_1, inv_2) and hoist it out of loop.
66 define i32 @test_ule(i32 %start, i32 %inv_1, i32 %inv_2) {
67 ; CHECK-LABEL: @test_ule(
69 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
70 ; CHECK-NEXT: br label [[LOOP:%.*]]
72 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
73 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ule i32 [[IV]], [[INVARIANT_UMIN]]
74 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
75 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
77 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
78 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
84 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
85 %cmp_1 = icmp ule i32 %iv, %inv_1
86 %cmp_2 = icmp ule i32 %iv, %inv_2
87 %loop_cond = and i1 %cmp_1, %cmp_2
88 %iv.next = add i32 %iv, 1
89 br i1 %loop_cond, label %loop, label %exit
95 ; turn to %iv <s smin(inv_1, inv_2) and hoist it out of loop.
96 define i32 @test_slt(i32 %start, i32 %inv_1, i32 %inv_2) {
97 ; CHECK-LABEL: @test_slt(
99 ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
100 ; CHECK-NEXT: br label [[LOOP:%.*]]
102 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
103 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_SMIN]]
104 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
105 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
107 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
108 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
114 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
115 %cmp_1 = icmp slt i32 %iv, %inv_1
116 %cmp_2 = icmp slt i32 %iv, %inv_2
117 %loop_cond = and i1 %cmp_1, %cmp_2
118 %iv.next = add i32 %iv, 1
119 br i1 %loop_cond, label %loop, label %exit
125 ; turn to %iv <=s smin(inv_1, inv_2) and hoist it out of loop.
126 define i32 @test_sle(i32 %start, i32 %inv_1, i32 %inv_2) {
127 ; CHECK-LABEL: @test_sle(
129 ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
130 ; CHECK-NEXT: br label [[LOOP:%.*]]
132 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
133 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sle i32 [[IV]], [[INVARIANT_SMIN]]
134 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
135 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
137 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
138 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
144 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
145 %cmp_1 = icmp sle i32 %iv, %inv_1
146 %cmp_2 = icmp sle i32 %iv, %inv_2
147 %loop_cond = and i1 %cmp_1, %cmp_2
148 %iv.next = add i32 %iv, 1
149 br i1 %loop_cond, label %loop, label %exit
155 ; turn to %iv >u umax(inv_1, inv_2) and hoist it out of loop.
156 define i32 @test_ugt(i32 %start, i32 %inv_1, i32 %inv_2) {
157 ; CHECK-LABEL: @test_ugt(
159 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
160 ; CHECK-NEXT: br label [[LOOP:%.*]]
162 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
163 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMAX]]
164 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
165 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
167 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
168 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
174 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
175 %cmp_1 = icmp ugt i32 %iv, %inv_1
176 %cmp_2 = icmp ugt i32 %iv, %inv_2
177 %loop_cond = and i1 %cmp_1, %cmp_2
178 %iv.next = add i32 %iv, 1
179 br i1 %loop_cond, label %loop, label %exit
185 ; turn to %iv >=u umax(inv_1, inv_2) and hoist it out of loop.
186 define i32 @test_uge(i32 %start, i32 %inv_1, i32 %inv_2) {
187 ; CHECK-LABEL: @test_uge(
189 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
190 ; CHECK-NEXT: br label [[LOOP:%.*]]
192 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
193 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMAX]]
194 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
195 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
197 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
198 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
204 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
205 %cmp_1 = icmp uge i32 %iv, %inv_1
206 %cmp_2 = icmp uge i32 %iv, %inv_2
207 %loop_cond = and i1 %cmp_1, %cmp_2
208 %iv.next = add i32 %iv, 1
209 br i1 %loop_cond, label %loop, label %exit
215 ; turn to %iv >s smax(inv_1, inv_2) and hoist it out of loop.
216 define i32 @test_sgt(i32 %start, i32 %inv_1, i32 %inv_2) {
217 ; CHECK-LABEL: @test_sgt(
219 ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
220 ; CHECK-NEXT: br label [[LOOP:%.*]]
222 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
223 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMAX]]
224 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
225 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
227 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
228 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
234 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
235 %cmp_1 = icmp sgt i32 %iv, %inv_1
236 %cmp_2 = icmp sgt i32 %iv, %inv_2
237 %loop_cond = and i1 %cmp_1, %cmp_2
238 %iv.next = add i32 %iv, 1
239 br i1 %loop_cond, label %loop, label %exit
245 ; turn to %iv >=s smax(inv_1, inv_2) and hoist it out of loop.
246 define i32 @test_sge(i32 %start, i32 %inv_1, i32 %inv_2) {
247 ; CHECK-LABEL: @test_sge(
249 ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
250 ; CHECK-NEXT: br label [[LOOP:%.*]]
252 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
253 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMAX]]
254 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
255 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
257 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
258 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
264 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
265 %cmp_1 = icmp sge i32 %iv, %inv_1
266 %cmp_2 = icmp sge i32 %iv, %inv_2
267 %loop_cond = and i1 %cmp_1, %cmp_2
268 %iv.next = add i32 %iv, 1
269 br i1 %loop_cond, label %loop, label %exit
275 ; Turn OR to AND and handle accordingly.
276 define i32 @test_ult_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
277 ; CHECK-LABEL: @test_ult_inv(
279 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
280 ; CHECK-NEXT: br label [[LOOP:%.*]]
282 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
283 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMAX]]
284 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
285 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
287 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
288 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
294 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
295 %cmp_1 = icmp ult i32 %iv, %inv_1
296 %cmp_2 = icmp ult i32 %iv, %inv_2
297 %loop_cond = or i1 %cmp_1, %cmp_2
298 %iv.next = add i32 %iv, 1
299 br i1 %loop_cond, label %loop, label %exit
305 ; Turn OR to AND and handle accordingly.
306 define i32 @test_ule_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
307 ; CHECK-LABEL: @test_ule_inv(
309 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
310 ; CHECK-NEXT: br label [[LOOP:%.*]]
312 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
313 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ule i32 [[IV]], [[INVARIANT_UMAX]]
314 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
315 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
317 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
318 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
324 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
325 %cmp_1 = icmp ule i32 %iv, %inv_1
326 %cmp_2 = icmp ule i32 %iv, %inv_2
327 %loop_cond = or i1 %cmp_1, %cmp_2
328 %iv.next = add i32 %iv, 1
329 br i1 %loop_cond, label %loop, label %exit
335 ; Turn OR to AND and handle accordingly.
336 define i32 @test_slt_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
337 ; CHECK-LABEL: @test_slt_inv(
339 ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
340 ; CHECK-NEXT: br label [[LOOP:%.*]]
342 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
343 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_SMAX]]
344 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
345 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
347 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
348 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
354 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
355 %cmp_1 = icmp slt i32 %iv, %inv_1
356 %cmp_2 = icmp slt i32 %iv, %inv_2
357 %loop_cond = or i1 %cmp_1, %cmp_2
358 %iv.next = add i32 %iv, 1
359 br i1 %loop_cond, label %loop, label %exit
365 ; Turn OR to AND and handle accordingly.
366 define i32 @test_sle_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
367 ; CHECK-LABEL: @test_sle_inv(
369 ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
370 ; CHECK-NEXT: br label [[LOOP:%.*]]
372 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
373 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sle i32 [[IV]], [[INVARIANT_SMAX]]
374 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
375 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
377 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
378 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
384 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
385 %cmp_1 = icmp sle i32 %iv, %inv_1
386 %cmp_2 = icmp sle i32 %iv, %inv_2
387 %loop_cond = or i1 %cmp_1, %cmp_2
388 %iv.next = add i32 %iv, 1
389 br i1 %loop_cond, label %loop, label %exit
395 ; Turn OR to AND and handle accordingly.
396 define i32 @test_ugt_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
397 ; CHECK-LABEL: @test_ugt_inv(
399 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
400 ; CHECK-NEXT: br label [[LOOP:%.*]]
402 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
403 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMIN]]
404 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
405 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
407 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
408 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
414 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
415 %cmp_1 = icmp ugt i32 %iv, %inv_1
416 %cmp_2 = icmp ugt i32 %iv, %inv_2
417 %loop_cond = or i1 %cmp_1, %cmp_2
418 %iv.next = add i32 %iv, 1
419 br i1 %loop_cond, label %loop, label %exit
425 ; Turn OR to AND and handle accordingly.
426 define i32 @test_uge_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
427 ; CHECK-LABEL: @test_uge_inv(
429 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
430 ; CHECK-NEXT: br label [[LOOP:%.*]]
432 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
433 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMIN]]
434 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
435 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
437 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
438 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
444 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
445 %cmp_1 = icmp uge i32 %iv, %inv_1
446 %cmp_2 = icmp uge i32 %iv, %inv_2
447 %loop_cond = or i1 %cmp_1, %cmp_2
448 %iv.next = add i32 %iv, 1
449 br i1 %loop_cond, label %loop, label %exit
455 ; Turn OR to AND and handle accordingly.
456 define i32 @test_sgt_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
457 ; CHECK-LABEL: @test_sgt_inv(
459 ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
460 ; CHECK-NEXT: br label [[LOOP:%.*]]
462 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
463 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMIN]]
464 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
465 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
467 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
468 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
474 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
475 %cmp_1 = icmp sgt i32 %iv, %inv_1
476 %cmp_2 = icmp sgt i32 %iv, %inv_2
477 %loop_cond = or i1 %cmp_1, %cmp_2
478 %iv.next = add i32 %iv, 1
479 br i1 %loop_cond, label %loop, label %exit
485 ; Turn OR to AND and handle accordingly.
486 define i32 @test_sge_inv(i32 %start, i32 %inv_1, i32 %inv_2) {
487 ; CHECK-LABEL: @test_sge_inv(
489 ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
490 ; CHECK-NEXT: br label [[LOOP:%.*]]
492 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
493 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMIN]]
494 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
495 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
497 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
498 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
504 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
505 %cmp_1 = icmp sge i32 %iv, %inv_1
506 %cmp_2 = icmp sge i32 %iv, %inv_2
507 %loop_cond = or i1 %cmp_1, %cmp_2
508 %iv.next = add i32 %iv, 1
509 br i1 %loop_cond, label %loop, label %exit
515 ; turn to %iv <u umin(inv_1, inv_2) and hoist it out of loop.
516 define i32 @test_ult_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
517 ; CHECK-LABEL: @test_ult_swapped(
519 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
520 ; CHECK-NEXT: br label [[LOOP:%.*]]
522 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
523 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]]
524 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
525 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
527 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
528 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
534 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
535 %cmp_1 = icmp ugt i32 %inv_1, %iv
536 %cmp_2 = icmp ugt i32 %inv_2, %iv
537 %loop_cond = and i1 %cmp_1, %cmp_2
538 %iv.next = add i32 %iv, 1
539 br i1 %loop_cond, label %loop, label %exit
545 ; turn to %iv <=u umin(inv_1, inv_2) and hoist it out of loop.
546 define i32 @test_ule_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
547 ; CHECK-LABEL: @test_ule_swapped(
549 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
550 ; CHECK-NEXT: br label [[LOOP:%.*]]
552 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
553 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ule i32 [[IV]], [[INVARIANT_UMIN]]
554 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
555 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
557 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
558 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
564 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
565 %cmp_1 = icmp uge i32 %inv_1, %iv
566 %cmp_2 = icmp uge i32 %inv_2, %iv
567 %loop_cond = and i1 %cmp_1, %cmp_2
568 %iv.next = add i32 %iv, 1
569 br i1 %loop_cond, label %loop, label %exit
575 ; turn to %iv <s smin(inv_1, inv_2) and hoist it out of loop.
576 define i32 @test_slt_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
577 ; CHECK-LABEL: @test_slt_swapped(
579 ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
580 ; CHECK-NEXT: br label [[LOOP:%.*]]
582 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
583 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[INVARIANT_SMIN]]
584 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
585 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
587 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
588 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
594 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
595 %cmp_1 = icmp sgt i32 %inv_1, %iv
596 %cmp_2 = icmp sgt i32 %inv_2, %iv
597 %loop_cond = and i1 %cmp_1, %cmp_2
598 %iv.next = add i32 %iv, 1
599 br i1 %loop_cond, label %loop, label %exit
605 ; turn to %iv <=s smin(inv_1, inv_2) and hoist it out of loop.
606 define i32 @test_sle_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
607 ; CHECK-LABEL: @test_sle_swapped(
609 ; CHECK-NEXT: [[INVARIANT_SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
610 ; CHECK-NEXT: br label [[LOOP:%.*]]
612 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
613 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sle i32 [[IV]], [[INVARIANT_SMIN]]
614 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
615 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
617 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
618 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
624 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
625 %cmp_1 = icmp sge i32 %inv_1, %iv
626 %cmp_2 = icmp sge i32 %inv_2, %iv
627 %loop_cond = and i1 %cmp_1, %cmp_2
628 %iv.next = add i32 %iv, 1
629 br i1 %loop_cond, label %loop, label %exit
635 ; turn to %iv >u umax(inv_1, inv_2) and hoist it out of loop.
636 define i32 @test_ugt_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
637 ; CHECK-LABEL: @test_ugt_swapped(
639 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
640 ; CHECK-NEXT: br label [[LOOP:%.*]]
642 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
643 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[IV]], [[INVARIANT_UMAX]]
644 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
645 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
647 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
648 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
654 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
655 %cmp_1 = icmp ult i32 %inv_1, %iv
656 %cmp_2 = icmp ult i32 %inv_2, %iv
657 %loop_cond = and i1 %cmp_1, %cmp_2
658 %iv.next = add i32 %iv, 1
659 br i1 %loop_cond, label %loop, label %exit
665 ; turn to %iv >=u umax(inv_1, inv_2) and hoist it out of loop.
666 define i32 @test_uge_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
667 ; CHECK-LABEL: @test_uge_swapped(
669 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
670 ; CHECK-NEXT: br label [[LOOP:%.*]]
672 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
673 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp uge i32 [[IV]], [[INVARIANT_UMAX]]
674 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
675 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
677 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
678 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
684 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
685 %cmp_1 = icmp ule i32 %inv_1, %iv
686 %cmp_2 = icmp ule i32 %inv_2, %iv
687 %loop_cond = and i1 %cmp_1, %cmp_2
688 %iv.next = add i32 %iv, 1
689 br i1 %loop_cond, label %loop, label %exit
695 ; turn to %iv >s smax(inv_1, inv_2) and hoist it out of loop.
696 define i32 @test_sgt_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
697 ; CHECK-LABEL: @test_sgt_swapped(
699 ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
700 ; CHECK-NEXT: br label [[LOOP:%.*]]
702 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
703 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[IV]], [[INVARIANT_SMAX]]
704 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
705 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
707 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
708 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
714 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
715 %cmp_1 = icmp slt i32 %inv_1, %iv
716 %cmp_2 = icmp slt i32 %inv_2, %iv
717 %loop_cond = and i1 %cmp_1, %cmp_2
718 %iv.next = add i32 %iv, 1
719 br i1 %loop_cond, label %loop, label %exit
725 ; turn to %iv >=s smax(inv_1, inv_2) and hoist it out of loop.
726 define i32 @test_sge_swapped(i32 %start, i32 %inv_1, i32 %inv_2) {
727 ; CHECK-LABEL: @test_sge_swapped(
729 ; CHECK-NEXT: [[INVARIANT_SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
730 ; CHECK-NEXT: br label [[LOOP:%.*]]
732 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
733 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sge i32 [[IV]], [[INVARIANT_SMAX]]
734 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
735 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
737 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
738 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
744 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
745 %cmp_1 = icmp sle i32 %inv_1, %iv
746 %cmp_2 = icmp sle i32 %inv_2, %iv
747 %loop_cond = and i1 %cmp_1, %cmp_2
748 %iv.next = add i32 %iv, 1
749 br i1 %loop_cond, label %loop, label %exit
755 ; inv_2 needs freeze because hoisted umax would create a new use that didn't exist before.
756 ; Counter-example: %cmp_1 = false, %inv_2 = poison.
757 define i32 @test_logical_and_ult_needs_freeze(i32 %start, i32 %inv_1, i32 %inv_2) {
758 ; CHECK-LABEL: @test_logical_and_ult_needs_freeze(
760 ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]]
761 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]])
762 ; CHECK-NEXT: br label [[LOOP:%.*]]
764 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
765 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]]
766 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
767 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
769 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
770 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
776 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
777 %cmp_1 = icmp ult i32 %iv, %inv_1
778 %cmp_2 = icmp ult i32 %iv, %inv_2
779 %loop_cond = select i1 %cmp_1, i1 %cmp_2, i1 false
780 %iv.next = add i32 %iv, 1
781 br i1 %loop_cond, label %loop, label %exit
787 ; turn to %iv <u umin(inv_1, inv_2) and hoist it out of loop.
788 ; https://alive2.llvm.org/ce/z/mhKGtT
789 define i32 @test_logical_and_ult_pos(i32 %start, i32 %inv_1, i32 noundef %inv_2) {
790 ; CHECK-LABEL: @test_logical_and_ult_pos(
792 ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]]
793 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]])
794 ; CHECK-NEXT: br label [[LOOP:%.*]]
796 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
797 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]]
798 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
799 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
801 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
802 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
808 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
809 %cmp_1 = icmp ult i32 %iv, %inv_1
810 %cmp_2 = icmp ult i32 %iv, %inv_2
811 %loop_cond = select i1 %cmp_1, i1 %cmp_2, i1 false
812 %iv.next = add i32 %iv, 1
813 br i1 %loop_cond, label %loop, label %exit
819 ; inv_2 needs freeze because hoisted umax would create a new use that didn't exist before.
820 define i32 @test_logical_or_ult_inv_needs_freeze(i32 %start, i32 %inv_1, i32 %inv_2) {
821 ; CHECK-LABEL: @test_logical_or_ult_inv_needs_freeze(
823 ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]]
824 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]])
825 ; CHECK-NEXT: br label [[LOOP:%.*]]
827 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
828 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMAX]]
829 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
830 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
832 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
833 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
839 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
840 %cmp_1 = icmp ult i32 %iv, %inv_1
841 %cmp_2 = icmp ult i32 %iv, %inv_2
842 %loop_cond = select i1 %cmp_1, i1 true, i1 %cmp_2
843 %iv.next = add i32 %iv, 1
844 br i1 %loop_cond, label %loop, label %exit
850 ; turn to %iv <u umax(inv_1, inv_2) and hoist it out of loop.
851 ; https://alive2.llvm.org/ce/z/zgyG5N
852 define i32 @test_logical_or_ult_inv_pos(i32 %start, i32 %inv_1, i32 noundef %inv_2) {
853 ; CHECK-LABEL: @test_logical_or_ult_inv_pos(
855 ; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]]
856 ; CHECK-NEXT: [[INVARIANT_UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]])
857 ; CHECK-NEXT: br label [[LOOP:%.*]]
859 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
860 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMAX]]
861 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
862 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
864 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
865 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
871 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
872 %cmp_1 = icmp ult i32 %iv, %inv_1
873 %cmp_2 = icmp ult i32 %iv, %inv_2
874 %loop_cond = select i1 %cmp_1, i1 true, i1 %cmp_2
875 %iv.next = add i32 %iv, 1
876 br i1 %loop_cond, label %loop, label %exit
882 ; Mismatched predicates, do not optimize.
883 define i32 @test_mismatched_predicates_neg(i32 %start, i32 %inv_1, i32 %inv_2) {
884 ; CHECK-LABEL: @test_mismatched_predicates_neg(
886 ; CHECK-NEXT: br label [[LOOP:%.*]]
888 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
889 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]]
890 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], [[INV_2:%.*]]
891 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
892 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
893 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
895 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
896 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
902 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
903 %cmp_1 = icmp ult i32 %iv, %inv_1
904 %cmp_2 = icmp ule i32 %iv, %inv_2
905 %loop_cond = and i1 %cmp_1, %cmp_2
906 %iv.next = add i32 %iv, 1
907 br i1 %loop_cond, label %loop, label %exit
913 ; TODO: Turn ule against constant into ult against constant, then do the same as in test_ult.
914 ; https://alive2.llvm.org/ce/z/rucunQ
915 define i32 @test_mismatched_predicates_constant_pos_1(i32 %start, i32 %inv_1, i32 %inv_2) {
916 ; CHECK-LABEL: @test_mismatched_predicates_constant_pos_1(
918 ; CHECK-NEXT: br label [[LOOP:%.*]]
920 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
921 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]]
922 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], 100
923 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
924 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
925 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
927 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
928 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
934 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
935 %cmp_1 = icmp ult i32 %iv, %inv_1
936 %cmp_2 = icmp ule i32 %iv, 100
937 %loop_cond = and i1 %cmp_1, %cmp_2
938 %iv.next = add i32 %iv, 1
939 br i1 %loop_cond, label %loop, label %exit
945 ; TODO: Turn ult against a constant into ule, then do the same as in test_ule.
946 ; https://alive2.llvm.org/ce/z/-ht-pU
947 define i32 @test_mismatched_predicates_constant_pos_2(i32 %start, i32 %inv_1, i32 %inv_2) {
948 ; CHECK-LABEL: @test_mismatched_predicates_constant_pos_2(
950 ; CHECK-NEXT: br label [[LOOP:%.*]]
952 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
953 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], 100
954 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], [[INV_2:%.*]]
955 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
956 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
957 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
959 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
960 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
966 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
967 %cmp_1 = icmp ult i32 %iv, 100
968 %cmp_2 = icmp ule i32 %iv, %inv_2
969 %loop_cond = and i1 %cmp_1, %cmp_2
970 %iv.next = add i32 %iv, 1
971 br i1 %loop_cond, label %loop, label %exit
977 ; Do not optimize: `ule -1` cannot be turned into `ult 0` because of overflow.
978 ; However, this condition is trivially true anyways, so do not bother about it.
979 define i32 @test_mismatched_predicates_constant_neg(i32 %start, i32 %inv_1, i32 %inv_2) {
980 ; CHECK-LABEL: @test_mismatched_predicates_constant_neg(
982 ; CHECK-NEXT: br label [[LOOP:%.*]]
984 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
985 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]]
986 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ule i32 [[IV]], -1
987 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
988 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
989 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
991 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
992 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
998 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
999 %cmp_1 = icmp ult i32 %iv, %inv_1
1000 %cmp_2 = icmp ule i32 %iv, -1
1001 %loop_cond = and i1 %cmp_1, %cmp_2
1002 %iv.next = add i32 %iv, 1
1003 br i1 %loop_cond, label %loop, label %exit
1009 ; Do not optimize: predicate eq.
1010 define i32 @test_eq_neg(i32 %start, i32 %inv_1, i32 %inv_2) {
1011 ; CHECK-LABEL: @test_eq_neg(
1012 ; CHECK-NEXT: entry:
1013 ; CHECK-NEXT: br label [[LOOP:%.*]]
1015 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
1016 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq i32 [[IV]], [[INV_1:%.*]]
1017 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp eq i32 [[IV]], [[INV_2:%.*]]
1018 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
1019 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
1020 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
1022 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
1023 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
1029 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
1030 %cmp_1 = icmp eq i32 %iv, %inv_1
1031 %cmp_2 = icmp eq i32 %iv, %inv_2
1032 %loop_cond = and i1 %cmp_1, %cmp_2
1033 %iv.next = add i32 %iv, 1
1034 br i1 %loop_cond, label %loop, label %exit
1040 ; Do not optimize: predicate ne.
1041 define i32 @test_ne_neg(i32 %start, i32 %inv_1, i32 %inv_2) {
1042 ; CHECK-LABEL: @test_ne_neg(
1043 ; CHECK-NEXT: entry:
1044 ; CHECK-NEXT: br label [[LOOP:%.*]]
1046 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
1047 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ne i32 [[IV]], [[INV_1:%.*]]
1048 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ne i32 [[IV]], [[INV_2:%.*]]
1049 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
1050 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
1051 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
1053 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
1054 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
1060 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
1061 %cmp_1 = icmp ne i32 %iv, %inv_1
1062 %cmp_2 = icmp ne i32 %iv, %inv_2
1063 %loop_cond = and i1 %cmp_1, %cmp_2
1064 %iv.next = add i32 %iv, 1
1065 br i1 %loop_cond, label %loop, label %exit
1071 ; Do not optimize: extra use.
1072 define i32 @test_ult_extra_use_1_neg(i32 %start, i32 %inv_1, i32 %inv_2) {
1073 ; CHECK-LABEL: @test_ult_extra_use_1_neg(
1074 ; CHECK-NEXT: entry:
1075 ; CHECK-NEXT: br label [[LOOP:%.*]]
1077 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
1078 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]]
1079 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV]], [[INV_2:%.*]]
1080 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
1081 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
1082 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
1084 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
1085 ; CHECK-NEXT: [[CMP_1_LCSSA:%.*]] = phi i1 [ [[CMP_1]], [[LOOP]] ]
1086 ; CHECK-NEXT: call void @use(i1 [[CMP_1_LCSSA]])
1087 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
1093 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
1094 %cmp_1 = icmp ult i32 %iv, %inv_1
1095 %cmp_2 = icmp ult i32 %iv, %inv_2
1096 %loop_cond = and i1 %cmp_1, %cmp_2
1097 %iv.next = add i32 %iv, 1
1098 br i1 %loop_cond, label %loop, label %exit
1101 call void @use(i1 %cmp_1)
1105 define i32 @test_ult_extra_use_2_neg(i32 %start, i32 %inv_1, i32 %inv_2) {
1106 ; CHECK-LABEL: @test_ult_extra_use_2_neg(
1107 ; CHECK-NEXT: entry:
1108 ; CHECK-NEXT: br label [[LOOP:%.*]]
1110 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
1111 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]]
1112 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV]], [[INV_2:%.*]]
1113 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
1114 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
1115 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
1117 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
1118 ; CHECK-NEXT: [[CMP_2_LCSSA:%.*]] = phi i1 [ [[CMP_2]], [[LOOP]] ]
1119 ; CHECK-NEXT: call void @use(i1 [[CMP_2_LCSSA]])
1120 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
1126 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
1127 %cmp_1 = icmp ult i32 %iv, %inv_1
1128 %cmp_2 = icmp ult i32 %iv, %inv_2
1129 %loop_cond = and i1 %cmp_1, %cmp_2
1130 %iv.next = add i32 %iv, 1
1131 br i1 %loop_cond, label %loop, label %exit
1134 call void @use(i1 %cmp_2)
1138 ; This can be optimized, despite the fact that loop_cond has other uses.
1139 define i32 @test_ult_extra_use_result_pos(i32 %start, i32 %inv_1, i32 %inv_2) {
1140 ; CHECK-LABEL: @test_ult_extra_use_result_pos(
1141 ; CHECK-NEXT: entry:
1142 ; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2:%.*]])
1143 ; CHECK-NEXT: br label [[LOOP:%.*]]
1145 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
1146 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]]
1147 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
1148 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
1150 ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[LOOP]] ]
1151 ; CHECK-NEXT: [[LOOP_COND_LCSSA:%.*]] = phi i1 [ [[LOOP_COND]], [[LOOP]] ]
1152 ; CHECK-NEXT: call void @use(i1 [[LOOP_COND_LCSSA]])
1153 ; CHECK-NEXT: ret i32 [[IV_LCSSA]]
1159 %iv = phi i32 [%start, %entry], [%iv.next, %loop]
1160 %cmp_1 = icmp ult i32 %iv, %inv_1
1161 %cmp_2 = icmp ult i32 %iv, %inv_2
1162 %loop_cond = and i1 %cmp_1, %cmp_2
1163 %iv.next = add i32 %iv, 1
1164 br i1 %loop_cond, label %loop, label %exit
1167 call void @use(i1 %loop_cond)
1171 ; Do not optimize: comparison against different variant values.
1172 define i32 @test_ult_different_variants_neg(i32 %start_1, i32 %start_2, i32 %inv_1, i32 %inv_2) {
1173 ; CHECK-LABEL: @test_ult_different_variants_neg(
1174 ; CHECK-NEXT: entry:
1175 ; CHECK-NEXT: br label [[LOOP:%.*]]
1177 ; CHECK-NEXT: [[IV_1:%.*]] = phi i32 [ [[START_1:%.*]], [[ENTRY:%.*]] ], [ [[IV_1_NEXT:%.*]], [[LOOP]] ]
1178 ; CHECK-NEXT: [[IV_2:%.*]] = phi i32 [ [[START_2:%.*]], [[ENTRY]] ], [ [[IV_2_NEXT:%.*]], [[LOOP]] ]
1179 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV_1]], [[INV_1:%.*]]
1180 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV_2]], [[INV_2:%.*]]
1181 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
1182 ; CHECK-NEXT: [[IV_1_NEXT]] = add i32 [[IV_1]], 1
1183 ; CHECK-NEXT: [[IV_2_NEXT]] = add i32 [[IV_2]], 1
1184 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
1186 ; CHECK-NEXT: [[IV_1_LCSSA:%.*]] = phi i32 [ [[IV_1]], [[LOOP]] ]
1187 ; CHECK-NEXT: ret i32 [[IV_1_LCSSA]]
1193 %iv_1 = phi i32 [%start_1, %entry], [%iv_1.next, %loop]
1194 %iv_2 = phi i32 [%start_2, %entry], [%iv_2.next, %loop]
1195 %cmp_1 = icmp ult i32 %iv_1, %inv_1
1196 %cmp_2 = icmp ult i32 %iv_2, %inv_2
1197 %loop_cond = and i1 %cmp_1, %cmp_2
1198 %iv_1.next = add i32 %iv_1, 1
1199 %iv_2.next = add i32 %iv_2, 1
1200 br i1 %loop_cond, label %loop, label %exit
1206 ; Do not optimize: one of comparisons is against loop-variant.
1207 define i32 @test_ult_compare_against_variant_neg(i32 %start_1, i32 %start_2, i32 %inv_1, i32 %inv_2) {
1208 ; CHECK-LABEL: @test_ult_compare_against_variant_neg(
1209 ; CHECK-NEXT: entry:
1210 ; CHECK-NEXT: br label [[LOOP:%.*]]
1212 ; CHECK-NEXT: [[IV_1:%.*]] = phi i32 [ [[START_1:%.*]], [[ENTRY:%.*]] ], [ [[IV_1_NEXT:%.*]], [[LOOP]] ]
1213 ; CHECK-NEXT: [[IV_2:%.*]] = phi i32 [ [[START_2:%.*]], [[ENTRY]] ], [ [[IV_2_NEXT:%.*]], [[LOOP]] ]
1214 ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV_1]], [[INV_1:%.*]]
1215 ; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV_1]], [[IV_2]]
1216 ; CHECK-NEXT: [[LOOP_COND:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
1217 ; CHECK-NEXT: [[IV_1_NEXT]] = add i32 [[IV_1]], 1
1218 ; CHECK-NEXT: [[IV_2_NEXT]] = add i32 [[IV_2]], 1
1219 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
1221 ; CHECK-NEXT: [[IV_1_LCSSA:%.*]] = phi i32 [ [[IV_1]], [[LOOP]] ]
1222 ; CHECK-NEXT: ret i32 [[IV_1_LCSSA]]
1228 %iv_1 = phi i32 [%start_1, %entry], [%iv_1.next, %loop]
1229 %iv_2 = phi i32 [%start_2, %entry], [%iv_2.next, %loop]
1230 %cmp_1 = icmp ult i32 %iv_1, %inv_1
1231 %cmp_2 = icmp ult i32 %iv_1, %iv_2
1232 %loop_cond = and i1 %cmp_1, %cmp_2
1233 %iv_1.next = add i32 %iv_1, 1
1234 %iv_2.next = add i32 %iv_2, 1
1235 br i1 %loop_cond, label %loop, label %exit
1241 declare void @use(i1)