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