https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/208256
>From 4edfb5154f7e43d45a2d16df890b16f4d4fcbb1a Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Fri, 28 Aug 2026 08:19:10 -0700 Subject: [PATCH 1/8] Addressed review comments --- clang/lib/AST/RecordLayoutBuilder.cpp | 196 +++++++++++++++++- .../pragma-pack-array-alignment-itanium.cpp | 40 ++++ .../pragma-pack-array-alignment-msvc.cpp | 40 ++++ 3 files changed, 266 insertions(+), 10 deletions(-) create mode 100644 clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp create mode 100644 clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index e6da6c78238c13..03a9318547fdea 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -781,6 +781,13 @@ class ItaniumRecordLayoutBuilder { UpdateAlignment(NewAlignment, NewAlignment, NewAlignment); } + /// Check if a type contains vector types. + bool TypeContainsVectors(QualType Ty); + + /// Get the natural alignment of vectors contained in a type, bypassing + /// any pragma pack that may have been applied to enclosing structs. + CharUnits GetNaturalVectorAlignment(QualType Ty); + /// Retrieve the externally-supplied field offset for the given /// field. /// @@ -1688,13 +1695,24 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // But, if there's a #pragma pack in play, that takes precedent over // even the 'aligned' attribute, for non-zero-width bitfields. + // However, pragma pack should not reduce the natural alignment of vector + // array elements. unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment); if (!MaxFieldAlignment.isZero() && FieldSize) { - UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); - if (FieldPacked) - FieldAlign = UnpackedFieldAlign; - else - FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + QualType FieldType = D->getType(); + // Only exempt arrays of vectors from pragma pack, not direct vector + // fields. + bool IsVectorArray = + !FieldType->isVectorType() && + FieldType->getBaseElementTypeUnsafe()->isVectorType(); + if (!IsVectorArray) { + UnpackedFieldAlign = + std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); + if (FieldPacked) + FieldAlign = UnpackedFieldAlign; + else + FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + } } // But, ms_struct just ignores all of that in unions, even explicit @@ -1910,6 +1928,17 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } else { setDeclInfo(false /* IsIncompleteArrayType */); + // If this is an array containing vectors (directly or in nested + // structs), we need to use the natural alignment of the vectors, not the + // potentially pragma-pack-clamped alignment from the struct layout. + QualType FieldType = D->getType(); + if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) { + // Get the natural vector alignment, bypassing any pragma pack on + // structs. + CharUnits VecAlign = GetNaturalVectorAlignment(FieldType); + FieldAlign = std::max(FieldAlign, VecAlign); + } + // A potentially-overlapping field occupies its dsize or nvsize, whichever // is larger. if (D->isPotentiallyOverlapping()) { @@ -2012,6 +2041,16 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD); PreferredAlign = FieldRecord.getPreferredAlignment(); + // If this is an array of records containing vectors, use the + // unadjusted alignment to avoid inheriting pragma pack from the nested + // struct. + QualType BaseQualTy = QualType(BaseTy, 0); + if (D->getType() != BaseQualTy && TypeContainsVectors(D->getType())) { + FieldAlign = + std::max(FieldAlign, FieldRecord.getUnadjustedAlignment()); + PreferredAlign = + std::max(PreferredAlign, FieldRecord.getUnadjustedAlignment()); + } } } @@ -2029,10 +2068,20 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars); // The maximum field alignment overrides the aligned attribute. + // However, pragma pack should not reduce the natural alignment of array + // elements that contain vectors (either arrays of vectors, or arrays of + // structs containing vectors). Direct vector fields ARE affected by pragma + // pack. if (!MaxFieldAlignment.isZero()) { - PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment); - PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment); - UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); + QualType FieldType = D->getType(); + // Only exempt arrays containing vectors, not direct vector fields. + bool IsArrayContainingVectors = + !FieldType->isVectorType() && TypeContainsVectors(FieldType); + if (!IsArrayContainingVectors) { + PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment); + PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment); + UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); + } } @@ -2210,6 +2259,52 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { } } +bool ItaniumRecordLayoutBuilder::TypeContainsVectors(QualType Ty) { + // Strip through arrays. + while (const ArrayType *AT = Context.getAsArrayType(Ty)) + Ty = AT->getElementType(); + + // Direct vector type. + if (Ty->isVectorType()) + return true; + + // Check if it's a record type with vector fields. + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + for (const FieldDecl *Field : RD->fields()) { + if (TypeContainsVectors(Field->getType())) + return true; + } + } + + return false; +} + +CharUnits ItaniumRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) { + // Strip through arrays. + while (const ArrayType *AT = Context.getAsArrayType(Ty)) + Ty = AT->getElementType(); + + // Direct vector type - get its natural alignment. + if (Ty->isVectorType()) + return Context.getTypeAlignInChars(Ty); + + // Record type - find the maximum vector alignment inside. + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + CharUnits MaxAlign = CharUnits::One(); + for (const FieldDecl *Field : RD->fields()) { + if (TypeContainsVectors(Field->getType())) { + CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType()); + MaxAlign = std::max(MaxAlign, FieldVecAlign); + } + } + return MaxAlign; + } + + return CharUnits::One(); +} + void ItaniumRecordLayoutBuilder::UpdateAlignment( CharUnits NewAlignment, CharUnits UnpackedNewAlignment, CharUnits PreferredNewAlignment) { @@ -2614,6 +2709,11 @@ struct MicrosoftRecordLayoutBuilder { void computeVtorDispSet( llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet, const CXXRecordDecl *RD) const; + /// Check if a type (recursively) contains vector types. + bool TypeContainsVectors(QualType Ty); + /// Get the natural alignment of vectors contained in a type, bypassing + /// any pragma pack that may have been applied to enclosing structs. + CharUnits GetNaturalVectorAlignment(QualType Ty); const ASTContext &Context; EmptySubobjectMap *EmptySubobjects; @@ -2680,6 +2780,52 @@ struct MicrosoftRecordLayoutBuilder { }; } // namespace +bool MicrosoftRecordLayoutBuilder::TypeContainsVectors(QualType Ty) { + // Strip through arrays. + while (const ArrayType *AT = Context.getAsArrayType(Ty)) + Ty = AT->getElementType(); + + // Direct vector type. + if (Ty->isVectorType()) + return true; + + // Check if it's a record type with vector fields. + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + for (const FieldDecl *Field : RD->fields()) { + if (TypeContainsVectors(Field->getType())) + return true; + } + } + + return false; +} + +CharUnits MicrosoftRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) { + // Strip through arrays. + while (const ArrayType *AT = Context.getAsArrayType(Ty)) + Ty = AT->getElementType(); + + // Direct vector type - get its natural alignment. + if (Ty->isVectorType()) + return Context.getTypeAlignInChars(Ty); + + // Record type - find the maximum vector alignment inside. + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + CharUnits MaxAlign = CharUnits::One(); + for (const FieldDecl *Field : RD->fields()) { + if (TypeContainsVectors(Field->getType())) { + CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType()); + MaxAlign = std::max(MaxAlign, FieldVecAlign); + } + } + return MaxAlign; + } + + return CharUnits::One(); +} + MicrosoftRecordLayoutBuilder::ElementInfo MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( const ASTRecordLayout &Layout) { @@ -2718,6 +2864,18 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( auto TInfo = Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType()); ElementInfo Info{TInfo.Width, TInfo.Align, CharUnits::Zero()}; + + // If this is an array containing vectors (directly or in nested + // structs), we need to use the natural alignment of the vectors, not the + // potentially pragma-pack-clamped alignment from the struct layout. + QualType FieldType = FD->getType(); + if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) { + // Get the natural vector alignment, bypassing any pragma pack on + // structs. + CharUnits VecAlign = GetNaturalVectorAlignment(FieldType); + Info.Alignment = std::max(Info.Alignment, VecAlign); + } + // Respect align attributes on the field. CharUnits DirectFieldAlignment = Context.toCharUnitsFromBits(FD->getMaxAlignment()); @@ -2742,6 +2900,14 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); FieldTypeRequiredAlignment = std::max(FieldTypeRequiredAlignment, Layout.getRequiredAlignment()); + // If this is an array of records containing vectors, use the + // unadjusted alignment to avoid inheriting pragma pack from the nested + // struct. + QualType BaseTy = QualType(FD->getType()->getBaseElementTypeUnsafe(), 0); + if (FD->getType() != BaseTy && TypeContainsVectors(FD->getType())) { + Info.Alignment = + std::max(Info.Alignment, Layout.getUnadjustedAlignment()); + } } // Capture required alignment as a side-effect. RequiredAlignment = @@ -2749,8 +2915,18 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( std::max(DirectFieldAlignment, FieldTypeRequiredAlignment)); } // Respect pragma pack, attribute pack and declspec align - if (!MaxFieldAlignment.isZero()) - Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); + // However, pragma pack should not reduce the natural alignment of array + // elements that contain vectors (either arrays of vectors, or arrays of + // structs containing vectors). Direct vector fields ARE affected by pragma + // pack. + if (!MaxFieldAlignment.isZero()) { + QualType FieldType = FD->getType(); + // Only exempt arrays containing vectors, not direct vector fields. + bool IsArrayContainingVectors = + !FieldType->isVectorType() && TypeContainsVectors(FieldType); + if (!IsArrayContainingVectors) + Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); + } if (FD->hasAttr<PackedAttr>()) Info.Alignment = CharUnits::One(); // The alignment used to update the record's alignment excludes over-alignment diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp new file mode 100644 index 00000000000000..bdac5298211659 --- /dev/null +++ b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s + +// Test that #pragma pack does not reduce natural type alignment for vector types +// when used as array elements (Itanium ABI). + +typedef float __m128 __attribute__((__vector_size__(16))); + +// Simple array-like struct with vector type under pragma pack. +#pragma pack(push, 8) +template<typename T, unsigned N> +struct array { + T _Elems[N]; +}; +#pragma pack(pop) + +// CHECK-LABEL: define {{.*}} @_Z17test_vector_arrayv +void test_vector_array() { + // CHECK: %matrix = alloca %struct.array, align 16 + array<__m128, 16> matrix; + matrix._Elems[0] = (__m128){}; +} + +// Struct containing vector under pragma pack. +#pragma pack(push, 8) +struct VectorStruct { + __m128 vec; +}; + +struct ArrayOfVectorStruct { + VectorStruct elems[4]; +}; +#pragma pack(pop) + +// CHECK-LABEL: define {{.*}} @_Z18test_vector_structv +void test_vector_struct() { + // CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16 + ArrayOfVectorStruct s; + s.elems[0].vec = (__m128){}; +} diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp new file mode 100644 index 00000000000000..bdea75d3862356 --- /dev/null +++ b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \ +// RUN: -emit-llvm -o - %s | FileCheck %s + +// Test that #pragma pack does not reduce natural type alignment for vector types +// when used as array elements (matching MSVC behavior). + +typedef float __m128 __attribute__((__vector_size__(16))); + +// Simple array-like struct with vector type under pragma pack. +#pragma pack(push, 8) +template<typename T, unsigned N> +struct array { + T _Elems[N]; +}; +#pragma pack(pop) + +// CHECK-LABEL: define {{.*}} @"?test_vector_array +void test_vector_array() { + // CHECK: %matrix = alloca %struct.array, align 16 + array<__m128, 16> matrix; + matrix._Elems[0] = (__m128){}; +} + +// Struct containing vector under pragma pack. +#pragma pack(push, 8) +struct VectorStruct { + __m128 vec; +}; + +struct ArrayOfVectorStruct { + VectorStruct elems[4]; +}; +#pragma pack(pop) + +// CHECK-LABEL: define {{.*}} @"?test_vector_struct +void test_vector_struct() { + // CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16 + ArrayOfVectorStruct s; + s.elems[0].vec = (__m128){}; +} >From a084b1c84d9fe6f93331278443bd6a07a432bef2 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Fri, 28 Aug 2026 13:10:16 -0700 Subject: [PATCH 2/8] Added fp80 handling --- clang/lib/AST/RecordLayoutBuilder.cpp | 155 ++++++++++++++---- .../pragma-pack-array-alignment-itanium.cpp | 46 +++++- .../pragma-pack-array-alignment-msvc.cpp | 47 +++++- 3 files changed, 210 insertions(+), 38 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 03a9318547fdea..184befbf64c8e6 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -781,12 +781,19 @@ class ItaniumRecordLayoutBuilder { UpdateAlignment(NewAlignment, NewAlignment, NewAlignment); } - /// Check if a type contains vector types. - bool TypeContainsVectors(QualType Ty); + /// Check if a type contains vector or x86_fp80 types. + bool TypeContainsVectorsOrFp80(QualType Ty); - /// Get the natural alignment of vectors contained in a type, bypassing - /// any pragma pack that may have been applied to enclosing structs. - CharUnits GetNaturalVectorAlignment(QualType Ty); + /// Helper for TypeContainsVectorsOrFp80 that tracks array context. + bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray); + + /// Get the natural alignment of vectors or x86_fp80 contained in a type, + /// bypassing any pragma pack that may have been applied to enclosing + /// structs. + CharUnits GetNaturalAlignment(QualType Ty); + + /// Helper for GetNaturalAlignment that tracks array context. + CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray); /// Retrieve the externally-supplied field offset for the given /// field. @@ -1932,10 +1939,10 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // structs), we need to use the natural alignment of the vectors, not the // potentially pragma-pack-clamped alignment from the struct layout. QualType FieldType = D->getType(); - if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) { + if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) { // Get the natural vector alignment, bypassing any pragma pack on // structs. - CharUnits VecAlign = GetNaturalVectorAlignment(FieldType); + CharUnits VecAlign = GetNaturalAlignment(FieldType); FieldAlign = std::max(FieldAlign, VecAlign); } @@ -2045,7 +2052,8 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // unadjusted alignment to avoid inheriting pragma pack from the nested // struct. QualType BaseQualTy = QualType(BaseTy, 0); - if (D->getType() != BaseQualTy && TypeContainsVectors(D->getType())) { + if (D->getType() != BaseQualTy && + TypeContainsVectorsOrFp80(D->getType())) { FieldAlign = std::max(FieldAlign, FieldRecord.getUnadjustedAlignment()); PreferredAlign = @@ -2076,7 +2084,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, QualType FieldType = D->getType(); // Only exempt arrays containing vectors, not direct vector fields. bool IsArrayContainingVectors = - !FieldType->isVectorType() && TypeContainsVectors(FieldType); + !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType); if (!IsArrayContainingVectors) { PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment); PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment); @@ -2259,20 +2267,38 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { } } -bool ItaniumRecordLayoutBuilder::TypeContainsVectors(QualType Ty) { +bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) { + QualType OrigTy = Ty; + // Strip through arrays. while (const ArrayType *AT = Context.getAsArrayType(Ty)) Ty = AT->getElementType(); + bool InArray = (Ty != OrigTy); + return TypeContainsVectorsOrFp80Impl(Ty, InArray); +} + +bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl( + QualType Ty, bool InArray) { // Direct vector type. if (Ty->isVectorType()) return true; - // Check if it's a record type with vector fields. + // x86_fp80 only matters if it's in an array, not a direct field. + if (InArray) { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble && + &Context.getTargetInfo().getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended()) + return true; + } + } + + // Check if it's a record type with vector or x86_fp80 fields. if (const RecordType *RT = Ty->getAs<RecordType>()) { const RecordDecl *RD = RT->getDecl(); for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectors(Field->getType())) + if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) return true; } } @@ -2280,23 +2306,42 @@ bool ItaniumRecordLayoutBuilder::TypeContainsVectors(QualType Ty) { return false; } -CharUnits ItaniumRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) { +CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) { + QualType OrigTy = Ty; + // Strip through arrays. while (const ArrayType *AT = Context.getAsArrayType(Ty)) Ty = AT->getElementType(); + bool InArray = (Ty != OrigTy); + return GetNaturalAlignmentImpl(Ty, InArray); +} + +CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl( + QualType Ty, bool InArray) { // Direct vector type - get its natural alignment. if (Ty->isVectorType()) return Context.getTypeAlignInChars(Ty); - // Record type - find the maximum vector alignment inside. + // x86_fp80 only matters if it's in an array, not a direct field. + if (InArray) { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble && + &Context.getTargetInfo().getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended()) + return Context.getTypeAlignInChars(Ty); + } + } + + // Record type - find the maximum alignment inside. if (const RecordType *RT = Ty->getAs<RecordType>()) { const RecordDecl *RD = RT->getDecl(); CharUnits MaxAlign = CharUnits::One(); for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectors(Field->getType())) { - CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType()); - MaxAlign = std::max(MaxAlign, FieldVecAlign); + if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) { + CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(), + InArray); + MaxAlign = std::max(MaxAlign, FieldAlign); } } return MaxAlign; @@ -2709,11 +2754,16 @@ struct MicrosoftRecordLayoutBuilder { void computeVtorDispSet( llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet, const CXXRecordDecl *RD) const; - /// Check if a type (recursively) contains vector types. - bool TypeContainsVectors(QualType Ty); - /// Get the natural alignment of vectors contained in a type, bypassing - /// any pragma pack that may have been applied to enclosing structs. - CharUnits GetNaturalVectorAlignment(QualType Ty); + /// Check if a type (recursively) contains vector or x86_fp80 types. + bool TypeContainsVectorsOrFp80(QualType Ty); + /// Helper for TypeContainsVectorsOrFp80 that tracks array context. + bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray); + /// Get the natural alignment of vectors or x86_fp80 contained in a type, + /// bypassing any pragma pack that may have been applied to enclosing + /// structs. + CharUnits GetNaturalAlignment(QualType Ty); + /// Helper for GetNaturalAlignment that tracks array context. + CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray); const ASTContext &Context; EmptySubobjectMap *EmptySubobjects; @@ -2780,20 +2830,38 @@ struct MicrosoftRecordLayoutBuilder { }; } // namespace -bool MicrosoftRecordLayoutBuilder::TypeContainsVectors(QualType Ty) { +bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) { + QualType OrigTy = Ty; + // Strip through arrays. while (const ArrayType *AT = Context.getAsArrayType(Ty)) Ty = AT->getElementType(); + bool InArray = (Ty != OrigTy); + return TypeContainsVectorsOrFp80Impl(Ty, InArray); +} + +bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl( + QualType Ty, bool InArray) { // Direct vector type. if (Ty->isVectorType()) return true; - // Check if it's a record type with vector fields. + // x86_fp80 only matters if it's in an array, not a direct field. + if (InArray) { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble && + &Context.getTargetInfo().getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended()) + return true; + } + } + + // Check if it's a record type with vector or x86_fp80 fields. if (const RecordType *RT = Ty->getAs<RecordType>()) { const RecordDecl *RD = RT->getDecl(); for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectors(Field->getType())) + if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) return true; } } @@ -2801,23 +2869,42 @@ bool MicrosoftRecordLayoutBuilder::TypeContainsVectors(QualType Ty) { return false; } -CharUnits MicrosoftRecordLayoutBuilder::GetNaturalVectorAlignment(QualType Ty) { +CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) { + QualType OrigTy = Ty; + // Strip through arrays. while (const ArrayType *AT = Context.getAsArrayType(Ty)) Ty = AT->getElementType(); + bool InArray = (Ty != OrigTy); + return GetNaturalAlignmentImpl(Ty, InArray); +} + +CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl( + QualType Ty, bool InArray) { // Direct vector type - get its natural alignment. if (Ty->isVectorType()) return Context.getTypeAlignInChars(Ty); - // Record type - find the maximum vector alignment inside. + // x86_fp80 only matters if it's in an array, not a direct field. + if (InArray) { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble && + &Context.getTargetInfo().getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended()) + return Context.getTypeAlignInChars(Ty); + } + } + + // Record type - find the maximum alignment inside. if (const RecordType *RT = Ty->getAs<RecordType>()) { const RecordDecl *RD = RT->getDecl(); CharUnits MaxAlign = CharUnits::One(); for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectors(Field->getType())) { - CharUnits FieldVecAlign = GetNaturalVectorAlignment(Field->getType()); - MaxAlign = std::max(MaxAlign, FieldVecAlign); + if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) { + CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(), + InArray); + MaxAlign = std::max(MaxAlign, FieldAlign); } } return MaxAlign; @@ -2869,10 +2956,10 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // structs), we need to use the natural alignment of the vectors, not the // potentially pragma-pack-clamped alignment from the struct layout. QualType FieldType = FD->getType(); - if (!FieldType->isVectorType() && TypeContainsVectors(FieldType)) { + if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) { // Get the natural vector alignment, bypassing any pragma pack on // structs. - CharUnits VecAlign = GetNaturalVectorAlignment(FieldType); + CharUnits VecAlign = GetNaturalAlignment(FieldType); Info.Alignment = std::max(Info.Alignment, VecAlign); } @@ -2904,7 +2991,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // unadjusted alignment to avoid inheriting pragma pack from the nested // struct. QualType BaseTy = QualType(FD->getType()->getBaseElementTypeUnsafe(), 0); - if (FD->getType() != BaseTy && TypeContainsVectors(FD->getType())) { + if (FD->getType() != BaseTy && TypeContainsVectorsOrFp80(FD->getType())) { Info.Alignment = std::max(Info.Alignment, Layout.getUnadjustedAlignment()); } @@ -2923,7 +3010,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( QualType FieldType = FD->getType(); // Only exempt arrays containing vectors, not direct vector fields. bool IsArrayContainingVectors = - !FieldType->isVectorType() && TypeContainsVectors(FieldType); + !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType); if (!IsArrayContainingVectors) Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); } diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp index bdac5298211659..488a3b5851fcb2 100644 --- a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp +++ b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp @@ -1,8 +1,10 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \ // RUN: | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mlong-double-80 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-FP80 -// Test that #pragma pack does not reduce natural type alignment for vector types -// when used as array elements (Itanium ABI). +// Test that #pragma pack does not reduce natural type alignment for vector +// and x86_fp80 types when used as array elements (Itanium ABI). typedef float __m128 __attribute__((__vector_size__(16))); @@ -38,3 +40,43 @@ void test_vector_struct() { ArrayOfVectorStruct s; s.elems[0].vec = (__m128){}; } + +// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack. +struct Klass { long double a; }; + +#pragma pack(push, 8) +template<typename T, unsigned N> +struct fp80_array { + T _Elems[N]; + + void fill(const T& val) { + for (unsigned i = 0; i < N; i++) + _Elems[i] = val; + } +}; +#pragma pack(pop) + +// CHECK-FP80-LABEL: define {{.*}} @_Z15test_fp80_arrayv +void test_fp80_array() { + // CHECK-FP80: %matrix = alloca %struct.fp80_array, align 16 + fp80_array<Klass, 16> matrix; + matrix.fill({}); +} + +// Struct containing x86_fp80 under pragma pack. +#pragma pack(push, 8) +struct Fp80Struct { + long double val; +}; + +struct ArrayOfFp80Struct { + Fp80Struct elems[4]; +}; +#pragma pack(pop) + +// CHECK-FP80-LABEL: define {{.*}} @_Z16test_fp80_structv +void test_fp80_struct() { + // CHECK-FP80: %s = alloca %struct.ArrayOfFp80Struct, align 16 + ArrayOfFp80Struct s; + s.elems[0].val = 1.0L; +} diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp index bdea75d3862356..0b90301e41418e 100644 --- a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp +++ b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp @@ -1,8 +1,11 @@ // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \ // RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \ +// RUN: -mlong-double-80 -emit-llvm -o - %s | FileCheck %s \ +// RUN: --check-prefix=CHECK-FP80 -// Test that #pragma pack does not reduce natural type alignment for vector types -// when used as array elements (matching MSVC behavior). +// Test that #pragma pack does not reduce natural type alignment for vector +// and x86_fp80 types when used as array elements (matching MSVC behavior). typedef float __m128 __attribute__((__vector_size__(16))); @@ -38,3 +41,43 @@ void test_vector_struct() { ArrayOfVectorStruct s; s.elems[0].vec = (__m128){}; } + +// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack. +struct Klass { long double a; }; + +#pragma pack(push, 8) +template<typename T, unsigned N> +struct fp80_array { + T _Elems[N]; + + void fill(const T& val) { + for (unsigned i = 0; i < N; i++) + _Elems[i] = val; + } +}; +#pragma pack(pop) + +// CHECK-FP80-LABEL: define {{.*}} @"?test_fp80_array +void test_fp80_array() { + // CHECK-FP80: %matrix = alloca %struct.fp80_array, align 16 + fp80_array<Klass, 16> matrix; + matrix.fill({}); +} + +// Struct containing x86_fp80 under pragma pack. +#pragma pack(push, 8) +struct Fp80Struct { + long double val; +}; + +struct ArrayOfFp80Struct { + Fp80Struct elems[4]; +}; +#pragma pack(pop) + +// CHECK-FP80-LABEL: define {{.*}} @"?test_fp80_struct +void test_fp80_struct() { + // CHECK-FP80: %s = alloca %struct.ArrayOfFp80Struct, align 16 + ArrayOfFp80Struct s; + s.elems[0].val = 1.0L; +} >From cfb1972568ccea0a071e320287e7023f55496690 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Thu, 3 Sep 2026 13:25:45 -0700 Subject: [PATCH 3/8] Fixed LIT for real msvc support --- .../test/CodeGen/pragma-pack-array-alignment-msvc.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp index 0b90301e41418e..5d730dee0bc365 100644 --- a/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp +++ b/clang/test/CodeGen/pragma-pack-array-alignment-msvc.cpp @@ -1,13 +1,14 @@ // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \ -// RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: -ffreestanding -emit-llvm -o - %s | FileCheck %s + // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fms-extensions \ -// RUN: -mlong-double-80 -emit-llvm -o - %s | FileCheck %s \ +// RUN: -ffreestanding -mlong-double-80 -emit-llvm -o - %s | FileCheck %s \ // RUN: --check-prefix=CHECK-FP80 // Test that #pragma pack does not reduce natural type alignment for vector // and x86_fp80 types when used as array elements (matching MSVC behavior). -typedef float __m128 __attribute__((__vector_size__(16))); +#include <xmmintrin.h> // Simple array-like struct with vector type under pragma pack. #pragma pack(push, 8) @@ -21,7 +22,7 @@ struct array { void test_vector_array() { // CHECK: %matrix = alloca %struct.array, align 16 array<__m128, 16> matrix; - matrix._Elems[0] = (__m128){}; + matrix._Elems[0] = _mm_setzero_ps(); } // Struct containing vector under pragma pack. @@ -39,7 +40,7 @@ struct ArrayOfVectorStruct { void test_vector_struct() { // CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16 ArrayOfVectorStruct s; - s.elems[0].vec = (__m128){}; + s.elems[0].vec = _mm_setzero_ps(); } // Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack. >From 67a3882075538b85cbb7806a2378435cb82319bb Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Thu, 3 Sep 2026 13:53:26 -0700 Subject: [PATCH 4/8] Fixed format --- clang/lib/AST/RecordLayoutBuilder.cpp | 32 +++++++++++++-------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 184befbf64c8e6..e804586b073f49 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -1709,9 +1709,8 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { QualType FieldType = D->getType(); // Only exempt arrays of vectors from pragma pack, not direct vector // fields. - bool IsVectorArray = - !FieldType->isVectorType() && - FieldType->getBaseElementTypeUnsafe()->isVectorType(); + bool IsVectorArray = !FieldType->isVectorType() && + FieldType->getBaseElementTypeUnsafe()->isVectorType(); if (!IsVectorArray) { UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); @@ -2054,8 +2053,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, QualType BaseQualTy = QualType(BaseTy, 0); if (D->getType() != BaseQualTy && TypeContainsVectorsOrFp80(D->getType())) { - FieldAlign = - std::max(FieldAlign, FieldRecord.getUnadjustedAlignment()); + FieldAlign = std::max(FieldAlign, FieldRecord.getUnadjustedAlignment()); PreferredAlign = std::max(PreferredAlign, FieldRecord.getUnadjustedAlignment()); } @@ -2278,8 +2276,8 @@ bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) { return TypeContainsVectorsOrFp80Impl(Ty, InArray); } -bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl( - QualType Ty, bool InArray) { +bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty + bool InArray) { // Direct vector type. if (Ty->isVectorType()) return true; @@ -2317,8 +2315,8 @@ CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) { return GetNaturalAlignmentImpl(Ty, InArray); } -CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl( - QualType Ty, bool InArray) { +CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty, + bool InArray) { // Direct vector type - get its natural alignment. if (Ty->isVectorType()) return Context.getTypeAlignInChars(Ty); @@ -2339,8 +2337,8 @@ CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl( CharUnits MaxAlign = CharUnits::One(); for (const FieldDecl *Field : RD->fields()) { if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) { - CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(), - InArray); + CharUnits FieldAlign = + GetNaturalAlignmentImpl(Field->getType(), InArray); MaxAlign = std::max(MaxAlign, FieldAlign); } } @@ -2841,8 +2839,8 @@ bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) { return TypeContainsVectorsOrFp80Impl(Ty, InArray); } -bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl( - QualType Ty, bool InArray) { +bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty, + bool InArray) { // Direct vector type. if (Ty->isVectorType()) return true; @@ -2880,8 +2878,8 @@ CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) { return GetNaturalAlignmentImpl(Ty, InArray); } -CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl( - QualType Ty, bool InArray) { +CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty, + bool InArray) { // Direct vector type - get its natural alignment. if (Ty->isVectorType()) return Context.getTypeAlignInChars(Ty); @@ -2902,8 +2900,8 @@ CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl( CharUnits MaxAlign = CharUnits::One(); for (const FieldDecl *Field : RD->fields()) { if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) { - CharUnits FieldAlign = GetNaturalAlignmentImpl(Field->getType(), - InArray); + CharUnits FieldAlign = + GetNaturalAlignmentImpl(Field->getType(), InArray); MaxAlign = std::max(MaxAlign, FieldAlign); } } >From 4c720c7a10589f40f0ca0a7c345845dc0dac7938 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Thu, 3 Sep 2026 14:08:22 -0700 Subject: [PATCH 5/8] Fix build error --- clang/lib/AST/RecordLayoutBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index e804586b073f49..a07150fc79c6da 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2276,7 +2276,7 @@ bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) { return TypeContainsVectorsOrFp80Impl(Ty, InArray); } -bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty +bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray) { // Direct vector type. if (Ty->isVectorType()) >From 8ee1872f7684d70d9397cde02a253fee81a96310 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Tue, 22 Sep 2026 11:35:45 -0700 Subject: [PATCH 6/8] Addressed review comments --- clang/include/clang/AST/ASTContext.h | 4 + clang/lib/AST/ASTContext.cpp | 30 +- clang/lib/AST/RecordLayoutBuilder.cpp | 300 ++---------------- .../pragma-pack-array-alignment-itanium.cpp | 82 ----- 4 files changed, 57 insertions(+), 359 deletions(-) delete mode 100644 clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index dd67c5d0410f81..55b3f0d9074058 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -183,6 +183,10 @@ enum class AlignRequirementKind { /// The alignment comes from an alignment attribute on a enum type. RequiredByEnum, + + /// The type's natural alignment is preserved under #pragma pack in MSVC + /// record layout (e.g., vectors, x87 fp80). + ResistPragmaPack, }; struct TypeInfo { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b502c4436de49d..b103aa5555d462 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2059,7 +2059,11 @@ bool ASTContext::isPromotableIntegerType(QualType T) const { } bool ASTContext::isAlignmentRequired(const Type *T) const { - return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None; + AlignRequirementKind Kind = getTypeInfo(T).AlignRequirement; + // ResistPragmaPack is only meant to resist #pragma pack in MSVC record + // layout, not to trigger other "aligned attribute" behaviors. + return Kind != AlignRequirementKind::None && + Kind != AlignRequirementKind::ResistPragmaPack; } bool ASTContext::isAlignmentRequired(QualType T) const { @@ -2189,6 +2193,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4) // Adjust the alignment for fixed-length RVV vectors. Align = std::min<unsigned>(64, Width); + // Vector types have their natural alignment resist reduction by + // #pragma pack in MSVC record layout. + AlignRequirement = AlignRequirementKind::ResistPragmaPack; break; } @@ -2350,6 +2357,11 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getLongDoubleWidth(); Align = Target->getLongDoubleAlign(); } + // x87 extended precision (fp80) has its natural alignment resist + // reduction by #pragma pack in MSVC record layout. + if (&Target->getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended()) + AlignRequirement = AlignRequirementKind::ResistPragmaPack; break; case BuiltinType::Float128: if (Target->hasFloat128Type() || !getLangOpts().OpenMP || @@ -2547,9 +2559,19 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); - AlignRequirement = RD->hasAttr<AlignedAttr>() - ? AlignRequirementKind::RequiredByRecord - : AlignRequirementKind::None; + if (RD->hasAttr<AlignedAttr>()) { + AlignRequirement = AlignRequirementKind::RequiredByRecord; + } else if (llvm::any_of(RD->fields(), [this](const FieldDecl *FD) { + return getTypeInfo(FD->getType()).AlignRequirement == + AlignRequirementKind::ResistPragmaPack; + })) { + // Propagate ResistPragmaPack if any field has that requirement, so + // pragma pack applied to enclosing records won't reduce alignment for + // records containing vector or x87 fp80 types. + AlignRequirement = AlignRequirementKind::ResistPragmaPack; + } else { + AlignRequirement = AlignRequirementKind::None; + } break; } diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index a07150fc79c6da..68652e2bdfd892 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -781,20 +781,6 @@ class ItaniumRecordLayoutBuilder { UpdateAlignment(NewAlignment, NewAlignment, NewAlignment); } - /// Check if a type contains vector or x86_fp80 types. - bool TypeContainsVectorsOrFp80(QualType Ty); - - /// Helper for TypeContainsVectorsOrFp80 that tracks array context. - bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray); - - /// Get the natural alignment of vectors or x86_fp80 contained in a type, - /// bypassing any pragma pack that may have been applied to enclosing - /// structs. - CharUnits GetNaturalAlignment(QualType Ty); - - /// Helper for GetNaturalAlignment that tracks array context. - CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray); - /// Retrieve the externally-supplied field offset for the given /// field. /// @@ -1702,23 +1688,13 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // But, if there's a #pragma pack in play, that takes precedent over // even the 'aligned' attribute, for non-zero-width bitfields. - // However, pragma pack should not reduce the natural alignment of vector - // array elements. unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment); if (!MaxFieldAlignment.isZero() && FieldSize) { - QualType FieldType = D->getType(); - // Only exempt arrays of vectors from pragma pack, not direct vector - // fields. - bool IsVectorArray = !FieldType->isVectorType() && - FieldType->getBaseElementTypeUnsafe()->isVectorType(); - if (!IsVectorArray) { - UnpackedFieldAlign = - std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); - if (FieldPacked) - FieldAlign = UnpackedFieldAlign; - else - FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); - } + UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); + if (FieldPacked) + FieldAlign = UnpackedFieldAlign; + else + FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); } // But, ms_struct just ignores all of that in unions, even explicit @@ -1934,17 +1910,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } else { setDeclInfo(false /* IsIncompleteArrayType */); - // If this is an array containing vectors (directly or in nested - // structs), we need to use the natural alignment of the vectors, not the - // potentially pragma-pack-clamped alignment from the struct layout. - QualType FieldType = D->getType(); - if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) { - // Get the natural vector alignment, bypassing any pragma pack on - // structs. - CharUnits VecAlign = GetNaturalAlignment(FieldType); - FieldAlign = std::max(FieldAlign, VecAlign); - } - // A potentially-overlapping field occupies its dsize or nvsize, whichever // is larger. if (D->isPotentiallyOverlapping()) { @@ -2047,16 +2012,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD); PreferredAlign = FieldRecord.getPreferredAlignment(); - // If this is an array of records containing vectors, use the - // unadjusted alignment to avoid inheriting pragma pack from the nested - // struct. - QualType BaseQualTy = QualType(BaseTy, 0); - if (D->getType() != BaseQualTy && - TypeContainsVectorsOrFp80(D->getType())) { - FieldAlign = std::max(FieldAlign, FieldRecord.getUnadjustedAlignment()); - PreferredAlign = - std::max(PreferredAlign, FieldRecord.getUnadjustedAlignment()); - } } } @@ -2074,20 +2029,10 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars); // The maximum field alignment overrides the aligned attribute. - // However, pragma pack should not reduce the natural alignment of array - // elements that contain vectors (either arrays of vectors, or arrays of - // structs containing vectors). Direct vector fields ARE affected by pragma - // pack. if (!MaxFieldAlignment.isZero()) { - QualType FieldType = D->getType(); - // Only exempt arrays containing vectors, not direct vector fields. - bool IsArrayContainingVectors = - !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType); - if (!IsArrayContainingVectors) { - PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment); - PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment); - UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); - } + PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment); + PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment); + UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); } @@ -2265,89 +2210,6 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { } } -bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) { - QualType OrigTy = Ty; - - // Strip through arrays. - while (const ArrayType *AT = Context.getAsArrayType(Ty)) - Ty = AT->getElementType(); - - bool InArray = (Ty != OrigTy); - return TypeContainsVectorsOrFp80Impl(Ty, InArray); -} - -bool ItaniumRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty, - bool InArray) { - // Direct vector type. - if (Ty->isVectorType()) - return true; - - // x86_fp80 only matters if it's in an array, not a direct field. - if (InArray) { - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { - if (BT->getKind() == BuiltinType::LongDouble && - &Context.getTargetInfo().getLongDoubleFormat() == - &llvm::APFloat::x87DoubleExtended()) - return true; - } - } - - // Check if it's a record type with vector or x86_fp80 fields. - if (const RecordType *RT = Ty->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) - return true; - } - } - - return false; -} - -CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) { - QualType OrigTy = Ty; - - // Strip through arrays. - while (const ArrayType *AT = Context.getAsArrayType(Ty)) - Ty = AT->getElementType(); - - bool InArray = (Ty != OrigTy); - return GetNaturalAlignmentImpl(Ty, InArray); -} - -CharUnits ItaniumRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty, - bool InArray) { - // Direct vector type - get its natural alignment. - if (Ty->isVectorType()) - return Context.getTypeAlignInChars(Ty); - - // x86_fp80 only matters if it's in an array, not a direct field. - if (InArray) { - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { - if (BT->getKind() == BuiltinType::LongDouble && - &Context.getTargetInfo().getLongDoubleFormat() == - &llvm::APFloat::x87DoubleExtended()) - return Context.getTypeAlignInChars(Ty); - } - } - - // Record type - find the maximum alignment inside. - if (const RecordType *RT = Ty->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - CharUnits MaxAlign = CharUnits::One(); - for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) { - CharUnits FieldAlign = - GetNaturalAlignmentImpl(Field->getType(), InArray); - MaxAlign = std::max(MaxAlign, FieldAlign); - } - } - return MaxAlign; - } - - return CharUnits::One(); -} - void ItaniumRecordLayoutBuilder::UpdateAlignment( CharUnits NewAlignment, CharUnits UnpackedNewAlignment, CharUnits PreferredNewAlignment) { @@ -2752,16 +2614,6 @@ struct MicrosoftRecordLayoutBuilder { void computeVtorDispSet( llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet, const CXXRecordDecl *RD) const; - /// Check if a type (recursively) contains vector or x86_fp80 types. - bool TypeContainsVectorsOrFp80(QualType Ty); - /// Helper for TypeContainsVectorsOrFp80 that tracks array context. - bool TypeContainsVectorsOrFp80Impl(QualType Ty, bool InArray); - /// Get the natural alignment of vectors or x86_fp80 contained in a type, - /// bypassing any pragma pack that may have been applied to enclosing - /// structs. - CharUnits GetNaturalAlignment(QualType Ty); - /// Helper for GetNaturalAlignment that tracks array context. - CharUnits GetNaturalAlignmentImpl(QualType Ty, bool InArray); const ASTContext &Context; EmptySubobjectMap *EmptySubobjects; @@ -2828,89 +2680,6 @@ struct MicrosoftRecordLayoutBuilder { }; } // namespace -bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80(QualType Ty) { - QualType OrigTy = Ty; - - // Strip through arrays. - while (const ArrayType *AT = Context.getAsArrayType(Ty)) - Ty = AT->getElementType(); - - bool InArray = (Ty != OrigTy); - return TypeContainsVectorsOrFp80Impl(Ty, InArray); -} - -bool MicrosoftRecordLayoutBuilder::TypeContainsVectorsOrFp80Impl(QualType Ty, - bool InArray) { - // Direct vector type. - if (Ty->isVectorType()) - return true; - - // x86_fp80 only matters if it's in an array, not a direct field. - if (InArray) { - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { - if (BT->getKind() == BuiltinType::LongDouble && - &Context.getTargetInfo().getLongDoubleFormat() == - &llvm::APFloat::x87DoubleExtended()) - return true; - } - } - - // Check if it's a record type with vector or x86_fp80 fields. - if (const RecordType *RT = Ty->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) - return true; - } - } - - return false; -} - -CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignment(QualType Ty) { - QualType OrigTy = Ty; - - // Strip through arrays. - while (const ArrayType *AT = Context.getAsArrayType(Ty)) - Ty = AT->getElementType(); - - bool InArray = (Ty != OrigTy); - return GetNaturalAlignmentImpl(Ty, InArray); -} - -CharUnits MicrosoftRecordLayoutBuilder::GetNaturalAlignmentImpl(QualType Ty, - bool InArray) { - // Direct vector type - get its natural alignment. - if (Ty->isVectorType()) - return Context.getTypeAlignInChars(Ty); - - // x86_fp80 only matters if it's in an array, not a direct field. - if (InArray) { - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { - if (BT->getKind() == BuiltinType::LongDouble && - &Context.getTargetInfo().getLongDoubleFormat() == - &llvm::APFloat::x87DoubleExtended()) - return Context.getTypeAlignInChars(Ty); - } - } - - // Record type - find the maximum alignment inside. - if (const RecordType *RT = Ty->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - CharUnits MaxAlign = CharUnits::One(); - for (const FieldDecl *Field : RD->fields()) { - if (TypeContainsVectorsOrFp80Impl(Field->getType(), InArray)) { - CharUnits FieldAlign = - GetNaturalAlignmentImpl(Field->getType(), InArray); - MaxAlign = std::max(MaxAlign, FieldAlign); - } - } - return MaxAlign; - } - - return CharUnits::One(); -} - MicrosoftRecordLayoutBuilder::ElementInfo MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( const ASTRecordLayout &Layout) { @@ -2949,26 +2718,23 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( auto TInfo = Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType()); ElementInfo Info{TInfo.Width, TInfo.Align, CharUnits::Zero()}; - - // If this is an array containing vectors (directly or in nested - // structs), we need to use the natural alignment of the vectors, not the - // potentially pragma-pack-clamped alignment from the struct layout. - QualType FieldType = FD->getType(); - if (!FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType)) { - // Get the natural vector alignment, bypassing any pragma pack on - // structs. - CharUnits VecAlign = GetNaturalAlignment(FieldType); - Info.Alignment = std::max(Info.Alignment, VecAlign); - } - // Respect align attributes on the field. CharUnits DirectFieldAlignment = Context.toCharUnitsFromBits(FD->getMaxAlignment()); // The portion of the field's required alignment that comes from its type // rather than from over-alignment applied directly to the field. CharUnits FieldTypeRequiredAlignment = CharUnits::Zero(); - // Respect align attributes on the type. - if (Context.isAlignmentRequired(FD->getType())) + // Types that resist #pragma pack (vectors, x87 fp80) contribute their + // natural alignment for the purpose of resisting pragma pack, but do not + // affect the record's required alignment. + CharUnits FieldTypePragmaPackResistantAlignment = CharUnits::Zero(); + AlignRequirementKind FieldAlignReq = + Context.getTypeInfo(FD->getType()).AlignRequirement; + if (FieldAlignReq == AlignRequirementKind::ResistPragmaPack) + FieldTypePragmaPackResistantAlignment = + Context.getTypeAlignInChars(FD->getType()); + else if (FieldAlignReq != AlignRequirementKind::None) + // Respect align attributes on the type. FieldTypeRequiredAlignment = Context.getTypeAlignInChars(FD->getType()); // Respect attributes applied to subobjects of the field. if (FD->isBitField()) @@ -2985,14 +2751,6 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); FieldTypeRequiredAlignment = std::max(FieldTypeRequiredAlignment, Layout.getRequiredAlignment()); - // If this is an array of records containing vectors, use the - // unadjusted alignment to avoid inheriting pragma pack from the nested - // struct. - QualType BaseTy = QualType(FD->getType()->getBaseElementTypeUnsafe(), 0); - if (FD->getType() != BaseTy && TypeContainsVectorsOrFp80(FD->getType())) { - Info.Alignment = - std::max(Info.Alignment, Layout.getUnadjustedAlignment()); - } } // Capture required alignment as a side-effect. RequiredAlignment = @@ -3000,20 +2758,16 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( std::max(DirectFieldAlignment, FieldTypeRequiredAlignment)); } // Respect pragma pack, attribute pack and declspec align - // However, pragma pack should not reduce the natural alignment of array - // elements that contain vectors (either arrays of vectors, or arrays of - // structs containing vectors). Direct vector fields ARE affected by pragma - // pack. - if (!MaxFieldAlignment.isZero()) { - QualType FieldType = FD->getType(); - // Only exempt arrays containing vectors, not direct vector fields. - bool IsArrayContainingVectors = - !FieldType->isVectorType() && TypeContainsVectorsOrFp80(FieldType); - if (!IsArrayContainingVectors) - Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); - } + if (!MaxFieldAlignment.isZero()) + Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); if (FD->hasAttr<PackedAttr>()) Info.Alignment = CharUnits::One(); + // Types that resist #pragma pack restore their natural alignment after + // pragma pack clamping, but only when neither the field nor the enclosing + // record is explicitly packed via __attribute__((packed)). + if (!FD->hasAttr<PackedAttr>() && !FD->getParent()->hasAttr<PackedAttr>()) + Info.Alignment = + std::max(Info.Alignment, FieldTypePragmaPackResistantAlignment); // The alignment used to update the record's alignment excludes over-alignment // applied directly to the field; the alignment used for placement includes // it. On targets that don't reuse over-aligned tail padding the two are the diff --git a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp b/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp deleted file mode 100644 index 488a3b5851fcb2..00000000000000 --- a/clang/test/CodeGen/pragma-pack-array-alignment-itanium.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s \ -// RUN: | FileCheck %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mlong-double-80 \ -// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-FP80 - -// Test that #pragma pack does not reduce natural type alignment for vector -// and x86_fp80 types when used as array elements (Itanium ABI). - -typedef float __m128 __attribute__((__vector_size__(16))); - -// Simple array-like struct with vector type under pragma pack. -#pragma pack(push, 8) -template<typename T, unsigned N> -struct array { - T _Elems[N]; -}; -#pragma pack(pop) - -// CHECK-LABEL: define {{.*}} @_Z17test_vector_arrayv -void test_vector_array() { - // CHECK: %matrix = alloca %struct.array, align 16 - array<__m128, 16> matrix; - matrix._Elems[0] = (__m128){}; -} - -// Struct containing vector under pragma pack. -#pragma pack(push, 8) -struct VectorStruct { - __m128 vec; -}; - -struct ArrayOfVectorStruct { - VectorStruct elems[4]; -}; -#pragma pack(pop) - -// CHECK-LABEL: define {{.*}} @_Z18test_vector_structv -void test_vector_struct() { - // CHECK: %s = alloca %struct.ArrayOfVectorStruct, align 16 - ArrayOfVectorStruct s; - s.elems[0].vec = (__m128){}; -} - -// Test x86_fp80 (long double with -mlong-double-80) arrays under pragma pack. -struct Klass { long double a; }; - -#pragma pack(push, 8) -template<typename T, unsigned N> -struct fp80_array { - T _Elems[N]; - - void fill(const T& val) { - for (unsigned i = 0; i < N; i++) - _Elems[i] = val; - } -}; -#pragma pack(pop) - -// CHECK-FP80-LABEL: define {{.*}} @_Z15test_fp80_arrayv -void test_fp80_array() { - // CHECK-FP80: %matrix = alloca %struct.fp80_array, align 16 - fp80_array<Klass, 16> matrix; - matrix.fill({}); -} - -// Struct containing x86_fp80 under pragma pack. -#pragma pack(push, 8) -struct Fp80Struct { - long double val; -}; - -struct ArrayOfFp80Struct { - Fp80Struct elems[4]; -}; -#pragma pack(pop) - -// CHECK-FP80-LABEL: define {{.*}} @_Z16test_fp80_structv -void test_fp80_struct() { - // CHECK-FP80: %s = alloca %struct.ArrayOfFp80Struct, align 16 - ArrayOfFp80Struct s; - s.elems[0].val = 1.0L; -} >From e9ecab5a9584e31f1a02c903d140887bbb75140e Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Tue, 22 Sep 2026 12:22:19 -0700 Subject: [PATCH 7/8] Fix format --- clang/lib/AST/ASTContext.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b103aa5555d462..7c96512feb7688 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2359,8 +2359,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } // x87 extended precision (fp80) has its natural alignment resist // reduction by #pragma pack in MSVC record layout. - if (&Target->getLongDoubleFormat() == - &llvm::APFloat::x87DoubleExtended()) + if (&Target->getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) AlignRequirement = AlignRequirementKind::ResistPragmaPack; break; case BuiltinType::Float128: >From 36995f132c2328e2bed2199af541d067b6724a79 Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Wed, 23 Sep 2026 07:05:54 -0700 Subject: [PATCH 8/8] Addressed review comments --- clang/include/clang/AST/ASTContext.h | 6 ++++-- clang/include/clang/AST/RecordLayout.h | 15 +++++++++++++-- clang/lib/AST/ASTContext.cpp | 22 +++++++--------------- clang/lib/AST/RecordLayout.cpp | 21 +++++++++++---------- clang/lib/AST/RecordLayoutBuilder.cpp | 25 ++++++++++++++++++++----- 5 files changed, 55 insertions(+), 34 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 55b3f0d9074058..e35a48f64b0deb 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -199,7 +199,8 @@ struct TypeInfo { AlignRequirementKind AlignRequirement) : Width(Width), Align(Align), AlignRequirement(AlignRequirement) {} bool isAlignRequired() { - return AlignRequirement != AlignRequirementKind::None; + return AlignRequirement != AlignRequirementKind::None && + AlignRequirement != AlignRequirementKind::ResistPragmaPack; } }; @@ -213,7 +214,8 @@ struct TypeInfoChars { AlignRequirementKind AlignRequirement) : Width(Width), Align(Align), AlignRequirement(AlignRequirement) {} bool isAlignRequired() { - return AlignRequirement != AlignRequirementKind::None; + return AlignRequirement != AlignRequirementKind::None && + AlignRequirement != AlignRequirementKind::ResistPragmaPack; } }; diff --git a/clang/include/clang/AST/RecordLayout.h b/clang/include/clang/AST/RecordLayout.h index 9af17df229b376..5ae2f94f062cfe 100644 --- a/clang/include/clang/AST/RecordLayout.h +++ b/clang/include/clang/AST/RecordLayout.h @@ -84,6 +84,10 @@ class ASTRecordLayout { /// the __declspec(align()) trumps #pramga pack and must always be obeyed. CharUnits RequiredAlignment; + /// Natural alignment of pragma-pack-resistant fields (vectors, x87 fp80), + /// or zero if none. + CharUnits PragmaPackResistantAlignment; + /// FieldOffsets - Array of field offsets in bits. ASTVector<uint64_t> FieldOffsets; @@ -157,7 +161,8 @@ class ASTRecordLayout { ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, CharUnits preferredAlignment, CharUnits unadjustedAlignment, - CharUnits requiredAlignment, CharUnits datasize, + CharUnits requiredAlignment, + CharUnits pragmaPackResistantAlignment, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets); using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy; @@ -165,7 +170,8 @@ class ASTRecordLayout { // Constructor for C++ records. ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, CharUnits preferredAlignment, CharUnits unadjustedAlignment, - CharUnits requiredAlignment, bool hasOwnVFPtr, + CharUnits requiredAlignment, + CharUnits pragmaPackResistantAlignment, bool hasOwnVFPtr, bool hasExtendableVFPtr, CharUnits vbptroffset, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets, CharUnits nonvirtualsize, CharUnits nonvirtualalignment, @@ -327,6 +333,11 @@ class ASTRecordLayout { CharUnits getRequiredAlignment() const { return RequiredAlignment; } + /// Get the natural alignment of pragma-pack-resistant fields. + CharUnits getPragmaPackResistantAlignment() const { + return PragmaPackResistantAlignment; + } + bool endsWithZeroSizedObject() const { return CXXInfo && CXXInfo->EndsWithZeroSizedObject; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 7c96512feb7688..3b32f4d5960ae1 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2059,11 +2059,7 @@ bool ASTContext::isPromotableIntegerType(QualType T) const { } bool ASTContext::isAlignmentRequired(const Type *T) const { - AlignRequirementKind Kind = getTypeInfo(T).AlignRequirement; - // ResistPragmaPack is only meant to resist #pragma pack in MSVC record - // layout, not to trigger other "aligned attribute" behaviors. - return Kind != AlignRequirementKind::None && - Kind != AlignRequirementKind::ResistPragmaPack; + return getTypeInfo(T).isAlignRequired(); } bool ASTContext::isAlignmentRequired(QualType T) const { @@ -2558,19 +2554,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); - if (RD->hasAttr<AlignedAttr>()) { + if (RD->hasAttr<AlignedAttr>()) AlignRequirement = AlignRequirementKind::RequiredByRecord; - } else if (llvm::any_of(RD->fields(), [this](const FieldDecl *FD) { - return getTypeInfo(FD->getType()).AlignRequirement == - AlignRequirementKind::ResistPragmaPack; - })) { - // Propagate ResistPragmaPack if any field has that requirement, so - // pragma pack applied to enclosing records won't reduce alignment for - // records containing vector or x87 fp80 types. + else if (!Layout.getPragmaPackResistantAlignment().isZero()) + // Propagate ResistPragmaPack so pragma pack applied to enclosing + // records won't reduce alignment for records containing vector or + // x87 fp80 types. AlignRequirement = AlignRequirementKind::ResistPragmaPack; - } else { + else AlignRequirement = AlignRequirementKind::None; - } break; } diff --git a/clang/lib/AST/RecordLayout.cpp b/clang/lib/AST/RecordLayout.cpp index 314b24a1f319e7..b5fefb2b97724e 100644 --- a/clang/lib/AST/RecordLayout.cpp +++ b/clang/lib/AST/RecordLayout.cpp @@ -27,17 +27,16 @@ void ASTRecordLayout::Destroy(ASTContext &Ctx) { Ctx.Deallocate(this); } -ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, - CharUnits alignment, - CharUnits preferredAlignment, - CharUnits unadjustedAlignment, - CharUnits requiredAlignment, - CharUnits datasize, - ArrayRef<uint64_t> fieldoffsets) +ASTRecordLayout::ASTRecordLayout( + const ASTContext &Ctx, CharUnits size, CharUnits alignment, + CharUnits preferredAlignment, CharUnits unadjustedAlignment, + CharUnits requiredAlignment, CharUnits pragmaPackResistantAlignment, + CharUnits datasize, ArrayRef<uint64_t> fieldoffsets) : Size(size), DataSize(datasize), Alignment(alignment), PreferredAlignment(preferredAlignment), UnadjustedAlignment(unadjustedAlignment), - RequiredAlignment(requiredAlignment) { + RequiredAlignment(requiredAlignment), + PragmaPackResistantAlignment(pragmaPackResistantAlignment) { FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end()); } @@ -45,8 +44,9 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, ASTRecordLayout::ASTRecordLayout( const ASTContext &Ctx, CharUnits size, CharUnits alignment, CharUnits preferredAlignment, CharUnits unadjustedAlignment, - CharUnits requiredAlignment, bool hasOwnVFPtr, bool hasExtendableVFPtr, - CharUnits vbptroffset, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets, + CharUnits requiredAlignment, CharUnits pragmaPackResistantAlignment, + bool hasOwnVFPtr, bool hasExtendableVFPtr, CharUnits vbptroffset, + CharUnits datasize, ArrayRef<uint64_t> fieldoffsets, CharUnits nonvirtualsize, CharUnits nonvirtualalignment, CharUnits preferrednvalignment, CharUnits nonrequirednvalignment, CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase, @@ -57,6 +57,7 @@ ASTRecordLayout::ASTRecordLayout( PreferredAlignment(preferredAlignment), UnadjustedAlignment(unadjustedAlignment), RequiredAlignment(requiredAlignment), + PragmaPackResistantAlignment(pragmaPackResistantAlignment), CXXInfo(new (Ctx) CXXRecordLayoutInfo) { FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end()); diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 68652e2bdfd892..994c34f3421b1c 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2633,6 +2633,9 @@ struct MicrosoftRecordLayoutBuilder { /// The alignment of the record ignoring any over-alignment imposed via /// __declspec(align()) / alignas on the record or its bases. CharUnits NonRequiredAlignment; + /// Natural alignment of pragma-pack-resistant fields (vectors, x87 fp80), + /// or zero if none. + CharUnits PragmaPackResistantAlignment; /// The size of the allocation of the currently active bitfield. /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield /// is true. @@ -2751,12 +2754,19 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); FieldTypeRequiredAlignment = std::max(FieldTypeRequiredAlignment, Layout.getRequiredAlignment()); + // Propagate pragma-pack-resistant alignment from nested records. + FieldTypePragmaPackResistantAlignment = + std::max(FieldTypePragmaPackResistantAlignment, + Layout.getPragmaPackResistantAlignment()); } // Capture required alignment as a side-effect. RequiredAlignment = std::max(RequiredAlignment, std::max(DirectFieldAlignment, FieldTypeRequiredAlignment)); } + // Capture pragma-pack-resistant alignment as a side-effect. + PragmaPackResistantAlignment = std::max( + PragmaPackResistantAlignment, FieldTypePragmaPackResistantAlignment); // Respect pragma pack, attribute pack and declspec align if (!MaxFieldAlignment.isZero()) Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); @@ -3469,7 +3479,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { Builder.cxxLayout(RD); NewEntry = new (*this) ASTRecordLayout( *this, Builder.Size, Builder.Alignment, Builder.Alignment, - Builder.Alignment, Builder.RequiredAlignment, Builder.HasOwnVFPtr, + Builder.Alignment, Builder.RequiredAlignment, + Builder.PragmaPackResistantAlignment, Builder.HasOwnVFPtr, Builder.HasOwnVFPtr || Builder.PrimaryBase, Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets, Builder.NonVirtualSize, Builder.Alignment, Builder.Alignment, Builder.NonRequiredAlignment, @@ -3481,7 +3492,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { Builder.layout(D); NewEntry = new (*this) ASTRecordLayout( *this, Builder.Size, Builder.Alignment, Builder.Alignment, - Builder.Alignment, Builder.RequiredAlignment, Builder.Size, + Builder.Alignment, Builder.RequiredAlignment, + Builder.PragmaPackResistantAlignment, Builder.Size, Builder.FieldOffsets); } } else { @@ -3505,7 +3517,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { *this, Builder.getSize(), Builder.Alignment, Builder.PreferredAlignment, Builder.UnadjustedAlignment, /*RequiredAlignment : used by MS-ABI)*/ - Builder.Alignment, Builder.HasOwnVFPtr, RD->isDynamicClass(), + Builder.Alignment, /*PragmaPackResistantAlignment=*/CharUnits::Zero(), + Builder.HasOwnVFPtr, RD->isDynamicClass(), CharUnits::fromQuantity(-1), DataSize, Builder.FieldOffsets, NonVirtualSize, Builder.NonVirtualAlignment, Builder.PreferredNVAlignment, Builder.NonVirtualAlignment, @@ -3520,7 +3533,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { *this, Builder.getSize(), Builder.Alignment, Builder.PreferredAlignment, Builder.UnadjustedAlignment, /*RequiredAlignment : used by MS-ABI)*/ - Builder.Alignment, Builder.getSize(), Builder.FieldOffsets); + Builder.Alignment, /*PragmaPackResistantAlignment=*/CharUnits::Zero(), + Builder.getSize(), Builder.FieldOffsets); } } @@ -3656,7 +3670,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D) const { *this, Builder.getSize(), Builder.Alignment, Builder.PreferredAlignment, Builder.UnadjustedAlignment, /*RequiredAlignment : used by MS-ABI)*/ - Builder.Alignment, Builder.getDataSize(), Builder.FieldOffsets); + Builder.Alignment, /*PragmaPackResistantAlignment=*/CharUnits::Zero(), + Builder.getDataSize(), Builder.FieldOffsets); ObjCLayouts[D] = NewEntry; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
