Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -1235,7 +1235,7 @@ 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; } @@ -1257,10 +1257,26 @@ llvm::Value *Signed = CGF.EmitScalarExpr(SignedOp); llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp); + // One of the operands may be smaller than the other. If so, [s|z]ext it. + bool NeedSExt = false; + bool NeedZExt = false; + if (Op1Info.Width < Op2Info.Width) { + NeedSExt = Op1Info.Signed; + NeedZExt = !Op1Info.Signed; + } else if (Op1Info.Width > Op2Info.Width) { + NeedSExt = Op2Info.Signed; + NeedZExt = !Op2Info.Signed; + } + if (NeedSExt) + Signed = CGF.Builder.CreateSExt(Signed, Unsigned->getType(), "op.sext"); + if (NeedZExt) + 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 +1294,8 @@ 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 +1313,9 @@ 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); Index: clang/test/CodeGen/builtins-overflow.c =================================================================== --- clang/test/CodeGen/builtins-overflow.c +++ clang/test/CodeGen/builtins-overflow.c @@ -339,6 +339,27 @@ 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 %0 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