From: Mike Stump Date: Wed, 1 Apr 2009 20:28:16 +0000 (+0000) Subject: Add -ftrapv support, patch from David Chisnall; well all except the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2add47387d39ee6c40dcb0e9f3d51c27ad1e113c;p=clang Add -ftrapv support, patch from David Chisnall; well all except the clang option code that is and two bug fixes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68240 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index b49d500470..818ccda48b 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -59,6 +59,9 @@ public: unsigned MathErrno : 1; // Math functions must respect errno // (modulo the platform support). + unsigned OverflowChecking : 1; // Extension to call a handler function when + // integer arithmetic overflows. + unsigned HeinousExtensions : 1; // Extensions that we really don't like and // may be ripped out at any time. private: @@ -87,6 +90,8 @@ public: EmitAllDecls = 0; MathErrno = 1; + OverflowChecking = 0; + InstantiationDepth = 99; } diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def index 019a0da098..33b24f63dd 100644 --- a/include/clang/Driver/Options.def +++ b/include/clang/Driver/Options.def @@ -448,6 +448,7 @@ OPTION("-ftemplate-depth-", ftemplate_depth_, Joined, f_Group, INVALID, "", 0, 0 OPTION("-fterminated-vtables", fterminated_vtables, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-ftime-report", ftime_report, Flag, clang_f_Group, INVALID, "", 0, 0, 0) OPTION("-ftraditional", ftraditional, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-ftrapv", ftrapv, Flag, clang_f_Group, INVALID, "", 0, 0, 0) OPTION("-funwind-tables", funwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fverbose-asm", fverbose_asm, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fwritable-strings", fwritable_strings, Flag, clang_f_Group, INVALID, "", 0, 0, 0) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 17b02e3fd0..b47d578734 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -22,6 +22,7 @@ #include "llvm/Function.h" #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" +#include "llvm/Module.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/CFG.h" #include "llvm/Target/TargetData.h" @@ -261,8 +262,13 @@ public: // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { + if (CGF.getContext().getLangOptions().OverflowChecking) + return EmitOverflowCheckedBinOp(Ops); return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } + /// Create a binary op that checks for overflow. + /// Currently only supports +, - and *. + Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops); Value *EmitDiv(const BinOpInfo &Ops); Value *EmitRem(const BinOpInfo &Ops); Value *EmitAdd(const BinOpInfo &Ops); @@ -825,10 +831,114 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); } +Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { + unsigned IID; + unsigned OpID = 0; + if (Ops.Ty->isSignedIntegerType()) { + switch (Ops.E->getOpcode()) { + case BinaryOperator::Add: + OpID = 1; + IID = llvm::Intrinsic::sadd_with_overflow; + break; + case BinaryOperator::Sub: + OpID = 2; + IID = llvm::Intrinsic::ssub_with_overflow; + break; + case BinaryOperator::Mul: + OpID = 3; + IID = llvm::Intrinsic::smul_with_overflow; + break; + default: + assert(false && "Unsupported operation for overflow detection"); + } + OpID <<= 1; + OpID |= 1; + } + else { + assert(Ops.Ty->isUnsignedIntegerType() && + "Must be either a signed or unsigned integer op"); + switch (Ops.E->getOpcode()) { + case BinaryOperator::Add: + OpID = 1; + IID = llvm::Intrinsic::uadd_with_overflow; + break; + case BinaryOperator::Sub: + OpID = 2; + IID = llvm::Intrinsic::usub_with_overflow; + break; + case BinaryOperator::Mul: + OpID = 3; + IID = llvm::Intrinsic::umul_with_overflow; + break; + default: + assert(false && "Unsupported operation for overflow detection"); + } + OpID <<= 1; + } + const llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty); + + llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, &opTy, 1); + + Value *resultAndOverflow = Builder.CreateCall2(intrinsic, Ops.LHS, Ops.RHS); + Value *result = Builder.CreateExtractValue(resultAndOverflow, 0); + Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1); + + // Branch in case of overflow. + llvm::BasicBlock *initialBB = Builder.GetInsertBlock(); + llvm::BasicBlock *overflowBB = + CGF.createBasicBlock("overflow", CGF.CurFn); + llvm::BasicBlock *continueBB = + CGF.createBasicBlock("overflow.continue", CGF.CurFn); + + Builder.CreateCondBr(overflow, overflowBB, continueBB); + + // Handle overflow + + Builder.SetInsertPoint(overflowBB); + + // Handler is: + // long long *__overflow_handler)(long long a, long long b, char op, + // char width) + std::vector handerArgTypes; + handerArgTypes.push_back(llvm::Type::Int64Ty); + handerArgTypes.push_back(llvm::Type::Int64Ty); + handerArgTypes.push_back(llvm::Type::Int8Ty); + handerArgTypes.push_back(llvm::Type::Int8Ty); + llvm::FunctionType *handlerTy = llvm::FunctionType::get(llvm::Type::Int64Ty, + handerArgTypes, false); + llvm::Value *handlerFunction = + CGF.CGM.getModule().getOrInsertGlobal("__overflow_handler", + llvm::PointerType::getUnqual(handlerTy)); + handlerFunction = Builder.CreateLoad(handlerFunction); + + llvm::Value *handlerResult = Builder.CreateCall4(handlerFunction, + Builder.CreateSExt(Ops.LHS, llvm::Type::Int64Ty), + Builder.CreateSExt(Ops.RHS, llvm::Type::Int64Ty), + llvm::ConstantInt::get(llvm::Type::Int8Ty, OpID), + llvm::ConstantInt::get(llvm::Type::Int8Ty, + cast(opTy)->getBitWidth())); + + handlerResult = Builder.CreateTrunc(handlerResult, opTy); + + Builder.CreateBr(continueBB); + + // Set up the continuation + Builder.SetInsertPoint(continueBB); + // Get the correct result + llvm::PHINode *phi = Builder.CreatePHI(opTy); + phi->reserveOperandSpace(2); + phi->addIncoming(result, initialBB); + phi->addIncoming(handlerResult, overflowBB); + + return phi; +} Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { - if (!Ops.Ty->isPointerType()) + if (!Ops.Ty->isPointerType()) { + if (CGF.getContext().getLangOptions().OverflowChecking) + return EmitOverflowCheckedBinOp(Ops); return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add"); + } if (Ops.Ty->getAsPointerType()->isVariableArrayType()) { // The amount of the addition needs to account for the VLA size @@ -875,8 +985,11 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { } Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { - if (!isa(Ops.LHS->getType())) + if (!isa(Ops.LHS->getType())) { + if (CGF.getContext().getLangOptions().OverflowChecking) + return EmitOverflowCheckedBinOp(Ops); return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); + } if (Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) { // The amount of the addition needs to account for the VLA size for diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index 6cfd168278..b149a1da92 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -675,6 +675,14 @@ void InitializeGCMode(LangOptions &Options) { Options.setGCMode(LangOptions::HybridGC); } +static llvm::cl::opt +OverflowChecking("ftrapv", + llvm::cl::desc("Trap on integer overflow"), + llvm::cl::init(false)); + +void InitializeOverflowChecking(LangOptions &Options) { + Options.OverflowChecking = OverflowChecking; +} //===----------------------------------------------------------------------===// // Target Triple Processing. //===----------------------------------------------------------------------===// @@ -1626,6 +1634,7 @@ int main(int argc, char **argv) { LangKind LK = GetLanguage(InFile); InitializeLangOptions(LangInfo, LK); InitializeGCMode(LangInfo); + InitializeOverflowChecking(LangInfo); InitializeLanguageStandard(LangInfo, LK, Target.get()); // Process the -I options and set them in the HeaderInfo.