https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/208256
>From a30928821d892d2c4495f64a1265ea8ad73db020 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Wed, 8 Jul 2026 09:24:56 -0700 Subject: [PATCH 1/9] [Clang] Fix x86_fp80 misalignment with pragma pack on Windows --- clang/lib/AST/RecordLayoutBuilder.cpp | 8 ++- clang/test/CodeGen/x86_fp80-alignment-win.cpp | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/x86_fp80-alignment-win.cpp diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index c27572bc7f50d..6df1bc37a890d 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2748,10 +2748,12 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( std::max(RequiredAlignment, std::max(DirectFieldAlignment, FieldTypeRequiredAlignment)); } - // Respect pragma pack, attribute pack and declspec align - if (!MaxFieldAlignment.isZero()) + // Respect pragma pack, attribute pack and declspec align, but not for types + // that require specific alignment for correctness (e.g., x86_fp80 needs + // 16-byte alignment for movaps instructions). + if (!MaxFieldAlignment.isZero() && !ContainsX86FP80) Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); - if (FD->hasAttr<PackedAttr>()) + if (FD->hasAttr<PackedAttr>() && !ContainsX86FP80) Info.Alignment = CharUnits::One(); // The alignment used to update the record's alignment excludes over-alignment // applied directly to the field; the alignment used for placement includes diff --git a/clang/test/CodeGen/x86_fp80-alignment-win.cpp b/clang/test/CodeGen/x86_fp80-alignment-win.cpp new file mode 100644 index 0000000000000..f446474c598be --- /dev/null +++ b/clang/test/CodeGen/x86_fp80-alignment-win.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -mlong-double-80 -emit-llvm -o - %s | FileCheck %s + +// Test that x86_fp80 (long double with /Qlong-double flag) maintains +// 16-byte alignment for correctness (required by movaps instructions), +// even when #pragma pack would normally reduce it. + +struct Klass { + long double a; +}; + +// Simulate std::array without including headers +template<typename T, unsigned N> +struct array { + T _Elems[N]; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_single_klass +// CHECK: %k = alloca %struct.Klass, align 16 +// CHECK-NOT: align 8 +// CHECK: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 +void test_single_klass() { + Klass k; + k.a = 0.0L; +} + +// CHECK-LABEL: define {{.*}} @{{.*}}test_struct_array +// CHECK: %matrix = alloca %struct.array, align 16 +// CHECK-NOT: align 8 +// CHECK: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 +void test_struct_array() { + array<Klass, 16> matrix; + for (int i = 0; i < 16; i++) + matrix._Elems[i].a = 0.0L; +} + +// CHECK-LABEL: define {{.*}} @{{.*}}test_direct_array +// CHECK: %arr = alloca [16 x %struct.Klass], align 16 +void test_direct_array() { + Klass arr[16]; + for (int i = 0; i < 16; i++) + arr[i].a = 0.0L; +} + +// Test with explicit pragma pack(8) - should still maintain 16-byte alignment +#pragma pack(push, 8) +struct PackedKlass { + long double b; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_explicit_pack +// CHECK: %pk = alloca %struct.PackedKlass, align 16 +// CHECK-NOT: align 8 +// CHECK: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 +void test_explicit_pack() { + PackedKlass pk; + pk.b = 0.0L; +} +#pragma pack(pop) >From 51049570ce04ee08ae18ec39b41e1ce5531b521f Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Fri, 10 Jul 2026 07:26:10 -0700 Subject: [PATCH 2/9] Leveraged FieldRequiredAlignment --- clang/lib/AST/RecordLayoutBuilder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 6df1bc37a890d..8b15c0a78a89f 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2751,9 +2751,9 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // Respect pragma pack, attribute pack and declspec align, but not for types // that require specific alignment for correctness (e.g., x86_fp80 needs // 16-byte alignment for movaps instructions). - if (!MaxFieldAlignment.isZero() && !ContainsX86FP80) + if (!MaxFieldAlignment.isZero()) Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); - if (FD->hasAttr<PackedAttr>() && !ContainsX86FP80) + if (FD->hasAttr<PackedAttr>()) Info.Alignment = CharUnits::One(); // The alignment used to update the record's alignment excludes over-alignment // applied directly to the field; the alignment used for placement includes >From f55ed7ecfd387cce528e58729f982ada6b0116a3 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Tue, 14 Jul 2026 08:24:02 -0700 Subject: [PATCH 3/9] Added vector type support and addressed review comments --- clang/include/clang/AST/ASTContext.h | 3 + clang/lib/AST/ASTContext.cpp | 28 +++- clang/lib/AST/RecordLayoutBuilder.cpp | 96 ++++++++++++- .../x86_fp80-alignment-pragma-pack.cpp | 136 ++++++++++++++++++ clang/test/CodeGen/x86_fp80-alignment-win.cpp | 58 -------- 5 files changed, 253 insertions(+), 68 deletions(-) create mode 100644 clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp delete mode 100644 clang/test/CodeGen/x86_fp80-alignment-win.cpp diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 763039e690dec..c53dd99df9cba 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -183,6 +183,9 @@ enum class AlignRequirementKind { /// The alignment comes from an alignment attribute on a enum type. RequiredByEnum, + + /// The alignment is required by the ABI for correctness. + RequiredByABI, }; struct TypeInfo { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 02a3f88431f58..6054d37554ef8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2348,6 +2348,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getLongDoubleWidth(); Align = Target->getLongDoubleAlign(); } + // On Windows targets, x86_fp80 requires 16-byte alignment for ABI + // correctness (movaps instructions will fault on misaligned addresses). + // Mark this as an ABI requirement that must not be reduced by #pragma + // pack. GCC preserves such alignment on other targets, but Clang + // historically has not; changing this would break existing Clang ABI on + // non-Windows platforms. + if (Target->getTriple().isOSWindows() && + &Target->getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) + AlignRequirement = AlignRequirementKind::RequiredByABI; break; case BuiltinType::Float128: if (Target->hasFloat128Type() || !getLangOpts().OpenMP || @@ -2539,9 +2548,22 @@ 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; + // Check if the record has an aligned attribute, or if it contains + // fields with ABI-required alignment (e.g., x86_fp80). + if (RD->hasAttr<AlignedAttr>()) { + AlignRequirement = AlignRequirementKind::RequiredByRecord; + } else { + // Check if any field has RequiredByABI alignment requirement. + // If so, propagate it to the record. + AlignRequirement = AlignRequirementKind::None; + for (const auto *Field : RD->fields()) { + TypeInfo FI = getTypeInfo(Field->getType().getTypePtr()); + if (FI.AlignRequirement == AlignRequirementKind::RequiredByABI) { + AlignRequirement = AlignRequirementKind::RequiredByABI; + break; + } + } + } break; } diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 8b15c0a78a89f..c0b183a2ce6a6 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -559,6 +559,61 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects( typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> ClassSetTy; +/// Helper for RequiresVectorAlignment - recursively checks types. +static bool CheckTypeForRequiredVectorAlignment(const ASTContext &Context, + QualType Ty) { + if (const auto *VT = Ty->getAs<VectorType>()) { + uint64_t VecWidth = Context.getTypeSize(VT); + return VT->getVectorKind() == VectorKind::Generic && + (VecWidth == 128 || VecWidth == 256) && + VecWidth == Context.getTypeAlign(VT); + } + if (const auto *AT = Ty->getAsArrayTypeUnsafe()) + return CheckTypeForRequiredVectorAlignment(Context, AT->getElementType()); + + if (const auto *RT = Ty->getAs<RecordType>()) { + for (const auto *Field : RT->getDecl()->fields()) + if (CheckTypeForRequiredVectorAlignment(Context, Field->getType())) + return true; + } + return false; +} + +/// Check if a type (or any type it contains) is a standard SIMD vector requiring +/// alignment preservation on Windows. This includes direct vectors, arrays of +/// vectors, and structs containing vectors. +static bool RequiresVectorAlignment(const ASTContext &Context, QualType Ty) { + if (!Context.getTargetInfo().getTriple().isOSWindows()) + return false; + return CheckTypeForRequiredVectorAlignment(Context, Ty); +} + +/// Check if we should prevent MaxFieldAlignment from reducing this field's +/// alignment. Returns true if the field has ABI-required alignment or contains +/// vectors requiring alignment, UNLESS the struct has explicit packed attribute. +static bool ShouldPreserveFieldAlignment(const ASTContext &Context, + const FieldDecl *FD, + AlignRequirementKind AlignReq, + bool StructHasPackedAttr) { + if (AlignReq == AlignRequirementKind::RequiredByABI) + return true; + if (!StructHasPackedAttr && RequiresVectorAlignment(Context, FD->getType())) + return true; + return false; +} + +/// Check if a record contains any fields with vectors requiring alignment. +/// Returns false if the record has explicit __attribute__((packed)). +static bool RecordContainsVectorRequiringAlignment(const ASTContext &Context, + const RecordDecl *RD) { + if (RD->hasAttr<PackedAttr>()) + return false; + for (const auto *Field : RD->fields()) + if (RequiresVectorAlignment(Context, Field->getType())) + return true; + return false; +} + class ItaniumRecordLayoutBuilder { protected: // FIXME: Remove this and make the appropriate fields public. @@ -2029,13 +2084,20 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars); // The maximum field alignment overrides the aligned attribute. - if (!MaxFieldAlignment.isZero()) { + // However, do not reduce alignment for ABI-required alignments (e.g., + // x86_fp80, vector types) which must be preserved for correctness. + // On Windows, check if the field type is a vector with standard SIMD + // alignment (16 or 32 bytes with size == alignment) - these need their + // alignment preserved under #pragma pack. However, honor explicit + // __attribute__((packed)) on the struct (Packed=true means the struct + // has the packed attribute, not the field). + if (!MaxFieldAlignment.isZero() && + !ShouldPreserveFieldAlignment(Context, D, AlignRequirement, Packed)) { PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment); PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment); UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); } - if (!FieldPacked) FieldAlign = UnpackedFieldAlign; if (DefaultsToAIXPowerAlignment) @@ -2748,10 +2810,25 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( std::max(RequiredAlignment, std::max(DirectFieldAlignment, FieldTypeRequiredAlignment)); } - // Respect pragma pack, attribute pack and declspec align, but not for types - // that require specific alignment for correctness (e.g., x86_fp80 needs - // 16-byte alignment for movaps instructions). - if (!MaxFieldAlignment.isZero()) + // Check if this is a vector type (or contains vectors) requiring alignment + // preservation on Windows. This includes direct vectors, arrays of vectors, + // and structs containing vectors. However, honor __attribute__((packed)) + // on the struct even for vectors (explicit intent to pack). + bool IsVectorRequiringAlignment = false; + if (const RecordDecl *RD = FD->getParent()) { + if (!RD->hasAttr<PackedAttr>()) { + IsVectorRequiringAlignment = RequiresVectorAlignment(Context, FD->getType()); + } + } + + // Respect pragma pack, attribute pack and declspec align. + // However, do not reduce alignment for ABI-required alignments (e.g., + // x86_fp80, vector types) which must be preserved for correctness. + bool StructHasPackedAttr = + FD->getParent() && FD->getParent()->hasAttr<PackedAttr>(); + if (!MaxFieldAlignment.isZero() && + !ShouldPreserveFieldAlignment(Context, FD, TInfo.AlignRequirement, + StructHasPackedAttr)) Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment); if (FD->hasAttr<PackedAttr>()) Info.Alignment = CharUnits::One(); @@ -3289,7 +3366,12 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { if (!RequiredAlignment.isZero()) { Alignment = std::max(Alignment, RequiredAlignment); auto RoundingAlignment = Alignment; - if (!MaxFieldAlignment.isZero()) + // Check if this struct contains vectors that require ABI alignment before + // allowing MaxFieldAlignment (from #pragma pack) to reduce the overall + // struct alignment. However, if the struct has __attribute__((packed)), + // honor that explicit request even for vectors. + if (!MaxFieldAlignment.isZero() && + !RecordContainsVectorRequiringAlignment(Context, RD)) RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment); RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment); Size = Size.alignTo(RoundingAlignment); diff --git a/clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp b/clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp new file mode 100644 index 0000000000000..accc79dde04f0 --- /dev/null +++ b/clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp @@ -0,0 +1,136 @@ +// RUN: %clang_cc1 -triple x86_64-pc-windows-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-FP80 + +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-VEC + +// Test that x86_fp80 (long double) and vector types maintain their required +// alignment for correctness (movaps/movapd instructions will fault on misaligned +// addresses), even when #pragma pack(8) would normally reduce it. This issue +// affects Windows targets where #pragma pack is commonly used. +// Note: GCC on Linux preserves such alignment even with #pragma pack, so this fix +// is Windows-specific to avoid breaking existing Clang ABI on other platforms. +// Note: We use windows-gnu (MinGW) for x86_fp80 tests because windows-msvc doesn't +// support 80-bit long double. + +typedef float v4f32 __attribute__((vector_size(16))); +typedef float v8f32 __attribute__((vector_size(32))); + +struct Klass { + long double a; +}; + +struct VectorKlass { + v4f32 v; +}; + +// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_single_klass +// CHECK-FP80: %k = alloca %struct.Klass, align 16 +// CHECK-FP80: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 +void test_single_klass() { + Klass k; + k.a = 0.0L; +} + +// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_vector_klass +// CHECK-VEC: %v = alloca %struct.VectorKlass, align 16 +void test_vector_klass() { + VectorKlass v; + v.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +// Test with pragma pack(8) - should STILL maintain required alignment +// This is the key test case for the bug fix +#pragma pack(push, 8) + +struct PackedKlass { + long double b; +}; + +struct PackedVectorKlass { + v4f32 v; +}; + +struct PackedLargeVectorKlass { + v8f32 v; +}; + +// Simulate std::array without including headers +template<typename T, unsigned N> +struct array { + T _Elems[N]; +}; + +// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_explicit_pack +// CHECK-FP80: %pk = alloca %struct.PackedKlass, align 16 +// CHECK-FP80: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 +void test_explicit_pack() { + PackedKlass pk; + pk.b = 0.0L; +} + +// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_packed_vector +// CHECK-VEC: %pv = alloca %struct.PackedVectorKlass, align 16 +void test_packed_vector() { + PackedVectorKlass pv; + pv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_packed_large_vector +// CHECK-VEC: %plv = alloca %struct.PackedLargeVectorKlass, align 32 +void test_packed_large_vector() { + PackedLargeVectorKlass plv; + plv.v = (v8f32){0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; +} + +// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_struct_array_packed +// CHECK-FP80: %matrix = alloca %struct.array, align 16 +void test_struct_array_packed() { + array<PackedKlass, 16> matrix; + for (int i = 0; i < 16; i++) + matrix._Elems[i].b = 0.0L; +} + +// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_direct_array_packed +// CHECK-FP80: %arr = alloca [16 x %struct.PackedKlass], align 16 +void test_direct_array_packed() { + PackedKlass arr[16]; + for (int i = 0; i < 16; i++) + arr[i].b = 0.0L; +} + +// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_vector_array_packed +// CHECK-VEC: %varr = alloca %struct.array{{.*}}, align 16 +void test_vector_array_packed() { + array<PackedVectorKlass, 4> varr; + for (int i = 0; i < 4; i++) + varr._Elems[i].v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +#pragma pack(pop) + +// Test that __attribute__((packed)) on the struct reduces vector alignment. +// This is needed for unaligned load/store intrinsics like _mm_loadu_ps. +struct __attribute__((packed)) ExplicitlyPackedVector { + v4f32 v; +}; + +// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_explicitly_packed_vector +// CHECK-VEC: %epv = alloca %struct.ExplicitlyPackedVector, align 1 +void test_explicitly_packed_vector() { + ExplicitlyPackedVector epv; + epv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +#pragma pack(push, 8) +struct FieldPackedVector { + v4f32 v __attribute__((packed)); +}; +#pragma pack(pop) + +// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_field_packed_vector +// CHECK-VEC: %fpv = alloca %struct.FieldPackedVector, align 1 +void test_field_packed_vector() { + FieldPackedVector fpv; + fpv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} diff --git a/clang/test/CodeGen/x86_fp80-alignment-win.cpp b/clang/test/CodeGen/x86_fp80-alignment-win.cpp deleted file mode 100644 index f446474c598be..0000000000000 --- a/clang/test/CodeGen/x86_fp80-alignment-win.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -mlong-double-80 -emit-llvm -o - %s | FileCheck %s - -// Test that x86_fp80 (long double with /Qlong-double flag) maintains -// 16-byte alignment for correctness (required by movaps instructions), -// even when #pragma pack would normally reduce it. - -struct Klass { - long double a; -}; - -// Simulate std::array without including headers -template<typename T, unsigned N> -struct array { - T _Elems[N]; -}; - -// CHECK-LABEL: define {{.*}} @{{.*}}test_single_klass -// CHECK: %k = alloca %struct.Klass, align 16 -// CHECK-NOT: align 8 -// CHECK: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 -void test_single_klass() { - Klass k; - k.a = 0.0L; -} - -// CHECK-LABEL: define {{.*}} @{{.*}}test_struct_array -// CHECK: %matrix = alloca %struct.array, align 16 -// CHECK-NOT: align 8 -// CHECK: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 -void test_struct_array() { - array<Klass, 16> matrix; - for (int i = 0; i < 16; i++) - matrix._Elems[i].a = 0.0L; -} - -// CHECK-LABEL: define {{.*}} @{{.*}}test_direct_array -// CHECK: %arr = alloca [16 x %struct.Klass], align 16 -void test_direct_array() { - Klass arr[16]; - for (int i = 0; i < 16; i++) - arr[i].a = 0.0L; -} - -// Test with explicit pragma pack(8) - should still maintain 16-byte alignment -#pragma pack(push, 8) -struct PackedKlass { - long double b; -}; - -// CHECK-LABEL: define {{.*}} @{{.*}}test_explicit_pack -// CHECK: %pk = alloca %struct.PackedKlass, align 16 -// CHECK-NOT: align 8 -// CHECK: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 -void test_explicit_pack() { - PackedKlass pk; - pk.b = 0.0L; -} -#pragma pack(pop) >From bdc8e5d64e3357483b6c374f8ade33dec4c014e2 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Tue, 14 Jul 2026 09:15:14 -0700 Subject: [PATCH 4/9] Fix format --- clang/lib/AST/RecordLayoutBuilder.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index c0b183a2ce6a6..cd0f48071a020 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -579,9 +579,9 @@ static bool CheckTypeForRequiredVectorAlignment(const ASTContext &Context, return false; } -/// Check if a type (or any type it contains) is a standard SIMD vector requiring -/// alignment preservation on Windows. This includes direct vectors, arrays of -/// vectors, and structs containing vectors. +/// Check if a type (or any type it contains) is a standard SIMD vector +/// requiring alignment preservation on Windows. This includes direct vectors, +/// arrays of vectors, and structs containing vectors. static bool RequiresVectorAlignment(const ASTContext &Context, QualType Ty) { if (!Context.getTargetInfo().getTriple().isOSWindows()) return false; @@ -590,7 +590,8 @@ static bool RequiresVectorAlignment(const ASTContext &Context, QualType Ty) { /// Check if we should prevent MaxFieldAlignment from reducing this field's /// alignment. Returns true if the field has ABI-required alignment or contains -/// vectors requiring alignment, UNLESS the struct has explicit packed attribute. +/// vectors requiring alignment, UNLESS the struct has explicit packed +/// attribute. static bool ShouldPreserveFieldAlignment(const ASTContext &Context, const FieldDecl *FD, AlignRequirementKind AlignReq, @@ -2817,7 +2818,8 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( bool IsVectorRequiringAlignment = false; if (const RecordDecl *RD = FD->getParent()) { if (!RD->hasAttr<PackedAttr>()) { - IsVectorRequiringAlignment = RequiresVectorAlignment(Context, FD->getType()); + IsVectorRequiringAlignment = + RequiresVectorAlignment(Context, FD->getType()); } } >From b1d3572cf9eb37cd8227e5987652778172e53504 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Tue, 14 Jul 2026 09:44:00 -0700 Subject: [PATCH 5/9] Removed obsolete code --- clang/lib/AST/RecordLayoutBuilder.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index cd0f48071a020..c0e8e30a3061a 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2811,17 +2811,6 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( std::max(RequiredAlignment, std::max(DirectFieldAlignment, FieldTypeRequiredAlignment)); } - // Check if this is a vector type (or contains vectors) requiring alignment - // preservation on Windows. This includes direct vectors, arrays of vectors, - // and structs containing vectors. However, honor __attribute__((packed)) - // on the struct even for vectors (explicit intent to pack). - bool IsVectorRequiringAlignment = false; - if (const RecordDecl *RD = FD->getParent()) { - if (!RD->hasAttr<PackedAttr>()) { - IsVectorRequiringAlignment = - RequiresVectorAlignment(Context, FD->getType()); - } - } // Respect pragma pack, attribute pack and declspec align. // However, do not reduce alignment for ABI-required alignments (e.g., >From 9909648225825d2b89c692bbe0708dc06fc4e2a8 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 16 Jul 2026 08:27:54 -0700 Subject: [PATCH 6/9] Limited changes to msvc and addressed code propagamtion comment --- clang/lib/AST/ASTContext.cpp | 15 +- clang/lib/AST/RecordLayoutBuilder.cpp | 6 +- .../vector-alignment-pragma-pack-msvc.cpp | 130 +++++++++++++++++ .../x86_fp80-alignment-pragma-pack.cpp | 136 ------------------ 4 files changed, 143 insertions(+), 144 deletions(-) create mode 100644 clang/test/CodeGen/vector-alignment-pragma-pack-msvc.cpp delete mode 100644 clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6054d37554ef8..7d345e836b5f8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2348,13 +2348,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getLongDoubleWidth(); Align = Target->getLongDoubleAlign(); } - // On Windows targets, x86_fp80 requires 16-byte alignment for ABI + // On Windows MSVC targets, x86_fp80 requires 16-byte alignment for ABI // correctness (movaps instructions will fault on misaligned addresses). // Mark this as an ABI requirement that must not be reduced by #pragma - // pack. GCC preserves such alignment on other targets, but Clang - // historically has not; changing this would break existing Clang ABI on - // non-Windows platforms. + // pack. This is MSVC-specific; MinGW has different layout rules. GCC + // preserves such alignment on other targets, but Clang historically has + // not; changing this would break existing Clang ABI on non-Windows + // platforms. if (Target->getTriple().isOSWindows() && + Target->getTriple().isWindowsMSVCEnvironment() && &Target->getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) AlignRequirement = AlignRequirementKind::RequiredByABI; break; @@ -2549,7 +2551,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); // Check if the record has an aligned attribute, or if it contains - // fields with ABI-required alignment (e.g., x86_fp80). + // fields with ABI-required alignment (e.g., vectors on MSVC). if (RD->hasAttr<AlignedAttr>()) { AlignRequirement = AlignRequirementKind::RequiredByRecord; } else { @@ -2558,7 +2560,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { AlignRequirement = AlignRequirementKind::None; for (const auto *Field : RD->fields()) { TypeInfo FI = getTypeInfo(Field->getType().getTypePtr()); - if (FI.AlignRequirement == AlignRequirementKind::RequiredByABI) { + if (FI.AlignRequirement == AlignRequirementKind::RequiredByABI || + FI.AlignRequirement == AlignRequirementKind::RequiredByRecord) { AlignRequirement = AlignRequirementKind::RequiredByABI; break; } diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index c0e8e30a3061a..58ce1353de4ea 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -583,7 +583,8 @@ static bool CheckTypeForRequiredVectorAlignment(const ASTContext &Context, /// requiring alignment preservation on Windows. This includes direct vectors, /// arrays of vectors, and structs containing vectors. static bool RequiresVectorAlignment(const ASTContext &Context, QualType Ty) { - if (!Context.getTargetInfo().getTriple().isOSWindows()) + if (!Context.getTargetInfo().getTriple().isOSWindows() || + !Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) return false; return CheckTypeForRequiredVectorAlignment(Context, Ty); } @@ -596,7 +597,8 @@ static bool ShouldPreserveFieldAlignment(const ASTContext &Context, const FieldDecl *FD, AlignRequirementKind AlignReq, bool StructHasPackedAttr) { - if (AlignReq == AlignRequirementKind::RequiredByABI) + if (AlignReq == AlignRequirementKind::RequiredByABI || + AlignReq == AlignRequirementKind::RequiredByRecord) return true; if (!StructHasPackedAttr && RequiresVectorAlignment(Context, FD->getType())) return true; diff --git a/clang/test/CodeGen/vector-alignment-pragma-pack-msvc.cpp b/clang/test/CodeGen/vector-alignment-pragma-pack-msvc.cpp new file mode 100644 index 0000000000000..d185236f2a500 --- /dev/null +++ b/clang/test/CodeGen/vector-alignment-pragma-pack-msvc.cpp @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -o - %s \ +// RUN: | FileCheck %s + +// Test that vector types maintain their required alignment for correctness +// (movaps/movapd instructions will fault on misaligned addresses), even when +// #pragma pack(8) would normally reduce it. This issue affects Windows MSVC +// targets where #pragma pack is commonly used (e.g., MSVC STL). + +typedef float v4f32 __attribute__((vector_size(16))); +typedef float v8f32 __attribute__((vector_size(32))); + +struct VectorKlass { + v4f32 v; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_vector_klass +// CHECK: %v = alloca %struct.VectorKlass, align 16 +void test_vector_klass() { + VectorKlass v; + v.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +#pragma pack(push, 8) +struct PackedVectorKlass { + v4f32 v; +}; + +struct PackedLargeVectorKlass { + v8f32 v; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_packed_vector +// CHECK: %pv = alloca %struct.PackedVectorKlass, align 16 +void test_packed_vector() { + PackedVectorKlass pv; + pv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +// CHECK-LABEL: define {{.*}} @{{.*}}test_packed_large_vector +// CHECK: %plv = alloca %struct.PackedLargeVectorKlass, align 32 +void test_packed_large_vector() { + PackedLargeVectorKlass plv; + plv.v = (v8f32){0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; +} + +struct InnerWithVector { + v4f32 v; +}; + +struct OuterWithVector { + InnerWithVector inner; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_nested_vector +// CHECK: %outer = alloca %struct.OuterWithVector, align 16 +void test_nested_vector() { + OuterWithVector outer; + outer.inner.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +// Test array of structs containing vectors +template<typename T, unsigned N> +struct array { + T _Elems[N]; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_vector_array_packed +// CHECK: %varr = alloca %struct.array, align 16 +void test_vector_array_packed() { + array<PackedVectorKlass, 4> varr; + for (int i = 0; i < 4; i++) + varr._Elems[i].v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} +#pragma pack(pop) + +struct __attribute__((packed)) ExplicitlyPackedVector { + v4f32 v; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_explicitly_packed_vector +// CHECK: %epv = alloca %struct.ExplicitlyPackedVector, align 1 +void test_explicitly_packed_vector() { + ExplicitlyPackedVector epv; + epv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +#pragma pack(push, 8) +struct FieldPackedVector { + v4f32 v __attribute__((packed)); +}; +#pragma pack(pop) + +// CHECK-LABEL: define {{.*}} @{{.*}}test_field_packed_vector +// CHECK: %fpv = alloca %struct.FieldPackedVector, align 1 +void test_field_packed_vector() { + FieldPackedVector fpv; + fpv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; +} + +#pragma pack(push, 8) +struct alignas(16) ExplicitAlignedInner { + long double x; +}; + +struct OuterWithExplicitAligned { + ExplicitAlignedInner inner; +}; + +struct ImplicitAlignedInner { + long double x; +}; + +struct OuterWithImplicitAligned { + ImplicitAlignedInner inner; +}; +#pragma pack(pop) + +// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_explicit_aligned_nested +// CHECK-FP80: %outer = alloca %struct.OuterWithExplicitAligned, align 16 +void test_explicit_aligned_nested() { + OuterWithExplicitAligned outer; + outer.inner.x = 0.0L; +} + +// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_implicit_aligned_nested +// CHECK-FP80: %outer = alloca %struct.OuterWithImplicitAligned, align 16 +void test_implicit_aligned_nested() { + OuterWithImplicitAligned outer; + outer.inner.x = 0.0L; +} diff --git a/clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp b/clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp deleted file mode 100644 index accc79dde04f0..0000000000000 --- a/clang/test/CodeGen/x86_fp80-alignment-pragma-pack.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-pc-windows-gnu -emit-llvm -o - %s \ -// RUN: | FileCheck %s --check-prefix=CHECK-FP80 - -// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -o - %s \ -// RUN: | FileCheck %s --check-prefix=CHECK-VEC - -// Test that x86_fp80 (long double) and vector types maintain their required -// alignment for correctness (movaps/movapd instructions will fault on misaligned -// addresses), even when #pragma pack(8) would normally reduce it. This issue -// affects Windows targets where #pragma pack is commonly used. -// Note: GCC on Linux preserves such alignment even with #pragma pack, so this fix -// is Windows-specific to avoid breaking existing Clang ABI on other platforms. -// Note: We use windows-gnu (MinGW) for x86_fp80 tests because windows-msvc doesn't -// support 80-bit long double. - -typedef float v4f32 __attribute__((vector_size(16))); -typedef float v8f32 __attribute__((vector_size(32))); - -struct Klass { - long double a; -}; - -struct VectorKlass { - v4f32 v; -}; - -// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_single_klass -// CHECK-FP80: %k = alloca %struct.Klass, align 16 -// CHECK-FP80: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 -void test_single_klass() { - Klass k; - k.a = 0.0L; -} - -// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_vector_klass -// CHECK-VEC: %v = alloca %struct.VectorKlass, align 16 -void test_vector_klass() { - VectorKlass v; - v.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; -} - -// Test with pragma pack(8) - should STILL maintain required alignment -// This is the key test case for the bug fix -#pragma pack(push, 8) - -struct PackedKlass { - long double b; -}; - -struct PackedVectorKlass { - v4f32 v; -}; - -struct PackedLargeVectorKlass { - v8f32 v; -}; - -// Simulate std::array without including headers -template<typename T, unsigned N> -struct array { - T _Elems[N]; -}; - -// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_explicit_pack -// CHECK-FP80: %pk = alloca %struct.PackedKlass, align 16 -// CHECK-FP80: store x86_fp80 {{.*}}, ptr {{.*}}, align 16 -void test_explicit_pack() { - PackedKlass pk; - pk.b = 0.0L; -} - -// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_packed_vector -// CHECK-VEC: %pv = alloca %struct.PackedVectorKlass, align 16 -void test_packed_vector() { - PackedVectorKlass pv; - pv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; -} - -// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_packed_large_vector -// CHECK-VEC: %plv = alloca %struct.PackedLargeVectorKlass, align 32 -void test_packed_large_vector() { - PackedLargeVectorKlass plv; - plv.v = (v8f32){0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; -} - -// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_struct_array_packed -// CHECK-FP80: %matrix = alloca %struct.array, align 16 -void test_struct_array_packed() { - array<PackedKlass, 16> matrix; - for (int i = 0; i < 16; i++) - matrix._Elems[i].b = 0.0L; -} - -// CHECK-FP80-LABEL: define {{.*}} @{{.*}}test_direct_array_packed -// CHECK-FP80: %arr = alloca [16 x %struct.PackedKlass], align 16 -void test_direct_array_packed() { - PackedKlass arr[16]; - for (int i = 0; i < 16; i++) - arr[i].b = 0.0L; -} - -// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_vector_array_packed -// CHECK-VEC: %varr = alloca %struct.array{{.*}}, align 16 -void test_vector_array_packed() { - array<PackedVectorKlass, 4> varr; - for (int i = 0; i < 4; i++) - varr._Elems[i].v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; -} - -#pragma pack(pop) - -// Test that __attribute__((packed)) on the struct reduces vector alignment. -// This is needed for unaligned load/store intrinsics like _mm_loadu_ps. -struct __attribute__((packed)) ExplicitlyPackedVector { - v4f32 v; -}; - -// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_explicitly_packed_vector -// CHECK-VEC: %epv = alloca %struct.ExplicitlyPackedVector, align 1 -void test_explicitly_packed_vector() { - ExplicitlyPackedVector epv; - epv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; -} - -#pragma pack(push, 8) -struct FieldPackedVector { - v4f32 v __attribute__((packed)); -}; -#pragma pack(pop) - -// CHECK-VEC-LABEL: define {{.*}} @{{.*}}test_field_packed_vector -// CHECK-VEC: %fpv = alloca %struct.FieldPackedVector, align 1 -void test_field_packed_vector() { - FieldPackedVector fpv; - fpv.v = (v4f32){0.0f, 0.0f, 0.0f, 0.0f}; -} >From 6c15a3e475d5d6b00ee383afee126e40e62d7015 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 16 Jul 2026 08:34:33 -0700 Subject: [PATCH 7/9] Fixed format --- 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 58ce1353de4ea..e136495ea83e6 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -583,7 +583,7 @@ static bool CheckTypeForRequiredVectorAlignment(const ASTContext &Context, /// requiring alignment preservation on Windows. This includes direct vectors, /// arrays of vectors, and structs containing vectors. static bool RequiresVectorAlignment(const ASTContext &Context, QualType Ty) { - if (!Context.getTargetInfo().getTriple().isOSWindows() || + if (!Context.getTargetInfo().getTriple().isOSWindows() || !Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) return false; return CheckTypeForRequiredVectorAlignment(Context, Ty); >From 6eb05cc32ec760896e87d7b595d95a7733e3cbbb Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 23 Jul 2026 10:41:45 -0700 Subject: [PATCH 8/9] Addressed review comments --- clang/include/clang/AST/ASTContext.h | 5 ++ clang/lib/AST/ASTContext.cpp | 26 +++++++++++ clang/lib/AST/RecordLayoutBuilder.cpp | 66 +++++++++------------------ 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index c53dd99df9cba..4f1fd163f6f38 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2761,6 +2761,11 @@ class ASTContext : public RefCountedBase<ASTContext> { TypeInfo getTypeInfo(const Type *T) const; TypeInfo getTypeInfo(QualType T) const { return getTypeInfo(T.getTypePtr()); } + /// Check if a type requires natural alignment preservation under #pragma pack + /// (but not explicit __attribute__((packed))). This includes x86_fp80 on + /// Windows MSVC and standard SIMD vectors (__m128, __m256). + bool typeRequiresPreserveAlignUnderPragmaPack(QualType T) const; + /// Get default simd alignment of the specified complete type in bits. unsigned getOpenMPDefaultSimdAlign(QualType T) const; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 7d345e836b5f8..6bcc7bda583a8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2100,6 +2100,32 @@ TypeInfo ASTContext::getTypeInfo(const Type *T) const { return TI; } +bool ASTContext::typeRequiresPreserveAlignUnderPragmaPack(QualType T) const { + T = T.getCanonicalType(); + const llvm::Triple &Triple = Target->getTriple(); + if (Triple.isOSWindows() && Triple.isWindowsMSVCEnvironment()) { + if (const auto *BT = T->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble && + &Target->getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) + return true; + } + if (const auto *VT = T->getAs<VectorType>()) { + uint64_t VecWidth = getTypeSize(VT); + return VT->getVectorKind() == VectorKind::Generic && + (VecWidth == 128 || VecWidth == 256) && + VecWidth == getTypeAlign(VT); + } + } + if (const auto *AT = T->getAsArrayTypeUnsafe()) + return typeRequiresPreserveAlignUnderPragmaPack(AT->getElementType()); + if (const auto *RT = T->getAs<RecordType>()) { + for (const auto *Field : RT->getDecl()->fields()) + if (typeRequiresPreserveAlignUnderPragmaPack(Field->getType())) + return true; + } + return false; +} + /// getTypeInfoImpl - Return the size of the specified type, in bits. This /// method does not work on incomplete types. /// diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index e136495ea83e6..23754c87faa3d 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -559,40 +559,10 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects( typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> ClassSetTy; -/// Helper for RequiresVectorAlignment - recursively checks types. -static bool CheckTypeForRequiredVectorAlignment(const ASTContext &Context, - QualType Ty) { - if (const auto *VT = Ty->getAs<VectorType>()) { - uint64_t VecWidth = Context.getTypeSize(VT); - return VT->getVectorKind() == VectorKind::Generic && - (VecWidth == 128 || VecWidth == 256) && - VecWidth == Context.getTypeAlign(VT); - } - if (const auto *AT = Ty->getAsArrayTypeUnsafe()) - return CheckTypeForRequiredVectorAlignment(Context, AT->getElementType()); - - if (const auto *RT = Ty->getAs<RecordType>()) { - for (const auto *Field : RT->getDecl()->fields()) - if (CheckTypeForRequiredVectorAlignment(Context, Field->getType())) - return true; - } - return false; -} - -/// Check if a type (or any type it contains) is a standard SIMD vector -/// requiring alignment preservation on Windows. This includes direct vectors, -/// arrays of vectors, and structs containing vectors. -static bool RequiresVectorAlignment(const ASTContext &Context, QualType Ty) { - if (!Context.getTargetInfo().getTriple().isOSWindows() || - !Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) - return false; - return CheckTypeForRequiredVectorAlignment(Context, Ty); -} - /// Check if we should prevent MaxFieldAlignment from reducing this field's -/// alignment. Returns true if the field has ABI-required alignment or contains -/// vectors requiring alignment, UNLESS the struct has explicit packed -/// attribute. +/// alignment. Returns true if the field has ABI-required alignment +/// (e.g., x86_fp80, SIMD vectors on Windows), unless the struct has explicit +/// __attribute__((packed)). static bool ShouldPreserveFieldAlignment(const ASTContext &Context, const FieldDecl *FD, AlignRequirementKind AlignReq, @@ -600,20 +570,27 @@ static bool ShouldPreserveFieldAlignment(const ASTContext &Context, if (AlignReq == AlignRequirementKind::RequiredByABI || AlignReq == AlignRequirementKind::RequiredByRecord) return true; - if (!StructHasPackedAttr && RequiresVectorAlignment(Context, FD->getType())) + + // Check if type requires alignment preservation under #pragma pack + // (but respect explicit __attribute__((packed))). + if (!StructHasPackedAttr && + Context.typeRequiresPreserveAlignUnderPragmaPack(FD->getType())) return true; return false; } -/// Check if a record contains any fields with vectors requiring alignment. +/// Check if a record contains any fields requiring alignment preservation. /// Returns false if the record has explicit __attribute__((packed)). -static bool RecordContainsVectorRequiringAlignment(const ASTContext &Context, - const RecordDecl *RD) { +static bool RecordContainsAlignPreservingFields(const ASTContext &Context, + const RecordDecl *RD) { if (RD->hasAttr<PackedAttr>()) return false; - for (const auto *Field : RD->fields()) - if (RequiresVectorAlignment(Context, Field->getType())) + for (const auto *Field : RD->fields()) { + TypeInfo TI = Context.getTypeInfo(Field->getType()); + if (TI.isAlignRequired() || + Context.typeRequiresPreserveAlignUnderPragmaPack(Field->getType())) return true; + } return false; } @@ -3359,12 +3336,13 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { if (!RequiredAlignment.isZero()) { Alignment = std::max(Alignment, RequiredAlignment); auto RoundingAlignment = Alignment; - // Check if this struct contains vectors that require ABI alignment before - // allowing MaxFieldAlignment (from #pragma pack) to reduce the overall - // struct alignment. However, if the struct has __attribute__((packed)), - // honor that explicit request even for vectors. + + // Check if this struct contains fields requiring alignment preservation + // (x86_fp80, vectors) before allowing MaxFieldAlignment (from #pragma pack) + // to reduce the overall struct alignment. However, if the struct has + // __attribute__((packed)), honor that explicit request. if (!MaxFieldAlignment.isZero() && - !RecordContainsVectorRequiringAlignment(Context, RD)) + !RecordContainsAlignPreservingFields(Context, RD)) RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment); RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment); Size = Size.alignTo(RoundingAlignment); >From 4f5cd74bff386232db452b96abbee5dca2e17e4f Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Fri, 24 Jul 2026 06:17:10 -0700 Subject: [PATCH 9/9] Make x86_fp80 abd vector behave the same way --- clang/lib/AST/ASTContext.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6bcc7bda583a8..b536fcec9110c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2374,17 +2374,6 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getLongDoubleWidth(); Align = Target->getLongDoubleAlign(); } - // On Windows MSVC targets, x86_fp80 requires 16-byte alignment for ABI - // correctness (movaps instructions will fault on misaligned addresses). - // Mark this as an ABI requirement that must not be reduced by #pragma - // pack. This is MSVC-specific; MinGW has different layout rules. GCC - // preserves such alignment on other targets, but Clang historically has - // not; changing this would break existing Clang ABI on non-Windows - // platforms. - if (Target->getTriple().isOSWindows() && - Target->getTriple().isWindowsMSVCEnvironment() && - &Target->getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) - AlignRequirement = AlignRequirementKind::RequiredByABI; break; case BuiltinType::Float128: if (Target->hasFloat128Type() || !getLangOpts().OpenMP || _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
