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) {
// 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<llvm::IntegerType>(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,

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