1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -indvars -S | FileCheck %s
3
4; PR31181: It may be necessary to drop nuw/nsw flags when moving from a
5; pre-increment comparison to a post-increment comparison.
6
7target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
8
9@a = global i32 0
10
11define i32 @test_drop_nuw() {
12; CHECK-LABEL: @test_drop_nuw(
13; CHECK-NEXT:  entry:
14; CHECK-NEXT:    br label [[LOOP:%.*]]
15; CHECK:       loop:
16; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
17; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* @a, align 4
18; CHECK-NEXT:    [[INC]] = add nsw i32 [[STOREMERGE]], 1
19; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 0
20; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
21; CHECK:       exit:
22; CHECK-NEXT:    ret i32 0
23;
24entry:
25  br label %loop
26
27loop:
28  %storemerge = phi i32 [ -2, %entry ], [ %inc, %loop ]
29  store i32 %storemerge, i32* @a
30  %cmp = icmp slt i32 %storemerge, -1
31  %inc = add nuw nsw i32 %storemerge, 1
32  br i1 %cmp, label %loop, label %exit
33
34exit:
35  ret i32 0
36}
37
38define i32 @test_drop_nsw() {
39; CHECK-LABEL: @test_drop_nsw(
40; CHECK-NEXT:  entry:
41; CHECK-NEXT:    br label [[LOOP:%.*]]
42; CHECK:       loop:
43; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
44; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* @a, align 4
45; CHECK-NEXT:    [[INC]] = add nuw i32 [[STOREMERGE]], 1
46; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[INC]], -2147483648
47; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
48; CHECK:       exit:
49; CHECK-NEXT:    ret i32 0
50;
51entry:
52  br label %loop
53
54loop:
55  %storemerge = phi i32 [ 0, %entry ], [ %inc, %loop ]
56  store i32 %storemerge, i32* @a
57  %cmp = icmp ult i32 %storemerge, 2147483647
58  %inc = add nuw nsw i32 %storemerge, 1
59  br i1 %cmp, label %loop, label %exit
60
61exit:
62  ret i32 0
63}
64
65define i32 @test_no_drop_nuw() {
66; CHECK-LABEL: @test_no_drop_nuw(
67; CHECK-NEXT:  entry:
68; CHECK-NEXT:    br label [[LOOP:%.*]]
69; CHECK:       loop:
70; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -3, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
71; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* @a, align 4
72; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[STOREMERGE]], 1
73; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[INC]], -1
74; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
75; CHECK:       exit:
76; CHECK-NEXT:    ret i32 0
77;
78entry:
79  br label %loop
80
81loop:
82  %storemerge = phi i32 [ -3, %entry ], [ %inc, %loop ]
83  store i32 %storemerge, i32* @a
84  %cmp = icmp slt i32 %storemerge, -2
85  %inc = add nuw nsw i32 %storemerge, 1
86  br i1 %cmp, label %loop, label %exit
87
88exit:
89  ret i32 0
90}
91
92
93define i32 @test_no_drop_nsw() {
94; CHECK-LABEL: @test_no_drop_nsw(
95; CHECK-NEXT:  entry:
96; CHECK-NEXT:    br label [[LOOP:%.*]]
97; CHECK:       loop:
98; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
99; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* @a, align 4
100; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[STOREMERGE]], 1
101; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 2147483647
102; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
103; CHECK:       exit:
104; CHECK-NEXT:    ret i32 0
105;
106entry:
107  br label %loop
108
109loop:
110  %storemerge = phi i32 [ 0, %entry ], [ %inc, %loop ]
111  store i32 %storemerge, i32* @a
112  %cmp = icmp ult i32 %storemerge, 2147483646
113  %inc = add nuw nsw i32 %storemerge, 1
114  br i1 %cmp, label %loop, label %exit
115
116exit:
117  ret i32 0
118}
119
120define i32 @test_no_add_nuw() {
121; CHECK-LABEL: @test_no_add_nuw(
122; CHECK-NEXT:  entry:
123; CHECK-NEXT:    br label [[LOOP:%.*]]
124; CHECK:       loop:
125; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
126; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* @a, align 4
127; CHECK-NEXT:    [[INC]] = add nsw i32 [[STOREMERGE]], 1
128; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 10
129; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
130; CHECK:       exit:
131; CHECK-NEXT:    ret i32 0
132;
133entry:
134  br label %loop
135
136loop:
137  %storemerge = phi i32 [ -1, %entry ], [ %inc, %loop ]
138  store i32 %storemerge, i32* @a
139  %cmp = icmp slt i32 %storemerge, 9
140  %inc = add i32 %storemerge, 1
141  br i1 %cmp, label %loop, label %exit
142
143exit:
144  ret i32 0
145}
146
147define i32 @test_drop_nsw_var_lim(i32 %lim) {
148; CHECK-LABEL: @test_drop_nsw_var_lim(
149; CHECK-NEXT:  entry:
150; CHECK-NEXT:    [[C:%.*]] = icmp ult i32 [[LIM:%.*]], -1
151; CHECK-NEXT:    br i1 [[C]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
152; CHECK:       loop.preheader:
153; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[LIM]], 1
154; CHECK-NEXT:    br label [[LOOP:%.*]]
155; CHECK:       loop:
156; CHECK-NEXT:    [[STOREMERGE:%.*]] = phi i32 [ [[INC:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
157; CHECK-NEXT:    store i32 [[STOREMERGE]], i32* @a, align 4
158; CHECK-NEXT:    [[INC]] = add nuw i32 [[STOREMERGE]], 1
159; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[INC]], [[TMP0]]
160; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
161; CHECK:       exit.loopexit:
162; CHECK-NEXT:    br label [[EXIT]]
163; CHECK:       exit:
164; CHECK-NEXT:    ret i32 0
165;
166entry:
167  %c = icmp ult i32 %lim, -1
168  br i1 %c, label %loop, label %exit
169
170loop:
171  %storemerge = phi i32 [ 0, %entry ], [ %inc, %loop ]
172  store i32 %storemerge, i32* @a
173  %cmp = icmp ult i32 %storemerge, %lim
174  %inc = add nuw nsw i32 %storemerge, 1
175  br i1 %cmp, label %loop, label %exit
176
177exit:
178  ret i32 0
179}
180
181; Adopted from D30446.
182; We switch from %iv to %iv2 and need to change nsw to nuw in the process.
183define i32 @switch_to_different_iv_post_inc(i32* %ptr, i1 %always_false) {
184; CHECK-LABEL: @switch_to_different_iv_post_inc(
185; CHECK-NEXT:  entry:
186; CHECK-NEXT:    br label [[FOR_COND:%.*]]
187; CHECK:       for.cond:
188; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
189; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN]] ]
190; CHECK-NEXT:    store i32 [[IV]], i32* [[PTR:%.*]], align 4
191; CHECK-NEXT:    br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
192; CHECK:       never_taken:
193; CHECK-NEXT:    store volatile i32 [[IV2]], i32* [[PTR]], align 4
194; CHECK-NEXT:    br label [[ALWAYS_TAKEN]]
195; CHECK:       always_taken:
196; CHECK-NEXT:    [[IV_INC]] = add nsw i32 [[IV]], 1
197; CHECK-NEXT:    [[IV2_INC]] = add nuw i32 [[IV2]], 1
198; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483627
199; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
200; CHECK:       for.end:
201; CHECK-NEXT:    ret i32 0
202;
203entry:
204  br label %for.cond
205
206for.cond:
207  %iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
208  %iv2 = phi i32 [ 0, %entry ], [ %iv2.inc, %always_taken ]
209  store i32 %iv, i32* %ptr
210  br i1 %always_false, label %never_taken, label %always_taken
211
212never_taken:
213  store volatile i32 %iv2, i32* %ptr
214  br label %always_taken
215
216always_taken:
217  %iv.inc = add nsw i32 %iv, 1
218  %iv2.inc = add nuw nsw i32 %iv2, 1
219  %cmp = icmp slt i32 %iv, 20
220  br i1 %cmp, label %for.cond, label %for.end
221
222for.end:
223  ret i32 0
224}
225
226; Same as previous test case, but with exit block and loop latch being distinct
227; blocks requiring the use of pre-increment.
228define i32 @switch_to_different_iv_pre_inc(i32* %ptr, i1 %always_false) {
229; CHECK-LABEL: @switch_to_different_iv_pre_inc(
230; CHECK-NEXT:  entry:
231; CHECK-NEXT:    br label [[FOR_COND:%.*]]
232; CHECK:       for.cond:
233; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
234; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN]] ]
235; CHECK-NEXT:    store i32 [[IV]], i32* [[PTR:%.*]], align 4
236; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV2]], -2147483628
237; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
238; CHECK:       for.body:
239; CHECK-NEXT:    br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
240; CHECK:       never_taken:
241; CHECK-NEXT:    store volatile i32 [[IV2]], i32* [[PTR]], align 4
242; CHECK-NEXT:    br label [[ALWAYS_TAKEN]]
243; CHECK:       always_taken:
244; CHECK-NEXT:    [[IV_INC]] = add nsw i32 [[IV]], 1
245; CHECK-NEXT:    [[IV2_INC]] = add nuw i32 [[IV2]], 1
246; CHECK-NEXT:    br label [[FOR_COND]]
247; CHECK:       for.end:
248; CHECK-NEXT:    ret i32 0
249;
250entry:
251  br label %for.cond
252
253for.cond:
254  %iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
255  %iv2 = phi i32 [ 0, %entry ], [ %iv2.inc, %always_taken ]
256  store i32 %iv, i32* %ptr
257  %cmp = icmp slt i32 %iv, 20
258  br i1 %cmp, label %for.body, label %for.end
259
260for.body:
261  br i1 %always_false, label %never_taken, label %always_taken
262
263never_taken:
264  store volatile i32 %iv2, i32* %ptr
265  br label %always_taken
266
267always_taken:
268  %iv.inc = add nsw i32 %iv, 1
269  %iv2.inc = add nuw nsw i32 %iv2, 1
270  br label %for.cond
271
272for.end:
273  ret i32 0
274}
275
276define i32 @switch_to_different_iv_first_poison(i32* %ptr, i1 %always_false) {
277; CHECK-LABEL: @switch_to_different_iv_first_poison(
278; CHECK-NEXT:  entry:
279; CHECK-NEXT:    br label [[FOR_COND:%.*]]
280; CHECK:       for.cond:
281; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
282; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN]] ]
283; CHECK-NEXT:    store i32 [[IV]], i32* [[PTR:%.*]], align 4
284; CHECK-NEXT:    br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
285; CHECK:       never_taken:
286; CHECK-NEXT:    store volatile i32 [[IV2]], i32* [[PTR]], align 4
287; CHECK-NEXT:    br label [[ALWAYS_TAKEN]]
288; CHECK:       always_taken:
289; CHECK-NEXT:    [[IV2_INC]] = add nuw nsw i32 [[IV2]], 1
290; CHECK-NEXT:    [[IV_INC]] = add nsw i32 [[IV]], 1
291; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483628
292; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
293; CHECK:       for.end:
294; CHECK-NEXT:    ret i32 0
295;
296entry:
297  br label %for.cond
298
299for.cond:
300  %iv2 = phi i32 [ -1, %entry ], [ %iv2.inc, %always_taken ]
301  %iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
302  store i32 %iv, i32* %ptr
303  br i1 %always_false, label %never_taken, label %always_taken
304
305never_taken:
306  store volatile i32 %iv2, i32* %ptr
307  br label %always_taken
308
309always_taken:
310  %iv2.inc = add nuw nsw i32 %iv2, 1
311  %iv.inc = add nsw i32 %iv, 1
312  %cmp = icmp slt i32 %iv, 20
313  br i1 %cmp, label %for.cond, label %for.end
314
315for.end:
316  ret i32 0
317}
318
319define i32 @switch_to_different_iv_second_poison(i32* %ptr, i1 %always_false) {
320; CHECK-LABEL: @switch_to_different_iv_second_poison(
321; CHECK-NEXT:  entry:
322; CHECK-NEXT:    br label [[FOR_COND:%.*]]
323; CHECK:       for.cond:
324; CHECK-NEXT:    [[IV2:%.*]] = phi i32 [ -2, [[ENTRY:%.*]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
325; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN]] ]
326; CHECK-NEXT:    store i32 [[IV]], i32* [[PTR:%.*]], align 4
327; CHECK-NEXT:    br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
328; CHECK:       never_taken:
329; CHECK-NEXT:    store volatile i32 [[IV2]], i32* [[PTR]], align 4
330; CHECK-NEXT:    br label [[ALWAYS_TAKEN]]
331; CHECK:       always_taken:
332; CHECK-NEXT:    [[IV2_INC]] = add nsw i32 [[IV2]], 1
333; CHECK-NEXT:    [[IV_INC]] = add nsw i32 [[IV]], 1
334; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483629
335; CHECK-NEXT:    br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
336; CHECK:       for.end:
337; CHECK-NEXT:    ret i32 0
338;
339entry:
340  br label %for.cond
341
342for.cond:
343  %iv2 = phi i32 [ -2, %entry ], [ %iv2.inc, %always_taken ]
344  %iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
345  store i32 %iv, i32* %ptr
346  br i1 %always_false, label %never_taken, label %always_taken
347
348never_taken:
349  store volatile i32 %iv2, i32* %ptr
350  br label %always_taken
351
352always_taken:
353  %iv2.inc = add nuw nsw i32 %iv2, 1
354  %iv.inc = add nsw i32 %iv, 1
355  %cmp = icmp slt i32 %iv, 20
356  br i1 %cmp, label %for.cond, label %for.end
357
358for.end:
359  ret i32 0
360}
361