Author: Folkert de Vries
Date: 2026-08-25T16:22:15+02:00
New Revision: 5106b28890c7028ad6bbb1d28caeaac36558942d

URL: 
https://github.com/llvm/llvm-project/commit/5106b28890c7028ad6bbb1d28caeaac36558942d
DIFF: 
https://github.com/llvm/llvm-project/commit/5106b28890c7028ad6bbb1d28caeaac36558942d.diff

LOG: [X86] fix `va_arg` alignment of `f128` (#218017)

fixes https://github.com/llvm/llvm-project/issues/217747

In a c-variadic call, an `f128` argument is passed with an alignment of
16, but was read with an alignment of only 4, often at the wrong offset
in the `va_list`.

Some types this does not cover:

- `__int128` (needs `-fforce-enable-int128` for i386)
- `_Complex __float128`

Those still get an alignment of 4.

Added: 
    clang/test/CodeGen/X86/x86_32-vaarg.c

Modified: 
    clang/lib/CodeGen/Targets/X86.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/Targets/X86.cpp 
b/clang/lib/CodeGen/Targets/X86.cpp
index f0d108f3279fd..1dc3bd0740baa 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -579,6 +579,9 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType 
Ty,
   if (Align <= MinABIStackAlignInBytes)
     return 0; // Use default alignment.
 
+  if (Ty->isFloat128Type())
+    return 16;
+
   if (IsLinuxABI) {
     // Exclude other System V OS (e.g Darwin, PS4 and FreeBSD) since we don't
     // want to spend any effort dealing with the ramifications of ABI breaks.

diff  --git a/clang/test/CodeGen/X86/x86_32-vaarg.c 
b/clang/test/CodeGen/X86/x86_32-vaarg.c
new file mode 100644
index 0000000000000..3fa90c0420cad
--- /dev/null
+++ b/clang/test/CodeGen/X86/x86_32-vaarg.c
@@ -0,0 +1,106 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -emit-llvm -o - %s | 
FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-freebsd -emit-llvm -o - %s | FileCheck 
%s
+// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: define dso_local fp128 @f128_test(
+// CHECK-SAME: i32 noundef [[Z:%.*]], ...) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[LIST:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[X:%.*]] = alloca fp128, align 16
+// CHECK-NEXT:    store i32 [[Z]], ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], 
i32 15
+// CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr 
[[TMP0]], i32 -16)
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR_ALIGNED]], i32 16
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[LIST]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load fp128, ptr [[ARGP_CUR_ALIGNED]], align 16
+// CHECK-NEXT:    store fp128 [[TMP1]], ptr [[X]], align 16
+// CHECK-NEXT:    call void @llvm.va_end.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[TMP2:%.*]] = load fp128, ptr [[X]], align 16
+// CHECK-NEXT:    ret fp128 [[TMP2]]
+//
+__float128 f128_test(int z, ...) {
+  __builtin_va_list list;
+  __builtin_va_start(list, z);
+  __float128 x = __builtin_va_arg(list, __float128);
+  __builtin_va_end(list);
+  return x;
+}
+
+// CHECK-LABEL: define dso_local x86_fp80 @ld_test(
+// CHECK-SAME: i32 noundef [[Z:%.*]], ...) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[LIST:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[X:%.*]] = alloca x86_fp80, align 4
+// CHECK-NEXT:    store i32 [[Z]], ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i32 12
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[LIST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load x86_fp80, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT:    store x86_fp80 [[TMP0]], ptr [[X]], align 4
+// CHECK-NEXT:    call void @llvm.va_end.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[TMP1:%.*]] = load x86_fp80, ptr [[X]], align 4
+// CHECK-NEXT:    ret x86_fp80 [[TMP1]]
+//
+long double ld_test(int z, ...) {
+  __builtin_va_list list;
+  __builtin_va_start(list, z);
+  long double x = __builtin_va_arg(list, long double);
+  __builtin_va_end(list);
+  return x;
+}
+
+// CHECK-LABEL: define dso_local double @double_test(
+// CHECK-SAME: i32 noundef [[Z:%.*]], ...) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[LIST:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[X:%.*]] = alloca double, align 8
+// CHECK-NEXT:    store i32 [[Z]], ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i32 8
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[LIST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT:    store double [[TMP0]], ptr [[X]], align 8
+// CHECK-NEXT:    call void @llvm.va_end.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[TMP1:%.*]] = load double, ptr [[X]], align 8
+// CHECK-NEXT:    ret double [[TMP1]]
+//
+double double_test(int z, ...) {
+  __builtin_va_list list;
+  __builtin_va_start(list, z);
+  double x = __builtin_va_arg(list, double);
+  __builtin_va_end(list);
+  return x;
+}
+
+// CHECK-LABEL: define dso_local i32 @int_test(
+// CHECK-SAME: i32 noundef [[Z:%.*]], ...) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[Z_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[LIST:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[X:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[Z]], ptr [[Z_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i32 4
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[LIST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[X]], align 4
+// CHECK-NEXT:    call void @llvm.va_end.p0(ptr [[LIST]])
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[X]], align 4
+// CHECK-NEXT:    ret i32 [[TMP1]]
+//
+int int_test(int z, ...) {
+  __builtin_va_list list;
+  __builtin_va_start(list, z);
+  int x = __builtin_va_arg(list, int);
+  __builtin_va_end(list);
+  return x;
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to