xref: /llvm-project/llvm/test/Transforms/LoopUnroll/full-unroll-keep-first-exit.ll (revision b9808e5660f5fe9e7414c0c0b93acd899235471c)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=loop-unroll < %s | FileCheck %s
3; RUN: opt -S -passes='require<opt-remark-emit>,loop(loop-unroll-full)' < %s | FileCheck %s
4
5; Unroll twice, with first loop exit kept
6define void @s32_max1(i32 %n, ptr %p) {
7;
8; CHECK-LABEL: @s32_max1(
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 1
11; CHECK-NEXT:    br label [[DO_BODY:%.*]]
12; CHECK:       do.body:
13; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]]
14; CHECK-NEXT:    store i32 [[N]], ptr [[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:%.*]]
18; CHECK:       do.body.1:
19; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]]
20; CHECK-NEXT:    store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4
21; CHECK-NEXT:    br label [[DO_END]]
22; CHECK:       do.end:
23; CHECK-NEXT:    ret void
24;
25entry:
26  %add = add i32 %n, 1
27  br label %do.body
28
29do.body:
30  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
31  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
32  store i32 %i.0, ptr %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
36
37do.end:
38  ret void
39}
40
41; Unroll thrice, with first loop exit kept
42define void @s32_max2(i32 %n, ptr %p) {
43;
44; CHECK-LABEL: @s32_max2(
45; CHECK-NEXT:  entry:
46; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 2
47; CHECK-NEXT:    br label [[DO_BODY:%.*]]
48; CHECK:       do.body:
49; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]]
50; CHECK-NEXT:    store i32 [[N]], ptr [[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:%.*]]
54; CHECK:       do.body.1:
55; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]]
56; CHECK-NEXT:    store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4
57; CHECK-NEXT:    [[INC_1:%.*]] = add i32 [[N]], 2
58; CHECK-NEXT:    [[ARRAYIDX_2:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC_1]]
59; CHECK-NEXT:    store i32 [[INC_1]], ptr [[ARRAYIDX_2]], align 4
60; CHECK-NEXT:    br label [[DO_END]]
61; CHECK:       do.end:
62; CHECK-NEXT:    ret void
63;
64entry:
65  %add = add i32 %n, 2
66  br label %do.body
67
68do.body:
69  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
70  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
71  store i32 %i.0, ptr %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
75
76do.end:
77  ret void
78}
79
80; Should not be unrolled
81define void @s32_maxx(i32 %n, i32 %x, ptr %p) {
82;
83; CHECK-LABEL: @s32_maxx(
84; CHECK-NEXT:  entry:
85; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], [[N:%.*]]
86; CHECK-NEXT:    br label [[DO_BODY:%.*]]
87; CHECK:       do.body:
88; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[DO_BODY]] ]
89; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]]
90; CHECK-NEXT:    store i32 [[I_0]], ptr [[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:%.*]]
94; CHECK:       do.end:
95; CHECK-NEXT:    ret void
96;
97entry:
98  %add = add i32 %x, %n
99  br label %do.body
100
101do.body:
102  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
103  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
104  store i32 %i.0, ptr %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
108
109do.end:
110  ret void
111}
112
113; Should not be unrolled
114define void @s32_max2_unpredictable_exit(i32 %n, i32 %x, ptr %p) {
115;
116; CHECK-LABEL: @s32_max2_unpredictable_exit(
117; CHECK-NEXT:  entry:
118; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 2
119; CHECK-NEXT:    br label [[DO_BODY:%.*]]
120; CHECK:       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]]
124; CHECK:       if.end:
125; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]]
126; CHECK-NEXT:    store i32 [[I_0]], ptr [[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]]
130; CHECK:       do.end:
131; CHECK-NEXT:    ret void
132;
133entry:
134  %add = add i32 %n, 2
135  br label %do.body
136
137do.body:
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
141
142if.end:
143  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
144  store i32 %i.0, ptr %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
148
149do.end:
150  ret void
151}
152
153; Unroll twice, with first loop exit kept
154define void @u32_max1(i32 %n, ptr %p) {
155;
156; CHECK-LABEL: @u32_max1(
157; CHECK-NEXT:  entry:
158; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 1
159; CHECK-NEXT:    br label [[DO_BODY:%.*]]
160; CHECK:       do.body:
161; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]]
162; CHECK-NEXT:    store i32 [[N]], ptr [[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:%.*]]
166; CHECK:       do.body.1:
167; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]]
168; CHECK-NEXT:    store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4
169; CHECK-NEXT:    br label [[DO_END]]
170; CHECK:       do.end:
171; CHECK-NEXT:    ret void
172;
173entry:
174  %add = add i32 %n, 1
175  br label %do.body
176
177do.body:
178  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
179  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
180  store i32 %i.0, ptr %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
184
185do.end:
186  ret void
187}
188
189; Unroll thrice, with first loop exit kept
190define void @u32_max2(i32 %n, ptr %p) {
191;
192; CHECK-LABEL: @u32_max2(
193; CHECK-NEXT:  entry:
194; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 2
195; CHECK-NEXT:    br label [[DO_BODY:%.*]]
196; CHECK:       do.body:
197; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[N]]
198; CHECK-NEXT:    store i32 [[N]], ptr [[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:%.*]]
202; CHECK:       do.body.1:
203; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC]]
204; CHECK-NEXT:    store i32 [[INC]], ptr [[ARRAYIDX_1]], align 4
205; CHECK-NEXT:    [[INC_1:%.*]] = add i32 [[N]], 2
206; CHECK-NEXT:    [[ARRAYIDX_2:%.*]] = getelementptr i32, ptr [[P]], i32 [[INC_1]]
207; CHECK-NEXT:    store i32 [[INC_1]], ptr [[ARRAYIDX_2]], align 4
208; CHECK-NEXT:    br label [[DO_END]]
209; CHECK:       do.end:
210; CHECK-NEXT:    ret void
211;
212entry:
213  %add = add i32 %n, 2
214  br label %do.body
215
216do.body:
217  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
218  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
219  store i32 %i.0, ptr %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
223
224do.end:
225  ret void
226}
227
228; Should not be unrolled
229define void @u32_maxx(i32 %n, i32 %x, ptr %p) {
230;
231; CHECK-LABEL: @u32_maxx(
232; CHECK-NEXT:  entry:
233; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X:%.*]], [[N:%.*]]
234; CHECK-NEXT:    br label [[DO_BODY:%.*]]
235; CHECK:       do.body:
236; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[DO_BODY]] ]
237; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]]
238; CHECK-NEXT:    store i32 [[I_0]], ptr [[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:%.*]]
242; CHECK:       do.end:
243; CHECK-NEXT:    ret void
244;
245entry:
246  %add = add i32 %x, %n
247  br label %do.body
248
249do.body:
250  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
251  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
252  store i32 %i.0, ptr %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
256
257do.end:
258  ret void
259}
260
261; Should not be unrolled
262define void @u32_max2_unpredictable_exit(i32 %n, i32 %x, ptr %p) {
263;
264; CHECK-LABEL: @u32_max2_unpredictable_exit(
265; CHECK-NEXT:  entry:
266; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[N:%.*]], 2
267; CHECK-NEXT:    br label [[DO_BODY:%.*]]
268; CHECK:       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]]
272; CHECK:       if.end:
273; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 [[I_0]]
274; CHECK-NEXT:    store i32 [[I_0]], ptr [[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]]
278; CHECK:       do.end:
279; CHECK-NEXT:    ret void
280;
281entry:
282  %add = add i32 %n, 2
283  br label %do.body
284
285do.body:
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
289
290if.end:
291  %arrayidx = getelementptr i32, ptr %p, i32 %i.0
292  store i32 %i.0, ptr %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
296
297do.end:
298  ret void
299}
300