зеркало из https://github.com/microsoft/clang-1.git
-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
This commit is contained in:
Родитель
df5faf5e7a
Коммит
9d3e226aca
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче