[cfe-commits] r162634 - in /cfe/trunk: lib/CodeGen/CGExprScalar.cpp test/CodeGen/catch-undef-behavior.c test/CodeGen/integer-overflow.c test/CodeGen/trapv.c test/CodeGenCXX/catch-undef-behavior.cpp

Richard Smith richard-llvm at metafoo.co.uk
Fri Aug 24 17:32:28 PDT 2012


Author: rsmith
Date: Fri Aug 24 19:32:28 2012
New Revision: 162634

URL: http://llvm.org/viewvc/llvm-project?rev=162634&view=rev
Log:
-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.

Modified:
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/test/CodeGen/catch-undef-behavior.c
    cfe/trunk/test/CodeGen/integer-overflow.c
    cfe/trunk/test/CodeGen/trapv.c
    cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=162634&r1=162633&r2=162634&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Fri Aug 24 19:32:28 2012
@@ -394,10 +394,12 @@
   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 @@
     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 @@
                                 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 @@
 
   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 @@
   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 @@
   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 @@
   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,

Modified: cfe/trunk/test/CodeGen/catch-undef-behavior.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/catch-undef-behavior.c?rev=162634&r1=162633&r2=162634&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/catch-undef-behavior.c (original)
+++ cfe/trunk/test/CodeGen/catch-undef-behavior.c Fri Aug 24 19:32:28 2012
@@ -19,3 +19,28 @@
   // 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;
+}

Modified: cfe/trunk/test/CodeGen/integer-overflow.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/integer-overflow.c?rev=162634&r1=162633&r2=162634&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/integer-overflow.c (original)
+++ cfe/trunk/test/CodeGen/integer-overflow.c Fri Aug 24 19:32:28 2012
@@ -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 @@
   // 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 @@
   // 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 @@
   // 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;
 }

Modified: cfe/trunk/test/CodeGen/trapv.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/trapv.c?rev=162634&r1=162633&r2=162634&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/trapv.c (original)
+++ cfe/trunk/test/CodeGen/trapv.c Fri Aug 24 19:32:28 2012
@@ -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;

Modified: cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp?rev=162634&r1=162633&r2=162634&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/catch-undef-behavior.cpp Fri Aug 24 19:32:28 2012
@@ -66,3 +66,23 @@
   // 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;
+}





More information about the cfe-commits mailing list