Skip to content

Commit 3203143

Browse files
committed
CodeGen: Improve generated IR for __builtin_mul_overflow(uint, uint, int)
Add a special case for handling __builtin_mul_overflow with unsigned inputs and a signed output to avoid emitting the __muloti4 library call on x86_64. __muloti4 is not implemented in libgcc, so avoiding this call fixes compilation of some programs that call __builtin_mul_overflow with these arguments. For example, this fixes the build of cpio with clang, which includes code from gnulib that calls __builtin_mul_overflow with these argument types. Reviewed By: vsk Differential Revision: https://reviews.llvm.org/D84405
1 parent 71a1b9f commit 3203143

File tree

2 files changed

+95
-3
lines changed

2 files changed

+95
-3
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,47 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) {
18321832
return RValue::get(BufAddr.getPointer());
18331833
}
18341834

1835+
static bool isSpecialUnsignedMultiplySignedResult(
1836+
unsigned BuiltinID, WidthAndSignedness Op1Info, WidthAndSignedness Op2Info,
1837+
WidthAndSignedness ResultInfo) {
1838+
return BuiltinID == Builtin::BI__builtin_mul_overflow &&
1839+
Op1Info.Width == Op2Info.Width && Op2Info.Width == ResultInfo.Width &&
1840+
!Op1Info.Signed && !Op2Info.Signed && ResultInfo.Signed;
1841+
}
1842+
1843+
static RValue EmitCheckedUnsignedMultiplySignedResult(
1844+
CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info,
1845+
const clang::Expr *Op2, WidthAndSignedness Op2Info,
1846+
const clang::Expr *ResultArg, QualType ResultQTy,
1847+
WidthAndSignedness ResultInfo) {
1848+
assert(isSpecialUnsignedMultiplySignedResult(
1849+
Builtin::BI__builtin_mul_overflow, Op1Info, Op2Info, ResultInfo) &&
1850+
"Cannot specialize this multiply");
1851+
1852+
llvm::Value *V1 = CGF.EmitScalarExpr(Op1);
1853+
llvm::Value *V2 = CGF.EmitScalarExpr(Op2);
1854+
1855+
llvm::Value *HasOverflow;
1856+
llvm::Value *Result = EmitOverflowIntrinsic(
1857+
CGF, llvm::Intrinsic::umul_with_overflow, V1, V2, HasOverflow);
1858+
1859+
// The intrinsic call will detect overflow when the value is > UINT_MAX,
1860+
// however, since the original builtin had a signed result, we need to report
1861+
// an overflow when the result is greater than INT_MAX.
1862+
auto IntMax = llvm::APInt::getSignedMaxValue(ResultInfo.Width);
1863+
llvm::Value *IntMaxValue = llvm::ConstantInt::get(Result->getType(), IntMax);
1864+
1865+
llvm::Value *IntMaxOverflow = CGF.Builder.CreateICmpUGT(Result, IntMaxValue);
1866+
HasOverflow = CGF.Builder.CreateOr(HasOverflow, IntMaxOverflow);
1867+
1868+
bool isVolatile =
1869+
ResultArg->getType()->getPointeeType().isVolatileQualified();
1870+
Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg);
1871+
CGF.Builder.CreateStore(CGF.EmitToMemory(Result, ResultQTy), ResultPtr,
1872+
isVolatile);
1873+
return RValue::get(HasOverflow);
1874+
}
1875+
18351876
/// Determine if a binop is a checked mixed-sign multiply we can specialize.
18361877
static bool isSpecialMixedSignMultiply(unsigned BuiltinID,
18371878
WidthAndSignedness Op1Info,
@@ -3952,6 +3993,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
39523993
RightInfo, ResultArg, ResultQTy,
39533994
ResultInfo);
39543995

3996+
if (isSpecialUnsignedMultiplySignedResult(BuiltinID, LeftInfo, RightInfo,
3997+
ResultInfo))
3998+
return EmitCheckedUnsignedMultiplySignedResult(
3999+
*this, LeftArg, LeftInfo, RightArg, RightInfo, ResultArg, ResultQTy,
4000+
ResultInfo);
4001+
39554002
WidthAndSignedness EncompassingInfo =
39564003
EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo});
39574004

clang/test/CodeGen/builtins-overflow.c

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Test CodeGen for Security Check Overflow Builtins.
22
// rdar://13421498
33

4-
// RUN: %clang_cc1 -triple "i686-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck %s
5-
// RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck %s
6-
// RUN: %clang_cc1 -triple "x86_64-mingw32" -emit-llvm -x c %s -o - | FileCheck %s
4+
// RUN: %clang_cc1 -triple "i686-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck -DLONG_TYPE=i32 -DLONG_MAX=2147483647 %s
5+
// RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck -DLONG_TYPE=i64 -DLONG_MAX=9223372036854775807 %s
6+
// RUN: %clang_cc1 -triple "x86_64-mingw32" -emit-llvm -x c %s -o - | FileCheck -DLONG_TYPE=i32 -DLONG_MAX=2147483647 %s
77

88
extern unsigned UnsignedErrorCode;
99
extern unsigned long UnsignedLongErrorCode;
@@ -111,6 +111,51 @@ unsigned test_mul_overflow_uint_uint_uint(unsigned x, unsigned y) {
111111
return r;
112112
}
113113

114+
int test_mul_overflow_uint_uint_int(unsigned x, unsigned y) {
115+
// CHECK-LABEL: define {{(dso_local )?}}i32 @test_mul_overflow_uint_uint_int
116+
// CHECK: [[S:%.+]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
117+
// CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0
118+
// CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1
119+
// CHECK: [[C1:%.+]] = icmp ugt i32 [[Q]], 2147483647
120+
// CHECK: [[C2:%.+]] = or i1 [[C]], [[C1]]
121+
// CHECK: store i32 [[Q]], i32*
122+
// CHECK: br i1 [[C2]]
123+
int r;
124+
if (__builtin_mul_overflow(x, y, &r))
125+
overflowed();
126+
return r;
127+
}
128+
129+
int test_mul_overflow_uint_uint_int_volatile(unsigned x, unsigned y) {
130+
// CHECK-LABEL: define {{(dso_local )?}}i32 @test_mul_overflow_uint_uint_int_volatile
131+
// CHECK: [[S:%.+]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %{{.+}}, i32 %{{.+}})
132+
// CHECK-DAG: [[Q:%.+]] = extractvalue { i32, i1 } [[S]], 0
133+
// CHECK-DAG: [[C:%.+]] = extractvalue { i32, i1 } [[S]], 1
134+
// CHECK: [[C1:%.+]] = icmp ugt i32 [[Q]], 2147483647
135+
// CHECK: [[C2:%.+]] = or i1 [[C]], [[C1]]
136+
// CHECK: store volatile i32 [[Q]], i32*
137+
// CHECK: br i1 [[C2]]
138+
volatile int r;
139+
if (__builtin_mul_overflow(x, y, &r))
140+
overflowed();
141+
return r;
142+
}
143+
144+
long test_mul_overflow_ulong_ulong_long(unsigned long x, unsigned long y) {
145+
// CHECK-LABEL: @test_mul_overflow_ulong_ulong_long
146+
// CHECK: [[S:%.+]] = call { [[LONG_TYPE]], i1 } @llvm.umul.with.overflow.[[LONG_TYPE]]([[LONG_TYPE]] %{{.+}}, [[LONG_TYPE]] %{{.+}})
147+
// CHECK-DAG: [[Q:%.+]] = extractvalue { [[LONG_TYPE]], i1 } [[S]], 0
148+
// CHECK-DAG: [[C:%.+]] = extractvalue { [[LONG_TYPE]], i1 } [[S]], 1
149+
// CHECK: [[C1:%.+]] = icmp ugt [[LONG_TYPE]] [[Q]], [[LONG_MAX]]
150+
// CHECK: [[C2:%.+]] = or i1 [[C]], [[C1]]
151+
// LONG64: store [[LONG_TYPE]] [[Q]], [[LONG_TYPE]]*
152+
// LONG64: br i1 [[C2]]
153+
long r;
154+
if (__builtin_mul_overflow(x, y, &r))
155+
overflowed();
156+
return r;
157+
}
158+
114159
int test_mul_overflow_int_int_int(int x, int y) {
115160
// CHECK-LABEL: define {{(dso_local )?}}i32 @test_mul_overflow_int_int_int
116161
// CHECK-NOT: ext

0 commit comments

Comments
 (0)