From: John McCall Date: Fri, 25 Jan 2013 23:36:19 +0000 (+0000) Subject: ARM says that the array cookie should always be eight bytes. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f3bbb155beb69cdad1c6b0472bc0ca20cece6c50;p=clang ARM says that the array cookie should always be eight bytes. ARM is not thinking about over-aligned structures. Overrule ARM in both our generic-ARM and iOS ABI implementations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173531 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 354887f446..52409929ee 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -890,50 +890,46 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, } CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) { - // On ARM, the cookie is always: + // ARM says that the cookie is always: // struct array_cookie { // std::size_t element_size; // element_size != 0 // std::size_t element_count; // }; - // TODO: what should we do if the allocated type actually wants - // greater alignment? - return CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes); + // But the base ABI doesn't give anything an alignment greater than + // 8, so we can dismiss this as typical ABI-author blindness to + // actual language complexity and round up to the element alignment. + return std::max(CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes), + CGM.getContext().getTypeAlignInChars(elementType)); } llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, - llvm::Value *NewPtr, - llvm::Value *NumElements, + llvm::Value *newPtr, + llvm::Value *numElements, const CXXNewExpr *expr, - QualType ElementType) { + QualType elementType) { assert(requiresArrayCookie(expr)); - // NewPtr is a char*. - - unsigned AS = NewPtr->getType()->getPointerAddressSpace(); - - ASTContext &Ctx = getContext(); - CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType()); - llvm::IntegerType *SizeTy = - cast(CGF.ConvertType(Ctx.getSizeType())); + // NewPtr is a char*, but we generalize to arbitrary addrspaces. + unsigned AS = newPtr->getType()->getPointerAddressSpace(); // The cookie is always at the start of the buffer. - llvm::Value *CookiePtr = NewPtr; + llvm::Value *cookie = newPtr; // The first element is the element size. - CookiePtr = CGF.Builder.CreateBitCast(CookiePtr, SizeTy->getPointerTo(AS)); - llvm::Value *ElementSize = llvm::ConstantInt::get(SizeTy, - Ctx.getTypeSizeInChars(ElementType).getQuantity()); - CGF.Builder.CreateStore(ElementSize, CookiePtr); + cookie = CGF.Builder.CreateBitCast(cookie, CGF.SizeTy->getPointerTo(AS)); + llvm::Value *elementSize = llvm::ConstantInt::get(CGF.SizeTy, + getContext().getTypeSizeInChars(elementType).getQuantity()); + CGF.Builder.CreateStore(elementSize, cookie); // The second element is the element count. - CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_32(CookiePtr, 1); - CGF.Builder.CreateStore(NumElements, CookiePtr); + cookie = CGF.Builder.CreateConstInBoundsGEP1_32(cookie, 1); + CGF.Builder.CreateStore(numElements, cookie); // Finally, compute a pointer to the actual data buffer by skipping // over the cookie completely. - CharUnits CookieSize = 2 * SizeSize; - return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr, - CookieSize.getQuantity()); + CharUnits cookieSize = ARMCXXABI::getArrayCookieSizeImpl(elementType); + return CGF.Builder.CreateConstInBoundsGEP1_64(newPtr, + cookieSize.getQuantity()); } llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp index 6c60f3057c..fc910af7ad 100644 --- a/test/CodeGenCXX/arm.cpp +++ b/test/CodeGenCXX/arm.cpp @@ -357,6 +357,58 @@ namespace test8 { } } +// rdar://12836470 +// Use a larger-than-mandated array cookie when allocating an +// array whose type is overaligned. +namespace test9 { + class __attribute__((aligned(16))) A { + float data[4]; + public: + A(); + ~A(); + }; + + A *testNew(unsigned n) { + return new A[n]; + } +// CHECK: define [[TEST9:%.*]]* @_ZN5test97testNewEj(i32 +// CHECK: [[N_VAR:%.*]] = alloca i32, align 4 +// CHECK: [[N:%.*]] = load i32* [[N_VAR]], align 4 +// CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 16) +// CHECK-NEXT: [[O0:%.*]] = extractvalue { i32, i1 } [[T0]], 1 +// CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 0 +// CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 16) +// CHECK-NEXT: [[O1:%.*]] = extractvalue { i32, i1 } [[T2]], 1 +// CHECK-NEXT: [[OVERFLOW:%.*]] = or i1 [[O0]], [[O1]] +// CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0 +// CHECK-NEXT: [[T4:%.*]] = select i1 [[OVERFLOW]], i32 -1, i32 [[T3]] +// CHECK-NEXT: [[ALLOC:%.*]] = call noalias i8* @_Znam(i32 [[T4]]) +// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[ALLOC]] to i32* +// CHECK-NEXT: store i32 16, i32* [[T0]] +// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i32* [[T0]], i32 1 +// CHECK-NEXT: store i32 [[N]], i32* [[T1]] +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8* [[ALLOC]], i64 16 +// CHECK-NEXT: bitcast i8* [[T0]] to [[TEST9]]* +// Array allocation follows. + + void testDelete(A *array) { + delete[] array; + } +// CHECK: define void @_ZN5test910testDeleteEPNS_1AE( +// CHECK: [[BEGIN:%.*]] = load [[TEST9]]** +// CHECK-NEXT: [[T0:%.*]] = icmp eq [[TEST9]]* [[BEGIN]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = bitcast [[TEST9]]* [[BEGIN]] to i8* +// CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8* [[T0]], i64 -16 +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8* [[ALLOC]], i64 4 +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32* +// CHECK-NEXT: [[N:%.*]] = load i32* [[T1]] +// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[TEST9]]* [[BEGIN]], i32 [[N]] +// CHECK-NEXT: [[T0:%.*]] = icmp eq [[TEST9]]* [[BEGIN]], [[END]] +// CHECK-NEXT: br i1 [[T0]], +// Array deallocation follows. +} + // CHECK: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev( // CHECK: call [[C]]* @_ZN5test21CD1Ev( // CHECK: ret [[C]]* undef