[clang] [Sparc][clang] implement `va_arg` in the clang frontend (PR #214981)
Folkert de Vries via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 26 02:50:31 PDT 2026
https://github.com/folkertdev updated https://github.com/llvm/llvm-project/pull/214981
>From 96a369577eb46bf68e4c9a9f3638c3560bb3ca18 Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Sat, 8 Aug 2026 17:39:12 +0200
Subject: [PATCH] [Sparc][clang] implement `va_arg` in the clang frontend
---
clang/lib/CodeGen/Targets/Sparc.cpp | 21 +++
clang/test/CodeGen/Sparc/sparc-vaarg.c | 117 +++++++++-----
clang/test/CodeGen/Sparc/variadic-aggregate.c | 147 ++++++++++++------
3 files changed, 204 insertions(+), 81 deletions(-)
diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp
index 25f0009fe7a09..875fadf330ebd 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -34,6 +34,8 @@ class SparcV8ABIInfo : public DefaultABIInfo {
ABIArgInfo classifyComplexType(const ComplexType *Ty, bool IsRet) const;
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty) const;
+ RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
+ AggValueSlot Slot) const override;
void computeInfo(CGFunctionInfo &FI) const override;
};
} // end anonymous namespace
@@ -94,6 +96,25 @@ void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const {
Arg.info = classifyArgumentType(Arg.type);
}
+RValue SparcV8ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty, AggValueSlot Slot) const {
+ CharUnits SlotSize = CharUnits::fromQuantity(4);
+ auto TInfo = getContext().getTypeInfoInChars(Ty);
+
+ // E.g. long double, larger _Complex and aggregate values are indirect.
+ bool IsIndirect = classifyArgumentType(Ty).isIndirect();
+
+ // An alignment higher than the slot size is not respected.
+ bool AllowHigherAlign = false;
+
+ // Force values smaller than a slot (e.g. _Complex char)
+ // into the right-most bytes.
+ bool ForceRightAdjust = true;
+
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TInfo, SlotSize,
+ AllowHigherAlign, Slot, ForceRightAdjust);
+}
+
namespace {
class SparcV8TargetCodeGenInfo : public TargetCodeGenInfo {
public:
diff --git a/clang/test/CodeGen/Sparc/sparc-vaarg.c b/clang/test/CodeGen/Sparc/sparc-vaarg.c
index 53d215f479fae..f322229e20c43 100644
--- a/clang/test/CodeGen/Sparc/sparc-vaarg.c
+++ b/clang/test/CodeGen/Sparc/sparc-vaarg.c
@@ -6,13 +6,13 @@
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[VARET:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], i32
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[VARET]], align 4
-// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[VARET]], align 4
-// CHECK-NEXT: ret i32 [[TMP2]]
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT: ret i32 [[TMP1]]
//
int get_int(va_list *args) {
return va_arg(*args, int);
@@ -20,68 +20,98 @@ int get_int(va_list *args) {
enum RGB { R = 1, G = 2, B = 3 };
+// Enums are passed like integers.
// CHECK-LABEL: define dso_local i32 @get_enum(
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[VARET:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], i32
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[VARET]], align 4
-// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[VARET]], align 4
-// CHECK-NEXT: ret i32 [[TMP2]]
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT: ret i32 [[TMP1]]
//
enum RGB get_enum(va_list *args) {
return va_arg(*args, enum RGB);
}
+// long long is passed directly, note how ARGP_CUR is advanced by 8.
+// The read is under-aligned however, the ARGP_CUR is only aligned to a slot.
// CHECK-LABEL: define dso_local i64 @get_long_long(
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[VARET:%.*]] = alloca i64, align 8
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], i64
-// CHECK-NEXT: store i64 [[TMP1]], ptr [[VARET]], align 8
-// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[VARET]], align 8
-// CHECK-NEXT: ret i64 [[TMP2]]
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 8
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT: ret i64 [[TMP1]]
//
long long get_long_long(va_list *args) {
return va_arg(*args, long long);
}
-struct Foo {
+struct Large {
long long x;
};
-// CHECK-LABEL: define dso_local void @get_struct(
-// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOO:%.*]]) align 8 [[AGG_RESULT:%.*]], ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
+// Aggregates are passed indirectly, note how ARGP_CUR is advanced by 4.
+// CHECK-LABEL: define dso_local void @get_struct_long_long(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_LARGE:%.*]]) align 8 [[AGG_RESULT:%.*]], ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[AGG_RESULT]], ptr align 8 [[TMP1]], i32 8, i1 false)
// CHECK-NEXT: ret void
//
-struct Foo get_struct(va_list *args) {
- return va_arg(*args, struct Foo);
+struct Large get_struct_long_long(va_list *args) {
+ return va_arg(*args, struct Large);
}
+struct Tiny {
+ char x;
+};
+
+// CHECK-LABEL: define dso_local void @get_struct_char(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TINY:%.*]]) align 1 [[AGG_RESULT:%.*]], ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_RESULT]], ptr align 1 [[TMP1]], i32 1, i1 false)
+// CHECK-NEXT: ret void
+//
+struct Tiny get_struct_char(va_list *args) {
+ return va_arg(*args, struct Tiny);
+}
+
+// long double is passed indirectly, note how ARGP_CUR is advanced by 4.
// CHECK-LABEL: define dso_local void @get_long_double(
// CHECK-SAME: ptr dead_on_unwind noalias writable sret(fp128) align 8 [[AGG_RESULT:%.*]], ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK-NEXT: [[VARET:%.*]] = alloca fp128, align 8
// CHECK-NEXT: store ptr [[AGG_RESULT]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], fp128
-// CHECK-NEXT: store fp128 [[TMP1]], ptr [[VARET]], align 8
-// CHECK-NEXT: [[TMP2:%.*]] = load fp128, ptr [[VARET]], align 8
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT: [[TMP2:%.*]] = load fp128, ptr [[TMP1]], align 8
// CHECK-NEXT: store fp128 [[TMP2]], ptr [[AGG_RESULT]], align 8
// CHECK-NEXT: [[TMP3:%.*]] = load fp128, ptr [[AGG_RESULT]], align 8
// CHECK-NEXT: store fp128 [[TMP3]], ptr [[AGG_RESULT]], align 8
@@ -93,15 +123,19 @@ long double get_long_double(va_list *args) {
_Complex char complex_char_sink;
+// _Complex char is passed in the right-most bytes of the slot, note the getelementptr with a value of 2.
// CHECK-LABEL: define dso_local void @get_complex_char(
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 2
// CHECK-NEXT: [[DOTREALP:%.*]] = getelementptr inbounds nuw { i8, i8 }, ptr [[TMP1]], i32 0, i32 0
-// CHECK-NEXT: [[DOTREAL:%.*]] = load i8, ptr [[DOTREALP]], align 1
+// 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
@@ -114,19 +148,22 @@ void get_complex_char(va_list *args) {
_Complex int complex_int_sink;
+// _Complex int is passed directly, note how ARGP_CUR is advanced by 8.
// CHECK-LABEL: define dso_local void @get_complex_int(
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
-// CHECK-NEXT: [[DOTREALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[TMP1]], i32 0, i32 0
-// CHECK-NEXT: [[DOTREAL:%.*]] = load i32, ptr [[DOTREALP]], align 4
-// CHECK-NEXT: [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[TMP1]], i32 0, i32 1
-// CHECK-NEXT: [[DOTIMAG:%.*]] = load i32, ptr [[DOTIMAGP]], align 4
-// CHECK-NEXT: store i32 [[DOTREAL]], ptr @complex_int_sink, align 4
-// CHECK-NEXT: store i32 [[DOTIMAG]], ptr getelementptr inbounds nuw (i8, ptr @complex_int_sink, i32 4), align 4
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 8
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[ARGP_CUR]], i32 0, i32 0
+// CHECK-NEXT: [[ARGP_CUR_REAL:%.*]] = load i32, ptr [[ARGP_CUR_REALP]], align 4
+// CHECK-NEXT: [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[ARGP_CUR]], i32 0, i32 1
+// CHECK-NEXT: [[ARGP_CUR_IMAG:%.*]] = load i32, ptr [[ARGP_CUR_IMAGP]], align 4
+// CHECK-NEXT: store i32 [[ARGP_CUR_REAL]], ptr @complex_int_sink, align 4
+// CHECK-NEXT: store i32 [[ARGP_CUR_IMAG]], ptr getelementptr inbounds nuw (i8, ptr @complex_int_sink, i32 4), align 4
// CHECK-NEXT: ret void
//
void get_complex_int(va_list *args) {
@@ -135,13 +172,17 @@ void get_complex_int(va_list *args) {
_Complex long long complex_long_long_sink;
+// _Complex long long is passed indirectly, note how ARGP_CUR is advanced by 4.
// CHECK-LABEL: define dso_local void @get_complex_long_long(
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// CHECK-NEXT: [[DOTREALP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[TMP1]], i32 0, i32 0
// CHECK-NEXT: [[DOTREAL:%.*]] = load i64, ptr [[DOTREALP]], align 8
// CHECK-NEXT: [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[TMP1]], i32 0, i32 1
@@ -156,13 +197,17 @@ void get_complex_long_long (va_list *args) {
_Complex long double complex_long_double_sink;
+// _Complex long double is passed indirectly, note how ARGP_CUR is advanced by 4.
// CHECK-LABEL: define dso_local void @get_complex_long_double(
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = va_arg ptr [[TMP0]], ptr
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// CHECK-NEXT: [[DOTREALP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[TMP1]], i32 0, i32 0
// CHECK-NEXT: [[DOTREAL:%.*]] = load fp128, ptr [[DOTREALP]], align 8
// CHECK-NEXT: [[DOTIMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[TMP1]], i32 0, i32 1
diff --git a/clang/test/CodeGen/Sparc/variadic-aggregate.c b/clang/test/CodeGen/Sparc/variadic-aggregate.c
index 03deebf384e9f..afaf297fcd7cb 100644
--- a/clang/test/CodeGen/Sparc/variadic-aggregate.c
+++ b/clang/test/CodeGen/Sparc/variadic-aggregate.c
@@ -65,9 +65,12 @@ struct float_float_float_float {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 2
// 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: [[DOTREAL:%.*]] = load i8, ptr [[DOTREALP]], align 2
// 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
@@ -130,7 +133,10 @@ void test_complex_char(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -165,15 +171,17 @@ void test_char_char(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC-NEXT: [[ARGP_CUR_REAL:%.*]] = load i16, ptr [[ARGP_CUR_REALP]], align 4
+// SPARC-NEXT: [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i16, i16 }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC-NEXT: [[ARGP_CUR_IMAG:%.*]] = load i16, ptr [[ARGP_CUR_IMAGP]], 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: store i16 [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 2
+// SPARC-NEXT: store i16 [[ARGP_CUR_IMAG]], 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
@@ -182,8 +190,8 @@ void test_char_char(va_list *ap) {
// 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: [[TMP1:%.*]] = load i32, ptr [[COERCE]], align 2
+// SPARC-NEXT: call void (i32, ...) @sink(i32 noundef 0, i32 noundef [[TMP1]])
// SPARC-NEXT: ret void
//
// SPARC64-LABEL: define dso_local void @test_complex_short(
@@ -230,7 +238,10 @@ void test_complex_short(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -265,15 +276,17 @@ void test_short_short(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 8
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC-NEXT: [[ARGP_CUR_REAL:%.*]] = load i32, ptr [[ARGP_CUR_REALP]], align 4
+// SPARC-NEXT: [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC-NEXT: [[ARGP_CUR_IMAG:%.*]] = load i32, ptr [[ARGP_CUR_IMAGP]], 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: store i32 [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 4
+// SPARC-NEXT: store i32 [[ARGP_CUR_IMAG]], 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
@@ -282,8 +295,8 @@ void test_short_short(va_list *ap) {
// 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: [[TMP1:%.*]] = load i64, ptr [[COERCE]], align 4
+// SPARC-NEXT: call void (i32, ...) @sink(i32 noundef 0, i64 noundef [[TMP1]])
// SPARC-NEXT: ret void
//
// SPARC64-LABEL: define dso_local void @test_complex_int(
@@ -329,7 +342,10 @@ void test_complex_int(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -362,15 +378,17 @@ void test_int_int(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 8
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_CUR_REALP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[ARGP_CUR]], i32 0, i32 0
+// SPARC-NEXT: [[ARGP_CUR_REAL:%.*]] = load i32, ptr [[ARGP_CUR_REALP]], align 4
+// SPARC-NEXT: [[ARGP_CUR_IMAGP:%.*]] = getelementptr inbounds nuw { i32, i32 }, ptr [[ARGP_CUR]], i32 0, i32 1
+// SPARC-NEXT: [[ARGP_CUR_IMAG:%.*]] = load i32, ptr [[ARGP_CUR_IMAGP]], 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: store i32 [[ARGP_CUR_REAL]], ptr [[X_REALP]], align 4
+// SPARC-NEXT: store i32 [[ARGP_CUR_IMAG]], 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
@@ -379,8 +397,8 @@ void test_int_int(va_list *ap) {
// 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: [[TMP1:%.*]] = load i64, ptr [[COERCE]], align 4
+// SPARC-NEXT: call void (i32, ...) @sink(i32 noundef 0, i64 noundef [[TMP1]])
// SPARC-NEXT: ret void
//
// SPARC64-LABEL: define dso_local void @test_complex_long(
@@ -429,7 +447,10 @@ void test_complex_long(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -465,7 +486,10 @@ void test_long_long(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -531,7 +555,10 @@ void test_complex_long_long(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -568,7 +595,10 @@ void test_long_long_long_long(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -634,7 +664,10 @@ void test_complex_float(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -670,7 +703,10 @@ void test_float_float(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -736,7 +772,10 @@ void test_complex_double(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -772,7 +811,10 @@ void test_double_double(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -835,7 +877,10 @@ void test_complex_long_double(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -870,7 +915,10 @@ void test_long_double_long_double(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -907,7 +955,10 @@ void test_aligned_int(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -946,7 +997,10 @@ void test_aligned_float(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
@@ -981,7 +1035,10 @@ void test_int_int_int_int(va_list *ap) {
// 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: [[ARGP_CUR:%.*]] = load ptr, ptr [[TMP0]], align 4
+// SPARC-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// SPARC-NEXT: store ptr [[ARGP_NEXT]], ptr [[TMP0]], align 4
+// SPARC-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4
// 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
More information about the cfe-commits
mailing list