Author: Hans Wennborg Date: 2026-05-12T07:55:36+02:00 New Revision: 8ecec455183fd42fc191089d061f80bdf7b158fc
URL: https://github.com/llvm/llvm-project/commit/8ecec455183fd42fc191089d061f80bdf7b158fc DIFF: https://github.com/llvm/llvm-project/commit/8ecec455183fd42fc191089d061f80bdf7b158fc.diff LOG: [clang] Fix x86_64-windows-msvc over- and under-alignment (#196505) This fixes two issues where Clang was both over- and under-aligning variables: 1) We were applying the x86_64 Sys V psABI "large array" alignment increase (default when inheriting from X86_64TargetInfo), but MSVC doesn't follow that ABI. 2) MSVC implements a similar scheme though, where it increases the alignment of large objects. This is documented for ARM64 [1] and was implemented in Clang b7c6d95af5e295c560d1445e7090e31eb9289932, but it also applies to x86_64. ([2] says "MSVC does size (total size, not element size) based alignment for global symbols on ARM64 *which is copied from AMD64*"). This patch stops doing 1) and implements 2) for x86_64-windows-msvc. [1] https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment [2] https://github.com/llvm/llvm-project/issues/40851 Fixes https://github.com/llvm/llvm-project/issues/196071 Fixes https://github.com/llvm/llvm-project/issues/171855 Added: clang/test/CodeGen/microsoft-64bit-struct-align.cpp Modified: clang/include/clang/Basic/TargetInfo.h clang/lib/Basic/TargetInfo.cpp clang/lib/Basic/Targets/AArch64.cpp clang/lib/Basic/Targets/X86.cpp clang/lib/Basic/Targets/X86.h clang/test/CodeGen/align-x68_64.c clang/test/CodeGen/asan-strings.c clang/test/CodeGenCXX/ms-constexpr-static-data-member.cpp clang/test/CodeGenObjC/encode-test-6.m clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp Removed: clang/test/CodeGen/arm64-microsoft-struct-align.cpp ################################################################################ diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 9f7d2a17a0f8a..e21155b2e4fd4 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1968,6 +1968,8 @@ class TargetInfo : public TransferrableTargetInfo, void CheckFixedPointBits() const; }; +unsigned Microsoft64BitMinGlobalAlign(uint64_t TypeSize); + namespace targets { std::unique_ptr<clang::TargetInfo> AllocateTarget(const llvm::Triple &Triple, const clang::TargetOptions &Opts); diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index e6ae89e0948c5..ad083242d9e3e 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -1114,3 +1114,20 @@ TargetInfo::simplifyConstraint(StringRef Constraint, } return Result; } + +unsigned clang::Microsoft64BitMinGlobalAlign(uint64_t TypeSize) { + // MSVC does size based alignment for arm64 based on alignment section in + // below document. Replicate that to keep alignment consistent with object + // files compiled by MSVC. + // https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions + // The same is done for x64, but not documented. + + if (TypeSize >= 512) // TypeSize >= 64 bytes + return 128; // align type at least 16 bytes + if (TypeSize >= 64) // TypeSize >= 8 bytes + return 64; // align type at least 8 bytes + if (TypeSize >= 16) // TypeSize >= 2 bytes + return 32; // align type at least 4 bytes + + return 0; +} diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 9b951e69cce33..9afe6cb10729d 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1815,18 +1815,7 @@ unsigned MicrosoftARM64TargetInfo::getMinGlobalAlign(uint64_t TypeSize, unsigned Align = WindowsARM64TargetInfo::getMinGlobalAlign(TypeSize, HasNonWeakDef); - // MSVC does size based alignment for arm64 based on alignment section in - // below document, replicate that to keep alignment consistent with object - // files compiled by MSVC. - // https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions - if (TypeSize >= 512) { // TypeSize >= 64 bytes - Align = std::max(Align, 128u); // align type at least 16 bytes - } else if (TypeSize >= 64) { // TypeSize >= 8 bytes - Align = std::max(Align, 64u); // align type at least 8 butes - } else if (TypeSize >= 16) { // TypeSize >= 2 bytes - Align = std::max(Align, 32u); // align type at least 4 bytes - } - return Align; + return std::max(Align, Microsoft64BitMinGlobalAlign(TypeSize)); } MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple, diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index cb941c94c84a7..60c001a826078 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1852,3 +1852,12 @@ X86_64TargetInfo::getTargetBuiltins() const { "__builtin_ia32_"}, }; } + +unsigned +MicrosoftX86_64TargetInfo::getMinGlobalAlign(uint64_t TypeSize, + bool HasNonWeakDef) const { + unsigned Align = + WindowsX86_64TargetInfo::getMinGlobalAlign(TypeSize, HasNonWeakDef); + + return std::max(Align, Microsoft64BitMinGlobalAlign(TypeSize)); +} diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index c7afcc7c86053..c8c5d280754b4 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -968,6 +968,8 @@ class LLVM_LIBRARY_VISIBILITY MicrosoftX86_64TargetInfo : WindowsX86_64TargetInfo(Triple, Opts) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + LargeArrayMinWidth = 0; + LargeArrayAlign = 0; } void getTargetDefines(const LangOptions &Opts, @@ -981,6 +983,9 @@ class LLVM_LIBRARY_VISIBILITY MicrosoftX86_64TargetInfo getCallingConvKind(bool ClangABICompat4) const override { return CCK_MicrosoftWin64; } + + unsigned getMinGlobalAlign(uint64_t TypeSize, + bool HasNonWeakDef) const override; }; // x86-64 MinGW target diff --git a/clang/test/CodeGen/align-x68_64.c b/clang/test/CodeGen/align-x68_64.c index cf128b43433ea..91f5fac199136 100644 --- a/clang/test/CodeGen/align-x68_64.c +++ b/clang/test/CodeGen/align-x68_64.c @@ -1,11 +1,21 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm %s -o - | FileCheck --check-prefix=MSVC %s // PR5599 +char arr[16]; + void test1_f(void *); void test1_g(void) { float x[4]; test1_f(x); } +// CHECK: @arr = {{.*}} align 16 // CHECK: @test1_g // CHECK: alloca [4 x float], align 16 + +// The "large array" alignment increase does not apply on windows-msvc. +// MSVC: @arr = {{.*}} align 8 +// MSVC: @test1_g +// MSVC: alloca [4 x float], align 4 diff --git a/clang/test/CodeGen/asan-strings.c b/clang/test/CodeGen/asan-strings.c index 0c7420034f89e..e71445eaf7fe4 100644 --- a/clang/test/CodeGen/asan-strings.c +++ b/clang/test/CodeGen/asan-strings.c @@ -12,6 +12,6 @@ const char *foo(void) { return "asdf"; } // LINUX: @.str = private unnamed_addr constant [5 x i8] c"asdf\00", align 1 -// WINDOWS: @"??_C@_04JIHMPGLA@asdf?$AA@" = linkonce_odr dso_local unnamed_addr constant [5 x i8] c"asdf\00", comdat, align 1 +// WINDOWS: @"??_C@_04JIHMPGLA@asdf?$AA@" = linkonce_odr dso_local unnamed_addr constant [5 x i8] c"asdf\00", comdat, align 4 -// WINWRITE: @.str = private unnamed_addr global [5 x i8] c"asdf\00", align 1 +// WINWRITE: @.str = private unnamed_addr global [5 x i8] c"asdf\00", align 4 diff --git a/clang/test/CodeGen/arm64-microsoft-struct-align.cpp b/clang/test/CodeGen/microsoft-64bit-struct-align.cpp similarity index 80% rename from clang/test/CodeGen/arm64-microsoft-struct-align.cpp rename to clang/test/CodeGen/microsoft-64bit-struct-align.cpp index 4076c3ca34ad7..c4e0f2f6dfc88 100644 --- a/clang/test/CodeGen/arm64-microsoft-struct-align.cpp +++ b/clang/test/CodeGen/microsoft-64bit-struct-align.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -triple aarch64-windows -ffreestanding -emit-llvm -O0 \ -// RUN: -x c++ -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-windows-msvc -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -o - %s | FileCheck %s struct size1 { char str[1]; }; struct size2 { char str[2]; }; -struct size7 { char str[4]; }; +struct size7 { char str[7]; }; struct size8 { char str[8]; }; struct size63 { char str[63]; }; struct size64 { char str[64]; }; diff --git a/clang/test/CodeGenCXX/ms-constexpr-static-data-member.cpp b/clang/test/CodeGenCXX/ms-constexpr-static-data-member.cpp index 604a49fefbacb..4b191fd472c20 100644 --- a/clang/test/CodeGenCXX/ms-constexpr-static-data-member.cpp +++ b/clang/test/CodeGenCXX/ms-constexpr-static-data-member.cpp @@ -19,8 +19,8 @@ void usethem() { useptr(&S::sdm_udt); } -// CHECK-DAG: @"?sdm_char_array@S@@2QBDB" = linkonce_odr dso_local constant [5 x i8] c"asdf\00", comdat, align 1 +// CHECK-DAG: @"?sdm_char_array@S@@2QBDB" = linkonce_odr dso_local constant [5 x i8] c"asdf\00", comdat, align 4 // CHECK-DAG: @"?sdm_char_ptr@S@@2QEBDEB" = linkonce_odr dso_local constant ptr @"??_C@_04JIHMPGLA@asdf?$AA@", comdat, align 8 -// CHECK-DAG: @"?sdm_udt@S@@2UFoo@@B" = linkonce_odr dso_local constant %struct.Foo { i32 1, i32 2 }, comdat, align 4 +// CHECK-DAG: @"?sdm_udt@S@@2UFoo@@B" = linkonce_odr dso_local constant %struct.Foo { i32 1, i32 2 }, comdat, align 8 diff --git a/clang/test/CodeGenObjC/encode-test-6.m b/clang/test/CodeGenObjC/encode-test-6.m index c32f8f24c0009..dd770f523e2f3 100644 --- a/clang/test/CodeGenObjC/encode-test-6.m +++ b/clang/test/CodeGenObjC/encode-test-6.m @@ -80,6 +80,6 @@ @implementation SCNCamera // CHECK-DWARF: define{{.*}} ptr @Test() // CHECK-DWARF: ret ptr @e -// CHECK-MSVC: @e = dso_local global [2 x i8] c"i\00", align 1 +// CHECK-MSVC: @e = dso_local global [2 x i8] c"i\00", align 4 // CHECK-MINGW: @e = dso_local global [2 x i8] c"i\00", align 1 // CHECK-ELF: @e = global [2 x i8] c"i\00", align 1 diff --git a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp index 410988e16acdc..528d27f85e54b 100644 --- a/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp +++ b/clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp @@ -148,14 +148,14 @@ int main() { // CHECK-HOST-LINUX @.str.5 = private unnamed_addr constant [30 x i8] c"_ZTS23fwd_ref_arg_kernel_name\00", align 1 // CHECK-HOST-LINUX: @.str.6 = private unnamed_addr constant [35 x i8] c"_ZTS28fwd_ref_arg_kernel_name_move\00", align 1 // CHECK-HOST-LINUX: @.str.7 = private unnamed_addr constant [33 x i8] c"_ZTS26rvalue_ref_arg_kernel_name\00", align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0CB@KFIJOMLB@_ZTS26single_purpose_kernel_name@" = linkonce_odr dso_local unnamed_addr constant [33 x i8] c"_ZTS26single_purpose_kernel_name\00", comdat, align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0BC@NHCDOLAA@_ZTSZ4mainEUlT_E_?$AA@" = linkonce_odr dso_local unnamed_addr constant [18 x i8] c"_ZTSZ4mainEUlT_E_\00", comdat, align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0M@BCGAEMBE@_ZTS6?N?$LE?O?$IE?O?$IH?$AA@" = linkonce_odr dso_local unnamed_addr constant [12 x i8] c"_ZTS6\CE\B4\CF\84\CF\87\00", comdat, align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0P@DLGHPODL@_ZTSZ4mainE2KN?$AA@" = linkonce_odr dso_local unnamed_addr constant [15 x i8] c"_ZTSZ4mainE2KN\00", comdat, align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0BK@PPDJPOBM@_ZTS19ref_arg_kernel_name?$AA@" = linkonce_odr dso_local unnamed_addr constant [26 x i8] c"_ZTS19ref_arg_kernel_name\00", comdat, align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0BO@KEIBIHKH@_ZTS23fwd_ref_arg_kernel_name?$AA@" = linkonce_odr dso_local unnamed_addr constant [30 x i8] c"_ZTS23fwd_ref_arg_kernel_name\00", comdat, align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0CD@FDALJLMM@_ZTS28fwd_ref_arg_kernel_name_mo@" = linkonce_odr dso_local unnamed_addr constant [35 x i8] c"_ZTS28fwd_ref_arg_kernel_name_move\00", comdat, align 1 -// CHECK-HOST-WINDOWS: @"??_C@_0CB@HCPMABHM@_ZTS26rvalue_ref_arg_kernel_name@" = linkonce_odr dso_local unnamed_addr constant [33 x i8] c"_ZTS26rvalue_ref_arg_kernel_name\00", comdat, align 1 +// CHECK-HOST-WINDOWS: @"??_C@_0CB@KFIJOMLB@_ZTS26single_purpose_kernel_name@" = linkonce_odr dso_local unnamed_addr constant [33 x i8] c"_ZTS26single_purpose_kernel_name\00", comdat +// CHECK-HOST-WINDOWS: @"??_C@_0BC@NHCDOLAA@_ZTSZ4mainEUlT_E_?$AA@" = linkonce_odr dso_local unnamed_addr constant [18 x i8] c"_ZTSZ4mainEUlT_E_\00", comdat +// CHECK-HOST-WINDOWS: @"??_C@_0M@BCGAEMBE@_ZTS6?N?$LE?O?$IE?O?$IH?$AA@" = linkonce_odr dso_local unnamed_addr constant [12 x i8] c"_ZTS6\CE\B4\CF\84\CF\87\00", comdat +// CHECK-HOST-WINDOWS: @"??_C@_0P@DLGHPODL@_ZTSZ4mainE2KN?$AA@" = linkonce_odr dso_local unnamed_addr constant [15 x i8] c"_ZTSZ4mainE2KN\00", comdat +// CHECK-HOST-WINDOWS: @"??_C@_0BK@PPDJPOBM@_ZTS19ref_arg_kernel_name?$AA@" = linkonce_odr dso_local unnamed_addr constant [26 x i8] c"_ZTS19ref_arg_kernel_name\00", comdat +// CHECK-HOST-WINDOWS: @"??_C@_0BO@KEIBIHKH@_ZTS23fwd_ref_arg_kernel_name?$AA@" = linkonce_odr dso_local unnamed_addr constant [30 x i8] c"_ZTS23fwd_ref_arg_kernel_name\00", comdat +// CHECK-HOST-WINDOWS: @"??_C@_0CD@FDALJLMM@_ZTS28fwd_ref_arg_kernel_name_mo@" = linkonce_odr dso_local unnamed_addr constant [35 x i8] c"_ZTS28fwd_ref_arg_kernel_name_move\00", comdat +// CHECK-HOST-WINDOWS: @"??_C@_0CB@HCPMABHM@_ZTS26rvalue_ref_arg_kernel_name@" = linkonce_odr dso_local unnamed_addr constant [33 x i8] c"_ZTS26rvalue_ref_arg_kernel_name\00", comdat // // CHECK-HOST-LINUX: define dso_local void @_Z26single_purpose_kernel_task21single_purpose_kernel() #{{[0-9]+}} { // CHECK-HOST-LINUX-NEXT: entry: _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
