1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -passes=loop-unroll -S %s -verify-loop-info -verify-dom-info -verify-loop-lcssa | FileCheck %s
4 %struct.spam = type { double, double, double, double, double, double, double }
6 define void @test2(ptr %arg, ptr %out) {
9 ; CHECK-NEXT: br label [[FOR_HEADER:%.*]]
11 ; CHECK-NEXT: store i32 0, ptr [[ARG:%.*]], align 4
12 ; CHECK-NEXT: br label [[FOR_LATCH:%.*]]
14 ; CHECK-NEXT: store volatile i64 0, ptr [[OUT:%.*]], align 4
15 ; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1
16 ; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4
17 ; CHECK-NEXT: br label [[FOR_LATCH_1:%.*]]
19 ; CHECK-NEXT: store volatile i64 1, ptr [[OUT]], align 4
20 ; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 2
21 ; CHECK-NEXT: store i32 0, ptr [[PTR_2]], align 4
22 ; CHECK-NEXT: br label [[FOR_LATCH_2:%.*]]
24 ; CHECK-NEXT: store volatile i64 2, ptr [[OUT]], align 4
25 ; CHECK-NEXT: [[PTR_3:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 3
26 ; CHECK-NEXT: store i32 0, ptr [[PTR_3]], align 4
27 ; CHECK-NEXT: br i1 true, label [[IF_END_LOOPEXIT:%.*]], label [[FOR_LATCH_3:%.*]]
29 ; CHECK-NEXT: store volatile i64 3, ptr [[OUT]], align 4
30 ; CHECK-NEXT: unreachable
31 ; CHECK: if.end.loopexit:
32 ; CHECK-NEXT: ret void
38 for.header: ; preds = %for.latch, %entry
39 %indvars.iv800 = phi i64 [ 0, %entry ], [ %indvars.iv.next801, %for.latch ]
40 %ptr = getelementptr inbounds i32, ptr %arg, i64 %indvars.iv800
41 store i32 0, ptr %ptr, align 4
42 %indvars.iv.next801 = add nuw nsw i64 %indvars.iv800, 1
43 %exitcond802 = icmp eq i64 %indvars.iv.next801, 4
44 br i1 %exitcond802, label %if.end.loopexit, label %for.latch
46 for.latch: ; preds = %for.header
47 store volatile i64 %indvars.iv800, ptr %out
50 if.end.loopexit: ; preds = %for.header
54 define double @test_with_lcssa(double %arg1, ptr %arg2) {
55 ; CHECK-LABEL: @test_with_lcssa(
57 ; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
59 ; CHECK-NEXT: [[RES:%.*]] = fsub double [[ARG1:%.*]], 3.000000e+00
60 ; CHECK-NEXT: br label [[LOOP_LATCH:%.*]]
62 ; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds double, ptr [[ARG2:%.*]], i64 1
63 ; CHECK-NEXT: [[LV:%.*]] = load double, ptr [[PTR]], align 8
64 ; CHECK-NEXT: [[RES_1:%.*]] = fsub double [[LV]], [[RES]]
65 ; CHECK-NEXT: br i1 true, label [[LOOP_EXIT:%.*]], label [[LOOP_LATCH_1:%.*]]
66 ; CHECK: loop.latch.1:
67 ; CHECK-NEXT: unreachable
69 ; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi double [ [[RES_1]], [[LOOP_LATCH]] ]
70 ; CHECK-NEXT: ret double [[RES_LCSSA]]
76 loop.header: ; preds = %entry, %loop.latch
77 %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
78 %d1 = phi double [ %arg1, %entry ], [ %lv, %loop.latch ]
79 %d2 = phi double [ 3.0, %entry ], [ %res, %loop.latch ]
80 %res = fsub double %d1, %d2
81 %iv.next = add nuw nsw i64 %iv, 1
82 %cond = icmp eq i64 %iv.next, 2
83 br i1 %cond, label %loop.exit, label %loop.latch
85 loop.latch: ; preds = %bb366
86 %ptr = getelementptr inbounds double, ptr %arg2, i64 %iv.next
87 %lv = load double, ptr %ptr, align 8
90 loop.exit: ; preds = %bb366
91 %res.lcssa = phi double [ %res, %loop.header ]
95 ; We unroll the outer loop and need to preserve LI for the inner loop.
96 define void @test_with_nested_loop(ptr %arg) {
97 ; CHECK-LABEL: @test_with_nested_loop(
99 ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
100 ; CHECK: outer.header:
101 ; CHECK-NEXT: br label [[INNER_BODY_PREHEADER:%.*]]
102 ; CHECK: inner.body.preheader:
103 ; CHECK-NEXT: br label [[INNER_BODY:%.*]]
105 ; CHECK-NEXT: [[J_IV:%.*]] = phi i64 [ [[J_IV_NEXT:%.*]], [[INNER_BODY]] ], [ 0, [[INNER_BODY_PREHEADER]] ]
106 ; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[ARG:%.*]], i64 [[J_IV]]
107 ; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4
108 ; CHECK-NEXT: [[J_IV_NEXT]] = add nuw nsw i64 [[J_IV]], 1
109 ; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i64 [[J_IV_NEXT]], 40000
110 ; CHECK-NEXT: br i1 [[INNER_COND]], label [[OUTER_LATCH:%.*]], label [[INNER_BODY]]
111 ; CHECK: outer.latch:
112 ; CHECK-NEXT: br label [[INNER_BODY_PREHEADER_1:%.*]]
113 ; CHECK: inner.body.preheader.1:
114 ; CHECK-NEXT: br label [[INNER_BODY_1:%.*]]
115 ; CHECK: inner.body.1:
116 ; CHECK-NEXT: [[J_IV_1:%.*]] = phi i64 [ [[J_IV_NEXT_1:%.*]], [[INNER_BODY_1]] ], [ 0, [[INNER_BODY_PREHEADER_1]] ]
117 ; CHECK-NEXT: [[IDX_1:%.*]] = add i64 1, [[J_IV_1]]
118 ; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_1]]
119 ; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4
120 ; CHECK-NEXT: [[J_IV_NEXT_1]] = add nuw nsw i64 [[J_IV_1]], 1
121 ; CHECK-NEXT: [[INNER_COND_1:%.*]] = icmp eq i64 [[J_IV_NEXT_1]], 40000
122 ; CHECK-NEXT: br i1 [[INNER_COND_1]], label [[OUTER_LATCH_1:%.*]], label [[INNER_BODY_1]]
123 ; CHECK: outer.latch.1:
124 ; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER_2:%.*]]
125 ; CHECK: inner.body.preheader.2:
126 ; CHECK-NEXT: br label [[INNER_BODY_2:%.*]]
127 ; CHECK: inner.body.2:
128 ; CHECK-NEXT: [[J_IV_2:%.*]] = phi i64 [ [[J_IV_NEXT_2:%.*]], [[INNER_BODY_2]] ], [ 0, [[INNER_BODY_PREHEADER_2]] ]
129 ; CHECK-NEXT: [[IDX_2:%.*]] = add i64 2, [[J_IV_2]]
130 ; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_2]]
131 ; CHECK-NEXT: store i32 0, ptr [[PTR_2]], align 4
132 ; CHECK-NEXT: [[J_IV_NEXT_2]] = add nuw nsw i64 [[J_IV_2]], 1
133 ; CHECK-NEXT: [[INNER_COND_2:%.*]] = icmp eq i64 [[J_IV_NEXT_2]], 40000
134 ; CHECK-NEXT: br i1 [[INNER_COND_2]], label [[OUTER_LATCH_2:%.*]], label [[INNER_BODY_2]]
135 ; CHECK: outer.latch.2:
136 ; CHECK-NEXT: unreachable
138 ; CHECK-NEXT: ret void
142 br label %outer.header
144 outer.header: ; preds = %outer.latch, %entry
145 %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
146 %outer.iv.next = add nuw nsw i64 %outer.iv, 1
147 %outer.cond = icmp eq i64 %outer.iv, 2
148 br i1 %outer.cond, label %exit, label %inner.body
151 %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ]
152 %idx = add i64 %outer.iv, %j.iv
153 %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx
154 store i32 0, ptr %ptr, align 4
155 %j.iv.next = add nuw nsw i64 %j.iv, 1
156 %inner.cond = icmp eq i64 %j.iv.next, 40000
157 br i1 %inner.cond, label %outer.latch, label %inner.body
159 outer.latch: ; preds = %inner.body
160 br label %outer.header
162 exit: ; preds = %outer.header
166 ; We unroll the inner loop and need to preserve LI for the outer loop.
167 define void @test_with_nested_loop_unroll_inner(ptr %arg) {
168 ; CHECK-LABEL: @test_with_nested_loop_unroll_inner(
170 ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
171 ; CHECK: outer.header:
172 ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[OUTER_IV_NEXT:%.*]], [[INNER_BODY:%.*]] ]
173 ; CHECK-NEXT: [[OUTER_IV_NEXT]] = add nuw nsw i64 [[OUTER_IV]], 1
174 ; CHECK-NEXT: [[OUTER_COND:%.*]] = icmp eq i64 [[OUTER_IV]], 40000
175 ; CHECK-NEXT: br i1 [[OUTER_COND]], label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER:%.*]]
176 ; CHECK: inner.body.preheader:
177 ; CHECK-NEXT: br label [[INNER_BODY]]
179 ; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[ARG:%.*]], i64 [[OUTER_IV]]
180 ; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4
181 ; CHECK-NEXT: [[IDX_1:%.*]] = add i64 [[OUTER_IV]], 1
182 ; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_1]]
183 ; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4
184 ; CHECK-NEXT: br label [[OUTER_HEADER]]
186 ; CHECK-NEXT: ret void
190 br label %outer.header
192 outer.header: ; preds = %outer.latch, %entry
193 %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
194 %outer.iv.next = add nuw nsw i64 %outer.iv, 1
195 %outer.cond = icmp eq i64 %outer.iv, 40000
196 br i1 %outer.cond, label %exit, label %inner.body
199 %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ]
200 %idx = add i64 %outer.iv, %j.iv
201 %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx
202 store i32 0, ptr %ptr, align 4
203 %j.iv.next = add nuw nsw i64 %j.iv, 1
204 %inner.cond = icmp eq i64 %j.iv.next, 2
205 br i1 %inner.cond, label %outer.latch, label %inner.body
207 outer.latch: ; preds = %inner.body
208 br label %outer.header
210 exit: ; preds = %outer.header
216 ; Check that we do not crash for headers with non-branch instructions, e.g.
217 ; switch. We do not unroll in those cases.
218 define void @test_switchinst_in_header() {
219 ; CHECK-LABEL: @test_switchinst_in_header(
221 ; CHECK-NEXT: br label [[WHILE_HEADER:%.*]]
222 ; CHECK: while.header:
223 ; CHECK-NEXT: switch i32 undef, label [[EXIT:%.*]] [
224 ; CHECK-NEXT: i32 11, label [[WHILE_BODY1:%.*]]
225 ; CHECK-NEXT: i32 5, label [[WHILE_BODY2:%.*]]
227 ; CHECK: while.body1:
228 ; CHECK-NEXT: unreachable
229 ; CHECK: while.body2:
230 ; CHECK-NEXT: br label [[WHILE_LATCH:%.*]]
231 ; CHECK: while.latch:
232 ; CHECK-NEXT: br label [[WHILE_HEADER]]
234 ; CHECK-NEXT: ret void
238 br label %while.header
240 while.header: ; preds = %while.latch, %entry
241 switch i32 undef, label %exit [
242 i32 11, label %while.body1
243 i32 5, label %while.body2
246 while.body1: ; preds = %while.header
249 while.body2: ; preds = %while.header
250 br label %while.latch
252 while.latch: ; preds = %while.body2
253 br label %while.header
255 exit: ; preds = %while.header