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
