[clang] 56bb311 - [MIPS] don't pass variadic arguments in float registers (#216519)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 19 04:53:25 PDT 2026
Author: Folkert de Vries
Date: 2026-08-19T13:53:19+02:00
New Revision: 56bb31141fe72e996d8c7babaf04136fa72bfc5d
URL: https://github.com/llvm/llvm-project/commit/56bb31141fe72e996d8c7babaf04136fa72bfc5d
DIFF: https://github.com/llvm/llvm-project/commit/56bb31141fe72e996d8c7babaf04136fa72bfc5d.diff
LOG: [MIPS] don't pass variadic arguments in float registers (#216519)
At least, I think that's what is going on here. Really it doesn't make
sense to use `inreg` float parameters here. Apparently the backend can
handle it on smaller floats but `_Complex long double` hits some edge
case and miscompiles.
https://godbolt.org/z/nqTM46Ej5
```c
extern void sink(int, ...);
void variadic_cld(_Complex long double z) { sink(0, z); }
```
Clang only sets up register 4 for the `int`, I think with the assumption
that the `f128` arguments are already in the right place:
```asm
variadic_cld:
.Lfunc_begin0 = .Ltmp0
daddiu $sp, $sp, -16
sd $ra, 8($sp)
sd $gp, 0($sp)
lui $1, %hi(%neg(%gp_rel(variadic_cld)))
daddu $1, $1, $25
daddiu $gp, $1, %lo(%neg(%gp_rel(variadic_cld)))
ld $25, %call16(sink)($gp)
jalr $25
daddiu $4, $zero, 0
ld $gp, 0($sp)
ld $ra, 8($sp)
jr $ra
daddiu $sp, $sp, 16
```
Contrast this with GCC
```asm
variadic_cld:
daddiu $sp,$sp,-16
sd $31,8($sp)
sd $28,0($sp)
lui $28,%hi(%neg(%gp_rel(variadic_cld)))
daddu $28,$28,$25
daddiu $28,$28,%lo(%neg(%gp_rel(variadic_cld)))
dmfc1 $5,$f13
dmfc1 $4,$f12
dmfc1 $3,$f15
dmfc1 $2,$f14
move $7,$5
move $6,$4
move $9,$3
move $8,$2
ld $25,%call16(sink)($28)
1: jalr $25
move $4,$0
ld $31,8($sp)
ld $28,0($sp)
jr $31
daddiu $sp,$sp,16
```
Which actually loads from the FPRs into GPRs. The behavior of this PR
matches GCC.
cc https://github.com/llvm/llvm-project/pull/216509
Added:
Modified:
clang/lib/CodeGen/Targets/Mips.cpp
clang/test/CodeGen/Mips/variadic-aggregate.c
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/Targets/Mips.cpp b/clang/lib/CodeGen/Targets/Mips.cpp
index 220bdcb5886f8..6286e309dab22 100644
--- a/clang/lib/CodeGen/Targets/Mips.cpp
+++ b/clang/lib/CodeGen/Targets/Mips.cpp
@@ -45,7 +45,8 @@ class MipsABIInfo : public ABIInfo {
StackAlignInBytes(IsO32 ? 8 : 16) {}
ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset,
+ bool IsNamedArg) const;
void computeInfo(CGFunctionInfo &FI) const override;
RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
AggValueSlot Slot) const override;
@@ -227,8 +228,8 @@ llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset,
return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8);
}
-ABIArgInfo
-MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
+ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset,
+ bool IsNamedArg) const {
Ty = useFirstFieldIfTransparentUnion(Ty);
uint64_t OrigOffset = Offset;
@@ -241,13 +242,14 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8;
// Only pass _Complex float and _Complex double in FPRs when there are 2 free
- // slots, otherwise use GPRs (or the stack).
+ // slots, and it's not a variadic argument otherwise use GPRs (or the stack).
//
// _Complex long double never uses GPRs. Its parts are an FPR pair each,
// so passing them as they are puts each part in a pair and spills to
// the stack the parts that don't fit.
- bool ComplexFitsInFPRs = true;
- if (!IsO32 && Ty->isComplexType() && isComplexGnuABI() && TySize < 256) {
+ bool ComplexFitsInFPRs = IsNamedArg;
+ if (!IsO32 && IsNamedArg && Ty->isComplexType() && isComplexGnuABI() &&
+ TySize < 256) {
unsigned NumArgSlots = 8;
uint64_t SlotsUsed = CurrOffset / MinABIStackAlignInBytes;
if (SlotsUsed + 2 <= NumArgSlots)
@@ -424,8 +426,9 @@ void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
// Zero-sized arguments are not passed, but do end the run of floats.
bool SawZeroSizedArg = false;
- for (auto &I : FI.arguments()) {
- I.info = classifyArgumentType(I.type, Offset);
+ for (auto [ArgNo, I] : llvm::enumerate(FI.arguments())) {
+ bool IsNamedArg = ArgNo < FI.getNumRequiredArgs();
+ I.info = classifyArgumentType(I.type, Offset, IsNamedArg);
// N32 and N64 always pass floating points in float registers.
if (!IsO32)
diff --git a/clang/test/CodeGen/Mips/variadic-aggregate.c b/clang/test/CodeGen/Mips/variadic-aggregate.c
index 4c72dcb639c1a..8047f78f37501 100644
--- a/clang/test/CodeGen/Mips/variadic-aggregate.c
+++ b/clang/test/CodeGen/Mips/variadic-aggregate.c
@@ -1181,11 +1181,9 @@ void test_long_long_long_long(va_list *ap) {
// GPR64N32-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1
// GPR64N32-NEXT: store float [[X_REAL]], ptr [[COERCE_REALP]], align 4
// GPR64N32-NEXT: store float [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
-// GPR64N32-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N32-NEXT: [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// GPR64N32-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N32-NEXT: [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// GPR64N32-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, float inreg noundef [[TMP2]], float inreg noundef [[TMP4]])
+// GPR64N32-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N32-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// GPR64N32-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 inreg noundef [[TMP2]])
// GPR64N32-NEXT: ret void
//
// GPR64N64BE-LABEL: define dso_local void @test_complex_float(
@@ -1215,11 +1213,9 @@ void test_long_long_long_long(va_list *ap) {
// GPR64N64BE-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1
// GPR64N64BE-NEXT: store float [[X_REAL]], ptr [[COERCE_REALP]], align 4
// GPR64N64BE-NEXT: store float [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
-// GPR64N64BE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N64BE-NEXT: [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// GPR64N64BE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N64BE-NEXT: [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// GPR64N64BE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, float inreg noundef [[TMP2]], float inreg noundef [[TMP4]])
+// GPR64N64BE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N64BE-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// GPR64N64BE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 inreg noundef [[TMP2]])
// GPR64N64BE-NEXT: ret void
//
// GPR64N64LE-LABEL: define dso_local void @test_complex_float(
@@ -1249,11 +1245,9 @@ void test_long_long_long_long(va_list *ap) {
// GPR64N64LE-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1
// GPR64N64LE-NEXT: store float [[X_REAL]], ptr [[COERCE_REALP]], align 4
// GPR64N64LE-NEXT: store float [[X_IMAG]], ptr [[COERCE_IMAGP]], align 4
-// GPR64N64LE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N64LE-NEXT: [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
-// GPR64N64LE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { float, float }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N64LE-NEXT: [[TMP4:%.*]] = load float, ptr [[TMP3]], align 4
-// GPR64N64LE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, float inreg noundef [[TMP2]], float inreg noundef [[TMP4]])
+// GPR64N64LE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N64LE-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// GPR64N64LE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 inreg noundef [[TMP2]])
// GPR64N64LE-NEXT: ret void
//
void test_complex_float(va_list *ap) {
@@ -1399,11 +1393,11 @@ void test_float_float(va_list *ap) {
// GPR64N32-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 1
// GPR64N32-NEXT: store double [[X_REAL]], ptr [[COERCE_REALP]], align 8
// GPR64N32-NEXT: store double [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
-// GPR64N32-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N32-NEXT: [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
-// GPR64N32-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N32-NEXT: [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
-// GPR64N32-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, double inreg noundef [[TMP2]], double inreg noundef [[TMP4]])
+// GPR64N32-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N32-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// GPR64N32-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[COERCE]], i32 0, i32 1
+// GPR64N32-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// GPR64N32-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 inreg noundef [[TMP2]], i64 inreg noundef [[TMP4]])
// GPR64N32-NEXT: ret void
//
// GPR64N64BE-LABEL: define dso_local void @test_complex_double(
@@ -1433,11 +1427,11 @@ void test_float_float(va_list *ap) {
// GPR64N64BE-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 1
// GPR64N64BE-NEXT: store double [[X_REAL]], ptr [[COERCE_REALP]], align 8
// GPR64N64BE-NEXT: store double [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
-// GPR64N64BE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N64BE-NEXT: [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
-// GPR64N64BE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N64BE-NEXT: [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
-// GPR64N64BE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, double inreg noundef [[TMP2]], double inreg noundef [[TMP4]])
+// GPR64N64BE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N64BE-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// GPR64N64BE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[COERCE]], i32 0, i32 1
+// GPR64N64BE-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// GPR64N64BE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 inreg noundef [[TMP2]], i64 inreg noundef [[TMP4]])
// GPR64N64BE-NEXT: ret void
//
// GPR64N64LE-LABEL: define dso_local void @test_complex_double(
@@ -1467,11 +1461,11 @@ void test_float_float(va_list *ap) {
// GPR64N64LE-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 1
// GPR64N64LE-NEXT: store double [[X_REAL]], ptr [[COERCE_REALP]], align 8
// GPR64N64LE-NEXT: store double [[X_IMAG]], ptr [[COERCE_IMAGP]], align 8
-// GPR64N64LE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N64LE-NEXT: [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
-// GPR64N64LE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { double, double }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N64LE-NEXT: [[TMP4:%.*]] = load double, ptr [[TMP3]], align 8
-// GPR64N64LE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, double inreg noundef [[TMP2]], double inreg noundef [[TMP4]])
+// GPR64N64LE-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N64LE-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+// GPR64N64LE-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[COERCE]], i32 0, i32 1
+// GPR64N64LE-NEXT: [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// GPR64N64LE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 inreg noundef [[TMP2]], i64 inreg noundef [[TMP4]])
// GPR64N64LE-NEXT: ret void
//
void test_complex_double(va_list *ap) {
@@ -1631,11 +1625,15 @@ void test_double_double(va_list *ap) {
// GPR64N32-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 1
// GPR64N32-NEXT: store fp128 [[X_REAL]], ptr [[COERCE_REALP]], align 16
// GPR64N32-NEXT: store fp128 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 16
-// GPR64N32-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N32-NEXT: [[TMP3:%.*]] = load fp128, ptr [[TMP2]], align 16
-// GPR64N32-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N32-NEXT: [[TMP5:%.*]] = load fp128, ptr [[TMP4]], align 16
-// GPR64N32-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 undef, fp128 inreg noundef [[TMP3]], fp128 inreg noundef [[TMP5]])
+// GPR64N32-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N32-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 16
+// GPR64N32-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 1
+// GPR64N32-NEXT: [[TMP5:%.*]] = load i64, ptr [[TMP4]], align 8
+// GPR64N32-NEXT: [[TMP6:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 2
+// GPR64N32-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 16
+// GPR64N32-NEXT: [[TMP8:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 3
+// GPR64N32-NEXT: [[TMP9:%.*]] = load i64, ptr [[TMP8]], align 8
+// GPR64N32-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 undef, i64 inreg noundef [[TMP3]], i64 inreg noundef [[TMP5]], i64 inreg noundef [[TMP7]], i64 inreg noundef [[TMP9]])
// GPR64N32-NEXT: ret void
//
// GPR64N64BE-LABEL: define dso_local void @test_complex_long_double(
@@ -1667,11 +1665,15 @@ void test_double_double(va_list *ap) {
// GPR64N64BE-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 1
// GPR64N64BE-NEXT: store fp128 [[X_REAL]], ptr [[COERCE_REALP]], align 16
// GPR64N64BE-NEXT: store fp128 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 16
-// GPR64N64BE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N64BE-NEXT: [[TMP3:%.*]] = load fp128, ptr [[TMP2]], align 16
-// GPR64N64BE-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N64BE-NEXT: [[TMP5:%.*]] = load fp128, ptr [[TMP4]], align 16
-// GPR64N64BE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 undef, fp128 inreg noundef [[TMP3]], fp128 inreg noundef [[TMP5]])
+// GPR64N64BE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N64BE-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 16
+// GPR64N64BE-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 1
+// GPR64N64BE-NEXT: [[TMP5:%.*]] = load i64, ptr [[TMP4]], align 8
+// GPR64N64BE-NEXT: [[TMP6:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 2
+// GPR64N64BE-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 16
+// GPR64N64BE-NEXT: [[TMP8:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 3
+// GPR64N64BE-NEXT: [[TMP9:%.*]] = load i64, ptr [[TMP8]], align 8
+// GPR64N64BE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 undef, i64 inreg noundef [[TMP3]], i64 inreg noundef [[TMP5]], i64 inreg noundef [[TMP7]], i64 inreg noundef [[TMP9]])
// GPR64N64BE-NEXT: ret void
//
// GPR64N64LE-LABEL: define dso_local void @test_complex_long_double(
@@ -1703,11 +1705,15 @@ void test_double_double(va_list *ap) {
// GPR64N64LE-NEXT: [[COERCE_IMAGP:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 1
// GPR64N64LE-NEXT: store fp128 [[X_REAL]], ptr [[COERCE_REALP]], align 16
// GPR64N64LE-NEXT: store fp128 [[X_IMAG]], ptr [[COERCE_IMAGP]], align 16
-// GPR64N64LE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 0
-// GPR64N64LE-NEXT: [[TMP3:%.*]] = load fp128, ptr [[TMP2]], align 16
-// GPR64N64LE-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw { fp128, fp128 }, ptr [[COERCE]], i32 0, i32 1
-// GPR64N64LE-NEXT: [[TMP5:%.*]] = load fp128, ptr [[TMP4]], align 16
-// GPR64N64LE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 undef, fp128 inreg noundef [[TMP3]], fp128 inreg noundef [[TMP5]])
+// GPR64N64LE-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 0
+// GPR64N64LE-NEXT: [[TMP3:%.*]] = load i64, ptr [[TMP2]], align 16
+// GPR64N64LE-NEXT: [[TMP4:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 1
+// GPR64N64LE-NEXT: [[TMP5:%.*]] = load i64, ptr [[TMP4]], align 8
+// GPR64N64LE-NEXT: [[TMP6:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 2
+// GPR64N64LE-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 16
+// GPR64N64LE-NEXT: [[TMP8:%.*]] = getelementptr inbounds nuw { i64, i64, i64, i64 }, ptr [[COERCE]], i32 0, i32 3
+// GPR64N64LE-NEXT: [[TMP9:%.*]] = load i64, ptr [[TMP8]], align 8
+// GPR64N64LE-NEXT: call void (i32, ...) @sink(i32 noundef signext 0, i64 undef, i64 inreg noundef [[TMP3]], i64 inreg noundef [[TMP5]], i64 inreg noundef [[TMP7]], i64 inreg noundef [[TMP9]])
// GPR64N64LE-NEXT: ret void
//
void test_complex_long_double(va_list *ap) {
More information about the cfe-commits
mailing list