https://github.com/folkertdev created 
https://github.com/llvm/llvm-project/pull/216524

https://godbolt.org/z/o1nGYEM33

```c
extern void sink(int, ...);

void variadic_cld(_Complex float z) { sink(0, z); }
```

Current clang just uses float registers

```asm
variadic_cld:
        mov     %g0, %o0
        fmovs %f0, %f2
        fmovs %f1, %f3
        mov     %o7, %g1
        call sink
        mov     %g1, %o7
```

GCC packs a complex float into a single register

```asm
variadic_cld:
        save    %sp, -192, %sp
        st      %f0, [%fp+2043]
        lduw    [%fp+2043], %g1
        sllx    %g1, 32, %g1
        srl     %o1, 0, %o1
        or      %o1, %g1, %o1
        st      %f1, [%fp+2043]
        lduw    [%fp+2043], %g2
        mov     -1, %g1
        sllx    %g1, 32, %g1
        and     %o1, %g1, %o1
        or      %o1, %g2, %o1
        call    sink, 0
         mov    0, %o0
        return  %i7+8
         nop
```

>From 8e0c52d5af73a6240b1ba7129d3df51991dff1e8 Mon Sep 17 00:00:00 2001
From: Folkert de Vries <[email protected]>
Date: Sun, 16 Aug 2026 01:31:43 +0200
Subject: [PATCH 1/2] [Sparc][NFC] test sparc variadic aggregate handling

---
 clang/test/CodeGen/Sparc/variadic-aggregate.c | 1015 +++++++++++++++++
 1 file changed, 1015 insertions(+)
 create mode 100644 clang/test/CodeGen/Sparc/variadic-aggregate.c

diff --git a/clang/test/CodeGen/Sparc/variadic-aggregate.c 
b/clang/test/CodeGen/Sparc/variadic-aggregate.c
new file mode 100644
index 0000000000000..92093e1133b8a
--- /dev/null
+++ b/clang/test/CodeGen/Sparc/variadic-aggregate.c
@@ -0,0 +1,1015 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple sparc -emit-llvm -o - %s \
+// RUN:   | FileCheck %s --check-prefixes=SPARC
+//
+// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm -o - %s \
+// RUN:   | FileCheck %s --check-prefixes=SPARC64
+
+#include <stdarg.h>
+
+extern void sink(int, ...);
+
+struct char_char {
+  char x, y;
+};
+
+struct short_short {
+  short x, y;
+};
+
+struct int_int {
+  int x, y;
+};
+
+struct long_long {
+  long x, y;
+};
+
+struct long_long_long_long {
+  long long x, y;
+};
+
+struct float_float {
+  float x, y;
+};
+
+struct double_double {
+  double x, y;
+};
+
+struct long_double_long_double {
+  long double x, y;
+};
+
+struct aligned_int {
+  int x;
+} __attribute__((aligned(16)));
+
+struct aligned_float {
+  float x;
+} __attribute__((aligned(16)));
+
+struct int_int_int_int {
+  int a, b, c, d;
+};
+
+struct float_float_float_float {
+  float a, b, c, d;
+};
+
+// SPARC-LABEL: define dso_local void @test_complex_char(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0:[0-9]+]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { i8, i8 }, align 1
+// SPARC-NEXT:    [[COERCE:%.*]] = alloca { i8, i8 }, align 1
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load i8, ptr [[DOTREALP]], align 1
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load i8, ptr [[DOTIMAGP]], align 1
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr 
[[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr 
[[X]], i32 0, i32 1
+// SPARC-NEXT:    store i8 [[DOTREAL]], ptr [[X_REALP]], align 1
+// SPARC-NEXT:    store i8 [[DOTIMAG]], ptr [[X_IMAGP]], align 1
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load i8, ptr [[X_REALP1]], align 1
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load i8, ptr [[X_IMAGP2]], align 1
+// SPARC-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 
}, ptr [[COERCE]], i32 0, i32 0
+// SPARC-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 
}, ptr [[COERCE]], i32 0, i32 1
+// SPARC-NEXT:    store i8 [[X_REAL]], ptr [[COERCE_REALP]], align 1
+// SPARC-NEXT:    store i8 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 1
+// SPARC-NEXT:    [[TMP2:%.*]] = load i16, ptr [[COERCE]], align 1
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, i16 noundef 
[[TMP2]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_char(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0:[0-9]+]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { i8, i8 }, align 1
+// SPARC64-NEXT:    [[COERCE:%.*]] = alloca { i8, i8 }, align 1
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 6
+// SPARC64-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[TMP1]], i32 0, i32 0
+// SPARC64-NEXT:    [[DOTREAL:%.*]] = load i8, ptr [[DOTREALP]], align 2
+// SPARC64-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[TMP1]], i32 0, i32 1
+// SPARC64-NEXT:    [[DOTIMAG:%.*]] = load i8, ptr [[DOTIMAGP]], align 1
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store i8 [[DOTREAL]], ptr [[X_REALP]], align 1
+// SPARC64-NEXT:    store i8 [[DOTIMAG]], ptr [[X_IMAGP]], align 1
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load i8, ptr [[X_REALP1]], align 1
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i8, i8 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load i8, ptr [[X_IMAGP2]], align 1
+// SPARC64-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i8, i8 
}, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i8, i8 
}, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    store i8 [[X_REAL]], ptr [[COERCE_REALP]], align 1
+// SPARC64-NEXT:    store i8 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 1
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i16, ptr [[COERCE]], align 1
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i16 
noundef [[TMP2]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_char(va_list *ap) {
+  _Complex char x = va_arg(*ap, _Complex char);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_char_char(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_CHAR_CHAR:%.*]], align 1
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[X]], ptr 
align 1 [[TMP1]], i32 2, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_CHAR_CHAR]]) align 1 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_char_char(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_CHAR_CHAR:%.*]], align 1
+// SPARC64-NEXT:    [[X_COERCE:%.*]] = alloca i64, align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 2, i1 false)
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[X_COERCE]], 
ptr align 1 [[X]], i64 2, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[X_COERCE]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP1]])
+// SPARC64-NEXT:    ret void
+//
+void test_char_char(va_list *ap) {
+  struct char_char x = va_arg(*ap, struct char_char);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_complex_short(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { i16, i16 }, align 2
+// SPARC-NEXT:    [[COERCE:%.*]] = alloca { i16, i16 }, align 2
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load i16, ptr [[DOTREALP]], align 2
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load i16, ptr [[DOTIMAGP]], align 2
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    store i16 [[DOTREAL]], ptr [[X_REALP]], align 2
+// SPARC-NEXT:    store i16 [[DOTIMAG]], ptr [[X_IMAGP]], align 2
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load i16, ptr [[X_REALP1]], align 2
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load i16, ptr [[X_IMAGP2]], align 2
+// SPARC-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 
}, ptr [[COERCE]], i32 0, i32 0
+// SPARC-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 
}, ptr [[COERCE]], i32 0, i32 1
+// SPARC-NEXT:    store i16 [[X_REAL]], ptr [[COERCE_REALP]], align 2
+// SPARC-NEXT:    store i16 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 2
+// SPARC-NEXT:    [[TMP2:%.*]] = load i32, ptr [[COERCE]], align 2
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, i32 noundef 
[[TMP2]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_short(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { i16, i16 }, align 2
+// SPARC64-NEXT:    [[COERCE:%.*]] = alloca { i16, i16 }, align 2
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 4
+// SPARC64-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { i16, i16 
}, ptr [[TMP1]], i32 0, i32 0
+// SPARC64-NEXT:    [[DOTREAL:%.*]] = load i16, ptr [[DOTREALP]], align 4
+// SPARC64-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 
}, ptr [[TMP1]], i32 0, i32 1
+// SPARC64-NEXT:    [[DOTIMAG:%.*]] = load i16, ptr [[DOTIMAGP]], align 2
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store i16 [[DOTREAL]], ptr [[X_REALP]], align 2
+// SPARC64-NEXT:    store i16 [[DOTIMAG]], ptr [[X_IMAGP]], align 2
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i16, i16 
}, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load i16, ptr [[X_REALP1]], align 2
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i16, i16 
}, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load i16, ptr [[X_IMAGP2]], align 2
+// SPARC64-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i16, 
i16 }, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i16, 
i16 }, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    store i16 [[X_REAL]], ptr [[COERCE_REALP]], align 2
+// SPARC64-NEXT:    store i16 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 2
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i32, ptr [[COERCE]], align 2
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i32 
noundef [[TMP2]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_short(va_list *ap) {
+  _Complex short x = va_arg(*ap, _Complex short);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_short_short(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_SHORT_SHORT:%.*]], align 2
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[X]], ptr 
align 2 [[TMP1]], i32 4, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_SHORT_SHORT]]) align 2 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_short_short(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_SHORT_SHORT:%.*]], align 2
+// SPARC64-NEXT:    [[X_COERCE:%.*]] = alloca i64, align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 2 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 4, i1 false)
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[X_COERCE]], 
ptr align 2 [[X]], i64 4, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[X_COERCE]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP1]])
+// SPARC64-NEXT:    ret void
+//
+void test_short_short(va_list *ap) {
+  struct short_short x = va_arg(*ap, struct short_short);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_complex_int(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { i32, i32 }, align 4
+// SPARC-NEXT:    [[COERCE:%.*]] = alloca { i32, i32 }, align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load i32, ptr [[DOTREALP]], align 4
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load i32, ptr [[DOTIMAGP]], align 4
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    store i32 [[DOTREAL]], ptr [[X_REALP]], align 4
+// SPARC-NEXT:    store i32 [[DOTIMAG]], ptr [[X_IMAGP]], align 4
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load i32, ptr [[X_REALP1]], align 4
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load i32, ptr [[X_IMAGP2]], align 4
+// SPARC-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 
}, ptr [[COERCE]], i32 0, i32 0
+// SPARC-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 
}, ptr [[COERCE]], i32 0, i32 1
+// SPARC-NEXT:    store i32 [[X_REAL]], ptr [[COERCE_REALP]], align 4
+// SPARC-NEXT:    store i32 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
+// SPARC-NEXT:    [[TMP2:%.*]] = load i64, ptr [[COERCE]], align 4
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, i64 noundef 
[[TMP2]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_int(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { i32, i32 }, align 4
+// SPARC64-NEXT:    [[COERCE:%.*]] = alloca { i32, i32 }, align 4
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i32, 
i32 }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC64-NEXT:    [[ARGP_CUR_REAL:%.*]] = load i32, ptr [[ARGP_CUR_REALP]], 
align 8
+// SPARC64-NEXT:    [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i32, 
i32 }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC64-NEXT:    [[ARGP_CUR_IMAG:%.*]] = load i32, ptr [[ARGP_CUR_IMAGP]], 
align 4
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store i32 [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 4
+// SPARC64-NEXT:    store i32 [[ARGP_CUR_IMAG]], ptr [[X_IMAGP]], align 4
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i32, i32 
}, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load i32, ptr [[X_REALP1]], align 4
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i32, i32 
}, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load i32, ptr [[X_IMAGP2]], align 4
+// SPARC64-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i32, 
i32 }, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i32, 
i32 }, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    store i32 [[X_REAL]], ptr [[COERCE_REALP]], align 4
+// SPARC64-NEXT:    store i32 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[COERCE]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
noundef [[TMP1]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_int(va_list *ap) {
+  _Complex int x = va_arg(*ap, _Complex int);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_int_int(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_INT_INT:%.*]], align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[X]], ptr 
align 4 [[TMP1]], i32 8, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_INT_INT]]) align 4 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_int_int(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_INT_INT:%.*]], align 4
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 8, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[X]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP1]])
+// SPARC64-NEXT:    ret void
+//
+void test_int_int(va_list *ap) {
+  struct int_int x = va_arg(*ap, struct int_int);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_complex_long(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { i32, i32 }, align 4
+// SPARC-NEXT:    [[COERCE:%.*]] = alloca { i32, i32 }, align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load i32, ptr [[DOTREALP]], align 4
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load i32, ptr [[DOTIMAGP]], align 4
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    store i32 [[DOTREAL]], ptr [[X_REALP]], align 4
+// SPARC-NEXT:    store i32 [[DOTIMAG]], ptr [[X_IMAGP]], align 4
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load i32, ptr [[X_REALP1]], align 4
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i32, i32 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load i32, ptr [[X_IMAGP2]], align 4
+// SPARC-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 
}, ptr [[COERCE]], i32 0, i32 0
+// SPARC-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 
}, ptr [[COERCE]], i32 0, i32 1
+// SPARC-NEXT:    store i32 [[X_REAL]], ptr [[COERCE_REALP]], align 4
+// SPARC-NEXT:    store i32 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
+// SPARC-NEXT:    [[TMP2:%.*]] = load i64, ptr [[COERCE]], align 4
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, i64 noundef 
[[TMP2]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_long(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { i64, i64 }, align 8
+// SPARC64-NEXT:    [[COERCE:%.*]] = alloca { i64, i64 }, align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC64-NEXT:    [[ARGP_CUR_REAL:%.*]] = load i64, ptr [[ARGP_CUR_REALP]], 
align 8
+// SPARC64-NEXT:    [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC64-NEXT:    [[ARGP_CUR_IMAG:%.*]] = load i64, ptr [[ARGP_CUR_IMAGP]], 
align 8
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store i64 [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 8
+// SPARC64-NEXT:    store i64 [[ARGP_CUR_IMAG]], ptr [[X_IMAGP]], align 8
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i64, i64 
}, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load i64, ptr [[X_REALP1]], align 8
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i64, i64 
}, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load i64, ptr [[X_IMAGP2]], align 8
+// SPARC64-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    store i64 [[X_REAL]], ptr [[COERCE_REALP]], align 8
+// SPARC64-NEXT:    store i64 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
noundef [[TMP2]], i64 noundef [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_long(va_list *ap) {
+  _Complex long x = va_arg(*ap, _Complex long);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_long_long(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_LONG_LONG:%.*]], align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[X]], ptr 
align 4 [[TMP1]], i32 8, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_LONG_LONG]]) align 4 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_long_long(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_LONG_LONG:%.*]], align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_LONG_LONG]], ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_LONG_LONG]], ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP2]], i64 [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_long_long(va_list *ap) {
+  struct long_long x = va_arg(*ap, struct long_long);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_complex_long_long(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { i64, i64 }, align 8
+// SPARC-NEXT:    [[BYVAL_TEMP:%.*]] = alloca { i64, i64 }, align 8
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load i64, ptr [[DOTREALP]], align 8
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load i64, ptr [[DOTIMAGP]], align 8
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    store i64 [[DOTREAL]], ptr [[X_REALP]], align 8
+// SPARC-NEXT:    store i64 [[DOTIMAG]], ptr [[X_IMAGP]], align 8
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load i64, ptr [[X_REALP1]], align 8
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load i64, ptr [[X_IMAGP2]], align 8
+// SPARC-NEXT:    [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[BYVAL_TEMP]], i32 0, i32 0
+// SPARC-NEXT:    [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[BYVAL_TEMP]], i32 0, i32 1
+// SPARC-NEXT:    store i64 [[X_REAL]], ptr [[BYVAL_TEMP_REALP]], align 8
+// SPARC-NEXT:    store i64 [[X_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 8
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval({ i64, i64 }) align 8 [[BYVAL_TEMP]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_long_long(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { i64, i64 }, align 8
+// SPARC64-NEXT:    [[COERCE:%.*]] = alloca { i64, i64 }, align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC64-NEXT:    [[ARGP_CUR_REAL:%.*]] = load i64, ptr [[ARGP_CUR_REALP]], 
align 8
+// SPARC64-NEXT:    [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC64-NEXT:    [[ARGP_CUR_IMAG:%.*]] = load i64, ptr [[ARGP_CUR_IMAGP]], 
align 8
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store i64 [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 8
+// SPARC64-NEXT:    store i64 [[ARGP_CUR_IMAG]], ptr [[X_IMAGP]], align 8
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { i64, i64 
}, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load i64, ptr [[X_REALP1]], align 8
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { i64, i64 
}, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load i64, ptr [[X_IMAGP2]], align 8
+// SPARC64-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { i64, 
i64 }, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    store i64 [[X_REAL]], ptr [[COERCE_REALP]], align 8
+// SPARC64-NEXT:    store i64 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
noundef [[TMP2]], i64 noundef [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_long_long(va_list *ap) {
+  _Complex long long x = va_arg(*ap, _Complex long long);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_long_long_long_long(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_LONG_LONG_LONG_LONG:%.*]], align 
8
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[X]], ptr 
align 8 [[TMP1]], i32 16, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_LONG_LONG_LONG_LONG]]) align 8 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_long_long_long_long(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_LONG_LONG_LONG_LONG:%.*]], 
align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_LONG_LONG_LONG_LONG]], ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_LONG_LONG_LONG_LONG]], ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP2]], i64 [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_long_long_long_long(va_list *ap) {
+  struct long_long_long_long x =
+      va_arg(*ap, struct long_long_long_long);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_complex_float(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { float, float }, align 4
+// SPARC-NEXT:    [[BYVAL_TEMP:%.*]] = alloca { float, float }, align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load float, ptr [[DOTREALP]], align 4
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load float, ptr [[DOTIMAGP]], align 4
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    store float [[DOTREAL]], ptr [[X_REALP]], align 4
+// SPARC-NEXT:    store float [[DOTIMAG]], ptr [[X_IMAGP]], align 4
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load float, ptr [[X_REALP1]], align 4
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load float, ptr [[X_IMAGP2]], align 4
+// SPARC-NEXT:    [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { 
float, float }, ptr [[BYVAL_TEMP]], i32 0, i32 0
+// SPARC-NEXT:    [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { 
float, float }, ptr [[BYVAL_TEMP]], i32 0, i32 1
+// SPARC-NEXT:    store float [[X_REAL]], ptr [[BYVAL_TEMP_REALP]], align 4
+// SPARC-NEXT:    store float [[X_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 4
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval({ float, float }) align 4 [[BYVAL_TEMP]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_float(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { float, float }, align 4
+// SPARC64-NEXT:    [[COERCE:%.*]] = alloca { float, float }, align 4
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { 
float, float }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC64-NEXT:    [[ARGP_CUR_REAL:%.*]] = load float, ptr 
[[ARGP_CUR_REALP]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { 
float, float }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC64-NEXT:    [[ARGP_CUR_IMAG:%.*]] = load float, ptr 
[[ARGP_CUR_IMAGP]], align 4
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store float [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 4
+// SPARC64-NEXT:    store float [[ARGP_CUR_IMAG]], ptr [[X_IMAGP]], align 4
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load float, ptr [[X_REALP1]], align 4
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load float, ptr [[X_IMAGP2]], align 4
+// SPARC64-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    store float [[X_REAL]], ptr [[COERCE_REALP]], align 4
+// SPARC64-NEXT:    store float [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg noundef [[TMP2]], float inreg noundef [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_float(va_list *ap) {
+  _Complex float x = va_arg(*ap, _Complex float);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_float_float(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_FLOAT_FLOAT:%.*]], align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[X]], ptr 
align 4 [[TMP1]], i32 8, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_FLOAT_FLOAT]]) align 4 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_float_float(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_FLOAT_FLOAT:%.*]], align 4
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 8, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg [[TMP2]], float inreg [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_float_float(va_list *ap) {
+  struct float_float x = va_arg(*ap, struct float_float);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_complex_double(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { double, double }, align 8
+// SPARC-NEXT:    [[BYVAL_TEMP:%.*]] = alloca { double, double }, align 8
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load double, ptr [[DOTREALP]], align 8
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load double, ptr [[DOTIMAGP]], align 8
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    store double [[DOTREAL]], ptr [[X_REALP]], align 8
+// SPARC-NEXT:    store double [[DOTIMAG]], ptr [[X_IMAGP]], align 8
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load double, ptr [[X_REALP1]], align 8
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load double, ptr [[X_IMAGP2]], align 8
+// SPARC-NEXT:    [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[BYVAL_TEMP]], i32 0, i32 0
+// SPARC-NEXT:    [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[BYVAL_TEMP]], i32 0, i32 1
+// SPARC-NEXT:    store double [[X_REAL]], ptr [[BYVAL_TEMP_REALP]], align 8
+// SPARC-NEXT:    store double [[X_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 8
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval({ double, double }) align 8 [[BYVAL_TEMP]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_double(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { double, double }, align 8
+// SPARC64-NEXT:    [[COERCE:%.*]] = alloca { double, double }, align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC64-NEXT:    [[ARGP_CUR_REAL:%.*]] = load double, ptr 
[[ARGP_CUR_REALP]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC64-NEXT:    [[ARGP_CUR_IMAG:%.*]] = load double, ptr 
[[ARGP_CUR_IMAGP]], align 8
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store double [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 8
+// SPARC64-NEXT:    store double [[ARGP_CUR_IMAG]], ptr [[X_IMAGP]], align 8
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load double, ptr [[X_REALP1]], align 8
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { double, 
double }, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load double, ptr [[X_IMAGP2]], align 8
+// SPARC64-NEXT:    [[COERCE_REALP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    store double [[X_REAL]], ptr [[COERCE_REALP]], align 8
+// SPARC64-NEXT:    store double [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, double 
noundef [[TMP2]], double noundef [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_double(va_list *ap) {
+  _Complex double x = va_arg(*ap, _Complex double);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_double_double(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_DOUBLE_DOUBLE:%.*]], align 8
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[X]], ptr 
align 8 [[TMP1]], i32 16, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_DOUBLE_DOUBLE]]) align 8 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_double_double(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_DOUBLE_DOUBLE:%.*]], align 8
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_DOUBLE]], ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_DOUBLE]], ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, double 
[[TMP2]], double [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_double_double(va_list *ap) {
+  struct double_double x = va_arg(*ap, struct double_double);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_complex_long_double(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca { fp128, fp128 }, align 8
+// SPARC-NEXT:    [[BYVAL_TEMP:%.*]] = alloca { fp128, fp128 }, align 8
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 
}, ptr [[TMP1]], i32 0, i32 0
+// SPARC-NEXT:    [[DOTREAL:%.*]] = load fp128, ptr [[DOTREALP]], align 8
+// SPARC-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 
}, ptr [[TMP1]], i32 0, i32 1
+// SPARC-NEXT:    [[DOTIMAG:%.*]] = load fp128, ptr [[DOTIMAGP]], align 8
+// SPARC-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 
}, ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 
}, ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    store fp128 [[DOTREAL]], ptr [[X_REALP]], align 8
+// SPARC-NEXT:    store fp128 [[DOTIMAG]], ptr [[X_IMAGP]], align 8
+// SPARC-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { fp128, fp128 
}, ptr [[X]], i32 0, i32 0
+// SPARC-NEXT:    [[X_REAL:%.*]] = load fp128, ptr [[X_REALP1]], align 8
+// SPARC-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { fp128, fp128 
}, ptr [[X]], i32 0, i32 1
+// SPARC-NEXT:    [[X_IMAG:%.*]] = load fp128, ptr [[X_IMAGP2]], align 8
+// SPARC-NEXT:    [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { 
fp128, fp128 }, ptr [[BYVAL_TEMP]], i32 0, i32 0
+// SPARC-NEXT:    [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { 
fp128, fp128 }, ptr [[BYVAL_TEMP]], i32 0, i32 1
+// SPARC-NEXT:    store fp128 [[X_REAL]], ptr [[BYVAL_TEMP_REALP]], align 8
+// SPARC-NEXT:    store fp128 [[X_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 8
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval({ fp128, fp128 }) align 8 [[BYVAL_TEMP]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_complex_long_double(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca { fp128, fp128 }, align 16
+// SPARC64-NEXT:    [[BYVAL_TEMP:%.*]] = alloca { fp128, fp128 }, align 16
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 8
+// SPARC64-NEXT:    [[DOTREALP:%.*]] = getelementptr inbounds nuw { fp128, 
fp128 }, ptr [[TMP1]], i32 0, i32 0
+// SPARC64-NEXT:    [[DOTREAL:%.*]] = load fp128, ptr [[DOTREALP]], align 16
+// SPARC64-NEXT:    [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { fp128, 
fp128 }, ptr [[TMP1]], i32 0, i32 1
+// SPARC64-NEXT:    [[DOTIMAG:%.*]] = load fp128, ptr [[DOTIMAGP]], align 16
+// SPARC64-NEXT:    [[X_REALP:%.*]] = getelementptr inbounds nuw { fp128, 
fp128 }, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, 
fp128 }, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    store fp128 [[DOTREAL]], ptr [[X_REALP]], align 16
+// SPARC64-NEXT:    store fp128 [[DOTIMAG]], ptr [[X_IMAGP]], align 16
+// SPARC64-NEXT:    [[X_REALP1:%.*]] = getelementptr inbounds nuw { fp128, 
fp128 }, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[X_REAL:%.*]] = load fp128, ptr [[X_REALP1]], align 16
+// SPARC64-NEXT:    [[X_IMAGP2:%.*]] = getelementptr inbounds nuw { fp128, 
fp128 }, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[X_IMAG:%.*]] = load fp128, ptr [[X_IMAGP2]], align 16
+// SPARC64-NEXT:    [[BYVAL_TEMP_REALP:%.*]] = getelementptr inbounds nuw { 
fp128, fp128 }, ptr [[BYVAL_TEMP]], i32 0, i32 0
+// SPARC64-NEXT:    [[BYVAL_TEMP_IMAGP:%.*]] = getelementptr inbounds nuw { 
fp128, fp128 }, ptr [[BYVAL_TEMP]], i32 0, i32 1
+// SPARC64-NEXT:    store fp128 [[X_REAL]], ptr [[BYVAL_TEMP_REALP]], align 16
+// SPARC64-NEXT:    store fp128 [[X_IMAG]], ptr [[BYVAL_TEMP_IMAGP]], align 16
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, ptr 
nofree noundef align 16 dead_on_return dereferenceable(32) [[BYVAL_TEMP]])
+// SPARC64-NEXT:    ret void
+//
+void test_complex_long_double(va_list *ap) {
+  _Complex long double x = va_arg(*ap, _Complex long double);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_long_double_long_double(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_LONG_DOUBLE_LONG_DOUBLE:%.*]], 
align 8
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[X]], ptr 
align 8 [[TMP1]], i32 32, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_LONG_DOUBLE_LONG_DOUBLE]]) align 8 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_long_double_long_double(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_LONG_DOUBLE_LONG_DOUBLE:%.*]], 
align 16
+// SPARC64-NEXT:    [[BYVAL_TEMP:%.*]] = alloca 
[[STRUCT_LONG_DOUBLE_LONG_DOUBLE]], align 16
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[X]], ptr 
align 16 [[TMP1]], i64 32, i1 false)
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 16 
[[BYVAL_TEMP]], ptr align 16 [[X]], i64 32, i1 false)
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, ptr 
nofree noundef align 16 dead_on_return dereferenceable(32) [[BYVAL_TEMP]])
+// SPARC64-NEXT:    ret void
+//
+void test_long_double_long_double(va_list *ap) {
+  struct long_double_long_double x =
+      va_arg(*ap, struct long_double_long_double);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_aligned_int(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_ALIGNED_INT:%.*]], align 16
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[X]], ptr 
align 16 [[TMP1]], i32 16, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_ALIGNED_INT]]) align 16 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_aligned_int(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_ALIGNED_INT:%.*]], align 16
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i32 15
+// SPARC64-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = call ptr 
@llvm.ptrmask.p0.i64(ptr [[TMP1]], i64 -16)
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR_ALIGNED]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[X]], ptr 
align 16 [[ARGP_CUR_ALIGNED]], i64 16, i1 false)
+// SPARC64-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 16
+// SPARC64-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP5:%.*]] = load i64, ptr [[TMP4]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
undef, i64 [[TMP3]], i64 [[TMP5]])
+// SPARC64-NEXT:    ret void
+//
+void test_aligned_int(va_list *ap) {
+  struct aligned_int x = va_arg(*ap, struct aligned_int);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_aligned_float(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_ALIGNED_FLOAT:%.*]], align 16
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[X]], ptr 
align 16 [[TMP1]], i32 16, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_ALIGNED_FLOAT]]) align 16 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_aligned_float(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_ALIGNED_FLOAT:%.*]], align 16
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i32 15
+// SPARC64-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = call ptr 
@llvm.ptrmask.p0.i64(ptr [[TMP1]], i64 -16)
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR_ALIGNED]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[X]], ptr 
align 16 [[ARGP_CUR_ALIGNED]], i64 16, i1 false)
+// SPARC64-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP3:%.*]] = load float, ptr [[TMP2]], align 16
+// SPARC64-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
+// SPARC64-NEXT:    [[TMP6:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 2
+// SPARC64-NEXT:    [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
undef, float inreg [[TMP3]], i32 inreg [[TMP5]], i64 inreg [[TMP7]])
+// SPARC64-NEXT:    ret void
+//
+void test_aligned_float(va_list *ap) {
+  struct aligned_float x = va_arg(*ap, struct aligned_float);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_int_int_int_int(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_INT_INT_INT_INT:%.*]], align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[X]], ptr 
align 4 [[TMP1]], i32 16, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_INT_INT_INT_INT]]) align 4 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_int_int_int_int(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_INT_INT_INT_INT:%.*]], align 4
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP2]], i64 [[TMP4]])
+// SPARC64-NEXT:    ret void
+//
+void test_int_int_int_int(va_list *ap) {
+  struct int_int_int_int x = va_arg(*ap, struct int_int_int_int);
+  sink(0, x);
+}
+
+// SPARC-LABEL: define dso_local void @test_float_float_float_float(
+// SPARC-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC-NEXT:  [[ENTRY:.*:]]
+// SPARC-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 4
+// SPARC-NEXT:    [[X:%.*]] = alloca [[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT:%.*]], 
align 4
+// SPARC-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 4
+// SPARC-NEXT:    [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// SPARC-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[X]], ptr 
align 4 [[TMP1]], i32 16, i1 false)
+// SPARC-NEXT:    call void (i32, ...) @sink(i32 noundef 0, ptr noundef 
byval([[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]]) align 4 [[X]])
+// SPARC-NEXT:    ret void
+//
+// SPARC64-LABEL: define dso_local void @test_float_float_float_float(
+// SPARC64-SAME: ptr noundef [[AP:%.*]]) #[[ATTR0]] {
+// SPARC64-NEXT:  [[ENTRY:.*:]]
+// SPARC64-NEXT:    [[AP_ADDR:%.*]] = alloca ptr, align 8
+// SPARC64-NEXT:    [[X:%.*]] = alloca [[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT:%.*]], 
align 4
+// SPARC64-NEXT:    store ptr [[AP]], ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[AP_ADDR]], align 8
+// SPARC64-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 8
+// SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
+// SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
+// SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
+// SPARC64-NEXT:    [[TMP5:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 2
+// SPARC64-NEXT:    [[TMP6:%.*]] = load float, ptr [[TMP5]], align 4
+// SPARC64-NEXT:    [[TMP7:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 3
+// SPARC64-NEXT:    [[TMP8:%.*]] = load float, ptr [[TMP7]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg [[TMP2]], float inreg [[TMP4]], float inreg [[TMP6]], float inreg 
[[TMP8]])
+// SPARC64-NEXT:    ret void
+//
+void test_float_float_float_float(va_list *ap) {
+  struct float_float_float_float x =
+      va_arg(*ap, struct float_float_float_float);
+  sink(0, x);
+}

>From 38d918afa0eda2f62817b7f965a06d8930fa215f Mon Sep 17 00:00:00 2001
From: Folkert de Vries <[email protected]>
Date: Sun, 16 Aug 2026 02:22:56 +0200
Subject: [PATCH 2/2] [Sparc]: don't pass variadic arguments in float registers

---
 clang/lib/CodeGen/Targets/Sparc.cpp           | 22 ++++---
 clang/test/CodeGen/Sparc/variadic-aggregate.c | 60 ++++++++-----------
 2 files changed, 38 insertions(+), 44 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index 25f0009fe7a09..ed9decb8d8726 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -163,7 +163,7 @@ class SparcV9ABIInfo : public ABIInfo {
   bool IsComplexGnuABI;
 
   ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit,
-                          unsigned &RegOffset) const;
+                          unsigned &RegOffset, bool IsVarArg) const;
   void computeInfo(CGFunctionInfo &FI) const override;
   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
                    AggValueSlot Slot) const override;
@@ -185,9 +185,10 @@ class SparcV9ABIInfo : public ABIInfo {
     SmallVector<llvm::Type*, 8> Elems;
     uint64_t Size;
     bool InReg;
+    bool IsVarArg;
 
-    CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl)
-      : Context(c), DL(dl), Size(0), InReg(false) {}
+    CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl, bool 
IsVarArg)
+      : Context(c), DL(dl), Size(0), InReg(false), IsVarArg(IsVarArg) {}
 
     // Pad Elems with integers until Size is ToSize.
     void pad(uint64_t ToSize) {
@@ -217,6 +218,9 @@ class SparcV9ABIInfo : public ABIInfo {
 
     // Add a floating point element at Offset.
     void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) {
+      // Varargs are treated as integers.
+      if (IsVarArg)
+        return;
       // Unaligned floats are treated as integers.
       if (Offset % Bits)
         return;
@@ -277,7 +281,7 @@ class SparcV9ABIInfo : public ABIInfo {
 } // end anonymous namespace
 
 ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit,
-                                        unsigned &RegOffset) const {
+                                        unsigned &RegOffset, bool IsVarArg) 
const {
   if (Ty->isVoidType())
     return ABIArgInfo::getIgnore();
 
@@ -369,7 +373,7 @@ ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, 
unsigned SizeLimit,
     return ABIArgInfo::getDirect(/*T=*/nullptr, /*Offset=*/0, Padding);
   }
 
-  CoerceBuilder CB(VMContext, getDataLayout());
+  CoerceBuilder CB(VMContext, getDataLayout(), IsVarArg);
   CB.addStruct(0, StrTy);
   // All structs, even empty ones, should take up a register argument slot,
   // so pin the minimum struct size to one bit.
@@ -406,13 +410,15 @@ RValue SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, 
Address VAListAddr,
 
 void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
   unsigned RetOffset = 0;
-  ABIArgInfo RetType = classifyType(FI.getReturnType(), 32 * 8, RetOffset);
+  ABIArgInfo RetType = classifyType(FI.getReturnType(), 32 * 8, RetOffset, 
/*IsVarArg=*/false);
   FI.getReturnInfo() = RetType;
 
   // Indirect returns will have its pointer passed as an argument.
   unsigned ArgOffset = RetType.isIndirect() ? RetOffset : 0;
-  for (auto &I : FI.arguments())
-    I.info = classifyType(I.type, 16 * 8, ArgOffset);
+  for (auto [ArgNo, I] : llvm::enumerate(FI.arguments())) {
+    bool IsVarArg = ArgNo >= FI.getNumRequiredArgs();
+    I.info = classifyType(I.type, 16 * 8, ArgOffset, IsVarArg);
+  }
 }
 
 namespace {
diff --git a/clang/test/CodeGen/Sparc/variadic-aggregate.c 
b/clang/test/CodeGen/Sparc/variadic-aggregate.c
index 92093e1133b8a..fb7524b887980 100644
--- a/clang/test/CodeGen/Sparc/variadic-aggregate.c
+++ b/clang/test/CodeGen/Sparc/variadic-aggregate.c
@@ -615,11 +615,8 @@ void test_long_long_long_long(va_list *ap) {
 // SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, 
float }, ptr [[COERCE]], i32 0, i32 1
 // SPARC64-NEXT:    store float [[X_REAL]], ptr [[COERCE_REALP]], align 4
 // SPARC64-NEXT:    store float [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[COERCE]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { float, float 
}, ptr [[COERCE]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg noundef [[TMP2]], float inreg noundef [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[COERCE]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
noundef [[TMP1]])
 // SPARC64-NEXT:    ret void
 //
 void test_complex_float(va_list *ap) {
@@ -650,11 +647,8 @@ void test_complex_float(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 8
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 8, i1 false)
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg [[TMP2]], float inreg [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[X]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP1]])
 // SPARC64-NEXT:    ret void
 //
 void test_float_float(va_list *ap) {
@@ -717,11 +711,11 @@ void test_float_float(va_list *ap) {
 // SPARC64-NEXT:    [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { 
double, double }, ptr [[COERCE]], i32 0, i32 1
 // SPARC64-NEXT:    store double [[X_REAL]], ptr [[COERCE_REALP]], align 8
 // SPARC64-NEXT:    store double [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { double, double 
}, ptr [[COERCE]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, double 
noundef [[TMP2]], double noundef [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[COERCE]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
noundef [[TMP2]], i64 noundef [[TMP4]])
 // SPARC64-NEXT:    ret void
 //
 void test_complex_double(va_list *ap) {
@@ -752,11 +746,11 @@ void test_complex_double(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_DOUBLE]], ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_DOUBLE_DOUBLE]], ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, double 
[[TMP2]], double [[TMP4]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP2]], i64 [[TMP4]])
 // SPARC64-NEXT:    ret void
 //
 void test_double_double(va_list *ap) {
@@ -925,13 +919,11 @@ void test_aligned_int(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR_ALIGNED]], i64 16
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[X]], ptr 
align 16 [[ARGP_CUR_ALIGNED]], i64 16, i1 false)
-// SPARC64-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP3:%.*]] = load float, ptr [[TMP2]], align 16
-// SPARC64-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
-// SPARC64-NEXT:    [[TMP6:%.*]] = getelementptr inbounds nuw { float, i32, 
i64 }, ptr [[X]], i32 0, i32 2
-// SPARC64-NEXT:    [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 8
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
undef, float inreg [[TMP3]], i32 inreg [[TMP5]], i64 inreg [[TMP7]])
+// SPARC64-NEXT:    [[TMP2:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 16
+// SPARC64-NEXT:    [[TMP4:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP5:%.*]] = load i64, ptr [[TMP4]], align 8
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
undef, i64 [[TMP3]], i64 [[TMP5]])
 // SPARC64-NEXT:    ret void
 //
 void test_aligned_float(va_list *ap) {
@@ -997,15 +989,11 @@ void test_int_int_int_int(va_list *ap) {
 // SPARC64-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr 
[[ARGP_CUR]], i64 16
 // SPARC64-NEXT:    store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 8
 // SPARC64-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[X]], ptr 
align 8 [[ARGP_CUR]], i64 16, i1 false)
-// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 0
-// SPARC64-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 1
-// SPARC64-NEXT:    [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// SPARC64-NEXT:    [[TMP5:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 2
-// SPARC64-NEXT:    [[TMP6:%.*]] = load float, ptr [[TMP5]], align 4
-// SPARC64-NEXT:    [[TMP7:%.*]] = getelementptr inbounds nuw 
[[STRUCT_FLOAT_FLOAT_FLOAT_FLOAT]], ptr [[X]], i32 0, i32 3
-// SPARC64-NEXT:    [[TMP8:%.*]] = load float, ptr [[TMP7]], align 4
-// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, float 
inreg [[TMP2]], float inreg [[TMP4]], float inreg [[TMP6]], float inreg 
[[TMP8]])
+// SPARC64-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 0
+// SPARC64-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// SPARC64-NEXT:    [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, 
ptr [[X]], i32 0, i32 1
+// SPARC64-NEXT:    [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 4
+// SPARC64-NEXT:    call void (i32, ...) @sink(i32 noundef signext 0, i64 
[[TMP2]], i64 [[TMP4]])
 // SPARC64-NEXT:    ret void
 //
 void test_float_float_float_float(va_list *ap) {

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

Reply via email to