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/2] 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 e6da6c78238c1..03a9318547fde 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 0000000000000..bdac529821165 --- /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 0000000000000..bdea75d386235 --- /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/2] 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 03a9318547fde..184befbf64c8e 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 bdac529821165..488a3b5851fcb 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 bdea75d386235..0b90301e41418 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; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
