From: Chris Lattner Date: Sat, 26 Jun 2010 21:25:03 +0000 (+0000) Subject: Implement support for -fwrapv, rdar://7221421 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a4d71455f0d418e16cc0c5c5aa55a3bad3494aee;p=clang Implement support for -fwrapv, rdar://7221421 As part of this, pull together trapv handling into the same enum. This also add support for NSW multiplies. This also makes PCH disagreement on overflow behavior silent, since it really doesn't matter except for warnings and codegen (no macros get defined etc). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106956 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 50937790d8..989ec38d29 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -189,9 +189,6 @@ def warn_pch_math_errno : Error< "math functions %select{do not respect|respect}0 'errno' in PCH " "file but they are currently set to %select{not respect|respect}1 " "'errno'">; -def warn_pch_overflow_checking : Error< - "signed integer overflow checking was %select{disabled|enabled}0 in PCH " - "file but is currently %select{disabled|enabled}1">; def warn_pch_optimize : Error< "the macro '__OPTIMIZE__' was %select{not defined|defined}0 in " "the PCH file but is currently %select{undefined|defined}1">; diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index cd9849d5db..c09d8aab44 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -66,9 +66,6 @@ public: unsigned MathErrno : 1; // Math functions must respect errno // (modulo the platform support). - unsigned OverflowChecking : 1; // Extension to call a handler function when - // signed integer arithmetic overflows. - unsigned HeinousExtensions : 1; // Extensions that we really don't like and // may be ripped out at any time. @@ -109,15 +106,12 @@ public: unsigned NoBitFieldTypeAlign : 1; private: - unsigned GC : 2; // Objective-C Garbage Collection modes. We - // declare this enum as unsigned because MSVC - // insists on making enums signed. Set/Query - // this value using accessors. + // We declare multibit enums as unsigned because MSVC insists on making enums + // signed. Set/Query these values using accessors. + unsigned GC : 2; // Objective-C Garbage Collection modes. unsigned SymbolVisibility : 3; // Symbol's visibility. - unsigned StackProtector : 2; // Whether stack protectors are on. We declare - // this enum as unsigned because MSVC insists - // on making enums signed. Set/Query this - // value using accessors. + unsigned StackProtector : 2; // Whether stack protectors are on. + unsigned SignedOverflowBehavior : 2; // How to handle signed integer overflow. public: unsigned InstantiationDepth; // Maximum template instantiation depth. @@ -131,6 +125,12 @@ public: Protected, Hidden }; + + enum SignedOverflowBehaviorTy { + SOB_Undefined, // Default C standard behavior. + SOB_Defined, // -fwrapv + SOB_Trapping // -ftrapv + }; LangOptions() { Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0; @@ -154,14 +154,15 @@ public: Blocks = 0; EmitAllDecls = 0; MathErrno = 1; - + SignedOverflowBehavior = SOB_Undefined; + AssumeSaneOperatorNew = 1; // FIXME: The default should be 1. AccessControl = 0; ElideConstructors = 1; - OverflowChecking = 0; + SignedOverflowBehavior = 0; ObjCGCBitmapPrint = 0; InstantiationDepth = 1024; @@ -197,6 +198,13 @@ public: return (VisibilityMode) SymbolVisibility; } void setVisibilityMode(VisibilityMode v) { SymbolVisibility = (unsigned) v; } + + SignedOverflowBehaviorTy getSignedOverflowBehavior() const { + return (SignedOverflowBehaviorTy)SignedOverflowBehavior; + } + void setSignedOverflowBehavior(SignedOverflowBehaviorTy V) { + SignedOverflowBehavior = (unsigned)V; + } }; } // end namespace clang diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index c1de8b1d3a..65284fbc9d 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -426,6 +426,8 @@ 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 fwrapv : Flag<"-fwrapv">, + HelpText<"Treat signed integer overflow as two's complement">; def pic_level : Separate<"-pic-level">, HelpText<"Value for __PIC__">; def pthread : Flag<"-pthread">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 129ce5e139..1e3669597f 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -388,6 +388,7 @@ def fuse_cxa_atexit : Flag<"-fuse-cxa-atexit">, Group; def fverbose_asm : Flag<"-fverbose-asm">, Group; def fvisibility_EQ : Joined<"-fvisibility=">, Group; def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">, Group; +def fwrapv : Flag<"-fwrapv">, Group; def fwritable_strings : Flag<"-fwritable-strings">, Group; def fzero_initialized_in_bss : Flag<"-fzero-initialized-in-bss">, Group; def ffunction_sections: Flag <"-ffunction-sections">, Group; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 4372279175..72da22695f 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -291,9 +291,17 @@ public: // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { - if (CGF.getContext().getLangOptions().OverflowChecking - && Ops.Ty->isSignedIntegerType()) - return EmitOverflowCheckedBinOp(Ops); + if (Ops.Ty->isSignedIntegerType()) { + switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { + case LangOptions::SOB_Undefined: + return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); + case LangOptions::SOB_Defined: + return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); + case LangOptions::SOB_Trapping: + return EmitOverflowCheckedBinOp(Ops); + } + } + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); @@ -1119,9 +1127,17 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { return Builder.CreateFNeg(Op, "neg"); // Signed integer overflow is undefined behavior. - if (E->getType()->isSignedIntegerType()) - return Builder.CreateNSWNeg(Op, "neg"); - + if (E->getType()->isSignedIntegerType()) { + switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { + case LangOptions::SOB_Trapping: + // FIXME: Implement -ftrapv for negate. + case LangOptions::SOB_Undefined: + return Builder.CreateNSWNeg(Op, "neg"); + case LangOptions::SOB_Defined: + return Builder.CreateNeg(Op, "neg"); + } + } + return Builder.CreateNeg(Op, "neg"); } @@ -1397,17 +1413,20 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { if (!Ops.Ty->isAnyPointerType()) { - if (CGF.getContext().getLangOptions().OverflowChecking && - Ops.Ty->isSignedIntegerType()) - return EmitOverflowCheckedBinOp(Ops); - + if (Ops.Ty->isSignedIntegerType()) { + switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { + case LangOptions::SOB_Undefined: + return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add"); + case LangOptions::SOB_Defined: + return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add"); + case LangOptions::SOB_Trapping: + return EmitOverflowCheckedBinOp(Ops); + } + } + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFAdd(Ops.LHS, Ops.RHS, "add"); - // Signed integer overflow is undefined behavior. - if (Ops.Ty->isSignedIntegerType()) - return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add"); - return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add"); } @@ -1473,17 +1492,20 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { if (!isa(Ops.LHS->getType())) { - if (CGF.getContext().getLangOptions().OverflowChecking - && Ops.Ty->isSignedIntegerType()) - return EmitOverflowCheckedBinOp(Ops); - + if (Ops.Ty->isSignedIntegerType()) { + switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { + case LangOptions::SOB_Undefined: + return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub"); + case LangOptions::SOB_Defined: + return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); + case LangOptions::SOB_Trapping: + return EmitOverflowCheckedBinOp(Ops); + } + } + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub"); - // Signed integer overflow is undefined behavior. - if (Ops.Ty->isSignedIntegerType()) - return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub"); - return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index e7cff8ea89..22b14825ef 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1182,6 +1182,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); + Args.AddLastArg(CmdArgs, options::OPT_fwrapv); Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); Args.AddLastArg(CmdArgs, options::OPT_pthread); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index e7a75a619d..76770ae36c 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -549,8 +549,11 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-femit-all-decls"); if (Opts.MathErrno) Res.push_back("-fmath-errno"); - if (Opts.OverflowChecking) - Res.push_back("-ftrapv"); + 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; + } if (Opts.HeinousExtensions) Res.push_back("-fheinous-gnu-extensions"); // Optimize is implicit. @@ -1257,8 +1260,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fvisibility_inlines_hidden)) Opts.InlineVisibilityHidden = 1; - - Opts.OverflowChecking = Args.hasArg(OPT_ftrapv); + + if (Args.hasArg(OPT_ftrapv)) + Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping); + else if (Args.hasArg(OPT_fwrapv)) + Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined); // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs // is specified, or -std is set to a conforming mode. diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 5bd3c0481a..c220e269c2 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -93,7 +93,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks); PARSE_LANGOPT_BENIGN(EmitAllDecls); PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno); - PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking); + PARSE_LANGOPT_BENIGN(getSignedOverflowBehavior()); PARSE_LANGOPT_IMPORTANT(HeinousExtensions, diag::warn_pch_heinous_extensions); // FIXME: Most of the options below are benign if the macro wasn't @@ -1915,7 +1915,8 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT(Blocks); PARSE_LANGOPT(EmitAllDecls); PARSE_LANGOPT(MathErrno); - PARSE_LANGOPT(OverflowChecking); + LangOpts.setSignedOverflowBehavior((LangOptions::SignedOverflowBehaviorTy) + Record[Idx++]); PARSE_LANGOPT(HeinousExtensions); PARSE_LANGOPT(Optimize); PARSE_LANGOPT(OptimizeSize); @@ -1926,13 +1927,10 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT(AccessControl); PARSE_LANGOPT(CharIsSigned); PARSE_LANGOPT(ShortWChar); - LangOpts.setGCMode((LangOptions::GCMode)Record[Idx]); - ++Idx; - LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]); - ++Idx; + LangOpts.setGCMode((LangOptions::GCMode)Record[Idx++]); + LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx++]); LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode) - Record[Idx]); - ++Idx; + Record[Idx++]); PARSE_LANGOPT(InstantiationDepth); PARSE_LANGOPT(OpenCL); PARSE_LANGOPT(CatchUndefined); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 3c42d474dc..efed0f0a6c 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -833,11 +833,8 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.MathErrno); // Math functions must respect errno // (modulo the platform support). - Record.push_back(LangOpts.OverflowChecking); // Extension to call a handler function when - // signed integer arithmetic overflows. - - Record.push_back(LangOpts.HeinousExtensions); // Extensions that we really don't like and - // may be ripped out at any time. + Record.push_back(LangOpts.getSignedOverflowBehavior()); + Record.push_back(LangOpts.HeinousExtensions); Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined. Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c index 1ffb05905a..4b9c3d5c42 100644 --- a/test/CodeGen/builtins-ppc-altivec.c +++ b/test/CodeGen/builtins-ppc-altivec.c @@ -428,13 +428,13 @@ int main () res_vus = vec_mladd(vus, vus, vus); // CHECK: mul <8 x i16> // CHECK: add <8 x i16> - res_vs = vec_mladd(vus, vs, vs); // CHECK: mul <8 x i16> + res_vs = vec_mladd(vus, vs, vs); // CHECK: mul nsw <8 x i16> // CHECK: add nsw <8 x i16> - res_vs = vec_mladd(vs, vus, vus); // CHECK: mul <8 x i16> + res_vs = vec_mladd(vs, vus, vus); // CHECK: mul nsw <8 x i16> // CHECK: add nsw <8 x i16> - res_vs = vec_mladd(vs, vs, vs); // CHECK: mul <8 x i16> + res_vs = vec_mladd(vs, vs, vs); // CHECK: mul nsw <8 x i16> // CHECK: add nsw <8 x i16> /* vec_mradds */ diff --git a/test/CodeGen/exprs.c b/test/CodeGen/exprs.c index a90ae58dc3..d182ce81ca 100644 --- a/test/CodeGen/exprs.c +++ b/test/CodeGen/exprs.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - // PR1895 // sizeof function @@ -119,16 +119,3 @@ void f9(struct S *x) { void f10() { __builtin_sin(0); } - -// Tests for signed integer overflow stuff. -// rdar://7432000 -void f11() { - // CHECK: define void @f11 - extern volatile int f11G, a, b; - // CHECK: add nsw i32 - f11G = a + b; - // CHECK: sub nsw i32 - f11G = a - b; - // CHECK: sub nsw i32 0, - f11G = -a; -} diff --git a/test/CodeGen/extern-inline.c b/test/CodeGen/extern-inline.c index 5dd9bfda57..60f6d034bf 100644 --- a/test/CodeGen/extern-inline.c +++ b/test/CodeGen/extern-inline.c @@ -19,7 +19,7 @@ int g2(void) {return f2(0,1);} static int f2(int a, int b) {return a*b;} // CHECK: load i32* %{{.*}} // CHECK: load i32* %{{.*}} -// CHECK: mul i32 %{{.*}}, %{{.*}} +// CHECK: mul nsw i32 %{{.*}}, %{{.*}} int h2(void) {return f2(1,2);} // CHECK: call i32 @f2 diff --git a/test/CodeGen/integer-overflow.c b/test/CodeGen/integer-overflow.c new file mode 100644 index 0000000000..7969216104 --- /dev/null +++ b/test/CodeGen/integer-overflow.c @@ -0,0 +1,33 @@ +// 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 + + +// Tests for signed integer overflow stuff. +// rdar://7432000 rdar://7221421 +void test1() { + // DEFAULT: define void @test1 + // WRAPV: define void @test1 + // TRAPV: define void @test1 + extern volatile int f11G, a, b; + + // DEFAULT: add nsw i32 + // WRAPV: add i32 + // TRAPV: llvm.sadd.with.overflow.i32 + f11G = a + b; + + // DEFAULT: sub nsw i32 + // WRAPV: sub i32 + // TRAPV: llvm.ssub.with.overflow.i32 + f11G = a - b; + + // DEFAULT: sub nsw i32 0, + // WRAPV: sub i32 0, + // TRAPV: sub nsw i32 0, + f11G = -a; + + // DEFAULT: mul nsw i32 + // WRAPV: mul i32 + // TRAPV: llvm.smul.with.overflow.i32 + f11G = a * b; +}