Index: cfe/trunk/include/clang/AST/ASTContext.h =================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h +++ cfe/trunk/include/clang/AST/ASTContext.h @@ -74,6 +74,15 @@ class FullComment; } + struct TypeInfo { + uint64_t Width; + unsigned Align; + bool AlignIsRequired : 1; + TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {} + TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired) + : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} + }; + /// \brief Holds long-lived AST nodes (such as types and decls) that can be /// referred to throughout the semantic analysis of a file. class ASTContext : public RefCountedBase { @@ -144,8 +153,7 @@ ObjCLayouts; /// \brief A cache from types to size and alignment information. - typedef llvm::DenseMap > TypeInfoMap; + typedef llvm::DenseMap TypeInfoMap; mutable TypeInfoMap MemoizedTypeInfo; /// \brief A cache mapping from CXXRecordDecls to key functions. @@ -1581,7 +1589,7 @@ private: CanQualType getFromTargetType(unsigned Type) const; - std::pair getTypeInfoImpl(const Type *T) const; + TypeInfo getTypeInfoImpl(const Type *T) const; //===--------------------------------------------------------------------===// // Type Predicates. @@ -1614,18 +1622,12 @@ const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const; /// \brief Get the size and alignment of the specified complete type in bits. - std::pair getTypeInfo(const Type *T) const; - std::pair getTypeInfo(QualType T) const { - return getTypeInfo(T.getTypePtr()); - } + TypeInfo getTypeInfo(const Type *T) const; + TypeInfo getTypeInfo(QualType T) const { return getTypeInfo(T.getTypePtr()); } /// \brief Return the size of the specified (complete) type \p T, in bits. - uint64_t getTypeSize(QualType T) const { - return getTypeInfo(T).first; - } - uint64_t getTypeSize(const Type *T) const { - return getTypeInfo(T).first; - } + uint64_t getTypeSize(QualType T) const { return getTypeInfo(T).Width; } + uint64_t getTypeSize(const Type *T) const { return getTypeInfo(T).Width; } /// \brief Return the size of the character type, in bits. uint64_t getCharWidth() const { @@ -1645,12 +1647,8 @@ /// \brief Return the ABI-specified alignment of a (complete) type \p T, in /// bits. - unsigned getTypeAlign(QualType T) const { - return getTypeInfo(T).second; - } - unsigned getTypeAlign(const Type *T) const { - return getTypeInfo(T).second; - } + unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).Align; } + unsigned getTypeAlign(const Type *T) const { return getTypeInfo(T).Align; } /// \brief Return the ABI-specified alignment of a (complete) type \p T, in /// characters. @@ -1664,6 +1662,11 @@ std::pair getTypeInfoInChars(const Type *T) const; std::pair getTypeInfoInChars(QualType T) const; + /// \brief Determine if the alignment the type has was required using an + /// alignment attribute. + bool isAlignmentRequired(const Type *T) const; + bool isAlignmentRequired(QualType T) const; + /// \brief Return the "preferred" alignment of the specified type \p T for /// the current target, in bits. /// Index: cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -1413,9 +1413,9 @@ ASTContext::getTypeInfoInChars(const Type *T) const { if (const ConstantArrayType *CAT = dyn_cast(T)) return getConstantArrayInfoInChars(*this, CAT); - std::pair Info = getTypeInfo(T); - return std::make_pair(toCharUnitsFromBits(Info.first), - toCharUnitsFromBits(Info.second)); + TypeInfo Info = getTypeInfo(T); + return std::make_pair(toCharUnitsFromBits(Info.Width), + toCharUnitsFromBits(Info.Align)); } std::pair @@ -1423,14 +1423,20 @@ return getTypeInfoInChars(T.getTypePtr()); } -std::pair ASTContext::getTypeInfo(const Type *T) const { - TypeInfoMap::iterator it = MemoizedTypeInfo.find(T); - if (it != MemoizedTypeInfo.end()) - return it->second; - - std::pair Info = getTypeInfoImpl(T); - MemoizedTypeInfo.insert(std::make_pair(T, Info)); - return Info; +bool ASTContext::isAlignmentRequired(const Type *T) const { + return getTypeInfo(T).AlignIsRequired; +} + +bool ASTContext::isAlignmentRequired(QualType T) const { + return isAlignmentRequired(T.getTypePtr()); +} + +TypeInfo ASTContext::getTypeInfo(const Type *T) const { + TypeInfo &TI = MemoizedTypeInfo[T]; + if (!TI.Align) + TI = getTypeInfoImpl(T); + + return TI; } /// getTypeInfoImpl - Return the size of the specified type, in bits. This @@ -1439,10 +1445,10 @@ /// FIXME: Pointers into different addr spaces could have different sizes and /// alignment requirements: getPointerInfo should take an AddrSpace, this /// should take a QualType, &c. -std::pair -ASTContext::getTypeInfoImpl(const Type *T) const { - uint64_t Width=0; - unsigned Align=8; +TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { + uint64_t Width = 0; + unsigned Align = 8; + bool AlignIsRequired = false; switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1471,12 +1477,12 @@ case Type::ConstantArray: { const ConstantArrayType *CAT = cast(T); - std::pair EltInfo = getTypeInfo(CAT->getElementType()); + TypeInfo EltInfo = getTypeInfo(CAT->getElementType()); uint64_t Size = CAT->getSize().getZExtValue(); - assert((Size == 0 || EltInfo.first <= (uint64_t)(-1)/Size) && + assert((Size == 0 || EltInfo.Width <= (uint64_t)(-1) / Size) && "Overflow in array type bit size evaluation"); - Width = EltInfo.first*Size; - Align = EltInfo.second; + Width = EltInfo.Width * Size; + Align = EltInfo.Align; if (!getTargetInfo().getCXXABI().isMicrosoft() || getTargetInfo().getPointerWidth(0) == 64) Width = llvm::RoundUpToAlignment(Width, Align); @@ -1485,8 +1491,8 @@ case Type::ExtVector: case Type::Vector: { const VectorType *VT = cast(T); - std::pair EltInfo = getTypeInfo(VT->getElementType()); - Width = EltInfo.first*VT->getNumElements(); + TypeInfo EltInfo = getTypeInfo(VT->getElementType()); + Width = EltInfo.Width * VT->getNumElements(); Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. @@ -1638,10 +1644,9 @@ case Type::Complex: { // Complex types have the same alignment as their elements, but twice the // size. - std::pair EltInfo = - getTypeInfo(cast(T)->getElementType()); - Width = EltInfo.first*2; - Align = EltInfo.second; + TypeInfo EltInfo = getTypeInfo(cast(T)->getElementType()); + Width = EltInfo.Width * 2; + Align = EltInfo.Align; break; } case Type::ObjCObject: @@ -1692,16 +1697,16 @@ case Type::Typedef: { const TypedefNameDecl *Typedef = cast(T)->getDecl(); - std::pair Info - = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. - if (unsigned AttrAlign = Typedef->getMaxAlignment()) + if (unsigned AttrAlign = Typedef->getMaxAlignment()) { Align = AttrAlign; - else - Align = Info.second; - Width = Info.first; + AlignIsRequired = true; + } else + Align = Info.Align; + Width = Info.Width; break; } @@ -1714,10 +1719,9 @@ case Type::Atomic: { // Start with the base type information. - std::pair Info - = getTypeInfo(cast(T)->getValueType()); - Width = Info.first; - Align = Info.second; + TypeInfo Info = getTypeInfo(cast(T)->getValueType()); + Width = Info.Width; + Align = Info.Align; // If the size of the type doesn't exceed the platform's max // atomic promotion width, make the size and alignment more @@ -1735,7 +1739,7 @@ } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); - return std::make_pair(Width, Align); + return TypeInfo(Width, Align, AlignIsRequired); } /// toCharUnitsFromBits - Convert a size in bits to a size in characters. @@ -1771,13 +1775,12 @@ /// alignment in cases where it is beneficial for performance to overalign /// a data type. unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { - unsigned ABIAlign = getTypeAlign(T); + TypeInfo TI = getTypeInfo(T); + unsigned ABIAlign = TI.Align; if (Target->getTriple().getArch() == llvm::Triple::xcore) return ABIAlign; // Never overalign on XCore. - const TypedefType *TT = T->getAs(); - // Double and long long should be naturally aligned if possible. T = T->getBaseElementTypeUnsafe(); if (const ComplexType *CT = T->getAs()) @@ -1787,7 +1790,7 @@ T->isSpecificBuiltinType(BuiltinType::ULongLong)) // Don't increase the alignment if an alignment attribute was specified on a // typedef declaration. - if (!TT || !TT->getDecl()->getMaxAlignment()) + if (!TI.AlignIsRequired) return std::max(ABIAlign, (unsigned)getTypeSize(T)); return ABIAlign; Index: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp =================================================================== --- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp +++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp @@ -1413,9 +1413,9 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr(); uint64_t FieldSize = D->getBitWidthValue(Context); - std::pair FieldInfo = Context.getTypeInfo(D->getType()); - uint64_t TypeSize = FieldInfo.first; - unsigned FieldAlign = FieldInfo.second; + TypeInfo FieldInfo = Context.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.Width; + unsigned FieldAlign = FieldInfo.Align; // UnfilledBitsInLastUnit is the difference between the end of the // last allocated bitfield (i.e. the first bit offset available for @@ -2260,12 +2260,18 @@ MicrosoftRecordLayoutBuilder::ElementInfo MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( const FieldDecl *FD) { + // Get the alignment of the field type's natural alignment, ignore any + // alignment attributes. ElementInfo Info; std::tie(Info.Size, Info.Alignment) = - Context.getTypeInfoInChars(FD->getType()); - // Respect align attributes. - CharUnits FieldRequiredAlignment = + Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType()); + // Respect align attributes on the field. + CharUnits FieldRequiredAlignment = Context.toCharUnitsFromBits(FD->getMaxAlignment()); + // Respect align attributes on the type. + if (Context.isAlignmentRequired(FD->getType())) + FieldRequiredAlignment = std::max( + Context.getTypeAlignInChars(FD->getType()), FieldRequiredAlignment); // Respect attributes applied to subobjects of the field. if (FD->isBitField()) // For some reason __declspec align impacts alignment rather than required Index: cfe/trunk/lib/CodeGen/CGAtomic.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGAtomic.cpp +++ cfe/trunk/lib/CodeGen/CGAtomic.cpp @@ -46,17 +46,21 @@ ASTContext &C = CGF.getContext(); - uint64_t valueAlignInBits; - std::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy); - - uint64_t atomicAlignInBits; - std::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy); + uint64_t ValueAlignInBits; + uint64_t AtomicAlignInBits; + TypeInfo ValueTI = C.getTypeInfo(ValueTy); + ValueSizeInBits = ValueTI.Width; + ValueAlignInBits = ValueTI.Align; + + TypeInfo AtomicTI = C.getTypeInfo(AtomicTy); + AtomicSizeInBits = AtomicTI.Width; + AtomicAlignInBits = AtomicTI.Align; assert(ValueSizeInBits <= AtomicSizeInBits); - assert(valueAlignInBits <= atomicAlignInBits); + assert(ValueAlignInBits <= AtomicAlignInBits); - AtomicAlign = C.toCharUnitsFromBits(atomicAlignInBits); - ValueAlign = C.toCharUnitsFromBits(valueAlignInBits); + AtomicAlign = C.toCharUnitsFromBits(AtomicAlignInBits); + ValueAlign = C.toCharUnitsFromBits(ValueAlignInBits); if (lvalue.getAlignment().isZero()) lvalue.setAlignment(AtomicAlign); Index: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp @@ -803,13 +803,15 @@ llvm::DIFile file = getOrCreateFile(loc); unsigned line = getLineNumber(loc); - uint64_t sizeInBits = 0; - unsigned alignInBits = 0; + uint64_t SizeInBits = 0; + unsigned AlignInBits = 0; if (!type->isIncompleteArrayType()) { - std::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type); + TypeInfo TI = CGM.getContext().getTypeInfo(type); + SizeInBits = TI.Width; + AlignInBits = TI.Align; if (sizeInBitsOverride) - sizeInBits = sizeInBitsOverride; + SizeInBits = sizeInBitsOverride; } unsigned flags = 0; @@ -818,8 +820,8 @@ else if (AS == clang::AS_protected) flags |= llvm::DIDescriptor::FlagProtected; - return DBuilder.createMemberType(scope, name, file, line, sizeInBits, - alignInBits, offsetInBits, flags, debugType); + return DBuilder.createMemberType(scope, name, file, line, SizeInBits, + AlignInBits, offsetInBits, flags, debugType); } /// CollectRecordLambdaFields - Helper for CollectRecordFields. @@ -3030,15 +3032,15 @@ llvm::DIType fieldType; if (capture->isByRef()) { - std::pair ptrInfo = C.getTypeInfo(C.VoidPtrTy); + TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy); // FIXME: this creates a second copy of this type! uint64_t xoffset; fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset); - fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first); - fieldType = DBuilder.createMemberType(tunit, name, tunit, line, - ptrInfo.first, ptrInfo.second, - offsetInBits, 0, fieldType); + fieldType = DBuilder.createPointerType(fieldType, PtrInfo.Width); + fieldType = + DBuilder.createMemberType(tunit, name, tunit, line, PtrInfo.Width, + PtrInfo.Align, offsetInBits, 0, fieldType); } else { fieldType = createFieldType(name, variable->getType(), 0, loc, AS_public, offsetInBits, tunit, tunit); Index: cfe/trunk/lib/Sema/SemaDeclObjC.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp @@ -2107,7 +2107,12 @@ // validate the basic, low-level compatibility of the two types. // As a minimum, require the sizes and alignments to match. - if (Context.getTypeInfo(left) != Context.getTypeInfo(right)) + TypeInfo LeftTI = Context.getTypeInfo(left); + TypeInfo RightTI = Context.getTypeInfo(right); + if (LeftTI.Width != RightTI.Width) + return false; + + if (LeftTI.Align != RightTI.Align) return false; // Consider all the kinds of non-dependent canonical types: @@ -2159,7 +2164,13 @@ return false; // Require size and alignment to match. - if (Context.getTypeInfo(lt) != Context.getTypeInfo(rt)) return false; + TypeInfo LeftTI = Context.getTypeInfo(lt); + TypeInfo RightTI = Context.getTypeInfo(rt); + if (LeftTI.Width != RightTI.Width) + return false; + + if (LeftTI.Align != RightTI.Align) + return false; // Require fields to match. RecordDecl::field_iterator li = left->field_begin(), le = left->field_end(); Index: cfe/trunk/test/Layout/ms-x86-pack-and-align.cpp =================================================================== --- cfe/trunk/test/Layout/ms-x86-pack-and-align.cpp +++ cfe/trunk/test/Layout/ms-x86-pack-and-align.cpp @@ -652,7 +652,94 @@ // CHECK-X64-NEXT: | [sizeof=12, align=1 // CHECK-X64-NEXT: | nvsize=8, nvalign=1] +struct __declspec(align(4)) PA { + int c; +}; + +typedef __declspec(align(8)) PA PB; + +#pragma pack(push, 1) +struct PC { + char a; + PB x; +}; +#pragma pack(pop) + +// CHECK: *** Dumping AST Record Layout +// CHECK: 0 | struct PC +// CHECK-NEXT: 0 | char a +// CHECK-NEXT: 8 | struct PA x +// CHECK-NEXT: 8 | int c +// CHECK-NEXT: | [sizeof=4, align=4 +// CHECK-NEXT: | nvsize=4, nvalign=4] +// CHECK-NEXT: | [sizeof=16, align=8 +// CHECK-NEXT: | nvsize=12, nvalign=8] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64: 0 | struct PC +// CHECK-X64-NEXT: 0 | char a +// CHECK-X64-NEXT: 8 | struct PA x +// CHECK-X64-NEXT: 8 | int c +// CHECK-X64-NEXT: | [sizeof=4, align=4 +// CHECK-X64-NEXT: | nvsize=4, nvalign=4] +// CHECK-X64-NEXT: | [sizeof=16, align=8 +// CHECK-X64-NEXT: | nvsize=12, nvalign=8] + +typedef int __declspec(align(2)) QA; +#pragma pack(push, 1) +struct QB { + char a; + QA b; +}; +#pragma pack(pop) +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct QB +// CHECK-NEXT: 0 | char a +// CHECK-NEXT: 2 | QA b +// CHECK-NEXT: | [sizeof=6, align=2 +// CHECK-NEXT: | nvsize=6, nvalign=2] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct QB +// CHECK-X64-NEXT: 0 | char a +// CHECK-X64-NEXT: 2 | QA b +// CHECK-X64-NEXT: | [sizeof=6, align=2 +// CHECK-X64-NEXT: | nvsize=6, nvalign=2] + +struct QC { + char a; + QA b; +}; + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct QC +// CHECK-NEXT: 0 | char a +// CHECK-NEXT: 4 | QA b +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | nvsize=8, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct QC +// CHECK-X64-NEXT: 0 | char a +// CHECK-X64-NEXT: 4 | QA b +// CHECK-X64-NEXT: | [sizeof=8, align=4 +// CHECK-X64-NEXT: | nvsize=8, nvalign=4] + +struct QD { + char a; + QA b : 3; +}; + +// CHECK: *** Dumping AST Record Layout +// CHECK-NEXT: 0 | struct QD +// CHECK-NEXT: 0 | char a +// CHECK-NEXT: 4 | QA b +// CHECK-NEXT: | [sizeof=8, align=4 +// CHECK-NEXT: | nvsize=8, nvalign=4] +// CHECK-X64: *** Dumping AST Record Layout +// CHECK-X64-NEXT: 0 | struct QD +// CHECK-X64-NEXT: 0 | char a +// CHECK-X64-NEXT: 4 | QA b +// CHECK-X64-NEXT: | [sizeof=8, align=4 +// CHECK-X64-NEXT: | nvsize=8, nvalign=4] int a[ sizeof(X)+ @@ -680,4 +767,8 @@ sizeof(RE)+ sizeof(ND)+ sizeof(OD)+ +sizeof(PC)+ +sizeof(QB)+ +sizeof(QC)+ +sizeof(QD)+ 0];