aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGExprScalar.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-08-25 00:32:28 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-08-25 00:32:28 +0000
commit9d3e226acad5e23e562cde0a69362bb266f2a333 (patch)
tree451bae1fb4f180c70d7c4e13fb30b50eeead561a /lib/CodeGen/CGExprScalar.cpp
parentdf5faf5e7ae6823d0af0b801c4ac26d47f2cee97 (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/CGExprScalar.cpp')
-rw-r--r--lib/CodeGen/CGExprScalar.cpp67
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,