aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGExprScalar.cpp67
-rw-r--r--test/CodeGen/catch-undef-behavior.c25
-rw-r--r--test/CodeGen/integer-overflow.c9
-rw-r--r--test/CodeGen/trapv.c1
-rw-r--r--test/CodeGenCXX/catch-undef-behavior.cpp20
5 files changed, 104 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,
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index 8c45fa5045..5832b6c830 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -19,3 +19,28 @@ int bar(int *a) {
// CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
return *a;
}
+
+// CHECK: @lsh_overflow
+int lsh_overflow(int a, int b) {
+ // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
+ // CHECK-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
+ // CHECK-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT]], 0
+ // CHECK-NEXT: br i1 %[[NO_OVERFLOW]]
+
+ // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK-NEXT: ret i32 %[[RET]]
+ return a << b;
+}
+
+// CHECK: @rsh_inbounds
+int rsh_inbounds(int a, int b) {
+ // CHECK: %[[INBOUNDS:.*]] = icmp ult i32 %[[RHS:.*]], 32
+ // CHECK: br i1 %[[INBOUNDS]]
+
+ // CHECK: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
+ // CHECK-NEXT: ret i32 %[[RET]]
+ return a >> b;
+}
diff --git a/test/CodeGen/integer-overflow.c b/test/CodeGen/integer-overflow.c
index d7fff4ee4a..176ee65ff5 100644
--- a/test/CodeGen/integer-overflow.c
+++ b/test/CodeGen/integer-overflow.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=DEFAULT
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv | FileCheck %s --check-prefix=WRAPV
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=TRAPV
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fcatch-undefined-behavior | FileCheck %s --check-prefix=CATCH_UB
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv -ftrapv-handler foo | FileCheck %s --check-prefix=TRAPV_HANDLER
@@ -15,24 +16,28 @@ void test1() {
// DEFAULT: add nsw i32
// WRAPV: add i32
// TRAPV: llvm.sadd.with.overflow.i32
+ // CATCH_UB: llvm.sadd.with.overflow.i32
// TRAPV_HANDLER: foo(
f11G = a + b;
// DEFAULT: sub nsw i32
// WRAPV: sub i32
// TRAPV: llvm.ssub.with.overflow.i32
+ // CATCH_UB: llvm.ssub.with.overflow.i32
// TRAPV_HANDLER: foo(
f11G = a - b;
// DEFAULT: mul nsw i32
// WRAPV: mul i32
// TRAPV: llvm.smul.with.overflow.i32
+ // CATCH_UB: 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
+ // CATCH_UB: llvm.ssub.with.overflow.i32(i32 0
// TRAPV_HANDLER: foo(
f11G = -a;
@@ -41,12 +46,14 @@ void test1() {
// DEFAULT: add nsw i32 {{.*}}, 1
// WRAPV: add i32 {{.*}}, 1
// TRAPV: llvm.sadd.with.overflow.i32({{.*}}, i32 1)
+ // CATCH_UB: 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)
+ // CATCH_UB: llvm.sadd.with.overflow.i32({{.*}}, i32 -1)
// TRAPV_HANDLER: foo(
--a;
@@ -56,11 +63,13 @@ void test1() {
// DEFAULT: getelementptr inbounds i32*
// WRAPV: getelementptr i32*
// TRAPV: getelementptr inbounds i32*
+ // CATCH_UB: getelementptr inbounds i32*
// PR9350: char increment never overflows.
extern volatile signed char PR9350;
// DEFAULT: add i8 {{.*}}, 1
// WRAPV: add i8 {{.*}}, 1
// TRAPV: add i8 {{.*}}, 1
+ // CATCH_UB: add i8 {{.*}}, 1
++PR9350;
}
diff --git a/test/CodeGen/trapv.c b/test/CodeGen/trapv.c
index f52dad5564..abad5850b4 100644
--- a/test/CodeGen/trapv.c
+++ b/test/CodeGen/trapv.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -ftrapv %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fcatch-undefined-behavior %s -emit-llvm -o - | FileCheck %s
unsigned int ui, uj, uk;
int i, j, k;
diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp
index ed0a7763f5..0ec1cc1e05 100644
--- a/test/CodeGenCXX/catch-undef-behavior.cpp
+++ b/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -66,3 +66,23 @@ void member_access(S *p) {
// CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
k = p->f();
}
+
+// CHECK: @_Z12lsh_overflow
+int lsh_overflow(int a, int b) {
+ // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
+ // CHECK-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
+
+ // This is present for C++11 but not for C: C++ core issue 1457 allows a '1'
+ // to be shifted into the sign bit, but not out of it.
+ // CHECK-NEXT: %[[SHIFTED_OUT_NOT_SIGN:.*]] = lshr i32 %[[SHIFTED_OUT]], 1
+
+ // CHECK-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT_NOT_SIGN]], 0
+ // CHECK-NEXT: br i1 %[[NO_OVERFLOW]]
+
+ // CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK-NEXT: ret i32 %[[RET]]
+ return a << b;
+}