1 ; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s
3 ; Check that IRCE is able to deal with loops where the latch comparison is
4 ; done against current value of the IV, not the IV.next.
6 ; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
7 ; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
8 ; CHECK-NOT: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
9 ; CHECK-NOT: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting>
11 ; SLT condition for increasing loop from 0 to 100.
12 define void @test_01(i32* %arr, i32* %a_len_ptr) #0 {
16 ; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0
17 ; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at
18 ; CHECK-NEXT: br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit
20 ; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ]
21 ; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1
22 ; CHECK-NEXT: %abc = icmp slt i32 %idx, %exit.mainloop.at
23 ; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
25 ; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx
26 ; CHECK-NEXT: store i32 0, i32* %addr
27 ; CHECK-NEXT: %next = icmp slt i32 %idx, 100
28 ; CHECK-NEXT: [[COND3:%[^ ]+]] = icmp slt i32 %idx, %exit.mainloop.at
29 ; CHECK-NEXT: br i1 [[COND3]], label %loop, label %main.exit.selector
30 ; CHECK: main.exit.selector:
31 ; CHECK-NEXT: %idx.lcssa = phi i32 [ %idx, %in.bounds ]
32 ; CHECK-NEXT: [[COND4:%[^ ]+]] = icmp slt i32 %idx.lcssa, 100
33 ; CHECK-NEXT: br i1 [[COND4]], label %main.pseudo.exit, label %exit
34 ; CHECK-NOT: loop.preloop:
35 ; CHECK: loop.postloop:
36 ; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ]
37 ; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1
38 ; CHECK-NEXT: %abc.postloop = icmp slt i32 %idx.postloop, %exit.mainloop.at
39 ; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit
42 %len = load i32, i32* %a_len_ptr, !range !0
46 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
47 %idx.next = add nsw nuw i32 %idx, 1
48 %abc = icmp slt i32 %idx, %len
49 br i1 %abc, label %in.bounds, label %out.of.bounds
52 %addr = getelementptr i32, i32* %arr, i32 %idx
53 store i32 0, i32* %addr
54 %next = icmp slt i32 %idx, 100
55 br i1 %next, label %loop, label %exit
64 ; ULT condition for increasing loop from 0 to 100.
65 define void @test_02(i32* %arr, i32* %a_len_ptr) #0 {
69 ; CHECK-NEXT: %exit.mainloop.at = load i32, i32* %a_len_ptr, !range !0
70 ; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at
71 ; CHECK-NEXT: br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit
73 ; CHECK-NEXT: %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ]
74 ; CHECK-NEXT: %idx.next = add nuw nsw i32 %idx, 1
75 ; CHECK-NEXT: %abc = icmp ult i32 %idx, %exit.mainloop.at
76 ; CHECK-NEXT: br i1 true, label %in.bounds, label %out.of.bounds.loopexit1
78 ; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx
79 ; CHECK-NEXT: store i32 0, i32* %addr
80 ; CHECK-NEXT: %next = icmp ult i32 %idx, 100
81 ; CHECK-NEXT: [[COND3:%[^ ]+]] = icmp ult i32 %idx, %exit.mainloop.at
82 ; CHECK-NEXT: br i1 [[COND3]], label %loop, label %main.exit.selector
83 ; CHECK: main.exit.selector:
84 ; CHECK-NEXT: %idx.lcssa = phi i32 [ %idx, %in.bounds ]
85 ; CHECK-NEXT: [[COND4:%[^ ]+]] = icmp ult i32 %idx.lcssa, 100
86 ; CHECK-NEXT: br i1 [[COND4]], label %main.pseudo.exit, label %exit
87 ; CHECK-NOT: loop.preloop:
88 ; CHECK: loop.postloop:
89 ; CHECK-NEXT: %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ]
90 ; CHECK-NEXT: %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1
91 ; CHECK-NEXT: %abc.postloop = icmp ult i32 %idx.postloop, %exit.mainloop.at
92 ; CHECK-NEXT: br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit
95 %len = load i32, i32* %a_len_ptr, !range !0
99 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
100 %idx.next = add nsw nuw i32 %idx, 1
101 %abc = icmp ult i32 %idx, %len
102 br i1 %abc, label %in.bounds, label %out.of.bounds
105 %addr = getelementptr i32, i32* %arr, i32 %idx
106 store i32 0, i32* %addr
107 %next = icmp ult i32 %idx, 100
108 br i1 %next, label %loop, label %exit
117 ; Same as test_01, but comparison happens against IV extended to a wider type.
118 ; This test ensures that IRCE rejects it and does not falsely assume that it was
119 ; a comparison against iv.next.
120 ; TODO: We can actually extend the recognition to cover this case.
121 define void @test_03(i32* %arr, i64* %a_len_ptr) #0 {
126 %len = load i64, i64* %a_len_ptr, !range !1
130 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
131 %idx.next = add nsw nuw i32 %idx, 1
132 %idx.ext = sext i32 %idx to i64
133 %abc = icmp slt i64 %idx.ext, %len
134 br i1 %abc, label %in.bounds, label %out.of.bounds
137 %addr = getelementptr i32, i32* %arr, i32 %idx
138 store i32 0, i32* %addr
139 %next = icmp slt i32 %idx, 100
140 br i1 %next, label %loop, label %exit
149 ; Same as test_02, but comparison happens against IV extended to a wider type.
150 ; This test ensures that IRCE rejects it and does not falsely assume that it was
151 ; a comparison against iv.next.
152 ; TODO: We can actually extend the recognition to cover this case.
153 define void @test_04(i32* %arr, i64* %a_len_ptr) #0 {
158 %len = load i64, i64* %a_len_ptr, !range !1
162 %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ]
163 %idx.next = add nsw nuw i32 %idx, 1
164 %idx.ext = sext i32 %idx to i64
165 %abc = icmp ult i64 %idx.ext, %len
166 br i1 %abc, label %in.bounds, label %out.of.bounds
169 %addr = getelementptr i32, i32* %arr, i32 %idx
170 store i32 0, i32* %addr
171 %next = icmp ult i32 %idx, 100
172 br i1 %next, label %loop, label %exit
181 !0 = !{i32 0, i32 50}
182 !1 = !{i64 0, i64 50}