Refactor the C++ ABI code a little bit to take advantage of
what I'm going to treat as basically universal properties of
array-cookie code.  Implement MS array cookies on top of that.
Based on a patch by Timur Iskhodzhanov!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155886 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index befebbe..8561ae3 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -145,6 +145,13 @@
 }
 
 CharUnits CGCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
+  if (!requiresArrayCookie(expr))
+    return CharUnits::Zero();
+  return getArrayCookieSizeImpl(expr->getAllocatedType());
+}
+
+CharUnits CGCXXABI::getArrayCookieSizeImpl(QualType elementType) {
+  // BOGUS
   return CharUnits::Zero();
 }
 
@@ -158,16 +165,53 @@
   return 0;
 }
 
-void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
-                               const CXXDeleteExpr *expr, QualType ElementType,
-                               llvm::Value *&NumElements,
-                               llvm::Value *&AllocPtr, CharUnits &CookieSize) {
-  ErrorUnsupportedABI(CGF, "array cookie reading");
+bool CGCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
+                                   QualType elementType) {
+  // If the class's usual deallocation function takes two arguments,
+  // it needs a cookie.
+  if (expr->doesUsualArrayDeleteWantSize())
+    return true;
 
-  // This should be enough to avoid assertions.
-  NumElements = 0;
-  AllocPtr = llvm::Constant::getNullValue(CGF.Builder.getInt8PtrTy());
-  CookieSize = CharUnits::Zero();
+  return elementType.isDestructedType();
+}
+
+bool CGCXXABI::requiresArrayCookie(const CXXNewExpr *expr) {
+  // If the class's usual deallocation function takes two arguments,
+  // it needs a cookie.
+  if (expr->doesUsualArrayDeleteWantSize())
+    return true;
+
+  return expr->getAllocatedType().isDestructedType();
+}
+
+void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *ptr,
+                               const CXXDeleteExpr *expr, QualType eltTy,
+                               llvm::Value *&numElements,
+                               llvm::Value *&allocPtr, CharUnits &cookieSize) {
+  // Derive a char* in the same address space as the pointer.
+  unsigned AS = cast<llvm::PointerType>(ptr->getType())->getAddressSpace();
+  llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
+  ptr = CGF.Builder.CreateBitCast(ptr, charPtrTy);
+
+  // If we don't need an array cookie, bail out early.
+  if (!requiresArrayCookie(expr, eltTy)) {
+    allocPtr = ptr;
+    numElements = 0;
+    cookieSize = CharUnits::Zero();
+    return;
+  }
+
+  cookieSize = getArrayCookieSizeImpl(eltTy);
+  allocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(ptr,
+                                                    -cookieSize.getQuantity());
+  numElements = readArrayCookieImpl(CGF, allocPtr, cookieSize);
+}
+
+llvm::Value *CGCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
+                                           llvm::Value *ptr,
+                                           CharUnits cookieSize) {
+  ErrorUnsupportedABI(CGF, "reading a new[] cookie");
+  return llvm::ConstantInt::get(CGF.SizeTy, 0);
 }
 
 void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 4e045f5..1621016 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -71,6 +71,9 @@
 
   ASTContext &getContext() const { return CGM.getContext(); }
 
+  virtual bool requiresArrayCookie(const CXXDeleteExpr *E, QualType eltType);
+  virtual bool requiresArrayCookie(const CXXNewExpr *E);
+
 public:
 
   virtual ~CGCXXABI();
@@ -209,7 +212,8 @@
   /// \param NewPtr - a char* which is the presumed-non-null
   ///   return value of the allocation function
   /// \param NumElements - the computed number of elements,
-  ///   potentially collapsed from the multidimensional array case
+  ///   potentially collapsed from the multidimensional array case;
+  ///   always a size_t
   /// \param ElementType - the base element allocated type,
   ///   i.e. the allocated type after stripping all array types
   virtual llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
@@ -236,6 +240,25 @@
                                QualType ElementType, llvm::Value *&NumElements,
                                llvm::Value *&AllocPtr, CharUnits &CookieSize);
 
+protected:
+  /// Returns the extra size required in order to store the array
+  /// cookie for the given type.  Assumes that an array cookie is
+  /// required.
+  virtual CharUnits getArrayCookieSizeImpl(QualType elementType);
+
+  /// Reads the array cookie for an allocation which is known to have one.
+  /// This is called by the standard implementation of ReadArrayCookie.
+  ///
+  /// \param ptr - a pointer to the allocation made for an array, as a char*
+  /// \param cookieSize - the computed cookie size of an array
+  /// Other parameters are as above.
+  /// \return a size_t
+  virtual llvm::Value *readArrayCookieImpl(CodeGenFunction &IGF,
+                                           llvm::Value *ptr,
+                                           CharUnits cookieSize);
+
+public:
+
   /*************************** Static local guards ****************************/
 
   /// Emits the guarded initializer and destructor setup for the given
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 38f5008..bde03a7 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -138,6 +138,7 @@
     union {
       unsigned char PointerAlignInBytes;
       unsigned char PointerSizeInBytes;
+      unsigned char SizeSizeInBytes;     // sizeof(size_t)
     };
   };
 
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 98f67f3..1a36a08 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -48,10 +48,6 @@
     return PtrDiffTy;
   }
 
-  bool NeedsArrayCookie(const CXXNewExpr *expr);
-  bool NeedsArrayCookie(const CXXDeleteExpr *expr,
-                        QualType elementType);
-
 public:
   ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
     CGCXXABI(CGM), PtrDiffTy(0), IsARM(IsARM) { }
@@ -111,16 +107,15 @@
 
   void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
 
-  CharUnits GetArrayCookieSize(const CXXNewExpr *expr);
+  CharUnits getArrayCookieSizeImpl(QualType elementType);
   llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
                                      llvm::Value *NewPtr,
                                      llvm::Value *NumElements,
                                      const CXXNewExpr *expr,
                                      QualType ElementType);
-  void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
-                       const CXXDeleteExpr *expr,
-                       QualType ElementType, llvm::Value *&NumElements,
-                       llvm::Value *&AllocPtr, CharUnits &CookieSize);
+  llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
+                                   llvm::Value *allocPtr,
+                                   CharUnits cookieSize);
 
   void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
                        llvm::GlobalVariable *DeclPtr, bool PerformInit);
@@ -148,16 +143,14 @@
 
   void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
 
-  CharUnits GetArrayCookieSize(const CXXNewExpr *expr);
+  CharUnits getArrayCookieSizeImpl(QualType elementType);
   llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
                                      llvm::Value *NewPtr,
                                      llvm::Value *NumElements,
                                      const CXXNewExpr *expr,
                                      QualType ElementType);
-  void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
-                       const CXXDeleteExpr *expr,
-                       QualType ElementType, llvm::Value *&NumElements,
-                       llvm::Value *&AllocPtr, CharUnits &CookieSize);
+  llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
+                                   CharUnits cookieSize);
 
 private:
   /// \brief Returns true if the given instance method is one of the
@@ -796,54 +789,11 @@
 
 /************************** Array allocation cookies **************************/
 
-bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) {
-  // If the class's usual deallocation function takes two arguments,
-  // it needs a cookie.
-  if (expr->doesUsualArrayDeleteWantSize())
-    return true;
-
-  // Automatic Reference Counting:
-  //   We need an array cookie for pointers with strong or weak lifetime.
-  QualType AllocatedType = expr->getAllocatedType();
-  if (getContext().getLangOpts().ObjCAutoRefCount &&
-      AllocatedType->isObjCLifetimeType()) {
-    switch (AllocatedType.getObjCLifetime()) {
-    case Qualifiers::OCL_None:
-    case Qualifiers::OCL_ExplicitNone:
-    case Qualifiers::OCL_Autoreleasing:
-      return false;
-      
-    case Qualifiers::OCL_Strong:
-    case Qualifiers::OCL_Weak:
-      return true;
-    }
-  }
-
-  // Otherwise, if the class has a non-trivial destructor, it always
-  // needs a cookie.
-  const CXXRecordDecl *record =
-    AllocatedType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
-  return (record && !record->hasTrivialDestructor());
-}
-
-bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr,
-                                     QualType elementType) {
-  // If the class's usual deallocation function takes two arguments,
-  // it needs a cookie.
-  if (expr->doesUsualArrayDeleteWantSize())
-    return true;
-
-  return elementType.isDestructedType();
-}
-
-CharUnits ItaniumCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
-  if (!NeedsArrayCookie(expr))
-    return CharUnits::Zero();
-  
-  // Padding is the maximum of sizeof(size_t) and alignof(elementType)
-  ASTContext &Ctx = getContext();
-  return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
-                  Ctx.getTypeAlignInChars(expr->getAllocatedType()));
+CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
+  // The array cookie is a size_t; pad that up to the element alignment.
+  // The cookie is actually right-justified in that space.
+  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),
+                  CGM.getContext().getTypeAlignInChars(elementType));
 }
 
 llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
@@ -851,7 +801,7 @@
                                                   llvm::Value *NumElements,
                                                   const CXXNewExpr *expr,
                                                   QualType ElementType) {
-  assert(NeedsArrayCookie(expr));
+  assert(requiresArrayCookie(expr));
 
   unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
 
@@ -862,6 +812,7 @@
   // The size of the cookie.
   CharUnits CookieSize =
     std::max(SizeSize, Ctx.getTypeAlignInChars(ElementType));
+  assert(CookieSize == getArrayCookieSizeImpl(ElementType));
 
   // Compute an offset to the cookie.
   llvm::Value *CookiePtr = NewPtr;
@@ -882,53 +833,25 @@
                                                 CookieSize.getQuantity());  
 }
 
-void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
-                                    llvm::Value *Ptr,
-                                    const CXXDeleteExpr *expr,
-                                    QualType ElementType,
-                                    llvm::Value *&NumElements,
-                                    llvm::Value *&AllocPtr,
-                                    CharUnits &CookieSize) {
-  // Derive a char* in the same address space as the pointer.
-  unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
-  llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
+llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
+                                                llvm::Value *allocPtr,
+                                                CharUnits cookieSize) {
+  // The element size is right-justified in the cookie.
+  llvm::Value *numElementsPtr = allocPtr;
+  CharUnits numElementsOffset =
+    cookieSize - CharUnits::fromQuantity(CGF.SizeSizeInBytes);
+  if (!numElementsOffset.isZero())
+    numElementsPtr =
+      CGF.Builder.CreateConstInBoundsGEP1_64(numElementsPtr,
+                                             numElementsOffset.getQuantity());
 
-  // If we don't need an array cookie, bail out early.
-  if (!NeedsArrayCookie(expr, ElementType)) {
-    AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
-    NumElements = 0;
-    CookieSize = CharUnits::Zero();
-    return;
-  }
-
-  QualType SizeTy = getContext().getSizeType();
-  CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy);
-  llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
-  
-  CookieSize
-    = std::max(SizeSize, getContext().getTypeAlignInChars(ElementType));
-
-  CharUnits NumElementsOffset = CookieSize - SizeSize;
-
-  // Compute the allocated pointer.
-  AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
-  AllocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr,
-                                                    -CookieSize.getQuantity());
-
-  llvm::Value *NumElementsPtr = AllocPtr;
-  if (!NumElementsOffset.isZero())
-    NumElementsPtr =
-      CGF.Builder.CreateConstInBoundsGEP1_64(NumElementsPtr,
-                                             NumElementsOffset.getQuantity());
-  NumElementsPtr = 
-    CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo(AS));
-  NumElements = CGF.Builder.CreateLoad(NumElementsPtr);
+  unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+  numElementsPtr = 
+    CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
+  return CGF.Builder.CreateLoad(numElementsPtr);
 }
 
-CharUnits ARMCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
-  if (!NeedsArrayCookie(expr))
-    return CharUnits::Zero();
-
+CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
   // On ARM, the cookie is always:
   //   struct array_cookie {
   //     std::size_t element_size; // element_size != 0
@@ -936,7 +859,7 @@
   //   };
   // TODO: what should we do if the allocated type actually wants
   // greater alignment?
-  return getContext().getTypeSizeInChars(getContext().getSizeType()) * 2;
+  return CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes);
 }
 
 llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
@@ -944,7 +867,7 @@
                                               llvm::Value *NumElements,
                                               const CXXNewExpr *expr,
                                               QualType ElementType) {
-  assert(NeedsArrayCookie(expr));
+  assert(requiresArrayCookie(expr));
 
   // NewPtr is a char*.
 
@@ -975,44 +898,18 @@
                                                 CookieSize.getQuantity());
 }
 
-void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
-                                llvm::Value *Ptr,
-                                const CXXDeleteExpr *expr,
-                                QualType ElementType,
-                                llvm::Value *&NumElements,
-                                llvm::Value *&AllocPtr,
-                                CharUnits &CookieSize) {
-  // Derive a char* in the same address space as the pointer.
-  unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
-  llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
+llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
+                                            llvm::Value *allocPtr,
+                                            CharUnits cookieSize) {
+  // The number of elements is at offset sizeof(size_t) relative to
+  // the allocated pointer.
+  llvm::Value *numElementsPtr
+    = CGF.Builder.CreateConstInBoundsGEP1_64(allocPtr, CGF.SizeSizeInBytes);
 
-  // If we don't need an array cookie, bail out early.
-  if (!NeedsArrayCookie(expr, ElementType)) {
-    AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
-    NumElements = 0;
-    CookieSize = CharUnits::Zero();
-    return;
-  }
-
-  QualType SizeTy = getContext().getSizeType();
-  CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy);
-  llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
-  
-  // The cookie size is always 2 * sizeof(size_t).
-  CookieSize = 2 * SizeSize;
-
-  // The allocated pointer is the input ptr, minus that amount.
-  AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
-  AllocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr,
-                                               -CookieSize.getQuantity());
-
-  // The number of elements is at offset sizeof(size_t) relative to that.
-  llvm::Value *NumElementsPtr
-    = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr,
-                                             SizeSize.getQuantity());
-  NumElementsPtr = 
-    CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo(AS));
-  NumElements = CGF.Builder.CreateLoad(NumElementsPtr);
+  unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+  numElementsPtr = 
+    CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
+  return CGF.Builder.CreateLoad(numElementsPtr);
 }
 
 /*********************** Static local initialization **************************/
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 825e041..a88c6ba 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -78,17 +78,77 @@
   //     delete[] p;
   //   }
   // Whereas it prints "104" and "104" if you give A a destructor.
-  void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
-                       const CXXDeleteExpr *expr,
-                       QualType ElementType, llvm::Value *&NumElements,
-                       llvm::Value *&AllocPtr, CharUnits &CookieSize) {
-    CGF.CGM.ErrorUnsupported(expr, "don't know how to handle array cookies "
-                                   "in the Microsoft C++ ABI");
-  }
+
+  bool requiresArrayCookie(const CXXDeleteExpr *expr, QualType elementType);
+  bool requiresArrayCookie(const CXXNewExpr *expr);
+  CharUnits getArrayCookieSizeImpl(QualType type);
+  llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
+                                     llvm::Value *NewPtr,
+                                     llvm::Value *NumElements,
+                                     const CXXNewExpr *expr,
+                                     QualType ElementType);
+  llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
+                                   llvm::Value *allocPtr,
+                                   CharUnits cookieSize);
 };
 
 }
 
+bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
+                                   QualType elementType) {
+  // Microsoft seems to completely ignore the possibility of a
+  // two-argument usual deallocation function.
+  return elementType.isDestructedType();
+}
+
+bool MicrosoftCXXABI::requiresArrayCookie(const CXXNewExpr *expr) {
+  // Microsoft seems to completely ignore the possibility of a
+  // two-argument usual deallocation function.
+  return expr->getAllocatedType().isDestructedType();
+}
+
+CharUnits MicrosoftCXXABI::getArrayCookieSizeImpl(QualType type) {
+  // The array cookie is always a size_t; we then pad that out to the
+  // alignment of the element type.
+  ASTContext &Ctx = getContext();
+  return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
+                  Ctx.getTypeAlignInChars(type));
+}
+
+llvm::Value *MicrosoftCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
+                                                  llvm::Value *allocPtr,
+                                                  CharUnits cookieSize) {
+  unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace();
+  llvm::Value *numElementsPtr =
+    CGF.Builder.CreateBitCast(allocPtr, CGF.SizeTy->getPointerTo(AS));
+  return CGF.Builder.CreateLoad(numElementsPtr);
+}
+
+llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
+                                                    llvm::Value *newPtr,
+                                                    llvm::Value *numElements,
+                                                    const CXXNewExpr *expr,
+                                                    QualType elementType) {
+  assert(requiresArrayCookie(expr));
+
+  // The size of the cookie.
+  CharUnits cookieSize = getArrayCookieSizeImpl(elementType);
+
+  // Compute an offset to the cookie.
+  llvm::Value *cookiePtr = newPtr;
+
+  // Write the number of elements into the appropriate slot.
+  unsigned AS = cast<llvm::PointerType>(newPtr->getType())->getAddressSpace();
+  llvm::Value *numElementsPtr
+    = CGF.Builder.CreateBitCast(cookiePtr, CGF.SizeTy->getPointerTo(AS));
+  CGF.Builder.CreateStore(numElements, numElementsPtr);
+
+  // Finally, compute a pointer to the actual data buffer by skipping
+  // over the cookie completely.
+  return CGF.Builder.CreateConstInBoundsGEP1_64(newPtr,
+                                                cookieSize.getQuantity());
+}
+
 CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
   return new MicrosoftCXXABI(CGM);
 }