xref: /llvm-project/llvm/test/Transforms/LoopUnroll/unroll-unconditional-latch.ll (revision ef992b60798b6cd2c50b25351bfc392e319896b7)
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
3
4%struct.spam = type { double, double, double, double, double, double, double }
5
6define void @test2(ptr %arg, ptr %out)  {
7; CHECK-LABEL: @test2(
8; CHECK-NEXT:  entry:
9; CHECK-NEXT:    br label [[FOR_HEADER:%.*]]
10; CHECK:       for.header:
11; CHECK-NEXT:    store i32 0, ptr [[ARG:%.*]], align 4
12; CHECK-NEXT:    br label [[FOR_LATCH:%.*]]
13; CHECK:       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:%.*]]
18; CHECK:       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:%.*]]
23; CHECK:       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:%.*]]
28; CHECK:       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
33;
34
35entry:
36  br label %for.header
37
38for.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
45
46for.latch: ; preds = %for.header
47  store volatile i64 %indvars.iv800, ptr %out
48  br label %for.header
49
50if.end.loopexit:                                  ; preds = %for.header
51  ret void
52}
53
54define double @test_with_lcssa(double %arg1, ptr %arg2) {
55; CHECK-LABEL: @test_with_lcssa(
56; CHECK-NEXT:  entry:
57; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
58; CHECK:       loop.header:
59; CHECK-NEXT:    [[RES:%.*]] = fsub double [[ARG1:%.*]], 3.000000e+00
60; CHECK-NEXT:    br label [[LOOP_LATCH:%.*]]
61; CHECK:       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
68; CHECK:       loop.exit:
69; CHECK-NEXT:    [[RES_LCSSA:%.*]] = phi double [ [[RES_1]], [[LOOP_LATCH]] ]
70; CHECK-NEXT:    ret double [[RES_LCSSA]]
71;
72
73entry:
74  br label %loop.header
75
76loop.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
84
85loop.latch:                                            ; preds = %bb366
86  %ptr = getelementptr inbounds double, ptr %arg2, i64 %iv.next
87  %lv = load double, ptr %ptr, align 8
88  br label %loop.header
89
90loop.exit:                                            ; preds = %bb366
91  %res.lcssa = phi double [ %res, %loop.header ]
92  ret double %res.lcssa
93}
94
95; We unroll the outer loop and need to preserve LI for the inner loop.
96define void @test_with_nested_loop(ptr %arg)  {
97; CHECK-LABEL: @test_with_nested_loop(
98; CHECK-NEXT:  entry:
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:%.*]]
104; CHECK:       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
137; CHECK:       exit:
138; CHECK-NEXT:    ret void
139;
140
141entry:
142  br label %outer.header
143
144outer.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
149
150inner.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
158
159outer.latch: ; preds = %inner.body
160  br label %outer.header
161
162exit:                                  ; preds = %outer.header
163  ret void
164}
165
166; We unroll the inner loop and need to preserve LI for the outer loop.
167define void @test_with_nested_loop_unroll_inner(ptr %arg)  {
168; CHECK-LABEL: @test_with_nested_loop_unroll_inner(
169; CHECK-NEXT:  entry:
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]]
178; CHECK:       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]]
185; CHECK:       exit:
186; CHECK-NEXT:    ret void
187;
188
189entry:
190  br label %outer.header
191
192outer.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
197
198inner.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
206
207outer.latch: ; preds = %inner.body
208  br label %outer.header
209
210exit:                                  ; preds = %outer.header
211  ret void
212}
213
214
215
216; Check that we do not crash for headers with non-branch instructions, e.g.
217; switch. We do not unroll in those cases.
218define void @test_switchinst_in_header() {
219; CHECK-LABEL: @test_switchinst_in_header(
220; CHECK-NEXT:  entry:
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:%.*]]
226; CHECK-NEXT:    ]
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]]
233; CHECK:       exit:
234; CHECK-NEXT:    ret void
235;
236
237entry:
238  br label %while.header
239
240while.header:                               ; preds = %while.latch, %entry
241  switch i32 undef, label %exit [
242  i32 11, label %while.body1
243  i32 5, label %while.body2
244  ]
245
246while.body1:                                ; preds = %while.header
247  unreachable
248
249while.body2:                                ; preds = %while.header
250  br label %while.latch
251
252while.latch:   								; preds = %while.body2
253  br label %while.header
254
255exit:                        			    ; preds = %while.header
256  ret void
257}
258