summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2018-01-16 14:49:22 +0000
committerHans Wennborg <hans@hanshq.net>2018-01-16 14:49:22 +0000
commit3809ab9a2ef9816f5d42b434df65207fe04a0e44 (patch)
treedec6826de0138edf893392e3e4276eca2563fad6
parent7113f640dca4b8966a625d0cbdda63c85ebd39c1 (diff)
downloadclang-3809ab9a2ef9816f5d42b434df65207fe04a0e44.tar.gz
Merging r321771:
------------------------------------------------------------------------ r321771 | vedantk | 2018-01-03 15:11:32 -0800 (Wed, 03 Jan 2018) | 21 lines [CGBuiltin] Handle unsigned mul overflow properly (PR35750) r320902 fixed the IRGen for some types of checked multiplications. It did not handle unsigned overflow correctly in the case where the signed operand is negative (PR35750). Eli pointed out that on overflow, the result must be equal to the unique value that is equivalent to the mathematically-correct result modulo two raised to the k power, where k is the number of bits in the result type. This patch fixes the specialized IRGen from r320902 accordingly. Testing: Apart from check-clang, I modified the test harness from r320902 to validate the results of all multiplications -- not just the ones which don't overflow: https://gist.github.com/vedantk/3eb9c88f82e5c32f2e590555b4af5081 llvm.org/PR35750, rdar://34963321 Differential Revision: https://reviews.llvm.org/D41717 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_60@322555 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/CGBuiltin.cpp6
-rw-r--r--test/CodeGen/builtins-overflow.c8
2 files changed, 11 insertions, 3 deletions
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index ba54f8342f..35ae114c4f 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -915,7 +915,11 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow);
}
- Result = CGF.Builder.CreateTrunc(UnsignedResult, ResTy);
+ // Negate the product if it would be negative in infinite precision.
+ Result = CGF.Builder.CreateSelect(
+ IsNegative, CGF.Builder.CreateNeg(UnsignedResult), UnsignedResult);
+
+ Result = CGF.Builder.CreateTrunc(Result, ResTy);
}
assert(Overflow && Result && "Missing overflow or result");
diff --git a/test/CodeGen/builtins-overflow.c b/test/CodeGen/builtins-overflow.c
index 7a30cfbd46..f83bbfb967 100644
--- a/test/CodeGen/builtins-overflow.c
+++ b/test/CodeGen/builtins-overflow.c
@@ -373,7 +373,9 @@ int test_mixed_sign_mull_overflow_unsigned(int x, unsigned y) {
// CHECK-NEXT: [[NotNull:%.*]] = icmp ne i32 [[UnsignedResult]], 0
// CHECK-NEXT: [[Underflow:%.*]] = and i1 [[IsNeg]], [[NotNull]]
// CHECK-NEXT: [[OFlow:%.*]] = or i1 [[UnsignedOFlow]], [[Underflow]]
-// CHECK-NEXT: store i32 [[UnsignedResult]], i32* %{{.*}}, align 4
+// CHECK-NEXT: [[NegatedResult:%.*]] = sub i32 0, [[UnsignedResult]]
+// CHECK-NEXT: [[Result:%.*]] = select i1 [[IsNeg]], i32 [[NegatedResult]], i32 [[UnsignedResult]]
+// CHECK-NEXT: store i32 [[Result]], i32* %{{.*}}, align 4
// CHECK: br i1 [[OFlow]]
unsigned result;
@@ -432,7 +434,9 @@ long long test_mixed_sign_mulll_overflow_trunc_unsigned(long long x, unsigned lo
// CHECK-NEXT: [[OVERFLOW_PRE_TRUNC:%.*]] = or i1 {{.*}}, [[UNDERFLOW]]
// CHECK-NEXT: [[TRUNC_OVERFLOW:%.*]] = icmp ugt i64 [[UNSIGNED_RESULT]], 4294967295
// CHECK-NEXT: [[OVERFLOW:%.*]] = or i1 [[OVERFLOW_PRE_TRUNC]], [[TRUNC_OVERFLOW]]
-// CHECK-NEXT: trunc i64 [[UNSIGNED_RESULT]] to i32
+// CHECK-NEXT: [[NEGATED:%.*]] = sub i64 0, [[UNSIGNED_RESULT]]
+// CHECK-NEXT: [[RESULT:%.*]] = select i1 {{.*}}, i64 [[NEGATED]], i64 [[UNSIGNED_RESULT]]
+// CHECK-NEXT: trunc i64 [[RESULT]] to i32
// CHECK-NEXT: store
unsigned result;
if (__builtin_mul_overflow(y, x, &result))