[cfe-commits] r151171 - in /cfe/trunk: lib/CodeGen/CGExprCXX.cpp test/CodeGenCXX/new-array-init.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Wed Feb 22 09:37:52 PST 2012


Author: cornedbee
Date: Wed Feb 22 11:37:52 2012
New Revision: 151171

URL: http://llvm.org/viewvc/llvm-project?rev=151171&view=rev
Log:
CodeGen for array new list initializers. Doesn't correctly clean up in the face of exceptions yet.

Added:
    cfe/trunk/test/CodeGenCXX/new-array-init.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=151171&r1=151170&r2=151171&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Feb 22 11:37:52 2012
@@ -508,6 +508,7 @@
 
 static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
                                         const CXXNewExpr *e,
+                                        unsigned minElements,
                                         llvm::Value *&numElements,
                                         llvm::Value *&sizeWithoutCookie) {
   QualType type = e->getAllocatedType();
@@ -581,6 +582,11 @@
     // Okay, compute a count at the right width.
     llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth);
 
+    // If there is a brace-initializer, we cannot allocate fewer elements than
+    // there are initializers. If we do, that's treated like an overflow.
+    if (adjustedCount.ult(minElements))
+      hasAnyOverflow = true;
+
     // Scale numElements by that.  This might overflow, but we don't
     // care because it only overflows if allocationSize does, too, and
     // if that overflows then we shouldn't use this.
@@ -612,14 +618,16 @@
 
   // Otherwise, we might need to use the overflow intrinsics.
   } else {
-    // There are up to four conditions we need to test for:
+    // There are up to five conditions we need to test for:
     // 1) if isSigned, we need to check whether numElements is negative;
     // 2) if numElementsWidth > sizeWidth, we need to check whether
     //   numElements is larger than something representable in size_t;
-    // 3) we need to compute
+    // 3) if minElements > 0, we need to check whether numElements is smaller
+    //    than that.
+    // 4) we need to compute
     //      sizeWithoutCookie := numElements * typeSizeMultiplier
     //    and check whether it overflows; and
-    // 4) if we need a cookie, we need to compute
+    // 5) if we need a cookie, we need to compute
     //      size := sizeWithoutCookie + cookieSize
     //    and check whether it overflows.
 
@@ -646,10 +654,11 @@
       // If there's a non-1 type size multiplier, then we can do the
       // signedness check at the same time as we do the multiply
       // because a negative number times anything will cause an
-      // unsigned overflow.  Otherwise, we have to do it here.
+      // unsigned overflow.  Otherwise, we have to do it here. But at least
+      // in this case, we can subsume the >= minElements check.
       if (typeSizeMultiplier == 1)
         hasOverflow = CGF.Builder.CreateICmpSLT(numElements,
-                                      llvm::ConstantInt::get(CGF.SizeTy, 0));
+                              llvm::ConstantInt::get(CGF.SizeTy, minElements));
 
     // Otherwise, zext up to size_t if necessary.
     } else if (numElementsWidth < sizeWidth) {
@@ -658,6 +667,21 @@
 
     assert(numElements->getType() == CGF.SizeTy);
 
+    if (minElements) {
+      // Don't allow allocation of fewer elements than we have initializers.
+      if (!hasOverflow) {
+        hasOverflow = CGF.Builder.CreateICmpULT(numElements,
+                              llvm::ConstantInt::get(CGF.SizeTy, minElements));
+      } else if (numElementsWidth > sizeWidth) {
+        // The other existing overflow subsumes this check.
+        // We do an unsigned comparison, since any signed value < -1 is
+        // taken care of either above or below.
+        hasOverflow = CGF.Builder.CreateOr(hasOverflow,
+                          CGF.Builder.CreateICmpULT(numElements,
+                              llvm::ConstantInt::get(CGF.SizeTy, minElements)));
+      }
+    }
+
     size = numElements;
 
     // Multiply by the type size if necessary.  This multiplier
@@ -741,11 +765,8 @@
   return size;
 }
 
-static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
-                                    llvm::Value *NewPtr) {
-
-  const Expr *Init = E->getInitializer();
-  QualType AllocType = E->getAllocatedType();
+static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
+                                    QualType AllocType, llvm::Value *NewPtr) {
 
   CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
   if (!CGF.hasAggregateLLVMType(AllocType))
@@ -775,26 +796,39 @@
   if (!E->hasInitializer())
     return; // We have a POD type.
 
-  // Check if the number of elements is constant.
-  bool checkZero = true;
-  if (llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements)) {
-    // If it's constant zero, skip the whole loop.
-    if (constNum->isZero()) return;
-
-    checkZero = false;
-  }
-
+  llvm::Value *explicitPtr = beginPtr;
   // Find the end of the array, hoisted out of the loop.
   llvm::Value *endPtr =
     Builder.CreateInBoundsGEP(beginPtr, numElements, "array.end");
 
+  unsigned initializerElements = 0;
+
+  const Expr *Init = E->getInitializer();
+  // If the initializer is an initializer list, first do the explicit elements.
+  if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+    initializerElements = ILE->getNumInits();
+    QualType elementType = E->getAllocatedType();
+    // FIXME: exception-safety for the explicit initializers
+    for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) {
+      StoreAnyExprIntoOneUnit(*this, ILE->getInit(i), elementType, explicitPtr);
+      explicitPtr =Builder.CreateConstGEP1_32(explicitPtr, 1, "array.exp.next");
+    }
+
+    // The remaining elements are filled with the array filler expression.
+    Init = ILE->getArrayFiller();
+  }
+
   // Create the continuation block.
   llvm::BasicBlock *contBB = createBasicBlock("new.loop.end");
 
-  // If we need to check for zero, do so now.
-  if (checkZero) {
+  // If the number of elements isn't constant, we have to now check if there is
+  // anything left to initialize.
+  if (llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements)) {
+    // If all elements have already been initialized, skip the whole loop.
+    if (constNum->getZExtValue() <= initializerElements) return;
+  } else {
     llvm::BasicBlock *nonEmptyBB = createBasicBlock("new.loop.nonempty");
-    llvm::Value *isEmpty = Builder.CreateICmpEQ(beginPtr, endPtr,
+    llvm::Value *isEmpty = Builder.CreateICmpEQ(explicitPtr, endPtr,
                                                 "array.isempty");
     Builder.CreateCondBr(isEmpty, contBB, nonEmptyBB);
     EmitBlock(nonEmptyBB);
@@ -808,8 +842,8 @@
 
   // Set up the current-element phi.
   llvm::PHINode *curPtr =
-    Builder.CreatePHI(beginPtr->getType(), 2, "array.cur");
-  curPtr->addIncoming(beginPtr, entryBB);
+    Builder.CreatePHI(explicitPtr->getType(), 2, "array.cur");
+  curPtr->addIncoming(explicitPtr, entryBB);
 
   // Enter a partial-destruction cleanup if necessary.
   QualType::DestructionKind dtorKind = elementType.isDestructedType();
@@ -823,7 +857,7 @@
   }
 
   // Emit the initializer into this element.
-  StoreAnyExprIntoOneUnit(*this, E, curPtr);
+  StoreAnyExprIntoOneUnit(*this, Init, E->getAllocatedType(), curPtr);
 
   // Leave the cleanup if we entered one.
   if (cleanupDominator) {
@@ -895,7 +929,7 @@
   if (!Init)
     return;
 
-  StoreAnyExprIntoOneUnit(CGF, E, NewPtr);
+  StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr);
 }
 
 namespace {
@@ -1069,10 +1103,18 @@
   // The allocation size is the first argument.
   QualType sizeType = getContext().getSizeType();
 
+  // If there is a brace-initializer, cannot allocate fewer elements than inits.
+  unsigned minElements = 0;
+  if (E->isArray() && E->hasInitializer()) {
+    if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E->getInitializer()))
+      minElements = ILE->getNumInits();
+  }
+
   llvm::Value *numElements = 0;
   llvm::Value *allocSizeWithoutCookie = 0;
   llvm::Value *allocSize =
-    EmitCXXNewAllocSize(*this, E, numElements, allocSizeWithoutCookie);
+    EmitCXXNewAllocSize(*this, E, minElements, numElements,
+                        allocSizeWithoutCookie);
   
   allocatorArgs.add(RValue::get(allocSize), sizeType);
 

Added: cfe/trunk/test/CodeGenCXX/new-array-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/new-array-init.cpp?rev=151171&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/new-array-init.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/new-array-init.cpp Wed Feb 22 11:37:52 2012
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+// CHECK: define void @_Z2fni
+void fn(int n) {
+  // CHECK: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+  // CHECK: store i32 1
+  // CHECK: store i32 2
+  // CHECK: store i32 3
+  // CHECK: icmp eq i32*
+  // CHECK-NEXT: br i1
+  new int[n] { 1, 2, 3 };
+}
+
+// CHECK: define void @_Z15const_underflowv
+void const_underflow() {
+  // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+  // CHECK: call noalias i8* @_Zna{{.}}(i{{32|64}} -1)
+  new int[2] { 1, 2, 3 };
+}
+
+// CHECK: define void @_Z11const_exactv
+void const_exact() {
+  // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+  // CHECK-NOT: icmp eq i32*
+  new int[3] { 1, 2, 3 };
+}
+
+// CHECK: define void @_Z16const_sufficientv
+void const_sufficient() {
+  // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
+  new int[4] { 1, 2, 3 };
+  // CHECK: ret void
+}





More information about the cfe-commits mailing list