Hi rnk,
The MS ABI has a notion of 'required alignment' for fields; this
alignment supercedes pragma pack directives.
MSVC takes into account alignment attributes on typedefs when
determining whether or not a field has a certain required alignment.
Do the same in clang by tracking whether or not we saw such an attribute
when calculating the type's bitwidth and alignment.
This fixes PR20418.
http://reviews.llvm.org/D4714
Files:
include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/AST/RecordLayoutBuilder.cpp
lib/CodeGen/CGAtomic.cpp
lib/CodeGen/CGDebugInfo.cpp
lib/Sema/SemaDeclObjC.cpp
test/Layout/ms-x86-pack-and-align.cpp
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -143,9 +143,19 @@
mutable llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>
ObjCLayouts;
+public:
+ 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) {}
+ };
+
+private:
/// \brief A cache from types to size and alignment information.
- typedef llvm::DenseMap<const Type*,
- std::pair<uint64_t, unsigned> > TypeInfoMap;
+ typedef llvm::DenseMap<const Type *, struct TypeInfo> TypeInfoMap;
mutable TypeInfoMap MemoizedTypeInfo;
/// \brief A cache mapping from CXXRecordDecls to key functions.
@@ -1581,7 +1591,7 @@
private:
CanQualType getFromTargetType(unsigned Type) const;
- std::pair<uint64_t, unsigned> getTypeInfoImpl(const Type *T) const;
+ TypeInfo getTypeInfoImpl(const Type *T) const;
//===--------------------------------------------------------------------===//
// Type Predicates.
@@ -1614,17 +1624,17 @@
const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const;
/// \brief Get the size and alignment of the specified complete type in bits.
- std::pair<uint64_t, unsigned> getTypeInfo(const Type *T) const;
- std::pair<uint64_t, unsigned> getTypeInfo(QualType T) const {
+ 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;
+ return getTypeInfo(T).Width;
}
uint64_t getTypeSize(const Type *T) const {
- return getTypeInfo(T).first;
+ return getTypeInfo(T).Width;
}
/// \brief Return the size of the character type, in bits.
@@ -1646,10 +1656,10 @@
/// \brief Return the ABI-specified alignment of a (complete) type \p T, in
/// bits.
unsigned getTypeAlign(QualType T) const {
- return getTypeInfo(T).second;
+ return getTypeInfo(T).Align;
}
unsigned getTypeAlign(const Type *T) const {
- return getTypeInfo(T).second;
+ return getTypeInfo(T).Align;
}
/// \brief Return the ABI-specified alignment of a (complete) type \p T, in
@@ -1664,6 +1674,11 @@
std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const;
std::pair<CharUnits, CharUnits> 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: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -1413,36 +1413,43 @@
ASTContext::getTypeInfoInChars(const Type *T) const {
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T))
return getConstantArrayInfoInChars(*this, CAT);
- std::pair<uint64_t, unsigned> 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<CharUnits, CharUnits>
ASTContext::getTypeInfoInChars(QualType T) const {
return getTypeInfoInChars(T.getTypePtr());
}
-std::pair<uint64_t, unsigned> ASTContext::getTypeInfo(const Type *T) const {
- TypeInfoMap::iterator it = MemoizedTypeInfo.find(T);
- if (it != MemoizedTypeInfo.end())
- return it->second;
+bool ASTContext::isAlignmentRequired(const Type *T) const {
+ return getTypeInfo(T).AlignIsRequired;
+}
+
+bool ASTContext::isAlignmentRequired(QualType T) const {
+ return isAlignmentRequired(T.getTypePtr());
+}
+
+ASTContext::TypeInfo ASTContext::getTypeInfo(const Type *T) const {
+ TypeInfo &TI = MemoizedTypeInfo[T];
+ if (!TI.Align)
+ TI = getTypeInfoImpl(T);
- std::pair<uint64_t, unsigned> Info = getTypeInfoImpl(T);
- MemoizedTypeInfo.insert(std::make_pair(T, Info));
- return Info;
+ return TI;
}
/// getTypeInfoImpl - Return the size of the specified type, in bits. This
/// method does not work on incomplete types.
///
/// 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<uint64_t, unsigned>
+ASTContext::TypeInfo
ASTContext::getTypeInfoImpl(const Type *T) const {
- uint64_t Width=0;
- unsigned Align=8;
+ uint64_t Width = 0;
+ unsigned Align = 8;
+ bool AlignIsRequired = false;
switch (T->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1471,22 +1478,22 @@
case Type::ConstantArray: {
const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
- std::pair<uint64_t, unsigned> 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);
break;
}
case Type::ExtVector:
case Type::Vector: {
const VectorType *VT = cast<VectorType>(T);
- std::pair<uint64_t, unsigned> 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 +1645,9 @@
case Type::Complex: {
// Complex types have the same alignment as their elements, but twice the
// size.
- std::pair<uint64_t, unsigned> EltInfo =
- getTypeInfo(cast<ComplexType>(T)->getElementType());
- Width = EltInfo.first*2;
- Align = EltInfo.second;
+ TypeInfo EltInfo = getTypeInfo(cast<ComplexType>(T)->getElementType());
+ Width = EltInfo.Width * 2;
+ Align = EltInfo.Align;
break;
}
case Type::ObjCObject:
@@ -1692,16 +1698,16 @@
case Type::Typedef: {
const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
- std::pair<uint64_t, unsigned> 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 +1720,9 @@
case Type::Atomic: {
// Start with the base type information.
- std::pair<uint64_t, unsigned> Info
- = getTypeInfo(cast<AtomicType>(T)->getValueType());
- Width = Info.first;
- Align = Info.second;
+ TypeInfo Info = getTypeInfo(cast<AtomicType>(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 +1740,7 @@
}
assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2");
- return std::make_pair(Width, Align);
+ return ASTContext::TypeInfo(Width, Align, AlignIsRequired);
}
/// toCharUnitsFromBits - Convert a size in bits to a size in characters.
@@ -1771,13 +1776,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);
+ ASTContext::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<TypedefType>();
-
// Double and long long should be naturally aligned if possible.
T = T->getBaseElementTypeUnsafe();
if (const ComplexType *CT = T->getAs<ComplexType>())
@@ -1787,7 +1791,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: lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- lib/AST/RecordLayoutBuilder.cpp
+++ lib/AST/RecordLayoutBuilder.cpp
@@ -1413,9 +1413,9 @@
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldSize = D->getBitWidthValue(Context);
- std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
- uint64_t TypeSize = FieldInfo.first;
- unsigned FieldAlign = FieldInfo.second;
+ ASTContext::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
@@ -2279,6 +2279,8 @@
FieldRequiredAlignment = std::max(FieldRequiredAlignment,
Layout.getRequiredAlignment());
}
+ if (Context.isAlignmentRequired(FD->getType()))
+ FieldRequiredAlignment = std::max(Info.Alignment, FieldRequiredAlignment);
// Capture required alignment as a side-effect.
RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment);
}
Index: lib/CodeGen/CGAtomic.cpp
===================================================================
--- lib/CodeGen/CGAtomic.cpp
+++ lib/CodeGen/CGAtomic.cpp
@@ -46,17 +46,21 @@
ASTContext &C = CGF.getContext();
- uint64_t valueAlignInBits;
- std::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy);
+ uint64_t ValueAlignInBits;
+ uint64_t AtomicAlignInBits;
+ ASTContext::TypeInfo ValueTI = C.getTypeInfo(ValueTy);
+ ValueSizeInBits = ValueTI.Width;
+ ValueAlignInBits = ValueTI.Align;
- uint64_t atomicAlignInBits;
- std::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy);
+ ASTContext::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: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -803,23 +803,25 @@
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);
+ ASTContext::TypeInfo TI = CGM.getContext().getTypeInfo(type);
+ SizeInBits = TI.Width;
+ AlignInBits = TI.Align;
if (sizeInBitsOverride)
- sizeInBits = sizeInBitsOverride;
+ SizeInBits = sizeInBitsOverride;
}
unsigned flags = 0;
if (AS == clang::AS_private)
flags |= llvm::DIDescriptor::FlagPrivate;
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<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy);
+ ASTContext::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: lib/Sema/SemaDeclObjC.cpp
===================================================================
--- lib/Sema/SemaDeclObjC.cpp
+++ 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))
+ ASTContext::TypeInfo LeftTI = Context.getTypeInfo(left);
+ ASTContext::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;
+ ASTContext::TypeInfo LeftTI = Context.getTypeInfo(lt);
+ ASTContext::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: test/Layout/ms-x86-pack-and-align.cpp
===================================================================
--- test/Layout/ms-x86-pack-and-align.cpp
+++ test/Layout/ms-x86-pack-and-align.cpp
@@ -652,7 +652,27 @@
// 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]
int a[
sizeof(X)+
@@ -680,4 +700,5 @@
sizeof(RE)+
sizeof(ND)+
sizeof(OD)+
+sizeof(PC)+
0];
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits