| |
@@ -0,0 +1,122 @@
|
| |
+ From f7e449be0f6ccf363380c33b3249055e36b76909 Mon Sep 17 00:00:00 2001
|
| |
+ From: Vedant Kumar <vsk@apple.com>
|
| |
+ Date: Tue, 18 Dec 2018 21:05:03 +0000
|
| |
+ Subject: [PATCH] [CodeGen] Handle mixed-width ops in mixed-sign
|
| |
+ mul-with-overflow lowering
|
| |
+
|
| |
+ The special lowering for __builtin_mul_overflow introduced in r320902
|
| |
+ fixed an ICE seen when passing mixed-sign operands to the builtin.
|
| |
+
|
| |
+ This patch extends the special lowering to cover mixed-width, mixed-sign
|
| |
+ operands. In a few common scenarios, calls to muloti4 will no longer be
|
| |
+ emitted.
|
| |
+
|
| |
+ This should address the latest comments in PR34920 and work around the
|
| |
+ link failure seen in:
|
| |
+
|
| |
+ https://bugzilla.redhat.com/show_bug.cgi?id=1657544
|
| |
+
|
| |
+ Testing:
|
| |
+ - check-clang
|
| |
+ - A/B output comparison with: https://gist.github.com/vedantk/3eb9c88f82e5c32f2e590555b4af5081
|
| |
+
|
| |
+ Differential Revision: https://reviews.llvm.org/D55843
|
| |
+
|
| |
+ llvm-svn: 349542
|
| |
+ ---
|
| |
+ clang/lib/CodeGen/CGBuiltin.cpp | 19 ++++++++++++++-----
|
| |
+ clang/test/CodeGen/builtins-overflow.c | 21 +++++++++++++++++++++
|
| |
+ 2 files changed, 35 insertions(+), 5 deletions(-)
|
| |
+
|
| |
+ diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
|
| |
+ index 0770c20..4303a7a 100644
|
| |
+ --- a/lib/CodeGen/CGBuiltin.cpp
|
| |
+ +++ b/lib/CodeGen/CGBuiltin.cpp
|
| |
+ @@ -1077,7 +1077,7 @@ static bool isSpecialMixedSignMultiply(unsigned BuiltinID,
|
| |
+ WidthAndSignedness Op2Info,
|
| |
+ WidthAndSignedness ResultInfo) {
|
| |
+ return BuiltinID == Builtin::BI__builtin_mul_overflow &&
|
| |
+ - Op1Info.Width == Op2Info.Width && Op1Info.Width >= ResultInfo.Width &&
|
| |
+ + std::max(Op1Info.Width, Op2Info.Width) >= ResultInfo.Width &&
|
| |
+ Op1Info.Signed != Op2Info.Signed;
|
| |
+ }
|
| |
+
|
| |
+ @@ -1098,11 +1098,20 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
|
| |
+ const clang::Expr *UnsignedOp = Op1Info.Signed ? Op2 : Op1;
|
| |
+ llvm::Value *Signed = CGF.EmitScalarExpr(SignedOp);
|
| |
+ llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp);
|
| |
+ + unsigned SignedOpWidth = Op1Info.Signed ? Op1Info.Width : Op2Info.Width;
|
| |
+ + unsigned UnsignedOpWidth = Op1Info.Signed ? Op2Info.Width : Op1Info.Width;
|
| |
+ +
|
| |
+ + // One of the operands may be smaller than the other. If so, [s|z]ext it.
|
| |
+ + if (SignedOpWidth < UnsignedOpWidth)
|
| |
+ + Signed = CGF.Builder.CreateSExt(Signed, Unsigned->getType(), "op.sext");
|
| |
+ + if (UnsignedOpWidth < SignedOpWidth)
|
| |
+ + Unsigned = CGF.Builder.CreateZExt(Unsigned, Signed->getType(), "op.zext");
|
| |
+
|
| |
+ llvm::Type *OpTy = Signed->getType();
|
| |
+ llvm::Value *Zero = llvm::Constant::getNullValue(OpTy);
|
| |
+ Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg);
|
| |
+ llvm::Type *ResTy = ResultPtr.getElementType();
|
| |
+ + unsigned OpWidth = std::max(Op1Info.Width, Op2Info.Width);
|
| |
+
|
| |
+ // Take the absolute value of the signed operand.
|
| |
+ llvm::Value *IsNegative = CGF.Builder.CreateICmpSLT(Signed, Zero);
|
| |
+ @@ -1120,8 +1129,8 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
|
| |
+ if (ResultInfo.Signed) {
|
| |
+ // Signed overflow occurs if the result is greater than INT_MAX or lesser
|
| |
+ // than INT_MIN, i.e when |Result| > (INT_MAX + IsNegative).
|
| |
+ - auto IntMax = llvm::APInt::getSignedMaxValue(ResultInfo.Width)
|
| |
+ - .zextOrSelf(Op1Info.Width);
|
| |
+ + auto IntMax =
|
| |
+ + llvm::APInt::getSignedMaxValue(ResultInfo.Width).zextOrSelf(OpWidth);
|
| |
+ llvm::Value *MaxResult =
|
| |
+ CGF.Builder.CreateAdd(llvm::ConstantInt::get(OpTy, IntMax),
|
| |
+ CGF.Builder.CreateZExt(IsNegative, OpTy));
|
| |
+ @@ -1139,9 +1148,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
|
| |
+ llvm::Value *Underflow = CGF.Builder.CreateAnd(
|
| |
+ IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult));
|
| |
+ Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow);
|
| |
+ - if (ResultInfo.Width < Op1Info.Width) {
|
| |
+ + if (ResultInfo.Width < OpWidth) {
|
| |
+ auto IntMax =
|
| |
+ - llvm::APInt::getMaxValue(ResultInfo.Width).zext(Op1Info.Width);
|
| |
+ + llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth);
|
| |
+ llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT(
|
| |
+ UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax));
|
| |
+ Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow);
|
| |
+ diff --git a/test/CodeGen/builtins-overflow.c b/test/CodeGen/builtins-overflow.c
|
| |
+ index 57f90eb..79a3186 100644
|
| |
+ --- a/test/CodeGen/builtins-overflow.c
|
| |
+ +++ b/test/CodeGen/builtins-overflow.c
|
| |
+ @@ -339,6 +339,27 @@ long long test_smulll_overflow(long long x, long long y) {
|
| |
+ return result;
|
| |
+ }
|
| |
+
|
| |
+ +int test_mixed_sign_mul_overflow_sext_signed_op(int x, unsigned long long y) {
|
| |
+ +// CHECK: @test_mixed_sign_mul_overflow_sext_signed_op
|
| |
+ +// CHECK: [[SignedOp:%.*]] = sext i32 %0 to i64
|
| |
+ +// CHECK: [[IsNeg:%.*]] = icmp slt i64 [[SignedOp]], 0
|
| |
+ + int result;
|
| |
+ + if (__builtin_mul_overflow(x, y, &result))
|
| |
+ + return LongErrorCode;
|
| |
+ + return result;
|
| |
+ +}
|
| |
+ +
|
| |
+ +int test_mixed_sign_mul_overflow_zext_unsigned_op(long long x, unsigned y) {
|
| |
+ +// CHECK: @test_mixed_sign_mul_overflow_zext_unsigned_op
|
| |
+ +// CHECK: [[UnsignedOp:%.*]] = zext i32 %1 to i64
|
| |
+ +// CHECK: [[IsNeg:%.*]] = icmp slt i64 %0, 0
|
| |
+ +// CHECK: @llvm.umul.with.overflow.i64({{.*}}, i64 [[UnsignedOp]])
|
| |
+ + int result;
|
| |
+ + if (__builtin_mul_overflow(x, y, &result))
|
| |
+ + return LongErrorCode;
|
| |
+ + return result;
|
| |
+ +}
|
| |
+ +
|
| |
+ int test_mixed_sign_mull_overflow(int x, unsigned y) {
|
| |
+ // CHECK: @test_mixed_sign_mull_overflow
|
| |
+ // CHECK: [[IsNeg:%.*]] = icmp slt i32 [[Op1:%.*]], 0
|
| |
+ --
|
| |
+ 1.8.3.1
|
| |
+
|
| |