[rtsan] Add fork/execve interceptors (#117198)
[llvm-project.git] / llvm / test / Transforms / SCCP / with.overflow.ll
bloba345f226ed035b3c50d809363ed4babd5a1b064d
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes=sccp < %s | FileCheck %s
4 declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8)
5 declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8)
6 declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8)
7 declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8)
8 declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8)
9 declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8)
10 declare { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8>, <2 x i8>)
11 declare void @use.i1(i1)
13 define void @unsigned_overflow(ptr %p) {
14 ; CHECK-LABEL: @unsigned_overflow(
15 ; CHECK-NEXT:    [[V0_100:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG0:![0-9]+]]
16 ; CHECK-NEXT:    [[V0_155:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG1:![0-9]+]]
17 ; CHECK-NEXT:    [[V0_156:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG2:![0-9]+]]
18 ; CHECK-NEXT:    [[V100_255:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG3:![0-9]+]]
19 ; CHECK-NEXT:    [[V99_255:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG4:![0-9]+]]
20 ; CHECK-NEXT:    [[V1_2:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG5:![0-9]+]]
21 ; CHECK-NEXT:    [[V1_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6:![0-9]+]]
22 ; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_155]])
23 ; CHECK-NEXT:    call void @use.i1(i1 false)
24 ; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_156]])
25 ; CHECK-NEXT:    [[OV2:%.*]] = extractvalue { i8, i1 } [[WO2]], 1
26 ; CHECK-NEXT:    call void @use.i1(i1 [[OV2]])
27 ; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V100_255]], i8 [[V0_100]])
28 ; CHECK-NEXT:    call void @use.i1(i1 false)
29 ; CHECK-NEXT:    [[WO4:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V99_255]], i8 [[V0_100]])
30 ; CHECK-NEXT:    [[OV4:%.*]] = extractvalue { i8, i1 } [[WO4]], 1
31 ; CHECK-NEXT:    call void @use.i1(i1 [[OV4]])
32 ; CHECK-NEXT:    [[WO5:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V0_100]], i8 [[V1_2]])
33 ; CHECK-NEXT:    call void @use.i1(i1 false)
34 ; CHECK-NEXT:    [[WO6:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V0_100]], i8 [[V1_3]])
35 ; CHECK-NEXT:    [[OV6:%.*]] = extractvalue { i8, i1 } [[WO6]], 1
36 ; CHECK-NEXT:    call void @use.i1(i1 [[OV6]])
37 ; CHECK-NEXT:    ret void
39   %v0_100 = load i8, ptr %p, !range !{i8 0, i8 101}
40   %v0_155 = load i8, ptr %p, !range !{i8 0, i8 156}
41   %v0_156 = load i8, ptr %p, !range !{i8 0, i8 157}
42   %v100_255 = load i8, ptr %p, !range !{i8 100, i8 0}
43   %v99_255 = load i8, ptr %p, !range !{i8 99, i8 0}
44   %v1_2 = load i8, ptr %p, !range !{i8 1, i8 3}
45   %v1_3 = load i8, ptr %p, !range !{i8 1, i8 4}
47   %wo1 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_100, i8 %v0_155)
48   %ov1 = extractvalue { i8, i1 } %wo1, 1
49   call void @use.i1(i1 %ov1)
51   %wo2 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_100, i8 %v0_156)
52   %ov2 = extractvalue { i8, i1 } %wo2, 1
53   call void @use.i1(i1 %ov2)
55   %wo3 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v100_255, i8 %v0_100)
56   %ov3 = extractvalue { i8, i1 } %wo3, 1
57   call void @use.i1(i1 %ov3)
59   %wo4 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v99_255, i8 %v0_100)
60   %ov4 = extractvalue { i8, i1 } %wo4, 1
61   call void @use.i1(i1 %ov4)
63   %wo5 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v0_100, i8 %v1_2)
64   %ov5 = extractvalue { i8, i1 } %wo5, 1
65   call void @use.i1(i1 %ov5)
67   %wo6 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v0_100, i8 %v1_3)
68   %ov6 = extractvalue { i8, i1 } %wo6, 1
69   call void @use.i1(i1 %ov6)
70   ret void
73 define void @signed_overflow(ptr %p) {
74 ; CHECK-LABEL: @signed_overflow(
75 ; CHECK-NEXT:    [[V0_100:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG0]]
76 ; CHECK-NEXT:    [[V0_27:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG7:![0-9]+]]
77 ; CHECK-NEXT:    [[V0_28:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG8:![0-9]+]]
78 ; CHECK-NEXT:    [[VM27_0:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG9:![0-9]+]]
79 ; CHECK-NEXT:    [[VM28_0:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG10:![0-9]+]]
80 ; CHECK-NEXT:    [[V1_4:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG11:![0-9]+]]
81 ; CHECK-NEXT:    [[V1_5:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG12:![0-9]+]]
82 ; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_27]])
83 ; CHECK-NEXT:    call void @use.i1(i1 false)
84 ; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_28]])
85 ; CHECK-NEXT:    [[OV2:%.*]] = extractvalue { i8, i1 } [[WO2]], 1
86 ; CHECK-NEXT:    call void @use.i1(i1 [[OV2]])
87 ; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_100]], i8 [[VM27_0]])
88 ; CHECK-NEXT:    call void @use.i1(i1 false)
89 ; CHECK-NEXT:    [[WO4:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_100]], i8 [[VM28_0]])
90 ; CHECK-NEXT:    [[OV4:%.*]] = extractvalue { i8, i1 } [[WO4]], 1
91 ; CHECK-NEXT:    call void @use.i1(i1 [[OV4]])
92 ; CHECK-NEXT:    [[WO5:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V0_27]], i8 [[V1_4]])
93 ; CHECK-NEXT:    call void @use.i1(i1 false)
94 ; CHECK-NEXT:    [[WO6:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V0_27]], i8 [[V1_5]])
95 ; CHECK-NEXT:    [[OV6:%.*]] = extractvalue { i8, i1 } [[WO6]], 1
96 ; CHECK-NEXT:    call void @use.i1(i1 [[OV6]])
97 ; CHECK-NEXT:    ret void
99   %v0_100 = load i8, ptr %p, !range !{i8 0, i8 101}
100   %v0_27 = load i8, ptr %p, !range !{i8 0, i8 28}
101   %v0_28 = load i8, ptr %p, !range !{i8 0, i8 29}
102   %vm27_0 = load i8, ptr %p, !range !{i8 -27, i8 0}
103   %vm28_0 = load i8, ptr %p, !range !{i8 -28, i8 0}
104   %v1_4 = load i8, ptr %p, !range !{i8 1, i8 5}
105   %v1_5 = load i8, ptr %p, !range !{i8 1, i8 6}
107   %wo1 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_100, i8 %v0_27)
108   %ov1 = extractvalue { i8, i1 } %wo1, 1
109   call void @use.i1(i1 %ov1)
111   %wo2 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_100, i8 %v0_28)
112   %ov2 = extractvalue { i8, i1 } %wo2, 1
113   call void @use.i1(i1 %ov2)
115   %wo3 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_100, i8 %vm27_0)
116   %ov3 = extractvalue { i8, i1 } %wo3, 1
117   call void @use.i1(i1 %ov3)
119   %wo4 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_100, i8 %vm28_0)
120   %ov4 = extractvalue { i8, i1 } %wo4, 1
121   call void @use.i1(i1 %ov4)
123   %wo5 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v0_27, i8 %v1_4)
124   %ov5 = extractvalue { i8, i1 } %wo5, 1
125   call void @use.i1(i1 %ov5)
127   %wo6 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v0_27, i8 %v1_5)
128   %ov6 = extractvalue { i8, i1 } %wo6, 1
129   call void @use.i1(i1 %ov6)
130   ret void
133 define void @unsigned_result(ptr %p) {
134 ; CHECK-LABEL: @unsigned_result(
135 ; CHECK-NEXT:    [[V0_20:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG13:![0-9]+]]
136 ; CHECK-NEXT:    [[V20_40:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG14:![0-9]+]]
137 ; CHECK-NEXT:    [[V0_10:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG15:![0-9]+]]
138 ; CHECK-NEXT:    [[V2_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG16:![0-9]+]]
139 ; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_20]], i8 [[V20_40]])
140 ; CHECK-NEXT:    [[RES1:%.*]] = extractvalue { i8, i1 } [[WO1]], 0
141 ; CHECK-NEXT:    call void @use.i1(i1 true)
142 ; CHECK-NEXT:    call void @use.i1(i1 true)
143 ; CHECK-NEXT:    [[CMP1_3:%.*]] = icmp ugt i8 [[RES1]], 20
144 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_3]])
145 ; CHECK-NEXT:    [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60
146 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_4]])
147 ; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V0_10]], i8 [[V20_40]])
148 ; CHECK-NEXT:    [[RES2:%.*]] = extractvalue { i8, i1 } [[WO2]], 0
149 ; CHECK-NEXT:    call void @use.i1(i1 true)
150 ; CHECK-NEXT:    call void @use.i1(i1 true)
151 ; CHECK-NEXT:    [[CMP2_3:%.*]] = icmp ugt i8 [[RES2]], -40
152 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_3]])
153 ; CHECK-NEXT:    [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10
154 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_4]])
155 ; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V20_40]], i8 [[V2_3]])
156 ; CHECK-NEXT:    [[RES3:%.*]] = extractvalue { i8, i1 } [[WO3]], 0
157 ; CHECK-NEXT:    call void @use.i1(i1 true)
158 ; CHECK-NEXT:    call void @use.i1(i1 true)
159 ; CHECK-NEXT:    [[CMP3_3:%.*]] = icmp ugt i8 [[RES3]], 40
160 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_3]])
161 ; CHECK-NEXT:    [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120
162 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_4]])
163 ; CHECK-NEXT:    ret void
165   %v0_20 = load i8, ptr %p, !range !{i8 0, i8 21}
166   %v20_40 = load i8, ptr %p, !range !{i8 20, i8 41}
167   %v0_10 = load i8, ptr %p, !range !{i8 0, i8 11}
168   %v2_3 = load i8, ptr %p, !range !{i8 2, i8 4}
169   %wo1 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_20, i8 %v20_40)
170   %res1 = extractvalue { i8, i1 } %wo1, 0
171   %cmp1.1 = icmp uge i8 %res1, 20
172   call void @use.i1(i1 %cmp1.1)
173   %cmp1.2 = icmp ule i8 %res1, 60
174   call void @use.i1(i1 %cmp1.2)
175   %cmp1.3 = icmp ugt i8 %res1, 20
176   call void @use.i1(i1 %cmp1.3)
177   %cmp1.4 = icmp ult i8 %res1, 60
178   call void @use.i1(i1 %cmp1.4)
180   ; This case actually does overflow, but we can still determine the range.
181   %wo2 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v0_10, i8 %v20_40)
182   %res2 = extractvalue { i8, i1 } %wo2, 0
183   %cmp2.1 = icmp uge i8 %res2, -40
184   call void @use.i1(i1 %cmp2.1)
185   %cmp2.2 = icmp ule i8 %res2, -10
186   call void @use.i1(i1 %cmp2.2)
187   %cmp2.3 = icmp ugt i8 %res2, -40
188   call void @use.i1(i1 %cmp2.3)
189   %cmp2.4 = icmp ult i8 %res2, -10
190   call void @use.i1(i1 %cmp2.4)
192   %wo3 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v20_40, i8 %v2_3)
193   %res3 = extractvalue { i8, i1 } %wo3, 0
194   %cmp3.1 = icmp uge i8 %res3, 40
195   call void @use.i1(i1 %cmp3.1)
196   %cmp3.2 = icmp ule i8 %res3, 120
197   call void @use.i1(i1 %cmp3.2)
198   %cmp3.3 = icmp ugt i8 %res3, 40
199   call void @use.i1(i1 %cmp3.3)
200   %cmp3.4 = icmp ult i8 %res3, 120
201   call void @use.i1(i1 %cmp3.4)
202   ret void
205 define void @signed_result(ptr %p) {
206 ; CHECK-LABEL: @signed_result(
207 ; CHECK-NEXT:    [[V0_20:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG13]]
208 ; CHECK-NEXT:    [[V20_40:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG14]]
209 ; CHECK-NEXT:    [[V0_10:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG15]]
210 ; CHECK-NEXT:    [[V2_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG16]]
211 ; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_20]], i8 [[V20_40]])
212 ; CHECK-NEXT:    [[RES1:%.*]] = extractvalue { i8, i1 } [[WO1]], 0
213 ; CHECK-NEXT:    call void @use.i1(i1 true)
214 ; CHECK-NEXT:    call void @use.i1(i1 true)
215 ; CHECK-NEXT:    [[CMP1_3:%.*]] = icmp ugt i8 [[RES1]], 20
216 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_3]])
217 ; CHECK-NEXT:    [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60
218 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_4]])
219 ; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_10]], i8 [[V20_40]])
220 ; CHECK-NEXT:    [[RES2:%.*]] = extractvalue { i8, i1 } [[WO2]], 0
221 ; CHECK-NEXT:    call void @use.i1(i1 true)
222 ; CHECK-NEXT:    call void @use.i1(i1 true)
223 ; CHECK-NEXT:    [[CMP2_3:%.*]] = icmp ugt i8 [[RES2]], -40
224 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_3]])
225 ; CHECK-NEXT:    [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10
226 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_4]])
227 ; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V20_40]], i8 [[V2_3]])
228 ; CHECK-NEXT:    [[RES3:%.*]] = extractvalue { i8, i1 } [[WO3]], 0
229 ; CHECK-NEXT:    call void @use.i1(i1 true)
230 ; CHECK-NEXT:    call void @use.i1(i1 true)
231 ; CHECK-NEXT:    [[CMP3_3:%.*]] = icmp ugt i8 [[RES3]], 40
232 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_3]])
233 ; CHECK-NEXT:    [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120
234 ; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_4]])
235 ; CHECK-NEXT:    ret void
237   %v0_20 = load i8, ptr %p, !range !{i8 0, i8 21}
238   %v20_40 = load i8, ptr %p, !range !{i8 20, i8 41}
239   %v0_10 = load i8, ptr %p, !range !{i8 0, i8 11}
240   %v2_3 = load i8, ptr %p, !range !{i8 2, i8 4}
241   %wo1 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_20, i8 %v20_40)
242   %res1 = extractvalue { i8, i1 } %wo1, 0
243   %cmp1.1 = icmp uge i8 %res1, 20
244   call void @use.i1(i1 %cmp1.1)
245   %cmp1.2 = icmp ule i8 %res1, 60
246   call void @use.i1(i1 %cmp1.2)
247   %cmp1.3 = icmp ugt i8 %res1, 20
248   call void @use.i1(i1 %cmp1.3)
249   %cmp1.4 = icmp ult i8 %res1, 60
250   call void @use.i1(i1 %cmp1.4)
252   %wo2 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_10, i8 %v20_40)
253   %res2 = extractvalue { i8, i1 } %wo2, 0
254   %cmp2.1 = icmp uge i8 %res2, -40
255   call void @use.i1(i1 %cmp2.1)
256   %cmp2.2 = icmp ule i8 %res2, -10
257   call void @use.i1(i1 %cmp2.2)
258   %cmp2.3 = icmp ugt i8 %res2, -40
259   call void @use.i1(i1 %cmp2.3)
260   %cmp2.4 = icmp ult i8 %res2, -10
261   call void @use.i1(i1 %cmp2.4)
263   %wo3 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v20_40, i8 %v2_3)
264   %res3 = extractvalue { i8, i1 } %wo3, 0
265   %cmp3.1 = icmp uge i8 %res3, 40
266   call void @use.i1(i1 %cmp3.1)
267   %cmp3.2 = icmp ule i8 %res3, 120
268   call void @use.i1(i1 %cmp3.2)
269   %cmp3.3 = icmp ugt i8 %res3, 40
270   call void @use.i1(i1 %cmp3.3)
271   %cmp3.4 = icmp ult i8 %res3, 120
272   call void @use.i1(i1 %cmp3.4)
273   ret void
276 ; SCCP doesn't really support vector ranges yet, just make sure we don't crash.
277 define <2 x i1> @vec(<2 x i8> %v1, <2 x i8> %v2) {
278 ; CHECK-LABEL: @vec(
279 ; CHECK-NEXT:    [[WO:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[V1:%.*]], <2 x i8> [[V2:%.*]])
280 ; CHECK-NEXT:    [[OV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[WO]], 1
281 ; CHECK-NEXT:    ret <2 x i1> [[OV]]
283   %wo = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> %v1, <2 x i8> %v2)
284   %ov = extractvalue { <2 x i8>, <2 x i1> } %wo, 1
285   ret <2 x i1> %ov