Add support for __block variables with alignment greater than __alignof(void *).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81602 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index eae5a0d..05c2533 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -224,41 +224,76 @@
return Info.first;
QualType Ty = D->getType();
- uint64_t Align = getContext().getDeclAlignInBytes(D);
- (void) Align;
- const llvm::Type *LTy = ConvertType(Ty);
- bool needsCopyDispose = BlockRequiresCopying(Ty);
- std::vector<const llvm::Type *> Types(needsCopyDispose*2+5);
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
+ std::vector<const llvm::Type *> Types;
+ const llvm::PointerType *Int8PtrTy
+ = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
+
llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(VMContext);
- Types[0] = PtrToInt8Ty;
- Types[1] = llvm::PointerType::getUnqual(ByRefTypeHolder);
- Types[2] = llvm::Type::getInt32Ty(VMContext);
- Types[3] = llvm::Type::getInt32Ty(VMContext);
- if (needsCopyDispose) {
- Types[4] = PtrToInt8Ty;
- Types[5] = PtrToInt8Ty;
+ // void *__isa;
+ Types.push_back(Int8PtrTy);
+
+ // void *__forwarding;
+ Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
+
+ // int32_t __flags;
+ Types.push_back(llvm::Type::getInt32Ty(VMContext));
+
+ // int32_t __size;
+ Types.push_back(llvm::Type::getInt32Ty(VMContext));
+
+ bool HasCopyAndDispose = BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ /// void *__copy_helper;
+ Types.push_back(Int8PtrTy);
+
+ /// void *__destroy_helper;
+ Types.push_back(Int8PtrTy);
}
- // FIXME: Align this on at least an Align boundary, assert if we can't.
- assert((Align <= unsigned(Target.getPointerAlign(0))/8)
- && "Can't align more than pointer yet");
+
+ bool Packed = false;
+ unsigned Align = getContext().getDeclAlignInBytes(D);
+ if (Align > Target.getPointerAlign(0) / 8) {
+ // We have to insert padding.
+
+ // The struct above has 2 32-bit integers.
+ unsigned CurrentOffsetInBytes = 4 * 2;
+
+ // And either 2 or 4 pointers.
+ CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
+ CGM.getTargetData().getTypeAllocSize(Int8PtrTy);
+
+ // Align the offset.
+ unsigned AlignedOffsetInBytes =
+ llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align);
+
+ unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes;
+ assert(NumPaddingBytes > 0 && "Can't append any padding!");
+
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(VMContext);
+ if (NumPaddingBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumPaddingBytes);
+
+ Types.push_back(Ty);
+
+ // We want a packed struct.
+ Packed = true;
+ }
+
+ // T x;
+ Types.push_back(ConvertType(Ty));
- unsigned FieldNumber = needsCopyDispose*2 + 4;
-
- Types[FieldNumber] = LTy;
-
- const llvm::Type *T = llvm::StructType::get(VMContext, Types, false);
+ const llvm::Type *T = llvm::StructType::get(VMContext, Types, Packed);
cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T);
CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(),
ByRefTypeHolder.get());
Info.first = ByRefTypeHolder.get();
- Info.second = FieldNumber;
+
+ Info.second = Types.size() - 1;
return Info.first;
}