1; RUN: opt -S -indvars < %s | FileCheck %s
2
3target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
4target triple = "x86_64-unknown-linux-gnu"
5
6define void @f_sadd(i8* %a) {
7; CHECK-LABEL: @f_sadd(
8entry:
9  br label %for.body
10
11for.cond.cleanup:                                 ; preds = %cont
12  ret void
13
14for.body:                                         ; preds = %entry, %cont
15  %i.04 = phi i32 [ 0, %entry ], [ %2, %cont ]
16  %idxprom = sext i32 %i.04 to i64
17  %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom
18  store i8 0, i8* %arrayidx, align 1
19  %0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %i.04, i32 1)
20  %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
24  br i1 %1, label %trap, label %cont, !nosanitize !{}
25
26trap:                                             ; preds = %for.body
27  tail call void @llvm.trap() #2, !nosanitize !{}
28  unreachable, !nosanitize !{}
29
30cont:                                             ; preds = %for.body
31  %2 = extractvalue { i32, i1 } %0, 0
32  %cmp = icmp slt i32 %2, 16
33  br i1 %cmp, label %for.body, label %for.cond.cleanup
34}
35
36define void @f_uadd(i8* %a) {
37; CHECK-LABEL: @f_uadd(
38entry:
39  br label %for.body
40
41for.cond.cleanup:                                 ; preds = %cont
42  ret void
43
44for.body:                                         ; preds = %entry, %cont
45  %i.04 = phi i32 [ 0, %entry ], [ %2, %cont ]
46  %idxprom = sext i32 %i.04 to i64
47  %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom
48  store i8 0, i8* %arrayidx, align 1
49  %0 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %i.04, i32 1)
50  %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
54  br i1 %1, label %trap, label %cont, !nosanitize !{}
55
56trap:                                             ; preds = %for.body
57  tail call void @llvm.trap(), !nosanitize !{}
58  unreachable, !nosanitize !{}
59
60cont:                                             ; preds = %for.body
61  %2 = extractvalue { i32, i1 } %0, 0
62  %cmp = icmp slt i32 %2, 16
63  br i1 %cmp, label %for.body, label %for.cond.cleanup
64}
65
66define void @f_ssub(i8* nocapture %a) {
67; CHECK-LABEL: @f_ssub(
68entry:
69  br label %for.body
70
71for.cond.cleanup:                                 ; preds = %cont
72  ret void
73
74for.body:                                         ; preds = %entry, %cont
75  %i.04 = phi i32 [ 15, %entry ], [ %2, %cont ]
76  %idxprom = sext i32 %i.04 to i64
77  %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom
78  store i8 0, i8* %arrayidx, align 1
79  %0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %i.04, i32 1)
80  %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
84  br i1 %1, label %trap, label %cont, !nosanitize !{}
85
86trap:                                             ; preds = %for.body
87  tail call void @llvm.trap(), !nosanitize !{}
88  unreachable, !nosanitize !{}
89
90cont:                                             ; preds = %for.body
91  %2 = extractvalue { i32, i1 } %0, 0
92  %cmp = icmp sgt i32 %2, -1
93  br i1 %cmp, label %for.body, label %for.cond.cleanup
94}
95
96define void @f_usub(i8* nocapture %a) {
97; CHECK-LABEL: @f_usub(
98entry:
99  br label %for.body
100
101for.cond.cleanup:                                 ; preds = %cont
102  ret void
103
104for.body:                                         ; preds = %entry, %cont
105  %i.04 = phi i32 [ 15, %entry ], [ %2, %cont ]
106  %idxprom = sext i32 %i.04 to i64
107  %arrayidx = getelementptr inbounds i8, i8* %a, i64 %idxprom
108  store i8 0, i8* %arrayidx, align 1
109  %0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %i.04, i32 1)
110  %1 = extractvalue { i32, i1 } %0, 1
111
112; It is theoretically possible to prove this, but SCEV cannot
113; represent non-unsigned-wrapping subtraction operations.
114
115; CHECK: for.body:
116; CHECK:  [[COND:%[^ ]+]] = extractvalue { i32, i1 } %1, 1
117; CHECK-NEXT:  br i1 [[COND]], label %trap, label %cont, !nosanitize !0
118  br i1 %1, label %trap, label %cont, !nosanitize !{}
119
120trap:                                             ; preds = %for.body
121  tail call void @llvm.trap(), !nosanitize !{}
122  unreachable, !nosanitize !{}
123
124cont:                                             ; preds = %for.body
125  %2 = extractvalue { i32, i1 } %0, 0
126  %cmp = icmp sgt i32 %2, -1
127  br i1 %cmp, label %for.body, label %for.cond.cleanup
128}
129
130declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) nounwind readnone
131declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32) nounwind readnone
132declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32) nounwind readnone
133declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32) nounwind readnone
134declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) nounwind readnone
135declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) nounwind readnone
136
137declare void @llvm.trap() #2
138