diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-08-25 00:32:28 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-08-25 00:32:28 +0000 |
commit | 9d3e226acad5e23e562cde0a69362bb266f2a333 (patch) | |
tree | 451bae1fb4f180c70d7c4e13fb30b50eeead561a /lib/CodeGen | |
parent | df5faf5e7ae6823d0af0b801c4ac26d47f2cee97 (diff) |
-fcatch-undefined-behavior: add the -ftrapv checks to the set of things caught
by this mode, and also check for signed left shift overflow. The rules for the
latter are a little subtle:
* neither C89 nor C++98 specify the behavior of a signed left shift at all
* in C99 and C11, shifting a 1 bit into the sign bit has undefined behavior
* in C++11, with core issue 1457, shifting a 1 bit *out* of the sign bit has
undefined behavior
As of this change, we use the C99 rules for all C language variants, and the
C++11 rules for all C++ language variants. Once we have individual
-fcatch-undefined-behavior= flags, this should be revisited.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162634 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 67 |
1 files changed, 49 insertions, 18 deletions
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 70d8bd7704..dd5af526eb 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -394,10 +394,12 @@ public: Value *EmitMul(const BinOpInfo &Ops) { if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getContext().getLangOpts().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_Undefined: + if (!CGF.CatchUndefined) + return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); + // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(Ops); } @@ -408,8 +410,8 @@ public: return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } bool isTrapvOverflowBehavior() { - return CGF.getContext().getLangOpts().getSignedOverflowBehavior() - == LangOptions::SOB_Trapping; + return CGF.getContext().getLangOpts().getSignedOverflowBehavior() + == LangOptions::SOB_Trapping || CGF.CatchUndefined; } /// Create a binary op that checks for overflow. /// Currently only supports +, - and *. @@ -1251,10 +1253,12 @@ EmitAddConsiderOverflowBehavior(const UnaryOperator *E, llvm::Value *InVal, llvm::Value *NextVal, bool IsInc) { switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec"); case LangOptions::SOB_Defined: return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec"); + case LangOptions::SOB_Undefined: + if (!CGF.CatchUndefined) + return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec"); + // Fall through. case LangOptions::SOB_Trapping: BinOpInfo BinOp; BinOp.LHS = InVal; @@ -2010,10 +2014,12 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); case LangOptions::SOB_Defined: return Builder.CreateAdd(op.LHS, op.RHS, "add"); + case LangOptions::SOB_Undefined: + if (!CGF.CatchUndefined) + return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); + // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(op); } @@ -2030,10 +2036,12 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { if (!op.LHS->getType()->isPointerTy()) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); case LangOptions::SOB_Defined: return Builder.CreateSub(op.LHS, op.RHS, "sub"); + case LangOptions::SOB_Undefined: + if (!CGF.CatchUndefined) + return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); + // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(op); } @@ -2110,14 +2118,38 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - if (CGF.CatchUndefined - && isa<llvm::IntegerType>(Ops.LHS->getType())) { + if (CGF.CatchUndefined && isa<llvm::IntegerType>(Ops.LHS->getType())) { unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); - llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); - CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, - llvm::ConstantInt::get(RHS->getType(), Width)), - Cont, CGF.getTrapBB()); + llvm::BasicBlock *Cont = CGF.createBasicBlock("shl.cont"); + llvm::BasicBlock *Trap = CGF.getTrapBB(); + llvm::Value *WidthMinusOne = + llvm::ConstantInt::get(RHS->getType(), Width - 1, "shl.width"); + CGF.Builder.CreateCondBr(Builder.CreateICmpULE(RHS, WidthMinusOne), + Cont, Trap); CGF.EmitBlock(Cont); + + if (Ops.Ty->hasSignedIntegerRepresentation()) { + // Check whether we are shifting any non-zero bits off the top of the + // integer. + Cont = CGF.createBasicBlock("shl.ok"); + llvm::Value *BitsShiftedOff = + Builder.CreateLShr(Ops.LHS, + Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros", + /*NUW*/true, /*NSW*/true), + "shl.check"); + if (CGF.getLangOpts().CPlusPlus) { + // In C99, we are not permitted to shift a 1 bit into the sign bit. + // Under C++11's rules, shifting a 1 bit into the sign bit is + // OK, but shifting a 1 bit out of it is not. (C89 and C++03 don't + // define signed left shifts, so we use the C99 and C++11 rules there). + llvm::Value *One = llvm::ConstantInt::get(BitsShiftedOff->getType(), 1); + BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One); + } + llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0); + Builder.CreateCondBr(Builder.CreateICmpEQ(BitsShiftedOff, Zero), + Cont, Trap); + CGF.EmitBlock(Cont); + } } return Builder.CreateShl(Ops.LHS, RHS, "shl"); @@ -2130,8 +2162,7 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - if (CGF.CatchUndefined - && isa<llvm::IntegerType>(Ops.LHS->getType())) { + if (CGF.CatchUndefined && isa<llvm::IntegerType>(Ops.LHS->getType())) { unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, |