1+ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
12; RUN: opt -S -passes=indvars < %s | FileCheck %s
23
34target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
45target triple = "x86_64-unknown-linux-gnu"
56
67define void @f_sadd (ptr %a ) {
7- ; CHECK-LABEL: @f_sadd(
8+ ; CHECK-LABEL: define void @f_sadd(
9+ ; CHECK-SAME: ptr [[A:%.*]]) {
10+ ; CHECK-NEXT: [[ENTRY:.*]]:
11+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
12+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
13+ ; CHECK-NEXT: ret void
14+ ; CHECK: [[FOR_BODY]]:
15+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 0, %[[ENTRY]] ]
16+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
17+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
18+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
19+ ; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0:![0-9]+]]
20+ ; CHECK: [[TRAP]]:
21+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
22+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
23+ ; CHECK: [[CONT]]:
24+ ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 16
25+ ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
26+ ;
827entry:
928 br label %for.body
1029
@@ -18,9 +37,6 @@ for.body: ; preds = %entry, %cont
1837 store i8 0 , ptr %arrayidx , align 1
1938 %0 = tail call { i32 , i1 } @llvm.sadd.with.overflow.i32 (i32 %i.04 , i32 1 )
2039 %1 = extractvalue { i32 , i1 } %0 , 1
21- ; CHECK: for.body:
22- ; CHECK-NOT: @llvm.sadd.with.overflow
23- ; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
2440 br i1 %1 , label %trap , label %cont , !nosanitize !{}
2541
2642trap: ; preds = %for.body
@@ -33,8 +49,71 @@ cont: ; preds = %for.body
3349 br i1 %cmp , label %for.body , label %for.cond.cleanup
3450}
3551
52+ define void @f_sadd_overflow (ptr %a ) {
53+ ; CHECK-LABEL: define void @f_sadd_overflow(
54+ ; CHECK-SAME: ptr [[A:%.*]]) {
55+ ; CHECK-NEXT: [[ENTRY:.*]]:
56+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
57+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
58+ ; CHECK-NEXT: ret void
59+ ; CHECK: [[FOR_BODY]]:
60+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 2147483645, %[[ENTRY]] ]
61+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
62+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
63+ ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV]], 2147483647
64+ ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
65+ ; CHECK: [[TRAP]]:
66+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
67+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
68+ ; CHECK: [[CONT]]:
69+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
70+ ; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
71+ ;
72+ entry:
73+ br label %for.body
74+
75+ for.cond.cleanup: ; preds = %cont
76+ ret void
77+
78+ for.body: ; preds = %entry, %cont
79+ %i.04 = phi i32 [ 2147483645 , %entry ], [ %2 , %cont ]
80+ %idxprom = sext i32 %i.04 to i64
81+ %arrayidx = getelementptr inbounds i8 , ptr %a , i64 %idxprom
82+ store i8 0 , ptr %arrayidx , align 1
83+ %0 = tail call { i32 , i1 } @llvm.sadd.with.overflow.i32 (i32 %i.04 , i32 1 )
84+ %1 = extractvalue { i32 , i1 } %0 , 1
85+ br i1 %1 , label %trap , label %cont , !nosanitize !{}
86+
87+ trap: ; preds = %for.body
88+ tail call void @llvm.trap () #2 , !nosanitize !{}
89+ unreachable , !nosanitize !{}
90+
91+ cont: ; preds = %for.body
92+ %2 = extractvalue { i32 , i1 } %0 , 0
93+ %cmp = icmp sle i32 %2 , 2147483647
94+ br i1 %cmp , label %for.body , label %for.cond.cleanup
95+ }
96+
3697define void @f_uadd (ptr %a ) {
37- ; CHECK-LABEL: @f_uadd(
98+ ; CHECK-LABEL: define void @f_uadd(
99+ ; CHECK-SAME: ptr [[A:%.*]]) {
100+ ; CHECK-NEXT: [[ENTRY:.*]]:
101+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
102+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
103+ ; CHECK-NEXT: ret void
104+ ; CHECK: [[FOR_BODY]]:
105+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 0, %[[ENTRY]] ]
106+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
107+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
108+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
109+ ; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
110+ ; CHECK: [[TRAP]]:
111+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
112+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
113+ ; CHECK: [[CONT]]:
114+ ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], 16
115+ ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
116+ ;
38117entry:
39118 br label %for.body
40119
@@ -48,9 +127,6 @@ for.body: ; preds = %entry, %cont
48127 store i8 0 , ptr %arrayidx , align 1
49128 %0 = tail call { i32 , i1 } @llvm.uadd.with.overflow.i32 (i32 %i.04 , i32 1 )
50129 %1 = extractvalue { i32 , i1 } %0 , 1
51- ; CHECK: for.body:
52- ; CHECK-NOT: @llvm.uadd.with.overflow
53- ; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
54130 br i1 %1 , label %trap , label %cont , !nosanitize !{}
55131
56132trap: ; preds = %for.body
@@ -63,8 +139,71 @@ cont: ; preds = %for.body
63139 br i1 %cmp , label %for.body , label %for.cond.cleanup
64140}
65141
142+ define void @f_uadd_overflow (ptr %a ) {
143+ ; CHECK-LABEL: define void @f_uadd_overflow(
144+ ; CHECK-SAME: ptr [[A:%.*]]) {
145+ ; CHECK-NEXT: [[ENTRY:.*]]:
146+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
147+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
148+ ; CHECK-NEXT: ret void
149+ ; CHECK: [[FOR_BODY]]:
150+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ -6, %[[ENTRY]] ]
151+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
152+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
153+ ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV]], -1
154+ ; CHECK-NEXT: br i1 [[EXITCOND]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
155+ ; CHECK: [[TRAP]]:
156+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
157+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
158+ ; CHECK: [[CONT]]:
159+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], 1
160+ ; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
161+ ;
162+ entry:
163+ br label %for.body
164+
165+ for.cond.cleanup: ; preds = %cont
166+ ret void
167+
168+ for.body: ; preds = %entry, %cont
169+ %i.04 = phi i32 [ 4294967290 , %entry ], [ %2 , %cont ]
170+ %idxprom = sext i32 %i.04 to i64
171+ %arrayidx = getelementptr inbounds i8 , ptr %a , i64 %idxprom
172+ store i8 0 , ptr %arrayidx , align 1
173+ %0 = tail call { i32 , i1 } @llvm.uadd.with.overflow.i32 (i32 %i.04 , i32 1 )
174+ %1 = extractvalue { i32 , i1 } %0 , 1
175+ br i1 %1 , label %trap , label %cont , !nosanitize !{}
176+
177+ trap: ; preds = %for.body
178+ tail call void @llvm.trap (), !nosanitize !{}
179+ unreachable , !nosanitize !{}
180+
181+ cont: ; preds = %for.body
182+ %2 = extractvalue { i32 , i1 } %0 , 0
183+ %cmp = icmp ule i32 %2 , 4294967295
184+ br i1 %cmp , label %for.body , label %for.cond.cleanup
185+ }
186+
66187define void @f_ssub (ptr nocapture %a ) {
67- ; CHECK-LABEL: @f_ssub(
188+ ; CHECK-LABEL: define void @f_ssub(
189+ ; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
190+ ; CHECK-NEXT: [[ENTRY:.*]]:
191+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
192+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
193+ ; CHECK-NEXT: ret void
194+ ; CHECK: [[FOR_BODY]]:
195+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 15, %[[ENTRY]] ]
196+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
197+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
198+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
199+ ; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
200+ ; CHECK: [[TRAP]]:
201+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
202+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
203+ ; CHECK: [[CONT]]:
204+ ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[INDVARS_IV_NEXT]], -1
205+ ; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
206+ ;
68207entry:
69208 br label %for.body
70209
@@ -78,9 +217,6 @@ for.body: ; preds = %entry, %cont
78217 store i8 0 , ptr %arrayidx , align 1
79218 %0 = tail call { i32 , i1 } @llvm.ssub.with.overflow.i32 (i32 %i.04 , i32 1 )
80219 %1 = extractvalue { i32 , i1 } %0 , 1
81- ; CHECK: for.body:
82- ; CHECK-NOT: @llvm.ssub.with.overflow.i32
83- ; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
84220 br i1 %1 , label %trap , label %cont , !nosanitize !{}
85221
86222trap: ; preds = %for.body
@@ -93,8 +229,76 @@ cont: ; preds = %for.body
93229 br i1 %cmp , label %for.body , label %for.cond.cleanup
94230}
95231
232+ ; It is theoretically possible to replace the `ssub.with.overflow` with a
233+ ; condition on the IV, but SCEV cannot represent non-unsigned-wrapping
234+ ; subtraction operations.
235+ define void @f_ssub_overflow (ptr nocapture %a ) {
236+ ; CHECK-LABEL: define void @f_ssub_overflow(
237+ ; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
238+ ; CHECK-NEXT: [[ENTRY:.*]]:
239+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
240+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
241+ ; CHECK-NEXT: ret void
242+ ; CHECK: [[FOR_BODY]]:
243+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ -2147483642, %[[ENTRY]] ]
244+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
245+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
246+ ; CHECK-NEXT: [[TMP0:%.*]] = trunc nsw i64 [[INDVARS_IV]] to i32
247+ ; CHECK-NEXT: [[TMP1:%.*]] = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[TMP0]], i32 1)
248+ ; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
249+ ; CHECK-NEXT: br i1 [[TMP2]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
250+ ; CHECK: [[TRAP]]:
251+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
252+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
253+ ; CHECK: [[CONT]]:
254+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
255+ ; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
256+ ;
257+ entry:
258+ br label %for.body
259+
260+ for.cond.cleanup: ; preds = %cont
261+ ret void
262+
263+ for.body: ; preds = %entry, %cont
264+ %i.04 = phi i32 [ -2147483642 , %entry ], [ %2 , %cont ]
265+ %idxprom = sext i32 %i.04 to i64
266+ %arrayidx = getelementptr inbounds i8 , ptr %a , i64 %idxprom
267+ store i8 0 , ptr %arrayidx , align 1
268+ %0 = tail call { i32 , i1 } @llvm.ssub.with.overflow.i32 (i32 %i.04 , i32 1 )
269+ %1 = extractvalue { i32 , i1 } %0 , 1
270+ br i1 %1 , label %trap , label %cont , !nosanitize !{}
271+
272+ trap: ; preds = %for.body
273+ tail call void @llvm.trap (), !nosanitize !{}
274+ unreachable , !nosanitize !{}
275+
276+ cont: ; preds = %for.body
277+ %2 = extractvalue { i32 , i1 } %0 , 0
278+ %cmp = icmp sge i32 %2 , -2147483648
279+ br i1 %cmp , label %for.body , label %for.cond.cleanup
280+ }
281+
96282define void @f_usub (ptr nocapture %a ) {
97- ; CHECK-LABEL: @f_usub(
283+ ; CHECK-LABEL: define void @f_usub(
284+ ; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
285+ ; CHECK-NEXT: [[ENTRY:.*]]:
286+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
287+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
288+ ; CHECK-NEXT: ret void
289+ ; CHECK: [[FOR_BODY]]:
290+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 15, %[[ENTRY]] ]
291+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
292+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
293+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
294+ ; CHECK-NEXT: br i1 false, label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
295+ ; CHECK: [[TRAP]]:
296+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
297+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
298+ ; CHECK: [[CONT]]:
299+ ; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i64 [[INDVARS_IV_NEXT]], 0
300+ ; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
301+ ;
98302entry:
99303 br label %for.body
100304
@@ -109,9 +313,6 @@ for.body: ; preds = %entry, %cont
109313 %0 = tail call { i32 , i1 } @llvm.usub.with.overflow.i32 (i32 %i.04 , i32 1 )
110314 %1 = extractvalue { i32 , i1 } %0 , 1
111315
112- ; CHECK: for.body:
113- ; CHECK-NOT: @llvm.usub.with.overflow.i32
114- ; CHECK: br i1 false, label %trap, label %cont, !nosanitize !0
115316 br i1 %1 , label %trap , label %cont , !nosanitize !{}
116317
117318trap: ; preds = %for.body
@@ -124,8 +325,31 @@ cont: ; preds = %for.body
124325 br i1 %cmp , label %for.body , label %for.cond.cleanup
125326}
126327
328+ ; It is theoretically possible to replace the `usub.with.overflow` with a
329+ ; condition on the IV, but SCEV cannot represent non-unsigned-wrapping
330+ ; subtraction operations.
127331define void @f_usub_overflow (ptr nocapture %a ) {
128- ; CHECK-LABEL: @f_usub_overflow(
332+ ; CHECK-LABEL: define void @f_usub_overflow(
333+ ; CHECK-SAME: ptr captures(none) [[A:%.*]]) {
334+ ; CHECK-NEXT: [[ENTRY:.*]]:
335+ ; CHECK-NEXT: br label %[[FOR_BODY:.*]]
336+ ; CHECK: [[FOR_COND_CLEANUP:.*]]:
337+ ; CHECK-NEXT: ret void
338+ ; CHECK: [[FOR_BODY]]:
339+ ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[CONT:.*]] ], [ 15, %[[ENTRY]] ]
340+ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDVARS_IV]]
341+ ; CHECK-NEXT: store i8 0, ptr [[ARRAYIDX]], align 1
342+ ; CHECK-NEXT: [[TMP0:%.*]] = trunc nuw nsw i64 [[INDVARS_IV]] to i32
343+ ; CHECK-NEXT: [[TMP1:%.*]] = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[TMP0]], i32 1)
344+ ; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
345+ ; CHECK-NEXT: br i1 [[TMP2]], label %[[TRAP:.*]], label %[[CONT]], !nosanitize [[META0]]
346+ ; CHECK: [[TRAP]]:
347+ ; CHECK-NEXT: tail call void @llvm.trap(), !nosanitize [[META0]]
348+ ; CHECK-NEXT: unreachable, !nosanitize [[META0]]
349+ ; CHECK: [[CONT]]:
350+ ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
351+ ; CHECK-NEXT: br i1 true, label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP]]
352+ ;
129353entry:
130354 br label %for.body
131355
@@ -139,13 +363,6 @@ for.body: ; preds = %entry, %cont
139363 store i8 0 , ptr %arrayidx , align 1
140364 %0 = tail call { i32 , i1 } @llvm.usub.with.overflow.i32 (i32 %i.04 , i32 1 )
141365 %1 = extractvalue { i32 , i1 } %0 , 1
142-
143- ; It is theoretically possible to prove this, but SCEV cannot
144- ; represent non-unsigned-wrapping subtraction operations.
145-
146- ; CHECK: for.body:
147- ; CHECK: [[COND:%[^ ]+]] = extractvalue { i32, i1 } %1, 1
148- ; CHECK-NEXT: br i1 [[COND]], label %trap, label %cont, !nosanitize !0
149366 br i1 %1 , label %trap , label %cont , !nosanitize !{}
150367
151368trap: ; preds = %for.body
@@ -166,3 +383,6 @@ declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) nounwind readnone
166383declare { i32 , i1 } @llvm.umul.with.overflow.i32 (i32 , i32 ) nounwind readnone
167384
168385declare void @llvm.trap () #2
386+ ;.
387+ ; CHECK: [[META0]] = !{}
388+ ;.
0 commit comments