1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -loop-unroll < %s | FileCheck %s
3 ; RUN: opt -S -passes='require<opt-remark-emit>,loop(loop-unroll-full)' < %s | FileCheck %s
5 ; Unroll twice, with first loop exit kept
6 define void @s32_max1(i32 %n, i32* %p) {
8 ; CHECK-LABEL: @s32_max1(
10 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 1
11 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
13 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[N]]
14 ; CHECK-NEXT: store i32 [[N]], i32* [[ARRAYIDX]], align 4
15 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1
16 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[N]], [[ADD]]
17 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]]
19 ; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, i32* [[P]], i32 [[INC]]
20 ; CHECK-NEXT: store i32 [[INC]], i32* [[ARRAYIDX_1]], align 4
21 ; CHECK-NEXT: br label [[DO_END]]
23 ; CHECK-NEXT: ret void
30 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
31 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
32 store i32 %i.0, i32* %arrayidx, align 4
33 %inc = add i32 %i.0, 1
34 %cmp = icmp slt i32 %i.0, %add
35 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 1 times
41 ; Unroll thrice, with first loop exit kept
42 define void @s32_max2(i32 %n, i32* %p) {
44 ; CHECK-LABEL: @s32_max2(
46 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2
47 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
49 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[N]]
50 ; CHECK-NEXT: store i32 [[N]], i32* [[ARRAYIDX]], align 4
51 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1
52 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[N]], [[ADD]]
53 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]]
55 ; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, i32* [[P]], i32 [[INC]]
56 ; CHECK-NEXT: store i32 [[INC]], i32* [[ARRAYIDX_1]], align 4
57 ; CHECK-NEXT: [[INC_1:%.*]] = add i32 [[INC]], 1
58 ; CHECK-NEXT: [[ARRAYIDX_2:%.*]] = getelementptr i32, i32* [[P]], i32 [[INC_1]]
59 ; CHECK-NEXT: store i32 [[INC_1]], i32* [[ARRAYIDX_2]], align 4
60 ; CHECK-NEXT: br label [[DO_END]]
62 ; CHECK-NEXT: ret void
69 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
70 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
71 store i32 %i.0, i32* %arrayidx, align 4
72 %inc = add i32 %i.0, 1
73 %cmp = icmp slt i32 %i.0, %add
74 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 2 times
80 ; Should not be unrolled
81 define void @s32_maxx(i32 %n, i32 %x, i32* %p) {
83 ; CHECK-LABEL: @s32_maxx(
85 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], [[N:%.*]]
86 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
88 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[DO_BODY]] ]
89 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[I_0]]
90 ; CHECK-NEXT: store i32 [[I_0]], i32* [[ARRAYIDX]], align 4
91 ; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1
92 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[ADD]]
93 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY]], label [[DO_END:%.*]]
95 ; CHECK-NEXT: ret void
102 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
103 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
104 store i32 %i.0, i32* %arrayidx, align 4
105 %inc = add i32 %i.0, 1
106 %cmp = icmp slt i32 %i.0, %add
107 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or x times
113 ; Should not be unrolled
114 define void @s32_max2_unpredictable_exit(i32 %n, i32 %x, i32* %p) {
116 ; CHECK-LABEL: @s32_max2_unpredictable_exit(
118 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2
119 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
121 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
122 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_0]], [[X:%.*]]
123 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_END:%.*]], label [[IF_END]]
125 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[I_0]]
126 ; CHECK-NEXT: store i32 [[I_0]], i32* [[ARRAYIDX]], align 4
127 ; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1
128 ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[I_0]], [[ADD]]
129 ; CHECK-NEXT: br i1 [[CMP1]], label [[DO_BODY]], label [[DO_END]]
131 ; CHECK-NEXT: ret void
138 %i.0 = phi i32 [ %n, %entry ], [ %inc, %if.end ]
139 %cmp = icmp eq i32 %i.0, %x
140 br i1 %cmp, label %do.end, label %if.end ; unpredictable
143 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
144 store i32 %i.0, i32* %arrayidx, align 4
145 %inc = add i32 %i.0, 1
146 %cmp1 = icmp slt i32 %i.0, %add
147 br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times
153 ; Unroll twice, with first loop exit kept
154 define void @u32_max1(i32 %n, i32* %p) {
156 ; CHECK-LABEL: @u32_max1(
158 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 1
159 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
161 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[N]]
162 ; CHECK-NEXT: store i32 [[N]], i32* [[ARRAYIDX]], align 4
163 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1
164 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[N]], [[ADD]]
165 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]]
167 ; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, i32* [[P]], i32 [[INC]]
168 ; CHECK-NEXT: store i32 [[INC]], i32* [[ARRAYIDX_1]], align 4
169 ; CHECK-NEXT: br label [[DO_END]]
171 ; CHECK-NEXT: ret void
178 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
179 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
180 store i32 %i.0, i32* %arrayidx, align 4
181 %inc = add i32 %i.0, 1
182 %cmp = icmp ult i32 %i.0, %add
183 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 1 times
189 ; Unroll thrice, with first loop exit kept
190 define void @u32_max2(i32 %n, i32* %p) {
192 ; CHECK-LABEL: @u32_max2(
194 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2
195 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
197 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[N]]
198 ; CHECK-NEXT: store i32 [[N]], i32* [[ARRAYIDX]], align 4
199 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[N]], 1
200 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[N]], [[ADD]]
201 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY_1:%.*]], label [[DO_END:%.*]]
203 ; CHECK-NEXT: [[ARRAYIDX_1:%.*]] = getelementptr i32, i32* [[P]], i32 [[INC]]
204 ; CHECK-NEXT: store i32 [[INC]], i32* [[ARRAYIDX_1]], align 4
205 ; CHECK-NEXT: [[INC_1:%.*]] = add i32 [[INC]], 1
206 ; CHECK-NEXT: [[ARRAYIDX_2:%.*]] = getelementptr i32, i32* [[P]], i32 [[INC_1]]
207 ; CHECK-NEXT: store i32 [[INC_1]], i32* [[ARRAYIDX_2]], align 4
208 ; CHECK-NEXT: br label [[DO_END]]
210 ; CHECK-NEXT: ret void
217 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
218 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
219 store i32 %i.0, i32* %arrayidx, align 4
220 %inc = add i32 %i.0, 1
221 %cmp = icmp ult i32 %i.0, %add
222 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 2 times
228 ; Should not be unrolled
229 define void @u32_maxx(i32 %n, i32 %x, i32* %p) {
231 ; CHECK-LABEL: @u32_maxx(
233 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], [[N:%.*]]
234 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
236 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[DO_BODY]] ]
237 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[I_0]]
238 ; CHECK-NEXT: store i32 [[I_0]], i32* [[ARRAYIDX]], align 4
239 ; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1
240 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[I_0]], [[ADD]]
241 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_BODY]], label [[DO_END:%.*]]
243 ; CHECK-NEXT: ret void
246 %add = add i32 %x, %n
250 %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
251 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
252 store i32 %i.0, i32* %arrayidx, align 4
253 %inc = add i32 %i.0, 1
254 %cmp = icmp ult i32 %i.0, %add
255 br i1 %cmp, label %do.body, label %do.end ; taken either 0 or x times
261 ; Should not be unrolled
262 define void @u32_max2_unpredictable_exit(i32 %n, i32 %x, i32* %p) {
264 ; CHECK-LABEL: @u32_max2_unpredictable_exit(
266 ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[N:%.*]], 2
267 ; CHECK-NEXT: br label [[DO_BODY:%.*]]
269 ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
270 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_0]], [[X:%.*]]
271 ; CHECK-NEXT: br i1 [[CMP]], label [[DO_END:%.*]], label [[IF_END]]
273 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P:%.*]], i32 [[I_0]]
274 ; CHECK-NEXT: store i32 [[I_0]], i32* [[ARRAYIDX]], align 4
275 ; CHECK-NEXT: [[INC]] = add i32 [[I_0]], 1
276 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[I_0]], [[ADD]]
277 ; CHECK-NEXT: br i1 [[CMP1]], label [[DO_BODY]], label [[DO_END]]
279 ; CHECK-NEXT: ret void
286 %i.0 = phi i32 [ %n, %entry ], [ %inc, %if.end ]
287 %cmp = icmp eq i32 %i.0, %x
288 br i1 %cmp, label %do.end, label %if.end ; unpredictable
291 %arrayidx = getelementptr i32, i32* %p, i32 %i.0
292 store i32 %i.0, i32* %arrayidx, align 4
293 %inc = add i32 %i.0, 1
294 %cmp1 = icmp ult i32 %i.0, %add
295 br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times