1 | // Test CodeGen for Security Check Overflow Builtins. |
2 | // rdar://13421498 |
3 | |
4 | // RUN: %clang_cc1 -triple "i686-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck %s |
5 | // RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck %s |
6 | // RUN: %clang_cc1 -triple "x86_64-mingw32" -emit-llvm -x c %s -o - | FileCheck %s |
7 | |
8 | extern unsigned UnsignedErrorCode; |
9 | extern unsigned long UnsignedLongErrorCode; |
10 | extern unsigned long long UnsignedLongLongErrorCode; |
11 | extern int IntErrorCode; |
12 | extern long LongErrorCode; |
13 | extern long long LongLongErrorCode; |
14 | void overflowed(void); |
15 | |
16 | unsigned test_add_overflow_uint_uint_uint(unsigned x, unsigned y) { |
17 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_add_overflow_uint_uint_uint |
18 | // CHECK-NOT: ext |
19 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
20 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
21 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
22 | // CHECK: store i32 [[Q]], i32* |
23 | // CHECK: br i1 [[C]] |
24 | unsigned r; |
25 | if (__builtin_add_overflow(x, y, &r)) |
26 | overflowed(); |
27 | return r; |
28 | } |
29 | |
30 | int test_add_overflow_int_int_int(int x, int y) { |
31 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_add_overflow_int_int_int |
32 | // CHECK-NOT: ext |
33 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
34 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
35 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
36 | // CHECK: store i32 [[Q]], i32* |
37 | // CHECK: br i1 [[C]] |
38 | int r; |
39 | if (__builtin_add_overflow(x, y, &r)) |
40 | overflowed(); |
41 | return r; |
42 | } |
43 | |
44 | unsigned test_sub_overflow_uint_uint_uint(unsigned x, unsigned y) { |
45 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_sub_overflow_uint_uint_uint |
46 | // CHECK-NOT: ext |
47 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
48 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
49 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
50 | // CHECK: store i32 [[Q]], i32* |
51 | // CHECK: br i1 [[C]] |
52 | unsigned r; |
53 | if (__builtin_sub_overflow(x, y, &r)) |
54 | overflowed(); |
55 | return r; |
56 | } |
57 | |
58 | int test_sub_overflow_int_int_int(int x, int y) { |
59 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_sub_overflow_int_int_int |
60 | // CHECK-NOT: ext |
61 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
62 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
63 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
64 | // CHECK: store i32 [[Q]], i32* |
65 | // CHECK: br i1 [[C]] |
66 | int r; |
67 | if (__builtin_sub_overflow(x, y, &r)) |
68 | overflowed(); |
69 | return r; |
70 | } |
71 | |
72 | unsigned test_mul_overflow_uint_uint_uint(unsigned x, unsigned y) { |
73 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_mul_overflow_uint_uint_uint |
74 | // CHECK-NOT: ext |
75 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
76 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
77 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
78 | // CHECK: store i32 [[Q]], i32* |
79 | // CHECK: br i1 [[C]] |
80 | unsigned r; |
81 | if (__builtin_mul_overflow(x, y, &r)) |
82 | overflowed(); |
83 | return r; |
84 | } |
85 | |
86 | int test_mul_overflow_int_int_int(int x, int y) { |
87 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_mul_overflow_int_int_int |
88 | // CHECK-NOT: ext |
89 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
90 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
91 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
92 | // CHECK: store i32 [[Q]], i32* |
93 | // CHECK: br i1 [[C]] |
94 | int r; |
95 | if (__builtin_mul_overflow(x, y, &r)) |
96 | overflowed(); |
97 | return r; |
98 | } |
99 | |
100 | int test_add_overflow_uint_int_int(unsigned x, int y) { |
101 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_add_overflow_uint_int_int |
102 | // CHECK: [[XE:%.+]] = zext i32 %{{.+}} to i33 |
103 | // CHECK: [[YE:%.+]] = sext i32 %{{.+}} to i33 |
104 | // CHECK: [[S:%.+]] = call { i33, i1 } @llvm.sadd.with.overflow.i33(i33 [[XE]], i33 [[YE]]) |
105 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i33, i1 } [[S]], 0 |
106 | // CHECK-DAG: [[C1:%.+]] = extractvalue { i33, i1 } [[S]], 1 |
107 | // CHECK: [[QT:%.+]] = trunc i33 [[Q]] to i32 |
108 | // CHECK: [[QTE:%.+]] = sext i32 [[QT]] to i33 |
109 | // CHECK: [[C2:%.+]] = icmp ne i33 [[Q]], [[QTE]] |
110 | // CHECK: [[C3:%.+]] = or i1 [[C1]], [[C2]] |
111 | // CHECK: store i32 [[QT]], i32* |
112 | // CHECK: br i1 [[C3]] |
113 | int r; |
114 | if (__builtin_add_overflow(x, y, &r)) |
115 | overflowed(); |
116 | return r; |
117 | } |
118 | |
119 | _Bool test_add_overflow_uint_uint_bool(unsigned x, unsigned y) { |
120 | // CHECK-LABEL: define {{.*}} i1 @test_add_overflow_uint_uint_bool |
121 | // CHECK-NOT: ext |
122 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
123 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
124 | // CHECK-DAG: [[C1:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
125 | // CHECK: [[QT:%.+]] = trunc i32 [[Q]] to i1 |
126 | // CHECK: [[QTE:%.+]] = zext i1 [[QT]] to i32 |
127 | // CHECK: [[C2:%.+]] = icmp ne i32 [[Q]], [[QTE]] |
128 | // CHECK: [[C3:%.+]] = or i1 [[C1]], [[C2]] |
129 | // CHECK: [[QT2:%.+]] = zext i1 [[QT]] to i8 |
130 | // CHECK: store i8 [[QT2]], i8* |
131 | // CHECK: br i1 [[C3]] |
132 | _Bool r; |
133 | if (__builtin_add_overflow(x, y, &r)) |
134 | overflowed(); |
135 | return r; |
136 | } |
137 | |
138 | unsigned test_add_overflow_bool_bool_uint(_Bool x, _Bool y) { |
139 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_add_overflow_bool_bool_uint |
140 | // CHECK: [[XE:%.+]] = zext i1 %{{.+}} to i32 |
141 | // CHECK: [[YE:%.+]] = zext i1 %{{.+}} to i32 |
142 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[XE]], i32 [[YE]]) |
143 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
144 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
145 | // CHECK: store i32 [[Q]], i32* |
146 | // CHECK: br i1 [[C]] |
147 | unsigned r; |
148 | if (__builtin_add_overflow(x, y, &r)) |
149 | overflowed(); |
150 | return r; |
151 | } |
152 | |
153 | _Bool test_add_overflow_bool_bool_bool(_Bool x, _Bool y) { |
154 | // CHECK-LABEL: define {{.*}} i1 @test_add_overflow_bool_bool_bool |
155 | // CHECK: [[S:%.+]] = call { i1, i1 } @llvm.uadd.with.overflow.i1(i1 %{{.+}}, i1 %{{.+}}) |
156 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i1, i1 } [[S]], 0 |
157 | // CHECK-DAG: [[C:%.+]] = extractvalue { i1, i1 } [[S]], 1 |
158 | // CHECK: [[QT2:%.+]] = zext i1 [[Q]] to i8 |
159 | // CHECK: store i8 [[QT2]], i8* |
160 | // CHECK: br i1 [[C]] |
161 | _Bool r; |
162 | if (__builtin_add_overflow(x, y, &r)) |
163 | overflowed(); |
164 | return r; |
165 | } |
166 | |
167 | int test_add_overflow_volatile(int x, int y) { |
168 | // CHECK-LABEL: define {{(dso_local )?}}i32 @test_add_overflow_volatile |
169 | // CHECK: [[S:%.+]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
170 | // CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0 |
171 | // CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1 |
172 | // CHECK: store volatile i32 [[Q]], i32* |
173 | // CHECK: br i1 [[C]] |
174 | volatile int result; |
175 | if (__builtin_add_overflow(x, y, &result)) |
176 | overflowed(); |
177 | return result; |
178 | } |
179 | |
180 | unsigned test_uadd_overflow(unsigned x, unsigned y) { |
181 | // CHECK: @test_uadd_overflow |
182 | // CHECK: %{{.+}} = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
183 | unsigned result; |
184 | if (__builtin_uadd_overflow(x, y, &result)) |
185 | return UnsignedErrorCode; |
186 | return result; |
187 | } |
188 | |
189 | unsigned long test_uaddl_overflow(unsigned long x, unsigned long y) { |
190 | // CHECK: @test_uaddl_overflow([[UL:i32|i64]] %x |
191 | // CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.uadd.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}}) |
192 | unsigned long result; |
193 | if (__builtin_uaddl_overflow(x, y, &result)) |
194 | return UnsignedLongErrorCode; |
195 | return result; |
196 | } |
197 | |
198 | unsigned long long test_uaddll_overflow(unsigned long long x, unsigned long long y) { |
199 | // CHECK: @test_uaddll_overflow |
200 | // CHECK: %{{.+}} = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}}) |
201 | unsigned long long result; |
202 | if (__builtin_uaddll_overflow(x, y, &result)) |
203 | return UnsignedLongLongErrorCode; |
204 | return result; |
205 | } |
206 | |
207 | unsigned test_usub_overflow(unsigned x, unsigned y) { |
208 | // CHECK: @test_usub_overflow |
209 | // CHECK: %{{.+}} = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
210 | unsigned result; |
211 | if (__builtin_usub_overflow(x, y, &result)) |
212 | return UnsignedErrorCode; |
213 | return result; |
214 | } |
215 | |
216 | unsigned long test_usubl_overflow(unsigned long x, unsigned long y) { |
217 | // CHECK: @test_usubl_overflow([[UL:i32|i64]] %x |
218 | // CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.usub.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}}) |
219 | unsigned long result; |
220 | if (__builtin_usubl_overflow(x, y, &result)) |
221 | return UnsignedLongErrorCode; |
222 | return result; |
223 | } |
224 | |
225 | unsigned long long test_usubll_overflow(unsigned long long x, unsigned long long y) { |
226 | // CHECK: @test_usubll_overflow |
227 | // CHECK: %{{.+}} = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}}) |
228 | unsigned long long result; |
229 | if (__builtin_usubll_overflow(x, y, &result)) |
230 | return UnsignedLongLongErrorCode; |
231 | return result; |
232 | } |
233 | |
234 | unsigned test_umul_overflow(unsigned x, unsigned y) { |
235 | // CHECK: @test_umul_overflow |
236 | // CHECK: %{{.+}} = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
237 | unsigned result; |
238 | if (__builtin_umul_overflow(x, y, &result)) |
239 | return UnsignedErrorCode; |
240 | return result; |
241 | } |
242 | |
243 | unsigned long test_umull_overflow(unsigned long x, unsigned long y) { |
244 | // CHECK: @test_umull_overflow([[UL:i32|i64]] %x |
245 | // CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.umul.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}}) |
246 | unsigned long result; |
247 | if (__builtin_umull_overflow(x, y, &result)) |
248 | return UnsignedLongErrorCode; |
249 | return result; |
250 | } |
251 | |
252 | unsigned long long test_umulll_overflow(unsigned long long x, unsigned long long y) { |
253 | // CHECK: @test_umulll_overflow |
254 | // CHECK: %{{.+}} = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}}) |
255 | unsigned long long result; |
256 | if (__builtin_umulll_overflow(x, y, &result)) |
257 | return UnsignedLongLongErrorCode; |
258 | return result; |
259 | } |
260 | |
261 | int test_sadd_overflow(int x, int y) { |
262 | // CHECK: @test_sadd_overflow |
263 | // CHECK: %{{.+}} = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
264 | int result; |
265 | if (__builtin_sadd_overflow(x, y, &result)) |
266 | return IntErrorCode; |
267 | return result; |
268 | } |
269 | |
270 | long test_saddl_overflow(long x, long y) { |
271 | // CHECK: @test_saddl_overflow([[UL:i32|i64]] %x |
272 | // CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.sadd.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}}) |
273 | long result; |
274 | if (__builtin_saddl_overflow(x, y, &result)) |
275 | return LongErrorCode; |
276 | return result; |
277 | } |
278 | |
279 | long long test_saddll_overflow(long long x, long long y) { |
280 | // CHECK: @test_saddll_overflow |
281 | // CHECK: %{{.+}} = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}}) |
282 | long long result; |
283 | if (__builtin_saddll_overflow(x, y, &result)) |
284 | return LongLongErrorCode; |
285 | return result; |
286 | } |
287 | |
288 | int test_ssub_overflow(int x, int y) { |
289 | // CHECK: @test_ssub_overflow |
290 | // CHECK: %{{.+}} = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
291 | int result; |
292 | if (__builtin_ssub_overflow(x, y, &result)) |
293 | return IntErrorCode; |
294 | return result; |
295 | } |
296 | |
297 | long test_ssubl_overflow(long x, long y) { |
298 | // CHECK: @test_ssubl_overflow([[UL:i32|i64]] %x |
299 | // CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.ssub.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}}) |
300 | long result; |
301 | if (__builtin_ssubl_overflow(x, y, &result)) |
302 | return LongErrorCode; |
303 | return result; |
304 | } |
305 | |
306 | long long test_ssubll_overflow(long long x, long long y) { |
307 | // CHECK: @test_ssubll_overflow |
308 | // CHECK: %{{.+}} = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}}) |
309 | long long result; |
310 | if (__builtin_ssubll_overflow(x, y, &result)) |
311 | return LongLongErrorCode; |
312 | return result; |
313 | } |
314 | |
315 | int test_smul_overflow(int x, int y) { |
316 | // CHECK: @test_smul_overflow |
317 | // CHECK: %{{.+}} = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}}) |
318 | int result; |
319 | if (__builtin_smul_overflow(x, y, &result)) |
320 | return IntErrorCode; |
321 | return result; |
322 | } |
323 | |
324 | long test_smull_overflow(long x, long y) { |
325 | // CHECK: @test_smull_overflow([[UL:i32|i64]] %x |
326 | // CHECK: %{{.+}} = call { [[UL]], i1 } @llvm.smul.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %{{.+}}) |
327 | long result; |
328 | if (__builtin_smull_overflow(x, y, &result)) |
329 | return LongErrorCode; |
330 | return result; |
331 | } |
332 | |
333 | long long test_smulll_overflow(long long x, long long y) { |
334 | // CHECK: @test_smulll_overflow |
335 | // CHECK: %{{.+}} = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %{{.+}}, i64 %{{.+}}) |
336 | long long result; |
337 | if (__builtin_smulll_overflow(x, y, &result)) |
338 | return LongLongErrorCode; |
339 | return result; |
340 | } |
341 | |
342 | int test_mixed_sign_mul_overflow_sext_signed_op(int x, unsigned long long y) { |
343 | // CHECK: @test_mixed_sign_mul_overflow_sext_signed_op |
344 | // CHECK: [[SignedOp:%.*]] = sext i32 %0 to i64 |
345 | // CHECK: [[IsNeg:%.*]] = icmp slt i64 [[SignedOp]], 0 |
346 | int result; |
347 | if (__builtin_mul_overflow(x, y, &result)) |
348 | return LongErrorCode; |
349 | return result; |
350 | } |
351 | |
352 | int test_mixed_sign_mul_overflow_zext_unsigned_op(long long x, unsigned y) { |
353 | // CHECK: @test_mixed_sign_mul_overflow_zext_unsigned_op |
354 | // CHECK: [[UnsignedOp:%.*]] = zext i32 %1 to i64 |
355 | // CHECK: [[IsNeg:%.*]] = icmp slt i64 %0, 0 |
356 | // CHECK: @llvm.umul.with.overflow.i64({{.*}}, i64 [[UnsignedOp]]) |
357 | int result; |
358 | if (__builtin_mul_overflow(x, y, &result)) |
359 | return LongErrorCode; |
360 | return result; |
361 | } |
362 | |
363 | int test_mixed_sign_mull_overflow(int x, unsigned y) { |
364 | // CHECK: @test_mixed_sign_mull_overflow |
365 | // CHECK: [[IsNeg:%.*]] = icmp slt i32 [[Op1:%.*]], 0 |
366 | // CHECK-NEXT: [[Signed:%.*]] = sub i32 0, [[Op1]] |
367 | // CHECK-NEXT: [[AbsSigned:%.*]] = select i1 [[IsNeg]], i32 [[Signed]], i32 [[Op1]] |
368 | // CHECK-NEXT: call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[AbsSigned]], i32 %{{.*}}) |
369 | // CHECK-NEXT: [[UnsignedOFlow:%.*]] = extractvalue { i32, i1 } %{{.*}}, 1 |
370 | // CHECK-NEXT: [[UnsignedResult:%.*]] = extractvalue { i32, i1 } %{{.*}}, 0 |
371 | // CHECK-NEXT: [[IsNegZext:%.*]] = zext i1 [[IsNeg]] to i32 |
372 | // CHECK-NEXT: [[MaxResult:%.*]] = add i32 2147483647, [[IsNegZext]] |
373 | // CHECK-NEXT: [[SignedOFlow:%.*]] = icmp ugt i32 [[UnsignedResult]], [[MaxResult]] |
374 | // CHECK-NEXT: [[OFlow:%.*]] = or i1 [[UnsignedOFlow]], [[SignedOFlow]] |
375 | // CHECK-NEXT: [[NegativeResult:%.*]] = sub i32 0, [[UnsignedResult]] |
376 | // CHECK-NEXT: [[Result:%.*]] = select i1 [[IsNeg]], i32 [[NegativeResult]], i32 [[UnsignedResult]] |
377 | // CHECK-NEXT: store i32 [[Result]], i32* %{{.*}}, align 4 |
378 | // CHECK: br i1 [[OFlow]] |
379 | |
380 | int result; |
381 | if (__builtin_mul_overflow(x, y, &result)) |
382 | return LongErrorCode; |
383 | return result; |
384 | } |
385 | |
386 | int test_mixed_sign_mull_overflow_unsigned(int x, unsigned y) { |
387 | // CHECK: @test_mixed_sign_mull_overflow_unsigned |
388 | // CHECK: [[IsNeg:%.*]] = icmp slt i32 [[Op1:%.*]], 0 |
389 | // CHECK-NEXT: [[Signed:%.*]] = sub i32 0, [[Op1]] |
390 | // CHECK-NEXT: [[AbsSigned:%.*]] = select i1 [[IsNeg]], i32 [[Signed]], i32 [[Op1]] |
391 | // CHECK-NEXT: call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[AbsSigned]], i32 %{{.*}}) |
392 | // CHECK-NEXT: [[UnsignedOFlow:%.*]] = extractvalue { i32, i1 } %{{.*}}, 1 |
393 | // CHECK-NEXT: [[UnsignedResult:%.*]] = extractvalue { i32, i1 } %{{.*}}, 0 |
394 | // CHECK-NEXT: [[NotNull:%.*]] = icmp ne i32 [[UnsignedResult]], 0 |
395 | // CHECK-NEXT: [[Underflow:%.*]] = and i1 [[IsNeg]], [[NotNull]] |
396 | // CHECK-NEXT: [[OFlow:%.*]] = or i1 [[UnsignedOFlow]], [[Underflow]] |
397 | // CHECK-NEXT: [[NegatedResult:%.*]] = sub i32 0, [[UnsignedResult]] |
398 | // CHECK-NEXT: [[Result:%.*]] = select i1 [[IsNeg]], i32 [[NegatedResult]], i32 [[UnsignedResult]] |
399 | // CHECK-NEXT: store i32 [[Result]], i32* %{{.*}}, align 4 |
400 | // CHECK: br i1 [[OFlow]] |
401 | |
402 | unsigned result; |
403 | if (__builtin_mul_overflow(x, y, &result)) |
404 | return LongErrorCode; |
405 | return result; |
406 | } |
407 | |
408 | int test_mixed_sign_mull_overflow_swapped(int x, unsigned y) { |
409 | // CHECK: @test_mixed_sign_mull_overflow_swapped |
410 | // CHECK: call { i32, i1 } @llvm.umul.with.overflow.i32 |
411 | // CHECK: add i32 2147483647 |
412 | int result; |
413 | if (__builtin_mul_overflow(y, x, &result)) |
414 | return LongErrorCode; |
415 | return result; |
416 | } |
417 | |
418 | long long test_mixed_sign_mulll_overflow(long long x, unsigned long long y) { |
419 | // CHECK: @test_mixed_sign_mulll_overflow |
420 | // CHECK: call { i64, i1 } @llvm.umul.with.overflow.i64 |
421 | // CHECK: add i64 92233720368547 |
422 | long long result; |
423 | if (__builtin_mul_overflow(x, y, &result)) |
424 | return LongLongErrorCode; |
425 | return result; |
426 | } |
427 | |
428 | long long test_mixed_sign_mulll_overflow_swapped(long long x, unsigned long long y) { |
429 | // CHECK: @test_mixed_sign_mulll_overflow_swapped |
430 | // CHECK: call { i64, i1 } @llvm.umul.with.overflow.i64 |
431 | // CHECK: add i64 92233720368547 |
432 | long long result; |
433 | if (__builtin_mul_overflow(y, x, &result)) |
434 | return LongLongErrorCode; |
435 | return result; |
436 | } |
437 | |
438 | long long test_mixed_sign_mulll_overflow_trunc_signed(long long x, unsigned long long y) { |
439 | // CHECK: @test_mixed_sign_mulll_overflow_trunc_signed |
440 | // CHECK: call { i64, i1 } @llvm.umul.with.overflow.i64 |
441 | // CHECK: add i64 2147483647 |
442 | // CHECK: trunc |
443 | // CHECK: store |
444 | int result; |
445 | if (__builtin_mul_overflow(y, x, &result)) |
446 | return LongLongErrorCode; |
447 | return result; |
448 | } |
449 | |
450 | long long test_mixed_sign_mulll_overflow_trunc_unsigned(long long x, unsigned long long y) { |
451 | // CHECK: @test_mixed_sign_mulll_overflow_trunc_unsigned |
452 | // CHECK: call { i64, i1 } @llvm.umul.with.overflow.i64 |
453 | // CHECK: [[NON_ZERO:%.*]] = icmp ne i64 [[UNSIGNED_RESULT:%.*]], 0 |
454 | // CHECK-NEXT: [[UNDERFLOW:%.*]] = and i1 {{.*}}, [[NON_ZERO]] |
455 | // CHECK-NEXT: [[OVERFLOW_PRE_TRUNC:%.*]] = or i1 {{.*}}, [[UNDERFLOW]] |
456 | // CHECK-NEXT: [[TRUNC_OVERFLOW:%.*]] = icmp ugt i64 [[UNSIGNED_RESULT]], 4294967295 |
457 | // CHECK-NEXT: [[OVERFLOW:%.*]] = or i1 [[OVERFLOW_PRE_TRUNC]], [[TRUNC_OVERFLOW]] |
458 | // CHECK-NEXT: [[NEGATED:%.*]] = sub i64 0, [[UNSIGNED_RESULT]] |
459 | // CHECK-NEXT: [[RESULT:%.*]] = select i1 {{.*}}, i64 [[NEGATED]], i64 [[UNSIGNED_RESULT]] |
460 | // CHECK-NEXT: trunc i64 [[RESULT]] to i32 |
461 | // CHECK-NEXT: store |
462 | unsigned result; |
463 | if (__builtin_mul_overflow(y, x, &result)) |
464 | return LongLongErrorCode; |
465 | return result; |
466 | } |
467 | |
468 | long long test_mixed_sign_mul_overflow_extend_signed(int x, unsigned y) { |
469 | // CHECK: @test_mixed_sign_mul_overflow_extend_signed |
470 | // CHECK: call { i64, i1 } @llvm.smul.with.overflow.i64 |
471 | long long result; |
472 | if (__builtin_mul_overflow(y, x, &result)) |
473 | return LongLongErrorCode; |
474 | return result; |
475 | } |
476 | |
477 | long long test_mixed_sign_mul_overflow_extend_unsigned(int x, unsigned y) { |
478 | // CHECK: @test_mixed_sign_mul_overflow_extend_unsigned |
479 | // CHECK: call { i65, i1 } @llvm.smul.with.overflow.i65 |
480 | unsigned long long result; |
481 | if (__builtin_mul_overflow(y, x, &result)) |
482 | return LongLongErrorCode; |
483 | return result; |
484 | } |
485 | |