r349542 - [CodeGen] Handle mixed-width ops in mixed-sign mul-with-overflow lowering

Vedant Kumar via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 18 13:05:03 PST 2018


Author: vedantk
Date: Tue Dec 18 13:05:03 2018
New Revision: 349542

URL: http://llvm.org/viewvc/llvm-project?rev=349542&view=rev
Log:
[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

Modified:
    cfe/trunk/lib/CodeGen/CGBuiltin.cpp
    cfe/trunk/test/CodeGen/builtins-overflow.c

Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=349542&r1=349541&r2=349542&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Tue Dec 18 13:05:03 2018
@@ -1235,7 +1235,7 @@ static bool isSpecialMixedSignMultiply(u
                                        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;
 }
 
@@ -1256,11 +1256,20 @@ EmitCheckedMixedSignMultiply(CodeGenFunc
   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);
@@ -1278,8 +1287,8 @@ EmitCheckedMixedSignMultiply(CodeGenFunc
   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));
@@ -1297,9 +1306,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunc
     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);

Modified: cfe/trunk/test/CodeGen/builtins-overflow.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins-overflow.c?rev=349542&r1=349541&r2=349542&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/builtins-overflow.c (original)
+++ cfe/trunk/test/CodeGen/builtins-overflow.c Tue Dec 18 13:05:03 2018
@@ -339,6 +339,27 @@ long long test_smulll_overflow(long long
   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




More information about the cfe-commits mailing list