Skip to content

Commit 77dfca8

Browse files
committedDec 18, 2018
[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
1 parent 7b3db0e commit 77dfca8

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed
 

‎clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,7 +1235,7 @@ static bool isSpecialMixedSignMultiply(unsigned BuiltinID,
12351235
WidthAndSignedness Op2Info,
12361236
WidthAndSignedness ResultInfo) {
12371237
return BuiltinID == Builtin::BI__builtin_mul_overflow &&
1238-
Op1Info.Width == Op2Info.Width && Op1Info.Width >= ResultInfo.Width &&
1238+
std::max(Op1Info.Width, Op2Info.Width) >= ResultInfo.Width &&
12391239
Op1Info.Signed != Op2Info.Signed;
12401240
}
12411241

@@ -1256,11 +1256,20 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
12561256
const clang::Expr *UnsignedOp = Op1Info.Signed ? Op2 : Op1;
12571257
llvm::Value *Signed = CGF.EmitScalarExpr(SignedOp);
12581258
llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp);
1259+
unsigned SignedOpWidth = Op1Info.Signed ? Op1Info.Width : Op2Info.Width;
1260+
unsigned UnsignedOpWidth = Op1Info.Signed ? Op2Info.Width : Op1Info.Width;
1261+
1262+
// One of the operands may be smaller than the other. If so, [s|z]ext it.
1263+
if (SignedOpWidth < UnsignedOpWidth)
1264+
Signed = CGF.Builder.CreateSExt(Signed, Unsigned->getType(), "op.sext");
1265+
if (UnsignedOpWidth < SignedOpWidth)
1266+
Unsigned = CGF.Builder.CreateZExt(Unsigned, Signed->getType(), "op.zext");
12591267

12601268
llvm::Type *OpTy = Signed->getType();
12611269
llvm::Value *Zero = llvm::Constant::getNullValue(OpTy);
12621270
Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg);
12631271
llvm::Type *ResTy = ResultPtr.getElementType();
1272+
unsigned OpWidth = std::max(Op1Info.Width, Op2Info.Width);
12641273

12651274
// Take the absolute value of the signed operand.
12661275
llvm::Value *IsNegative = CGF.Builder.CreateICmpSLT(Signed, Zero);
@@ -1278,8 +1287,8 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
12781287
if (ResultInfo.Signed) {
12791288
// Signed overflow occurs if the result is greater than INT_MAX or lesser
12801289
// than INT_MIN, i.e when |Result| > (INT_MAX + IsNegative).
1281-
auto IntMax = llvm::APInt::getSignedMaxValue(ResultInfo.Width)
1282-
.zextOrSelf(Op1Info.Width);
1290+
auto IntMax =
1291+
llvm::APInt::getSignedMaxValue(ResultInfo.Width).zextOrSelf(OpWidth);
12831292
llvm::Value *MaxResult =
12841293
CGF.Builder.CreateAdd(llvm::ConstantInt::get(OpTy, IntMax),
12851294
CGF.Builder.CreateZExt(IsNegative, OpTy));
@@ -1297,9 +1306,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
12971306
llvm::Value *Underflow = CGF.Builder.CreateAnd(
12981307
IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult));
12991308
Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow);
1300-
if (ResultInfo.Width < Op1Info.Width) {
1309+
if (ResultInfo.Width < OpWidth) {
13011310
auto IntMax =
1302-
llvm::APInt::getMaxValue(ResultInfo.Width).zext(Op1Info.Width);
1311+
llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth);
13031312
llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT(
13041313
UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax));
13051314
Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow);

‎clang/test/CodeGen/builtins-overflow.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,27 @@ long long test_smulll_overflow(long long x, long long y) {
339339
return result;
340340
}
341341

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+
342363
int test_mixed_sign_mull_overflow(int x, unsigned y) {
343364
// CHECK: @test_mixed_sign_mull_overflow
344365
// CHECK: [[IsNeg:%.*]] = icmp slt i32 [[Op1:%.*]], 0

0 commit comments

Comments
 (0)
Please sign in to comment.