From: David Chisnall Date: Fri, 17 Sep 2010 18:29:54 +0000 (+0000) Subject: Add a -ftrapv-handler= option which allows a handler to invoke instead of simply... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7f18e67e1b577a50402e8b43508ab2311a5c45b5;p=clang Add a -ftrapv-handler= option which allows a handler to invoke instead of simply aborting when a signed operation overflows. This mirrors the (GCC-incompatible) behaviour from clang 1.0 and 1.1 when -ftrapv was specified, but allows the handler to be defined for each compilation unit. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114192 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 5bd0d04a4e..fec984fae8 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -134,6 +134,9 @@ public: SOB_Defined, // -fwrapv SOB_Trapping // -ftrapv }; + /// The name of the handler function to be called when -ftrapv is specified. + /// If none is specified, abort (GCC-compatible behaviour). + std::string OverflowHandler; LangOptions() { Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0; diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 99f748e6a7..512c2ca23b 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -455,6 +455,9 @@ def fobjc_nonfragile_abi2 : Flag<"-fobjc-nonfragile-abi2">, HelpText<"enable objective-c's enhanced nonfragile abi">; def ftrapv : Flag<"-ftrapv">, HelpText<"Trap on integer overflow">; +def ftrapv_handler : Separate<"-ftrapv-handler">, + MetaVarName<"">, + HelpText<"Specify the function to be called on overflow.">; def fwrapv : Flag<"-fwrapv">, HelpText<"Treat signed integer overflow as two's complement">; def pic_level : Separate<"-pic-level">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 040b2b2efc..c00e93fdbf 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -390,6 +390,7 @@ def fterminated_vtables : Flag<"-fterminated-vtables">, Group; def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group; def ftime_report : Flag<"-ftime-report">, Group; def ftrapv : Flag<"-ftrapv">, Group; +def ftrapv_handler_EQ : Joined<"-ftrapv-handler=">, Group; def funit_at_a_time : Flag<"-funit-at-a-time">, Group; def funroll_loops : Flag<"-funroll-loops">, Group; def funsigned_bitfields : Flag<"-funsigned-bitfields">, Group; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 68e0ff9497..bacb5641a7 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1627,18 +1627,56 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { 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("nooverflow", CGF.CurFn); Builder.CreateCondBr(overflow, overflowBB, continueBB); // Handle overflow with llvm.trap. - // TODO: it would be better to generate one of these blocks per function. - EmitOverflowBB(overflowBB); - - // Continue on. + const std::string *handlerName = + &CGF.getContext().getLangOptions().OverflowHandler; + if (handlerName->empty()) { + EmitOverflowBB(overflowBB); + Builder.SetInsertPoint(continueBB); + return result; + } + + // If an overflow handler is set, then we want to call it and then use its + // result, if it returns. + Builder.SetInsertPoint(overflowBB); + + // Get the overflow handler. + const llvm::Type *Int8Ty = llvm::Type::getInt8Ty(VMContext); + std::vector argTypes; + argTypes.push_back(CGF.Int64Ty); argTypes.push_back(CGF.Int64Ty); + argTypes.push_back(Int8Ty); argTypes.push_back(Int8Ty); + llvm::FunctionType *handlerTy = + llvm::FunctionType::get(CGF.Int64Ty, argTypes, true); + llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName); + + // Sign extend the args to 64-bit, so that we can use the same handler for + // all types of overflow. + llvm::Value *lhs = Builder.CreateSExt(Ops.LHS, CGF.Int64Ty); + llvm::Value *rhs = Builder.CreateSExt(Ops.RHS, CGF.Int64Ty); + + // Call the handler with the two arguments, the operation, and the size of + // the result. + llvm::Value *handlerResult = Builder.CreateCall4(handler, lhs, rhs, + Builder.getInt8(OpID), + Builder.getInt8(cast(opTy)->getBitWidth())); + + // Truncate the result back to the desired size. + handlerResult = Builder.CreateTrunc(handlerResult, opTy); + Builder.CreateBr(continueBB); + Builder.SetInsertPoint(continueBB); - return 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) { diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 1e1af35478..028db8ca02 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1178,6 +1178,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); + + if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { + CmdArgs.push_back("-ftrapv-handler"); + CmdArgs.push_back(A->getValue(Args)); + } + Args.AddLastArg(CmdArgs, options::OPT_fwrapv); Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); Args.AddLastArg(CmdArgs, options::OPT_funroll_loops); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 64ac3bad8c..d793fc01be 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -581,7 +581,12 @@ static void LangOptsToArgs(const LangOptions &Opts, switch (Opts.getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: break; case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break; - case LangOptions::SOB_Trapping: Res.push_back("-ftrapv"); break; + case LangOptions::SOB_Trapping: + Res.push_back("-ftrapv"); break; + if (!Opts.OverflowHandler.empty()) { + Res.push_back("-ftrapv-handler"); + Res.push_back(Opts.OverflowHandler); + } } if (Opts.HeinousExtensions) Res.push_back("-fheinous-gnu-extensions"); @@ -1312,8 +1317,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fvisibility_inlines_hidden)) Opts.InlineVisibilityHidden = 1; - if (Args.hasArg(OPT_ftrapv)) + if (Args.hasArg(OPT_ftrapv)) { Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping); + // Set the handler, if one is specified. + Opts.OverflowHandler = + Args.getLastArgValue(OPT_ftrapv_handler); + } else if (Args.hasArg(OPT_fwrapv)) Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined); diff --git a/test/CodeGen/integer-overflow.c b/test/CodeGen/integer-overflow.c index 9bed741b32..103cc8427b 100644 --- a/test/CodeGen/integer-overflow.c +++ b/test/CodeGen/integer-overflow.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s --check-prefix=DEFAULT // RUN: %clang_cc1 %s -emit-llvm -o - -fwrapv | FileCheck %s --check-prefix=WRAPV // RUN: %clang_cc1 %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=TRAPV +// RUN: %clang_cc1 %s -emit-llvm -o - -ftrapv -ftrapv-handler foo | FileCheck %s --check-prefix=TRAPV_HANDLER // Tests for signed integer overflow stuff. @@ -14,21 +15,25 @@ void test1() { // DEFAULT: add nsw i32 // WRAPV: add i32 // TRAPV: llvm.sadd.with.overflow.i32 + // TRAPV_HANDLER: foo( f11G = a + b; // DEFAULT: sub nsw i32 // WRAPV: sub i32 // TRAPV: llvm.ssub.with.overflow.i32 + // TRAPV_HANDLER: foo( f11G = a - b; // DEFAULT: mul nsw i32 // WRAPV: mul i32 // TRAPV: llvm.smul.with.overflow.i32 + // TRAPV_HANDLER: foo( f11G = a * b; // DEFAULT: sub nsw i32 0, // WRAPV: sub i32 0, // TRAPV: llvm.ssub.with.overflow.i32(i32 0 + // TRAPV_HANDLER: foo( f11G = -a; // PR7426 - Overflow checking for increments. @@ -36,10 +41,12 @@ void test1() { // DEFAULT: add nsw i32 {{.*}}, 1 // WRAPV: add i32 {{.*}}, 1 // TRAPV: llvm.sadd.with.overflow.i32({{.*}}, i32 1) + // TRAPV_HANDLER: foo( ++a; // DEFAULT: add nsw i32 {{.*}}, -1 // WRAPV: add i32 {{.*}}, -1 // TRAPV: llvm.sadd.with.overflow.i32({{.*}}, i32 -1) + // TRAPV_HANDLER: foo( --a; }