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.

llvm-svn: 173531
This commit is contained in:
John McCall 2013-01-25 23:36:19 +00:00
parent 5762592b49
commit c19c7066c2
2 changed files with 73 additions and 25 deletions

View File

@ -890,50 +890,46 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
} }
CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) { CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
// On ARM, the cookie is always: // ARM says that the cookie is always:
// struct array_cookie { // struct array_cookie {
// std::size_t element_size; // element_size != 0 // std::size_t element_size; // element_size != 0
// std::size_t element_count; // std::size_t element_count;
// }; // };
// TODO: what should we do if the allocated type actually wants // But the base ABI doesn't give anything an alignment greater than
// greater alignment? // 8, so we can dismiss this as typical ABI-author blindness to
return CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes); // 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 *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr, llvm::Value *newPtr,
llvm::Value *NumElements, llvm::Value *numElements,
const CXXNewExpr *expr, const CXXNewExpr *expr,
QualType ElementType) { QualType elementType) {
assert(requiresArrayCookie(expr)); assert(requiresArrayCookie(expr));
// NewPtr is a char*. // NewPtr is a char*, but we generalize to arbitrary addrspaces.
unsigned AS = newPtr->getType()->getPointerAddressSpace();
unsigned AS = NewPtr->getType()->getPointerAddressSpace();
ASTContext &Ctx = getContext();
CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType());
llvm::IntegerType *SizeTy =
cast<llvm::IntegerType>(CGF.ConvertType(Ctx.getSizeType()));
// The cookie is always at the start of the buffer. // 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. // The first element is the element size.
CookiePtr = CGF.Builder.CreateBitCast(CookiePtr, SizeTy->getPointerTo(AS)); cookie = CGF.Builder.CreateBitCast(cookie, CGF.SizeTy->getPointerTo(AS));
llvm::Value *ElementSize = llvm::ConstantInt::get(SizeTy, llvm::Value *elementSize = llvm::ConstantInt::get(CGF.SizeTy,
Ctx.getTypeSizeInChars(ElementType).getQuantity()); getContext().getTypeSizeInChars(elementType).getQuantity());
CGF.Builder.CreateStore(ElementSize, CookiePtr); CGF.Builder.CreateStore(elementSize, cookie);
// The second element is the element count. // The second element is the element count.
CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_32(CookiePtr, 1); cookie = CGF.Builder.CreateConstInBoundsGEP1_32(cookie, 1);
CGF.Builder.CreateStore(NumElements, CookiePtr); CGF.Builder.CreateStore(numElements, cookie);
// Finally, compute a pointer to the actual data buffer by skipping // Finally, compute a pointer to the actual data buffer by skipping
// over the cookie completely. // over the cookie completely.
CharUnits CookieSize = 2 * SizeSize; CharUnits cookieSize = ARMCXXABI::getArrayCookieSizeImpl(elementType);
return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr, return CGF.Builder.CreateConstInBoundsGEP1_64(newPtr,
CookieSize.getQuantity()); cookieSize.getQuantity());
} }
llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,

View File

@ -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: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev(
// CHECK: call [[C]]* @_ZN5test21CD1Ev( // CHECK: call [[C]]* @_ZN5test21CD1Ev(
// CHECK: ret [[C]]* undef // CHECK: ret [[C]]* undef