commit 3cffb6cf41b96816a97a4027d3daaa2cf738e769
Author: Timur Iskhodzhanov <timurrrr@google.com>
Date:   Mon Apr 16 21:45:18 2012 +0400

    Fix http://llvm.org/bugs/show_bug.cgi?id=12333 (array cookies)

diff --git lib/CodeGen/MicrosoftCXXABI.cpp lib/CodeGen/MicrosoftCXXABI.cpp
index 825e041..38b3ab4 100644
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -78,17 +78,135 @@ public:
   //     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");
-  }
+
+  virtual CharUnits GetArrayCookieSize(const CXXNewExpr *expr);
+
+  virtual llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
+                                             llvm::Value *NewPtr,
+                                             llvm::Value *NumElements,
+                                             const CXXNewExpr *expr,
+                                             QualType ElementType);
+
+  virtual void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
+                               const CXXDeleteExpr *expr,
+                               QualType ElementType, llvm::Value *&NumElements,
+                               llvm::Value *&AllocPtr, CharUnits &CookieSize);
+
+private:
+  bool NeedArrayCookie(const CXXNewExpr* newExpr) const;
+
+  bool NeedArrayCookie(const CXXDeleteExpr* delExpr,
+                       QualType elementType) const;
+
+  CharUnits GetArrayCookieSizeInternal(const QualType &type);
 };
 
 }
 
+bool MicrosoftCXXABI::NeedArrayCookie(const CXXNewExpr* newExpr) const {
+  if (newExpr->doesUsualArrayDeleteWantSize()) {
+    return true;
+  }
+
+  const CXXRecordDecl* type =
+          newExpr->getAllocatedType()->
+              getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+
+  return (type && !type->hasTrivialDestructor());
+}
+
+bool MicrosoftCXXABI::NeedArrayCookie(const CXXDeleteExpr* delExpr,
+                                      QualType elemType) const {
+  if (delExpr->doesUsualArrayDeleteWantSize()) {
+    return true;
+  }
+
+  const CXXRecordDecl* type =
+    elemType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+
+  return (type && !type->hasTrivialDestructor());
+}
+
+CharUnits MicrosoftCXXABI::GetArrayCookieSizeInternal(const QualType &type) {
+  // Padding is the maximum of sizeof(Char32Ty) and alignof(elementType)
+  ASTContext &Ctx = getContext();
+  return std::max(Ctx.getTypeSizeInChars(Ctx.Char32Ty),
+                  Ctx.getTypeAlignInChars(type));
+}
+
+CharUnits MicrosoftCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) {
+  if (!NeedArrayCookie(expr)) {
+    return CharUnits::Zero();
+  }
+
+  return GetArrayCookieSizeInternal(expr->getAllocatedType());
+}
+
+void MicrosoftCXXABI::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);
+
+  // If we don't need an array cookie, bail out early.
+  if (!NeedArrayCookie(expr, ElementType)) {
+    AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
+    NumElements = 0;
+    CookieSize = CharUnits::Zero();
+    return;
+  }
+
+  ASTContext &Ctx = getContext();
+  QualType SizeTy = Ctx.Char32Ty;
+  llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
+
+  CookieSize = GetArrayCookieSizeInternal(ElementType);
+
+  // Compute the allocated pointer.
+  AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
+  AllocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr,
+    -CookieSize.getQuantity());
+
+  llvm::Value *NumElementsPtr =
+    CGF.Builder.CreateBitCast(AllocPtr, SizeLTy->getPointerTo(AS));
+  NumElements = CGF.Builder.CreateLoad(NumElementsPtr);
+}
+
+llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
+                                                    llvm::Value *NewPtr,
+                                                    llvm::Value *NumElements,
+                                                    const CXXNewExpr *expr,
+                                                    QualType ElementType) {
+  assert(NeedArrayCookie(expr));
+
+  unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
+
+  ASTContext &Ctx = getContext();
+  QualType SizeTy = Ctx.Char32Ty;
+
+  // The size of the cookie.
+  CharUnits CookieSize = GetArrayCookieSizeInternal(ElementType);
+
+  // Compute an offset to the cookie.
+  llvm::Value *CookiePtr = NewPtr;
+
+  // Write the number of elements into the appropriate slot.
+  llvm::Value *NumElementsPtr
+    = CGF.Builder.CreateBitCast(CookiePtr,
+                                CGF.ConvertType(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);
 }
diff --git test/CodeGenCXX/mangle-ms.cpp test/CodeGenCXX/mangle-ms.cpp
index 3e07f64..6556ab7 100644
--- test/CodeGenCXX/mangle-ms.cpp
+++ test/CodeGenCXX/mangle-ms.cpp
@@ -113,7 +113,6 @@ void operator_new_delete() {
   char *array = new char[42];
 // CHECK: @"\01??_U@YAPAXI@Z"
 
-  // FIXME: enable once http://llvm.org/bugs/show_bug.cgi?id=12333 is fixed
-  // delete [] array;
-// Should be: @"\01??_V@YAXPAX@Z"
+  delete [] array;
+// CHECK: @"\01??_V@YAXPAX@Z"
 }
diff --git test/CodeGenCXX/microsoft-abi-array-cookies.cpp test/CodeGenCXX/microsoft-abi-array-cookies.cpp
new file mode 100644
index 0000000..aff9d2e
--- /dev/null
+++ test/CodeGenCXX/microsoft-abi-array-cookies.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+// FIXME: Add a test for a struct that doesn't need array cookies.
+// The current array cookies code does not work exactly the same as the Windows
+// one, need to find out why Clang++ still want to emit cookies in this case.
+// However, this doesn't seem to affect running programs much unless they want
+// to read the cookie.
+
+struct ClassWithDtor {
+  char x;
+  ~ClassWithDtor() {}
+};
+
+void check_array_cookies_simple() {
+// CHECK: define {{.*}} @"\01?check_array_cookies_simple@@YAXXZ"()
+
+  ClassWithDtor *array = new ClassWithDtor[42];
+// CHECK: [[ALLOCATED:%.*]] = call noalias i8* @"\01??_U@YAPAXI@Z"(i32 46)
+// 46 = 42 + size of cookie (4)
+// CHECK: [[COOKIE:%.*]] = bitcast i8* [[ALLOCATED]] to i32*
+// CHECK: store i32 42, i32* [[COOKIE]]
+// CHECK: [[ARRAY:%.*]] = getelementptr inbounds i8* [[ALLOCATED]], i{{[0-9]+}} 4
+// CHECK: bitcast i8* [[ARRAY]] to %struct.ClassWithDtor*
+
+  delete [] array;
+// CHECK: [[ARRAY_AS_CHAR:%.*]] = bitcast %struct.ClassWithDtor* %3 to i8*
+// CHECK: getelementptr inbounds i8* [[ARRAY_AS_CHAR]], i{{[0-9]+}} -4
+}
+
+struct __attribute__((aligned(8))) ClassWithAlignment {
+  // FIXME: replace __attribute__((aligned(8))) with __declspec(align(8)) once
+  // http://llvm.org/bugs/show_bug.cgi?id=12631 is fixed.
+  int *x, *y;
+  ~ClassWithAlignment() {}
+};
+
+void check_array_cookies_aligned() {
+// CHECK: define {{.*}} @"\01?check_array_cookies_aligned@@YAXXZ"()
+  ClassWithAlignment *array = new ClassWithAlignment[42];
+// CHECK: [[ALLOCATED:%.*]] = call noalias i8* @"\01??_U@YAPAXI@Z"(i32 344)
+//   344 = 42*8 + size of cookie (8, due to aligment)
+// CHECK: [[COOKIE:%.*]] = bitcast i8* [[ALLOCATED]] to i32*
+// CHECK: store i32 42, i32* [[COOKIE]]
+// CHECK: [[ARRAY:%.*]] = getelementptr inbounds i8* [[ALLOCATED]], i{{[0-9]+}} 8
+// CHECK: bitcast i8* [[ARRAY]] to %struct.ClassWithAlignment*
+
+  delete [] array;
+// CHECK: [[ARRAY_AS_CHAR:%.*]] = bitcast %struct.ClassWithAlignment* %3 to i8*
+// CHECK: getelementptr inbounds i8* [[ARRAY_AS_CHAR]], i{{[0-9]+}} -8
+}
