diff options
| author | John McCall <rjmccall@apple.com> | 2015-10-29 20:48:01 +0000 |
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2015-10-29 20:48:01 +0000 |
| commit | 03107a4ef015e65608e989cddc444d862563c2b1 (patch) | |
| tree | 7a7c8209f3288f6df7b611364742257ed5b2a72b /clang/lib | |
| parent | b25423525c4a27c37599efb8482c3e60515df638 (diff) | |
| download | bcm5719-llvm-03107a4ef015e65608e989cddc444d862563c2b1.tar.gz bcm5719-llvm-03107a4ef015e65608e989cddc444d862563c2b1.zip | |
Add support for __builtin_{add,sub,mul}_overflow.
Patch by David Grayson!
llvm-svn: 251651
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 128 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 39 |
2 files changed, 166 insertions, 1 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 8b8b54ddeb3..425f7dbf8a2 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -279,6 +279,50 @@ static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF, return CGF.Builder.CreateExtractValue(Tmp, 0); } +namespace { + struct WidthAndSignedness { + unsigned Width; + bool Signed; + }; +} + +static WidthAndSignedness +getIntegerWidthAndSignedness(const clang::ASTContext &context, + const clang::QualType Type) { + assert(Type->isIntegerType() && "Given type is not an integer."); + unsigned Width = Type->isBooleanType() ? 1 : context.getTypeInfo(Type).Width; + bool Signed = Type->isSignedIntegerType(); + return {Width, Signed}; +} + +// Given one or more integer types, this function produces an integer type that +// encompasses them: any value in one of the given types could be expressed in +// the encompassing type. +static struct WidthAndSignedness +EncompassingIntegerType(ArrayRef<struct WidthAndSignedness> Types) { + assert(Types.size() > 0 && "Empty list of types."); + + // If any of the given types is signed, we must return a signed type. + bool Signed = false; + for (const auto &Type : Types) { + Signed |= Type.Signed; + } + + // The encompassing type must have a width greater than or equal to the width + // of the specified types. Aditionally, if the encompassing type is signed, + // its width must be strictly greater than the width of any unsigned types + // given. + unsigned Width = 0; + for (const auto &Type : Types) { + unsigned MinWidth = Type.Width + (Signed && !Type.Signed); + if (Width < MinWidth) { + Width = MinWidth; + } + } + + return {Width, Signed}; +} + Value *CodeGenFunction::EmitVAStartEnd(Value *ArgValue, bool IsStart) { llvm::Type *DestType = Int8PtrTy; if (ArgValue->getType() != DestType) @@ -1606,6 +1650,88 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateStore(CarryOut, CarryOutPtr); return RValue::get(Sum2); } + + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: { + const clang::Expr *LeftArg = E->getArg(0); + const clang::Expr *RightArg = E->getArg(1); + const clang::Expr *ResultArg = E->getArg(2); + + clang::QualType ResultQTy = + ResultArg->getType()->castAs<PointerType>()->getPointeeType(); + + WidthAndSignedness LeftInfo = + getIntegerWidthAndSignedness(CGM.getContext(), LeftArg->getType()); + WidthAndSignedness RightInfo = + getIntegerWidthAndSignedness(CGM.getContext(), RightArg->getType()); + WidthAndSignedness ResultInfo = + getIntegerWidthAndSignedness(CGM.getContext(), ResultQTy); + WidthAndSignedness EncompassingInfo = + EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo}); + + llvm::Type *EncompassingLLVMTy = + llvm::IntegerType::get(CGM.getLLVMContext(), EncompassingInfo.Width); + + llvm::Type *ResultLLVMTy = CGM.getTypes().ConvertType(ResultQTy); + + llvm::Intrinsic::ID IntrinsicId; + switch (BuiltinID) { + default: + llvm_unreachable("Unknown overflow builtin id."); + case Builtin::BI__builtin_add_overflow: + IntrinsicId = EncompassingInfo.Signed + ? llvm::Intrinsic::sadd_with_overflow + : llvm::Intrinsic::uadd_with_overflow; + break; + case Builtin::BI__builtin_sub_overflow: + IntrinsicId = EncompassingInfo.Signed + ? llvm::Intrinsic::ssub_with_overflow + : llvm::Intrinsic::usub_with_overflow; + break; + case Builtin::BI__builtin_mul_overflow: + IntrinsicId = EncompassingInfo.Signed + ? llvm::Intrinsic::smul_with_overflow + : llvm::Intrinsic::umul_with_overflow; + break; + } + + llvm::Value *Left = EmitScalarExpr(LeftArg); + llvm::Value *Right = EmitScalarExpr(RightArg); + Address ResultPtr = EmitPointerWithAlignment(ResultArg); + + // Extend each operand to the encompassing type. + Left = Builder.CreateIntCast(Left, EncompassingLLVMTy, LeftInfo.Signed); + Right = Builder.CreateIntCast(Right, EncompassingLLVMTy, RightInfo.Signed); + + // Perform the operation on the extended values. + llvm::Value *Overflow, *Result; + Result = EmitOverflowIntrinsic(*this, IntrinsicId, Left, Right, Overflow); + + if (EncompassingInfo.Width > ResultInfo.Width) { + // The encompassing type is wider than the result type, so we need to + // truncate it. + llvm::Value *ResultTrunc = Builder.CreateTrunc(Result, ResultLLVMTy); + + // To see if the truncation caused an overflow, we will extend + // the result and then compare it to the original result. + llvm::Value *ResultTruncExt = Builder.CreateIntCast( + ResultTrunc, EncompassingLLVMTy, ResultInfo.Signed); + llvm::Value *TruncationOverflow = + Builder.CreateICmpNE(Result, ResultTruncExt); + + Overflow = Builder.CreateOr(Overflow, TruncationOverflow); + Result = ResultTrunc; + } + + // Finally, store the result using the pointer. + bool isVolatile = + ResultArg->getType()->getPointeeType().isVolatileQualified(); + Builder.CreateStore(EmitToMemory(Result, ResultQTy), ResultPtr, isVolatile); + + return RValue::get(Overflow); + } + case Builtin::BI__builtin_uadd_overflow: case Builtin::BI__builtin_uaddl_overflow: case Builtin::BI__builtin_uaddll_overflow: @@ -1635,7 +1761,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // Decide which of the overflow intrinsics we are lowering to: llvm::Intrinsic::ID IntrinsicId; switch (BuiltinID) { - default: llvm_unreachable("Unknown security overflow builtin id."); + default: llvm_unreachable("Unknown overflow builtin id."); case Builtin::BI__builtin_uadd_overflow: case Builtin::BI__builtin_uaddl_overflow: case Builtin::BI__builtin_uaddll_overflow: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8d9a1b23bb4..4a5ad1bc961 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -112,6 +112,39 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { return false; } +static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { + if (checkArgCount(S, TheCall, 3)) + return true; + + // First two arguments should be integers. + for (unsigned I = 0; I < 2; ++I) { + Expr *Arg = TheCall->getArg(I); + QualType Ty = Arg->getType(); + if (!Ty->isIntegerType()) { + S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_int) + << Ty << Arg->getSourceRange(); + return true; + } + } + + // Third argument should be a pointer to a non-const integer. + // IRGen correctly handles volatile, restrict, and address spaces, and + // the other qualifiers aren't possible. + { + Expr *Arg = TheCall->getArg(2); + QualType Ty = Arg->getType(); + const auto *PtrTy = Ty->getAs<PointerType>(); + if (!(PtrTy && PtrTy->getPointeeType()->isIntegerType() && + !PtrTy->getPointeeType().isConstQualified())) { + S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_ptr_int) + << Ty << Arg->getSourceRange(); + return true; + } + } + + return false; +} + static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, CallExpr *TheCall, unsigned SizeIdx, unsigned DstSizeIdx) { @@ -457,6 +490,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinAddressof(*this, TheCall)) return ExprError(); break; + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + if (SemaBuiltinOverflow(*this, TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_operator_new: case Builtin::BI__builtin_operator_delete: if (!getLangOpts().CPlusPlus) { |

