1; RUN: opt -S -loop-unroll < %s | FileCheck %s
2; RUN: opt -S -passes='require<opt-remark-emit>,loop(loop-unroll-full)' < %s | FileCheck %s
3
4; Unroll twice, with first loop exit kept
5; CHECK-LABEL: @s32_max1
6; CHECK: do.body:
7; CHECK:  store
8; CHECK:  br i1 %cmp, label %do.body.1, label %do.end
9; CHECK: do.end:
10; CHECK:  ret void
11; CHECK: do.body.1:
12; CHECK:  store
13; CHECK:  br label %do.end
14define void @s32_max1(i32 %n, i32* %p) {
15entry:
16  %add = add i32 %n, 1
17  br label %do.body
18
19do.body:
20  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
21  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
22  store i32 %i.0, i32* %arrayidx, align 4
23  %inc = add i32 %i.0, 1
24  %cmp = icmp slt i32 %i.0, %add
25  br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 1 times
26
27do.end:
28  ret void
29}
30
31; Unroll thrice, with first loop exit kept
32; CHECK-LABEL: @s32_max2
33; CHECK: do.body:
34; CHECK:  store
35; CHECK:  br i1 %cmp, label %do.body.1, label %do.end
36; CHECK: do.end:
37; CHECK:  ret void
38; CHECK: do.body.1:
39; CHECK:  store
40; CHECK:  store
41; CHECK:  br label %do.end
42define void @s32_max2(i32 %n, i32* %p) {
43entry:
44  %add = add i32 %n, 2
45  br label %do.body
46
47do.body:
48  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
49  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
50  store i32 %i.0, i32* %arrayidx, align 4
51  %inc = add i32 %i.0, 1
52  %cmp = icmp slt i32 %i.0, %add
53  br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 2 times
54
55do.end:
56  ret void
57}
58
59; Should not be unrolled
60; CHECK-LABEL: @s32_maxx
61; CHECK: do.body:
62; CHECK: do.end:
63; CHECK-NOT: do.body.1:
64define void @s32_maxx(i32 %n, i32 %x, i32* %p) {
65entry:
66  %add = add i32 %x, %n
67  br label %do.body
68
69do.body:
70  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
71  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
72  store i32 %i.0, i32* %arrayidx, align 4
73  %inc = add i32 %i.0, 1
74  %cmp = icmp slt i32 %i.0, %add
75  br i1 %cmp, label %do.body, label %do.end ; taken either 0 or x times
76
77do.end:
78  ret void
79}
80
81; Should not be unrolled
82; CHECK-LABEL: @s32_max2_unpredictable_exit
83; CHECK: do.body:
84; CHECK: do.end:
85; CHECK-NOT: do.body.1:
86define void @s32_max2_unpredictable_exit(i32 %n, i32 %x, i32* %p) {
87entry:
88  %add = add i32 %n, 2
89  br label %do.body
90
91do.body:
92  %i.0 = phi i32 [ %n, %entry ], [ %inc, %if.end ]
93  %cmp = icmp eq i32 %i.0, %x
94  br i1 %cmp, label %do.end, label %if.end ; unpredictable
95
96if.end:
97  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
98  store i32 %i.0, i32* %arrayidx, align 4
99  %inc = add i32 %i.0, 1
100  %cmp1 = icmp slt i32 %i.0, %add
101  br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times
102
103do.end:
104  ret void
105}
106
107; Unroll twice, with first loop exit kept
108; CHECK-LABEL: @u32_max1
109; CHECK: do.body:
110; CHECK:  store
111; CHECK:  br i1 %cmp, label %do.body.1, label %do.end
112; CHECK: do.end:
113; CHECK:  ret void
114; CHECK: do.body.1:
115; CHECK:  store
116; CHECK:  br label %do.end
117define void @u32_max1(i32 %n, i32* %p) {
118entry:
119  %add = add i32 %n, 1
120  br label %do.body
121
122do.body:
123  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
124  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
125  store i32 %i.0, i32* %arrayidx, align 4
126  %inc = add i32 %i.0, 1
127  %cmp = icmp ult i32 %i.0, %add
128  br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 1 times
129
130do.end:
131  ret void
132}
133
134; Unroll thrice, with first loop exit kept
135; CHECK-LABEL: @u32_max2
136; CHECK: do.body:
137; CHECK:  store
138; CHECK:  br i1 %cmp, label %do.body.1, label %do.end
139; CHECK: do.end:
140; CHECK:  ret void
141; CHECK: do.body.1:
142; CHECK:  store
143; CHECK:  store
144; CHECK:  br label %do.end
145define void @u32_max2(i32 %n, i32* %p) {
146entry:
147  %add = add i32 %n, 2
148  br label %do.body
149
150do.body:
151  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
152  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
153  store i32 %i.0, i32* %arrayidx, align 4
154  %inc = add i32 %i.0, 1
155  %cmp = icmp ult i32 %i.0, %add
156  br i1 %cmp, label %do.body, label %do.end ; taken either 0 or 2 times
157
158do.end:
159  ret void
160}
161
162; Should not be unrolled
163; CHECK-LABEL: @u32_maxx
164; CHECK: do.body:
165; CHECK: do.end:
166; CHECK-NOT: do.body.1:
167define void @u32_maxx(i32 %n, i32 %x, i32* %p) {
168entry:
169  %add = add i32 %x, %n
170  br label %do.body
171
172do.body:
173  %i.0 = phi i32 [ %n, %entry ], [ %inc, %do.body ]
174  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
175  store i32 %i.0, i32* %arrayidx, align 4
176  %inc = add i32 %i.0, 1
177  %cmp = icmp ult i32 %i.0, %add
178  br i1 %cmp, label %do.body, label %do.end ; taken either 0 or x times
179
180do.end:
181  ret void
182}
183
184; Should not be unrolled
185; CHECK-LABEL: @u32_max2_unpredictable_exit
186; CHECK: do.body:
187; CHECK: do.end:
188; CHECK-NOT: do.body.1:
189define void @u32_max2_unpredictable_exit(i32 %n, i32 %x, i32* %p) {
190entry:
191  %add = add i32 %n, 2
192  br label %do.body
193
194do.body:
195  %i.0 = phi i32 [ %n, %entry ], [ %inc, %if.end ]
196  %cmp = icmp eq i32 %i.0, %x
197  br i1 %cmp, label %do.end, label %if.end ; unpredictable
198
199if.end:
200  %arrayidx = getelementptr i32, i32* %p, i32 %i.0
201  store i32 %i.0, i32* %arrayidx, align 4
202  %inc = add i32 %i.0, 1
203  %cmp1 = icmp ult i32 %i.0, %add
204  br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times
205
206do.end:
207  ret void
208}
209