https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/208256
>From b925b2c3fa0f15b20898bd6456329eddfdb027ea Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat <[email protected]> Date: Wed, 20 May 2026 05:48:13 -0700 Subject: [PATCH 1/7] [OpenMP] Prevent parser infinite loop on unimplemented clauses --- clang/lib/Basic/OpenMPKinds.cpp | 1 + clang/lib/Parse/ParseOpenMP.cpp | 9 ++ clang/lib/Sema/SemaOpenMP.cpp | 4 + .../OpenMP/unimplemented_clause_messages.cpp | 93 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 clang/test/OpenMP/unimplemented_clause_messages.cpp diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 287eb217ba458..675d86349c933 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -965,6 +965,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_simd: case OMPD_single: case OMPD_target_data: + case OMPD_taskgraph: case OMPD_taskgroup: case OMPD_stripe: // These directives (when standalone) use OMPD_unknown as the region, diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 45a47ec797f01..ba3d3113700ff 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2388,6 +2388,8 @@ StmtResult Parser::ParseOpenMPExecutableDirective( ImplicitClauseAllowed = false; Actions.OpenMP().StartOpenMPClause(CKind); HasImplicitClause = false; + SourceLocation ClauseLoc = Tok.getLocation(); + OMPClause *Clause = ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); SeenClauses[unsigned(CKind)] = true; @@ -2398,6 +2400,13 @@ StmtResult Parser::ParseOpenMPExecutableDirective( if (Tok.is(tok::comma)) ConsumeToken(); Actions.OpenMP().EndOpenMPClause(); + + // If ParseOpenMPClause returned without consuming any tokens, skip + // to end to avoid an infinite loop. + if (Tok.getLocation() == ClauseLoc) { + skipUntilPragmaOpenMPEnd(DKind); + break; + } } // End location of the directive. EndLoc = Tok.getLocation(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index d6f6bc919a31b..76b40a5039180 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -6778,6 +6778,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_begin_declare_variant: case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); + case OMPD_taskgraph: + Diag(StartLoc, diag::err_omp_unexpected_directive) + << 1 << getOpenMPDirectiveName(OMPD_taskgraph); + return StmtError(); case OMPD_unknown: default: llvm_unreachable("Unknown OpenMP directive"); diff --git a/clang/test/OpenMP/unimplemented_clause_messages.cpp b/clang/test/OpenMP/unimplemented_clause_messages.cpp new file mode 100644 index 0000000000000..172203ea5d040 --- /dev/null +++ b/clang/test/OpenMP/unimplemented_clause_messages.cpp @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -verify=expected,omp60 -fopenmp -fopenmp-version=60 %s +// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp -fopenmp-version=51 %s +// RUN: %clang_cc1 -verify=expected,omp60 -fopenmp-simd -fopenmp-version=60 %s +// RUN: %clang_cc1 -verify=expected,omp51 -fopenmp-simd -fopenmp-version=51 %s + + +void test_induction_basic() { + int i; + // omp60-warning@+4{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-warning@+2{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp51-error@+1{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} +#pragma omp parallel for induction(i) + for (i = 0; i < 10; ++i) + ; +} + +void test_apply() { + // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are ignored}} +#pragma omp tile sizes(10) apply(intratile: unroll) + for (int i = 0; i < 10; ++i) + ; +} + +void test_empty_apply() { + // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-error@+2{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp tile' are ignored}} +#pragma omp tile sizes(10) apply() + for (int i = 0; i < 10; ++i) + ; +} + +void test_nested_apply() +{ + // omp60-error@+5{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp60-warning@+4{{extra tokens at the end of '#pragma omp tile' are ignored}} + //omp51-error@+3{{unexpected OpenMP clause 'apply' in directive '#pragma omp tile'}} + // omp51-warning@+2{{extra tokens at the end of '#pragma omp tile' are ignored}} +#pragma omp tile sizes(10) \ + apply(intratile: unroll partial(2) apply(reverse)) + for (int i = 0; i < 100; ++i) + ; +} + +void test_induction_with_following_clause() { + int i; + // omp60-warning@+4{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp60-error@+3{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-error@+2{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp parallel for' are ignored}} +#pragma omp parallel for induction(i) num_threads(4) + for (i = 0; i < 10; ++i) + ; +} + +class Point { + float x, y, m; + char color; + +}; + +void processPointsInLine() { + float separation; + // omp60-error@+4{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp60-warning@+3{{extra tokens at the end of '#pragma omp parallel for' are ignored}} + // omp51-error@+2{{unexpected OpenMP clause 'induction' in directive '#pragma omp parallel for'}} + // omp51-warning@+1{{extra tokens at the end of '#pragma omp parallel for' are ignored}} +#pragma omp parallel for induction(step(Separation)) + for (int i = 0; i < 10; ++i) { + ; + } +} + +// Make sure test doesn't crash. +void test_tasgraph() +{ + // omp60-error@+2{{unexpected OpenMP directive '#pragma omp taskgraph'}} + // omp51-error@+1{{unexpected OpenMP directive '#pragma omp taskgraph'}} +#pragma omp taskgraph + for (int i = 0; i < 10; ++i) + ; +} + +void test_implemented_clause() { +#pragma omp tile sizes(10) + for (int i = 0; i < 10; ++i) + ; +} >From 51b5dd59154f0213e4052d9a8cb7365c7afde0fd Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Wed, 8 Jul 2026 09:24:56 -0700 Subject: [PATCH 2/7] [Clang] Fix x86_fp80 misalignment with pragma pack on Windows --- clang/lib/AST/RecordLayoutBuilder.cpp | 27 ++++++++- clang/test/CodeGen/x86_fp80-alignment-win.cpp | 58 +++++++++++++++++++ 2 files changed, 82 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 854f88f20b2b6..aa9161f5dccea 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2693,6 +2693,25 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( auto TInfo = Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType()); ElementInfo Info{TInfo.Width, TInfo.Align}; + // Types like x86_fp80 (long double with /Qlong-double) require 16-byte + // (or greater) for correctness. + bool ContainsX86FP80 = false; + std::function<bool(QualType)> CheckForX86FP80 = [&](QualType Ty) -> bool { + const Type *BaseType = Ty->getBaseElementTypeUnsafe(); + if (const auto *BT = dyn_cast<BuiltinType>(BaseType)) { + return BT->getKind() == BuiltinType::LongDouble && + &Context.getTargetInfo().getLongDoubleFormat() == + &llvm::APFloat::x87DoubleExtended(); + } + if (const auto *RT = dyn_cast<RecordType>(BaseType)) { + for (const auto *Field : RT->getDecl()->fields()) { + if (CheckForX86FP80(Field->getType())) + return true; + } + } + return false; + }; + ContainsX86FP80 = CheckForX86FP80(FD->getType()); // Respect align attributes on the field. CharUnits FieldRequiredAlignment = Context.toCharUnitsFromBits(FD->getMaxAlignment()); @@ -2717,10 +2736,12 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // Capture required alignment as a side-effect. RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment); } - // 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(); Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment); return Info; 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 6f8a42b0e9bc5aaf0e33b185751d9e9acd9d06c2 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Fri, 10 Jul 2026 07:26:10 -0700 Subject: [PATCH 3/7] Leveraged FieldRequiredAlignment --- clang/lib/AST/RecordLayoutBuilder.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index aa9161f5dccea..f0d9caf3c2469 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2693,9 +2693,12 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( auto TInfo = Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType()); ElementInfo Info{TInfo.Width, TInfo.Align}; + // Respect align attributes on the field. + CharUnits FieldRequiredAlignment = + Context.toCharUnitsFromBits(FD->getMaxAlignment()); + // Types like x86_fp80 (long double with /Qlong-double) require 16-byte // (or greater) for correctness. - bool ContainsX86FP80 = false; std::function<bool(QualType)> CheckForX86FP80 = [&](QualType Ty) -> bool { const Type *BaseType = Ty->getBaseElementTypeUnsafe(); if (const auto *BT = dyn_cast<BuiltinType>(BaseType)) { @@ -2711,10 +2714,10 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( } return false; }; - ContainsX86FP80 = CheckForX86FP80(FD->getType()); - // Respect align attributes on the field. - CharUnits FieldRequiredAlignment = - Context.toCharUnitsFromBits(FD->getMaxAlignment()); + if (CheckForX86FP80(FD->getType())) + FieldRequiredAlignment = + std::max(FieldRequiredAlignment, CharUnits::fromQuantity(16)); + // Respect align attributes on the type. if (Context.isAlignmentRequired(FD->getType())) FieldRequiredAlignment = std::max( @@ -2739,9 +2742,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(); Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment); return Info; >From 5d419b70ae0c07378269a25d8ee83933b914c3d5 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Tue, 14 Jul 2026 08:24:02 -0700 Subject: [PATCH 4/7] 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 | 117 +++++++++++---- .../x86_fp80-alignment-pragma-pack.cpp | 136 ++++++++++++++++++ clang/test/CodeGen/x86_fp80-alignment-win.cpp | 58 -------- 5 files changed, 253 insertions(+), 89 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 c04b380f9ec5b..509acc91e35bf 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 94ea9aeba02c1..8841b819eb104 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 f0d9caf3c2469..e35ea89de2757 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) @@ -2697,27 +2759,6 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( CharUnits FieldRequiredAlignment = Context.toCharUnitsFromBits(FD->getMaxAlignment()); - // Types like x86_fp80 (long double with /Qlong-double) require 16-byte - // (or greater) for correctness. - std::function<bool(QualType)> CheckForX86FP80 = [&](QualType Ty) -> bool { - const Type *BaseType = Ty->getBaseElementTypeUnsafe(); - if (const auto *BT = dyn_cast<BuiltinType>(BaseType)) { - return BT->getKind() == BuiltinType::LongDouble && - &Context.getTargetInfo().getLongDoubleFormat() == - &llvm::APFloat::x87DoubleExtended(); - } - if (const auto *RT = dyn_cast<RecordType>(BaseType)) { - for (const auto *Field : RT->getDecl()->fields()) { - if (CheckForX86FP80(Field->getType())) - return true; - } - } - return false; - }; - if (CheckForX86FP80(FD->getType())) - FieldRequiredAlignment = - std::max(FieldRequiredAlignment, CharUnits::fromQuantity(16)); - // Respect align attributes on the type. if (Context.isAlignmentRequired(FD->getType())) FieldRequiredAlignment = std::max( @@ -2739,10 +2780,25 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // Capture required alignment as a side-effect. RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment); } - // 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(); @@ -3262,7 +3318,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 bdeca94ba4f50efd30f3f0fbbab715a459669177 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Tue, 14 Jul 2026 09:15:14 -0700 Subject: [PATCH 5/7] 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 e35ea89de2757..dedb457dcbd4b 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, @@ -2787,7 +2788,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 3ddb9fb413a821caa4e56093f474af0e93cd43d9 Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Tue, 14 Jul 2026 09:44:00 -0700 Subject: [PATCH 6/7] 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 dedb457dcbd4b..121f309c76791 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2781,17 +2781,6 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // Capture required alignment as a side-effect. RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment); } - // 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 b78a90703f79e44f8097aa5b51a59d1cda8c991e Mon Sep 17 00:00:00 2001 From: Ammarguellat <[email protected]> Date: Thu, 16 Jul 2026 08:27:54 -0700 Subject: [PATCH 7/7] 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 8841b819eb104..5f62b16d7985f 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 121f309c76791..d9d9a8c8c3d24 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}; -} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
