https://github.com/folkertdev created https://github.com/llvm/llvm-project/pull/215015
Aggregates are left-adjusted, but GCC right-adjusts complex values within the 8-byte slot https://godbolt.org/z/as3PevMGd ```c #include <stdarg.h> _Complex char complex_char_sink; void get_complex_char(va_list *args) { complex_char_sink = va_arg(*args, _Complex char); } struct ManualComplexChar { char re; char im }; struct ManualComplexChar manual_complex_char_sink; void get_manual_complex_char(va_list *args) { manual_complex_char_sink = va_arg(*args, struct ManualComplexChar); } ``` Note how Clang has ```asm ldub [%o1], %o0 ldub [%o1+1], %o1 ``` but GCC has ```asm ldub [%g1+6], %g3 ldub [%g1+7], %g2 ``` For `ManualComplexChar` GCC does pass it left-aligned: ```asm ldub [%g1], %g2 stb %g2, [%l7] ldub [%g1+1], %g2 ``` I'm not sure about `IsComplexGnuAbi` here. It's easy to add but then you carry it forever. >From fc05816f82b58fb46ebcd4cd72211f5bbc648f01 Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Sat, 8 Aug 2026 21:42:16 +0200 Subject: [PATCH] [Sparc][clang] `_Complex char` in c-variadic call is right-adjusted --- clang/lib/CodeGen/Targets/Sparc.cpp | 5 ++++- clang/test/CodeGen/Sparc/sparcv9-vaarg.c | 15 ++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index e23771653e251..25f0009fe7a09 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -394,11 +394,14 @@ RValue SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // Zero-sized types have a width of one byte for parameter passing purposes. TInfo.Width = std::max(TInfo.Width, CharUnits::fromQuantity(1)); + // Small _Complex types are right-adjusted, but small aggregates are not. + bool ForceRightAdjust = Ty->isAnyComplexType(); + // Arguments bigger than 2*SlotSize bytes are passed indirectly. return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*IsIndirect=*/TInfo.Width > 2 * SlotSize, TInfo, SlotSize, - /*AllowHigherAlign=*/true, Slot); + /*AllowHigherAlign=*/true, Slot, ForceRightAdjust); } void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const { diff --git a/clang/test/CodeGen/Sparc/sparcv9-vaarg.c b/clang/test/CodeGen/Sparc/sparcv9-vaarg.c index a23d9f1c6506f..8c9578e4eacc6 100644 --- a/clang/test/CodeGen/Sparc/sparcv9-vaarg.c +++ b/clang/test/CodeGen/Sparc/sparcv9-vaarg.c @@ -149,7 +149,7 @@ __int128 get_int128(va_list *args) { _Complex char complex_char_sink; -// FIXME: _Complex char should be passed in the right-most bytes of the slot, using a getelementptr with a value of 6. +// _Complex char is passed in the right-most bytes of the slot, note the getelementptr with a value of 6. // CHECK-LABEL: define dso_local void @get_complex_char( // CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] @@ -159,12 +159,13 @@ _Complex char complex_char_sink; // CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8 // CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i64 8 // CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8 -// CHECK-NEXT: [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[ARGP_CUR]], i32 0, i32 0 -// CHECK-NEXT: [[ARGP_CUR_REAL:%.*]] = load i8, ptr [[ARGP_CUR_REALP]], align 8 -// CHECK-NEXT: [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[ARGP_CUR]], i32 0, i32 1 -// CHECK-NEXT: [[ARGP_CUR_IMAG:%.*]] = load i8, ptr [[ARGP_CUR_IMAGP]], align 1 -// CHECK-NEXT: store i8 [[ARGP_CUR_REAL]], ptr @complex_char_sink, align 1 -// CHECK-NEXT: store i8 [[ARGP_CUR_IMAG]], ptr getelementptr inbounds nuw (i8, ptr @complex_char_sink, i64 1), align 1 +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i64 6 +// CHECK-NEXT: [[DOTREALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[TMP1]], i32 0, i32 0 +// CHECK-NEXT: [[DOTREAL:%.*]] = load i8, ptr [[DOTREALP]], align 2 +// CHECK-NEXT: [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[TMP1]], i32 0, i32 1 +// CHECK-NEXT: [[DOTIMAG:%.*]] = load i8, ptr [[DOTIMAGP]], align 1 +// CHECK-NEXT: store i8 [[DOTREAL]], ptr @complex_char_sink, align 1 +// CHECK-NEXT: store i8 [[DOTIMAG]], ptr getelementptr inbounds nuw (i8, ptr @complex_char_sink, i64 1), align 1 // CHECK-NEXT: ret void // void get_complex_char(va_list *args) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
