https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/170580
Backport 3e16aef2a650a8c2da4ebd5c58c6a9e261361828 3d598c33350a6691807441666f9c5014c18aff39 Requested by: @brad0 >From 2fa6c5b27795693cc45821fa19d0804cdf91e4bc Mon Sep 17 00:00:00 2001 From: Koakuma <[email protected]> Date: Sat, 29 Nov 2025 21:30:39 +0700 Subject: [PATCH 1/2] [SPARC] Properly handle CC for long double on sparc32 (#162226) Pass and return `long double`s indirectly, as specified in the psABI. This continues the patch at https://reviews.llvm.org/D89130. This should fix the issue at https://github.com/llvm/llvm-project/issues/41838. (cherry picked from commit 3e16aef2a650a8c2da4ebd5c58c6a9e261361828) --- clang/lib/Basic/Targets/Sparc.cpp | 1 + clang/lib/Basic/Targets/Sparc.h | 7 + clang/lib/CodeGen/Targets/Sparc.cpp | 34 ++- clang/test/CodeGen/sparcv8-abi.c | 36 +++- clang/test/Preprocessor/init.c | 22 +- .../Preprocessor/predefined-arch-macros.c | 5 + compiler-rt/lib/builtins/CMakeLists.txt | 5 +- compiler-rt/test/builtins/CMakeLists.txt | 3 +- .../sanitizer_common/TestCases/printf-ldbl.c | 3 - .../sanitizer_common/TestCases/scanf-ldbl.c | 3 - .../ubsan/TestCases/Float/cast-overflow.cpp | 3 - .../ubsan/TestCases/Misc/log-path_test.cpp | 3 - llvm/lib/Target/Sparc/SparcCallingConv.td | 9 +- llvm/lib/Target/Sparc/SparcISelLowering.cpp | 177 ++++++++++------ llvm/test/CodeGen/SPARC/fp128-abi.ll | 89 ++++++++ llvm/test/CodeGen/SPARC/fp16-promote.ll | 21 +- llvm/test/CodeGen/SPARC/llvm.sincos.ll | 195 ++++++++---------- 17 files changed, 402 insertions(+), 214 deletions(-) create mode 100644 llvm/test/CodeGen/SPARC/fp128-abi.ll diff --git a/clang/lib/Basic/Targets/Sparc.cpp b/clang/lib/Basic/Targets/Sparc.cpp index d1a891092b0f5..2dcf31fc5591d 100644 --- a/clang/lib/Basic/Targets/Sparc.cpp +++ b/clang/lib/Basic/Targets/Sparc.cpp @@ -160,6 +160,7 @@ void SparcV8TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } + Builder.defineMacro("__LONG_DOUBLE_128__"); } void SparcV9TargetInfo::getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h index 3215e648ba6c3..acc27194c38ea 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -166,6 +166,13 @@ class LLVM_LIBRARY_VISIBILITY SparcV8TargetInfo : public SparcTargetInfo { PtrDiffType = SignedLong; break; } + + // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit + // aligned. + LongDoubleWidth = 128; + LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + // Up to 32 bits (V8) or 64 bits (V9) are lock-free atomic, but we're // willing to do atomic ops on up to 64 bits. MaxAtomicPromoteWidth = 64; diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index 0461f121d76c9..7f20c10338c52 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -26,23 +26,39 @@ class SparcV8ABIInfo : public DefaultABIInfo { private: ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override; }; } // end anonymous namespace +ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { + const auto *CT = Ty->getAs<ComplexType>(); + const auto *BT = Ty->getAs<BuiltinType>(); + if (CT) + BT = CT->getElementType()->getAs<BuiltinType>(); + bool IsLongDouble = BT && BT->getKind() == BuiltinType::LongDouble; -ABIArgInfo -SparcV8ABIInfo::classifyReturnType(QualType Ty) const { - if (Ty->isAnyComplexType()) { - return ABIArgInfo::getDirect(); - } - else { - return DefaultABIInfo::classifyReturnType(Ty); - } + // long double _Complex is special in that it should be marked as inreg. + if (CT) + return IsLongDouble ? ABIArgInfo::getDirectInReg() + : ABIArgInfo::getDirect(); + + if (IsLongDouble) + return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), + /*ByVal=*/false); + + return DefaultABIInfo::classifyReturnType(Ty); } -void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const { +ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const { + if (const auto *BT = Ty->getAs<BuiltinType>(); + BT && BT->getKind() == BuiltinType::LongDouble) + return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace()); + return DefaultABIInfo::classifyArgumentType(Ty); +} + +void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &Arg : FI.arguments()) Arg.info = classifyArgumentType(Arg.type); diff --git a/clang/test/CodeGen/sparcv8-abi.c b/clang/test/CodeGen/sparcv8-abi.c index c5faf130890f8..7beddd20e5e4d 100644 --- a/clang/test/CodeGen/sparcv8-abi.c +++ b/clang/test/CodeGen/sparcv8-abi.c @@ -1,22 +1,52 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "^define |^entry:" --version 6 // RUN: %clang_cc1 -triple sparc-unknown-unknown -emit-llvm %s -o - | FileCheck %s -// CHECK-LABEL: define{{.*}} { float, float } @p(ptr noundef byval({ float, float }) align 4 %a, ptr noundef byval({ float, float }) align 4 %b) #0 { float __complex__ +// CHECK-LABEL: define dso_local { float, float } @p( +// CHECK-SAME: ptr noundef byval({ float, float }) align 4 [[A:%.*]], ptr noundef byval({ float, float }) align 4 [[B:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK: [[ENTRY:.*:]] +// p (float __complex__ a, float __complex__ b) { return 0; } -// CHECK-LABEL: define{{.*}} { double, double } @q(ptr noundef byval({ double, double }) align 8 %a, ptr noundef byval({ double, double }) align 8 %b) #0 { double __complex__ +// CHECK-LABEL: define dso_local { double, double } @q( +// CHECK-SAME: ptr noundef byval({ double, double }) align 8 [[A:%.*]], ptr noundef byval({ double, double }) align 8 [[B:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// q (double __complex__ a, double __complex__ b) { return 0; } -// CHECK-LABEL: define{{.*}} { i64, i64 } @r(ptr noundef byval({ i64, i64 }) align 8 %a, ptr noundef byval({ i64, i64 }) align 8 %b) #0 { long long __complex__ +// CHECK-LABEL: define dso_local { i64, i64 } @r( +// CHECK-SAME: ptr noundef byval({ i64, i64 }) align 8 [[A:%.*]], ptr noundef byval({ i64, i64 }) align 8 [[B:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// r (long long __complex__ a, long long __complex__ b) { return 0; } + +long double +// CHECK-LABEL: define dso_local void @s( +// CHECK-SAME: ptr dead_on_unwind noalias writable sret(fp128) align 8 [[AGG_RESULT:%.*]], ptr noundef byval(fp128) align 8 [[TMP0:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +s(long double a) +{ + return 0; +} + +long double _Complex +// CHECK-LABEL: define dso_local inreg { fp128, fp128 } @t( +// CHECK-SAME: ptr noundef byval({ fp128, fp128 }) align 8 [[A:%.*]]) #[[ATTR0]] { +// CHECK: [[ENTRY:.*:]] +// +t(long double _Complex a) +{ + return 0; +} diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c index 7e0df96141364..3ef33de35f9ec 100644 --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -1106,19 +1106,19 @@ // SPARC:#define __INT_LEAST8_MAX__ 127 // SPARC:#define __INT_LEAST8_TYPE__ signed char // SPARC:#define __INT_MAX__ 2147483647 -// SPARC:#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L -// SPARC:#define __LDBL_DIG__ 15 -// SPARC:#define __LDBL_EPSILON__ 2.2204460492503131e-16L +// SPARC:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L +// SPARC:#define __LDBL_DIG__ 33 +// SPARC:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L // SPARC:#define __LDBL_HAS_DENORM__ 1 // SPARC:#define __LDBL_HAS_INFINITY__ 1 // SPARC:#define __LDBL_HAS_QUIET_NAN__ 1 -// SPARC:#define __LDBL_MANT_DIG__ 53 -// SPARC:#define __LDBL_MAX_10_EXP__ 308 -// SPARC:#define __LDBL_MAX_EXP__ 1024 -// SPARC:#define __LDBL_MAX__ 1.7976931348623157e+308L -// SPARC:#define __LDBL_MIN_10_EXP__ (-307) -// SPARC:#define __LDBL_MIN_EXP__ (-1021) -// SPARC:#define __LDBL_MIN__ 2.2250738585072014e-308L +// SPARC:#define __LDBL_MANT_DIG__ 113 +// SPARC:#define __LDBL_MAX_10_EXP__ 4932 +// SPARC:#define __LDBL_MAX_EXP__ 16384 +// SPARC:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L +// SPARC:#define __LDBL_MIN_10_EXP__ (-4931) +// SPARC:#define __LDBL_MIN_EXP__ (-16381) +// SPARC:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L // SPARC:#define __LONG_LONG_MAX__ 9223372036854775807LL // SPARC:#define __LONG_MAX__ 2147483647L // SPARC-NOT:#define __LP64__ @@ -1134,7 +1134,7 @@ // SPARC:#define __SIZEOF_DOUBLE__ 8 // SPARC:#define __SIZEOF_FLOAT__ 4 // SPARC:#define __SIZEOF_INT__ 4 -// SPARC:#define __SIZEOF_LONG_DOUBLE__ 8 +// SPARC:#define __SIZEOF_LONG_DOUBLE__ 16 // SPARC:#define __SIZEOF_LONG_LONG__ 8 // SPARC:#define __SIZEOF_LONG__ 4 // SPARC:#define __SIZEOF_POINTER__ 4 diff --git a/clang/test/Preprocessor/predefined-arch-macros.c b/clang/test/Preprocessor/predefined-arch-macros.c index e82d825704439..0fd927a02fcb7 100644 --- a/clang/test/Preprocessor/predefined-arch-macros.c +++ b/clang/test/Preprocessor/predefined-arch-macros.c @@ -4206,6 +4206,11 @@ // CHECK_SPARC-NOT: #define __sparcv9 1 // CHECK_SPARC-NOT: #define __sparcv9__ 1 +// RUN: %clang -E -dM %s -o - 2>&1 \ +// RUN: -target sparc-unknown-linux \ +// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SPARC_LDBL +// CHECK_SPARC_LDBL: #define __LONG_DOUBLE_128__ 1 + // RUN: %clang -mcpu=v9 -E -dM %s -o - 2>&1 \ // RUN: -target sparc-unknown-linux \ // RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SPARC-V9 diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 3ab92403d4168..b43d9aff45c48 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -948,9 +948,10 @@ else () list(APPEND BUILTIN_CFLAGS_${arch} -fomit-frame-pointer -DCOMPILER_RT_ARMHF_TARGET) endif() - # For RISCV32, we must force enable int128 for compiling long + # For RISCV32 and 32-bit SPARC, we must force enable int128 for compiling long # double routines. - if(COMPILER_RT_ENABLE_SOFTWARE_INT128 OR "${arch}" STREQUAL "riscv32") + if (COMPILER_RT_ENABLE_SOFTWARE_INT128 OR ("${arch}" MATCHES "riscv32|sparc$" + AND NOT CMAKE_COMPILER_IS_GNUCC)) list(APPEND BUILTIN_CFLAGS_${arch} -fforce-enable-int128) endif() diff --git a/compiler-rt/test/builtins/CMakeLists.txt b/compiler-rt/test/builtins/CMakeLists.txt index 63f4c94605c90..270624fdf6ecd 100644 --- a/compiler-rt/test/builtins/CMakeLists.txt +++ b/compiler-rt/test/builtins/CMakeLists.txt @@ -44,7 +44,8 @@ foreach(arch ${BUILTIN_TEST_ARCH}) string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}") endif() - if (COMPILER_RT_ENABLE_SOFTWARE_INT128 OR ${arch} STREQUAL "riscv32") + if (COMPILER_RT_ENABLE_SOFTWARE_INT128 OR ("${arch}" MATCHES "riscv32|sparc$" + AND NOT CMAKE_COMPILER_IS_GNUCC)) list(APPEND BUILTINS_TEST_TARGET_CFLAGS -fforce-enable-int128) string(REPLACE ";" " " BUILTINS_TEST_TARGET_CFLAGS "${BUILTINS_TEST_TARGET_CFLAGS}") endif() diff --git a/compiler-rt/test/sanitizer_common/TestCases/printf-ldbl.c b/compiler-rt/test/sanitizer_common/TestCases/printf-ldbl.c index cfe8d800d3834..f6629ab81c3b3 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/printf-ldbl.c +++ b/compiler-rt/test/sanitizer_common/TestCases/printf-ldbl.c @@ -1,8 +1,5 @@ // RUN: %clang %s -o %t && %run %t 2>&1 -// Issue #41838 -// XFAIL: sparc-target-arch && target={{.*solaris.*}} - #include <assert.h> #include <stdio.h> #include <string.h> diff --git a/compiler-rt/test/sanitizer_common/TestCases/scanf-ldbl.c b/compiler-rt/test/sanitizer_common/TestCases/scanf-ldbl.c index a38f34a245fae..9ca30f4a65688 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/scanf-ldbl.c +++ b/compiler-rt/test/sanitizer_common/TestCases/scanf-ldbl.c @@ -1,8 +1,5 @@ // RUN: %clang %s -o %t && %run %t 2>&1 -// Issue #41838 -// XFAIL: sparc-target-arch && target={{.*solaris.*}} - #include <assert.h> #include <stdio.h> #include <string.h> diff --git a/compiler-rt/test/ubsan/TestCases/Float/cast-overflow.cpp b/compiler-rt/test/ubsan/TestCases/Float/cast-overflow.cpp index 8638bf69f749e..80063b7a0f9f9 100644 --- a/compiler-rt/test/ubsan/TestCases/Float/cast-overflow.cpp +++ b/compiler-rt/test/ubsan/TestCases/Float/cast-overflow.cpp @@ -9,9 +9,6 @@ // RUN: %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6 // RUN: %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7 -// Issue #41838 -// XFAIL: sparc-target-arch && target={{.*solaris.*}} - // This test assumes float and double are IEEE-754 single- and double-precision. #if defined(__APPLE__) diff --git a/compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp b/compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp index ffd95a5f9c0bb..3edb296d90556 100644 --- a/compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp +++ b/compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp @@ -25,9 +25,6 @@ // FIXME: log_path is not supported on Windows yet. // XFAIL: target={{.*windows-msvc.*}} -// Issue #41838 -// XFAIL: sparc-target-arch && target={{.*solaris.*}} - #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td b/llvm/lib/Target/Sparc/SparcCallingConv.td index 8afd0a7fc09ad..d9c50483a029c 100644 --- a/llvm/lib/Target/Sparc/SparcCallingConv.td +++ b/llvm/lib/Target/Sparc/SparcCallingConv.td @@ -17,6 +17,9 @@ def CC_Sparc32 : CallingConv<[ // Custom assign SRet to [sp+64]. CCIfSRet<CCCustom<"CC_Sparc_Assign_SRet">>, + // f128 arguments are passed indirectly, using i32 pointers. + // FIXME GCC in soft-float mode passes f128 as if 2xi64 values. + CCIfType<[f128], CCPassIndirect<i32>>, // i32 f32 arguments get passed in integer registers if there is space. CCIfType<[i32, f32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>, // f64 arguments are split and passed through registers or through stack. @@ -24,20 +27,20 @@ def CC_Sparc32 : CallingConv<[ // As are v2i32 arguments (this would be the default behavior for // v2i32 if it wasn't allocated to the IntPair register-class) CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Split_64">>, - - // Alternatively, they are assigned to the stack in 4-byte aligned units. CCAssignToStack<4, 4> ]>; + def RetCC_Sparc32 : CallingConv<[ CCIfType<[i32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>, CCIfType<[f32], CCAssignToReg<[F0, F1, F2, F3]>>, CCIfType<[f64], CCAssignToReg<[D0, D1]>>, + // FIXME GCC in soft-float mode passes f128 as if 2xi64 values. + CCIfType<[f128], CCIfInReg<CCIfConsecutiveRegs<CCAssignToReg<[Q0, Q1]>>>>, CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Ret_Split_64">> ]>; - //===----------------------------------------------------------------------===// // SPARC v9 64-bit. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 57e7ff3a52cec..0ce29010f688e 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -439,6 +439,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_32( MachineFunction &MF = DAG.getMachineFunction(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>(); + EVT PtrVT = getPointerTy(DAG.getDataLayout()); // Assign locations to all of the incoming arguments. SmallVector<CCValAssign, 16> ArgLocs; @@ -452,6 +453,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_32( unsigned InIdx = 0; for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i, ++InIdx) { CCValAssign &VA = ArgLocs[i]; + EVT LocVT = VA.getLocVT(); if (Ins[InIdx].Flags.isSRet()) { if (InIdx != 0) @@ -465,6 +467,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_32( continue; } + SDValue Arg; if (VA.isRegLoc()) { if (VA.needsCustom()) { assert(VA.getLocVT() == MVT::f64 || VA.getLocVT() == MVT::v2i32); @@ -499,76 +502,85 @@ SDValue SparcTargetLowering::LowerFormalArguments_32( } Register VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass); MF.getRegInfo().addLiveIn(VA.getLocReg(), VReg); - SDValue Arg = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); - if (VA.getLocVT() == MVT::f32) - Arg = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Arg); - else if (VA.getLocVT() != MVT::i32) { - Arg = DAG.getNode(ISD::AssertSext, dl, MVT::i32, Arg, - DAG.getValueType(VA.getLocVT())); - Arg = DAG.getNode(ISD::TRUNCATE, dl, VA.getLocVT(), Arg); + Arg = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); + if (VA.getLocInfo() != CCValAssign::Indirect) { + if (VA.getLocVT() == MVT::f32) + Arg = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Arg); + else if (VA.getLocVT() != MVT::i32) { + Arg = DAG.getNode(ISD::AssertSext, dl, MVT::i32, Arg, + DAG.getValueType(VA.getLocVT())); + Arg = DAG.getNode(ISD::TRUNCATE, dl, VA.getLocVT(), Arg); + } + InVals.push_back(Arg); + continue; } - InVals.push_back(Arg); - continue; - } + } else { + assert(VA.isMemLoc()); - assert(VA.isMemLoc()); + unsigned Offset = VA.getLocMemOffset() + StackOffset; - unsigned Offset = VA.getLocMemOffset()+StackOffset; - auto PtrVT = getPointerTy(DAG.getDataLayout()); + if (VA.needsCustom()) { + assert(VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::v2i32); + // If it is double-word aligned, just load. + if (Offset % 8 == 0) { + int FI = MF.getFrameInfo().CreateFixedObject(8, Offset, true); + SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); + SDValue Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, + MachinePointerInfo()); + InVals.push_back(Load); + continue; + } - if (VA.needsCustom()) { - assert(VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::v2i32); - // If it is double-word aligned, just load. - if (Offset % 8 == 0) { - int FI = MF.getFrameInfo().CreateFixedObject(8, - Offset, - true); + int FI = MF.getFrameInfo().CreateFixedObject(4, Offset, true); SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); - SDValue Load = - DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo()); - InVals.push_back(Load); - continue; - } + SDValue HiVal = + DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo()); + int FI2 = MF.getFrameInfo().CreateFixedObject(4, Offset + 4, true); + SDValue FIPtr2 = DAG.getFrameIndex(FI2, PtrVT); - int FI = MF.getFrameInfo().CreateFixedObject(4, - Offset, - true); - SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); - SDValue HiVal = - DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo()); - int FI2 = MF.getFrameInfo().CreateFixedObject(4, - Offset+4, - true); - SDValue FIPtr2 = DAG.getFrameIndex(FI2, PtrVT); + SDValue LoVal = + DAG.getLoad(MVT::i32, dl, Chain, FIPtr2, MachinePointerInfo()); - SDValue LoVal = - DAG.getLoad(MVT::i32, dl, Chain, FIPtr2, MachinePointerInfo()); + if (IsLittleEndian) + std::swap(LoVal, HiVal); - if (IsLittleEndian) - std::swap(LoVal, HiVal); + SDValue WholeValue = + DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal); + WholeValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), WholeValue); + InVals.push_back(WholeValue); + continue; + } - SDValue WholeValue = - DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal); - WholeValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), WholeValue); - InVals.push_back(WholeValue); - continue; + int FI = MF.getFrameInfo().CreateFixedObject(LocVT.getSizeInBits() / 8, + Offset, true); + SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); + SDValue Load = DAG.getLoad(LocVT, dl, Chain, FIPtr, + MachinePointerInfo::getFixedStack(MF, FI)); + if (VA.getLocInfo() != CCValAssign::Indirect) { + InVals.push_back(Load); + continue; + } + Arg = Load; } - int FI = MF.getFrameInfo().CreateFixedObject(4, - Offset, - true); - SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); - SDValue Load ; - if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) { - Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo()); - } else if (VA.getValVT() == MVT::f128) { - report_fatal_error("SPARCv8 does not handle f128 in calls; " - "pass indirectly"); - } else { - // We shouldn't see any other value types here. - llvm_unreachable("Unexpected ValVT encountered in frame lowering."); + assert(VA.getLocInfo() == CCValAssign::Indirect); + + SDValue ArgValue = + DAG.getLoad(VA.getValVT(), dl, Chain, Arg, MachinePointerInfo()); + InVals.push_back(ArgValue); + + unsigned ArgIndex = Ins[InIdx].OrigArgIndex; + assert(Ins[InIdx].PartOffset == 0); + while (i + 1 != e && Ins[InIdx + 1].OrigArgIndex == ArgIndex) { + CCValAssign &PartVA = ArgLocs[i + 1]; + unsigned PartOffset = Ins[InIdx + 1].PartOffset; + SDValue Address = DAG.getMemBasePlusOffset( + ArgValue, TypeSize::getFixed(PartOffset), dl); + InVals.push_back(DAG.getLoad(PartVA.getValVT(), dl, Chain, Address, + MachinePointerInfo())); + ++i; + ++InIdx; } - InVals.push_back(Load); } if (MF.getFunction().hasStructRetAttr()) { @@ -835,6 +847,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, CallingConv::ID CallConv = CLI.CallConv; bool isVarArg = CLI.IsVarArg; MachineFunction &MF = DAG.getMachineFunction(); + LLVMContext &Ctx = *DAG.getContext(); + EVT PtrVT = getPointerTy(MF.getDataLayout()); // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; @@ -913,7 +927,9 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, // Promote the value if needed. switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); - case CCValAssign::Full: break; + case CCValAssign::Full: + case CCValAssign::Indirect: + break; case CCValAssign::SExt: Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); break; @@ -1012,6 +1028,49 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, continue; } + if (VA.getLocInfo() == CCValAssign::Indirect) { + // Store the argument in a stack slot and pass its address. + unsigned ArgIndex = Outs[realArgIdx].OrigArgIndex; + assert(Outs[realArgIdx].PartOffset == 0); + + EVT SlotVT; + if (i + 1 != e && Outs[realArgIdx + 1].OrigArgIndex == ArgIndex) { + Type *OrigArgType = CLI.Args[ArgIndex].Ty; + EVT OrigArgVT = getValueType(MF.getDataLayout(), OrigArgType); + MVT PartVT = + getRegisterTypeForCallingConv(Ctx, CLI.CallConv, OrigArgVT); + unsigned N = + getNumRegistersForCallingConv(Ctx, CLI.CallConv, OrigArgVT); + SlotVT = EVT::getIntegerVT(Ctx, PartVT.getSizeInBits() * N); + } else { + SlotVT = Outs[realArgIdx].VT; + } + + SDValue SpillSlot = DAG.CreateStackTemporary(SlotVT); + int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex(); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Arg, SpillSlot, + MachinePointerInfo::getFixedStack(MF, FI))); + // If the original argument was split (e.g. f128), we need + // to store all parts of it here (and pass just one address). + while (i + 1 != e && Outs[realArgIdx + 1].OrigArgIndex == ArgIndex) { + SDValue PartValue = OutVals[realArgIdx + 1]; + unsigned PartOffset = Outs[realArgIdx + 1].PartOffset; + SDValue Address = DAG.getMemBasePlusOffset( + DAG.getFrameIndex(FI, PtrVT), TypeSize::getFixed(PartOffset), dl); + MemOpChains.push_back( + DAG.getStore(Chain, dl, PartValue, Address, + MachinePointerInfo::getFixedStack(MF, FI))); + assert((PartOffset + PartValue.getValueType().getStoreSize() <= + SlotVT.getStoreSize()) && + "Not enough space for argument part!"); + ++i; + ++realArgIdx; + } + + Arg = SpillSlot; + } + // Arguments that can be passed on register must be kept at // RegsToPass vector if (VA.isRegLoc()) { diff --git a/llvm/test/CodeGen/SPARC/fp128-abi.ll b/llvm/test/CodeGen/SPARC/fp128-abi.ll new file mode 100644 index 0000000000000..341e05d80e71e --- /dev/null +++ b/llvm/test/CodeGen/SPARC/fp128-abi.ll @@ -0,0 +1,89 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc < %s -mtriple=sparc | FileCheck %s --check-prefix=SPARC32 +; RUN: llc < %s -mtriple=sparcv9 | FileCheck %s --check-prefix=SPARC64 + +define fp128 @f128_direct(fp128 %num) nounwind { +; SPARC32-LABEL: f128_direct: +; SPARC32: ! %bb.0: +; SPARC32-NEXT: save %sp, -144, %sp +; SPARC32-NEXT: ldd [%i0], %f0 +; SPARC32-NEXT: ldd [%i0+8], %f4 +; SPARC32-NEXT: ld [%fp+64], %i0 +; SPARC32-NEXT: add %fp, -16, %i1 +; SPARC32-NEXT: st %i1, [%sp+64] +; SPARC32-NEXT: std %f4, [%fp+-40] +; SPARC32-NEXT: std %f0, [%fp+-48] +; SPARC32-NEXT: std %f4, [%fp+-24] +; SPARC32-NEXT: add %fp, -32, %o0 +; SPARC32-NEXT: add %fp, -48, %o1 +; SPARC32-NEXT: call f128_callee +; SPARC32-NEXT: std %f0, [%fp+-32] +; SPARC32-NEXT: unimp 16 +; SPARC32-NEXT: ldd [%fp+-8], %f0 +; SPARC32-NEXT: ldd [%fp+-16], %f4 +; SPARC32-NEXT: std %f0, [%i0+8] +; SPARC32-NEXT: std %f4, [%i0] +; SPARC32-NEXT: ret +; SPARC32-NEXT: restore +; +; SPARC64-LABEL: f128_direct: +; SPARC64: ! %bb.0: +; SPARC64-NEXT: save %sp, -176, %sp +; SPARC64-NEXT: fmovd %f0, %f4 +; SPARC64-NEXT: fmovd %f2, %f6 +; SPARC64-NEXT: call f128_callee +; SPARC64-NEXT: nop +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore + %ret = call fp128 @f128_callee(fp128 %num, fp128 %num) + ret fp128 %ret +} +declare fp128 @f128_callee(fp128 %a, fp128 %b) + +define fp128 @f128_direct_spill(i32 %o0, i32 %o1, i32 %o2, i32 %o3, i32 %o4, i32 %o5, i32 %ss0, fp128 %num) nounwind { +; SPARC32-LABEL: f128_direct_spill: +; SPARC32: ! %bb.0: +; SPARC32-NEXT: save %sp, -136, %sp +; SPARC32-NEXT: ld [%fp+96], %g2 +; SPARC32-NEXT: ldd [%g2], %f0 +; SPARC32-NEXT: ldd [%g2+8], %f4 +; SPARC32-NEXT: ld [%fp+64], %l0 +; SPARC32-NEXT: mov %i5, %o5 +; SPARC32-NEXT: mov %i4, %o4 +; SPARC32-NEXT: mov %i3, %o3 +; SPARC32-NEXT: mov %i2, %o2 +; SPARC32-NEXT: mov %i1, %o1 +; SPARC32-NEXT: mov %i0, %o0 +; SPARC32-NEXT: add %fp, -32, %i0 +; SPARC32-NEXT: st %i0, [%sp+92] +; SPARC32-NEXT: add %fp, -16, %i0 +; SPARC32-NEXT: st %i0, [%sp+64] +; SPARC32-NEXT: std %f4, [%fp+-24] +; SPARC32-NEXT: call f128_callee_spill +; SPARC32-NEXT: std %f0, [%fp+-32] +; SPARC32-NEXT: unimp 16 +; SPARC32-NEXT: ldd [%fp+-8], %f0 +; SPARC32-NEXT: ldd [%fp+-16], %f4 +; SPARC32-NEXT: std %f0, [%l0+8] +; SPARC32-NEXT: std %f4, [%l0] +; SPARC32-NEXT: ret +; SPARC32-NEXT: restore +; +; SPARC64-LABEL: f128_direct_spill: +; SPARC64: ! %bb.0: +; SPARC64-NEXT: save %sp, -192, %sp +; SPARC64-NEXT: fmovd %f16, %f12 +; SPARC64-NEXT: fmovd %f18, %f14 +; SPARC64-NEXT: mov %i5, %o5 +; SPARC64-NEXT: mov %i4, %o4 +; SPARC64-NEXT: mov %i3, %o3 +; SPARC64-NEXT: mov %i2, %o2 +; SPARC64-NEXT: mov %i1, %o1 +; SPARC64-NEXT: call f128_callee_spill +; SPARC64-NEXT: mov %i0, %o0 +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore + %ret = call fp128 @f128_callee_spill(i32 %o0, i32 %o1, i32 %o2, i32 %o3, i32 %o4, i32 %o5, fp128 %num) + ret fp128 %ret +} +declare fp128 @f128_callee_spill(i32 %o0, i32 %o1, i32 %o2, i32 %o3, i32 %o4, i32 %o5, fp128 %a) diff --git a/llvm/test/CodeGen/SPARC/fp16-promote.ll b/llvm/test/CodeGen/SPARC/fp16-promote.ll index efe67b04e8fb3..84d9eda1af0ee 100644 --- a/llvm/test/CodeGen/SPARC/fp16-promote.ll +++ b/llvm/test/CodeGen/SPARC/fp16-promote.ll @@ -268,19 +268,20 @@ define void @test_fptrunc_double(double %d, ptr %p) nounwind { define void @test_fptrunc_fp128(ptr %dp, ptr %p) nounwind { ; V8-OPT-LABEL: test_fptrunc_fp128: ; V8-OPT: ! %bb.0: -; V8-OPT-NEXT: save %sp, -104, %sp +; V8-OPT-NEXT: save %sp, -112, %sp ; V8-OPT-NEXT: ldd [%i0], %f0 ; V8-OPT-NEXT: ldd [%i0+8], %f4 -; V8-OPT-NEXT: std %f4, [%sp+100] +; V8-OPT-NEXT: std %f4, [%fp+-8] +; V8-OPT-NEXT: add %fp, -16, %o0 ; V8-OPT-NEXT: call __trunctfhf2 -; V8-OPT-NEXT: std %f0, [%sp+92] +; V8-OPT-NEXT: std %f0, [%fp+-16] ; V8-OPT-NEXT: sth %o0, [%i1] ; V8-OPT-NEXT: ret ; V8-OPT-NEXT: restore ; ; V8-UNOPT-LABEL: test_fptrunc_fp128: ; V8-UNOPT: ! %bb.0: -; V8-UNOPT-NEXT: save %sp, -104, %sp +; V8-UNOPT-NEXT: save %sp, -112, %sp ; V8-UNOPT-NEXT: ldd [%i0], %f4 ; V8-UNOPT-NEXT: ! implicit-def: $q0 ; V8-UNOPT-NEXT: fmovs %f4, %f0 @@ -290,22 +291,24 @@ define void @test_fptrunc_fp128(ptr %dp, ptr %p) nounwind { ; V8-UNOPT-NEXT: fmovs %f5, %f3 ; V8-UNOPT-NEXT: fmovs %f2, %f4 ; V8-UNOPT-NEXT: fmovs %f3, %f5 -; V8-UNOPT-NEXT: std %f4, [%sp+100] +; V8-UNOPT-NEXT: std %f4, [%fp+-8] ; V8-UNOPT-NEXT: ! kill: def $d0 killed $d0 killed $q0 +; V8-UNOPT-NEXT: std %f0, [%fp+-16] ; V8-UNOPT-NEXT: call __trunctfhf2 -; V8-UNOPT-NEXT: std %f0, [%sp+92] +; V8-UNOPT-NEXT: add %fp, -16, %o0 ; V8-UNOPT-NEXT: sth %o0, [%i1] ; V8-UNOPT-NEXT: ret ; V8-UNOPT-NEXT: restore ; ; V9-LABEL: test_fptrunc_fp128: ; V9: ! %bb.0: -; V9-NEXT: save %sp, -104, %sp +; V9-NEXT: save %sp, -112, %sp ; V9-NEXT: ldd [%i0], %f0 ; V9-NEXT: ldd [%i0+8], %f4 -; V9-NEXT: std %f4, [%sp+100] +; V9-NEXT: std %f4, [%fp+-8] +; V9-NEXT: add %fp, -16, %o0 ; V9-NEXT: call __trunctfhf2 -; V9-NEXT: std %f0, [%sp+92] +; V9-NEXT: std %f0, [%fp+-16] ; V9-NEXT: sth %o0, [%i1] ; V9-NEXT: ret ; V9-NEXT: restore diff --git a/llvm/test/CodeGen/SPARC/llvm.sincos.ll b/llvm/test/CodeGen/SPARC/llvm.sincos.ll index 87b9c8e7ba47b..d4bfe577e4dc4 100644 --- a/llvm/test/CodeGen/SPARC/llvm.sincos.ll +++ b/llvm/test/CodeGen/SPARC/llvm.sincos.ll @@ -904,42 +904,38 @@ define { <2 x double>, <2 x double> } @test_sincos_v2f64(<2 x double> %a) #0 { define void @test_sincos_f128(ptr sret({ fp128, fp128 }) %ret, ptr %in) #0 { ; SPARC32-LABEL: test_sincos_f128: ; SPARC32: ! %bb.0: -; SPARC32-NEXT: save %sp, -168, %sp +; SPARC32-NEXT: save %sp, -184, %sp ; SPARC32-NEXT: ld [%fp+64], %i1 ; SPARC32-NEXT: ldd [%i0], %f0 -; SPARC32-NEXT: std %f0, [%fp+-64] -; SPARC32-NEXT: std %f2, [%fp+-56] ! 16-byte Folded Spill +; SPARC32-NEXT: std %f0, [%fp+-88] +; SPARC32-NEXT: std %f2, [%fp+-80] ! 16-byte Folded Spill ; SPARC32-NEXT: ldd [%i0+8], %f4 -; SPARC32-NEXT: std %f4, [%fp+-48] ! 8-byte Folded Spill -; SPARC32-NEXT: add %fp, -32, %i0 +; SPARC32-NEXT: std %f4, [%fp+-72] ! 8-byte Folded Spill +; SPARC32-NEXT: add %fp, -48, %i0 ; SPARC32-NEXT: st %i0, [%sp+64] -; SPARC32-NEXT: std %f4, [%sp+100] +; SPARC32-NEXT: std %f4, [%fp+-56] +; SPARC32-NEXT: add %fp, -64, %o0 ; SPARC32-NEXT: call sinl -; SPARC32-NEXT: std %f0, [%sp+92] +; SPARC32-NEXT: std %f0, [%fp+-64] ; SPARC32-NEXT: unimp 16 ; SPARC32-NEXT: add %fp, -16, %i0 ; SPARC32-NEXT: st %i0, [%sp+64] -; SPARC32-NEXT: ldd [%fp+-48], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%sp+100] -; SPARC32-NEXT: ldd [%fp+-64], %f0 -; SPARC32-NEXT: ldd [%fp+-56], %f2 ! 16-byte Folded Reload -; SPARC32-NEXT: std %f0, [%sp+92] -; SPARC32-NEXT: ldd [%fp+-32], %f0 -; SPARC32-NEXT: std %f0, [%fp+-48] -; SPARC32-NEXT: std %f2, [%fp+-40] ! 16-byte Folded Spill -; SPARC32-NEXT: ldd [%fp+-24], %f0 +; SPARC32-NEXT: ldd [%fp+-72], %f0 ! 8-byte Folded Reload +; SPARC32-NEXT: std %f0, [%fp+-24] +; SPARC32-NEXT: add %fp, -32, %o0 +; SPARC32-NEXT: ldd [%fp+-88], %f0 +; SPARC32-NEXT: ldd [%fp+-80], %f2 ! 16-byte Folded Reload ; SPARC32-NEXT: call cosl -; SPARC32-NEXT: std %f0, [%fp+-64] +; SPARC32-NEXT: std %f0, [%fp+-32] ; SPARC32-NEXT: unimp 16 ; SPARC32-NEXT: ldd [%fp+-8], %f0 ; SPARC32-NEXT: ldd [%fp+-16], %f4 +; SPARC32-NEXT: ldd [%fp+-40], %f2 +; SPARC32-NEXT: ldd [%fp+-48], %f8 ; SPARC32-NEXT: std %f0, [%i1+24] ; SPARC32-NEXT: std %f4, [%i1+16] -; SPARC32-NEXT: ldd [%fp+-64], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%i1+8] -; SPARC32-NEXT: ldd [%fp+-48], %f0 -; SPARC32-NEXT: ldd [%fp+-40], %f2 ! 16-byte Folded Reload -; SPARC32-NEXT: std %f0, [%i1] +; SPARC32-NEXT: std %f2, [%i1+8] +; SPARC32-NEXT: std %f8, [%i1] ; SPARC32-NEXT: jmp %i7+12 ; SPARC32-NEXT: restore %g0, %i1, %o0 ; @@ -967,15 +963,16 @@ define void @test_sincos_f128(ptr sret({ fp128, fp128 }) %ret, ptr %in) #0 { ; ; GNU32-LABEL: test_sincos_f128: ; GNU32: ! %bb.0: -; GNU32-NEXT: save %sp, -136, %sp +; GNU32-NEXT: save %sp, -144, %sp ; GNU32-NEXT: ld [%fp+64], %i1 ; GNU32-NEXT: ldd [%i0], %f0 ; GNU32-NEXT: ldd [%i0+8], %f4 -; GNU32-NEXT: std %f4, [%sp+100] -; GNU32-NEXT: add %fp, -16, %o0 -; GNU32-NEXT: add %fp, -32, %o1 +; GNU32-NEXT: std %f4, [%fp+-40] +; GNU32-NEXT: add %fp, -48, %o0 +; GNU32-NEXT: add %fp, -16, %o1 +; GNU32-NEXT: add %fp, -32, %o2 ; GNU32-NEXT: call sincosl -; GNU32-NEXT: std %f0, [%sp+92] +; GNU32-NEXT: std %f0, [%fp+-48] ; GNU32-NEXT: ldd [%fp+-24], %f0 ; GNU32-NEXT: ldd [%fp+-32], %f4 ; GNU32-NEXT: ldd [%fp+-8], %f2 @@ -1018,85 +1015,71 @@ define void @test_sincos_f128(ptr sret({ fp128, fp128 }) %ret, ptr %in) #0 { define void @test_sincos_v2f128(ptr sret({ <2 x fp128>, <2 x fp128> }) %ret, ptr %in) #0 { ; SPARC32-LABEL: test_sincos_v2f128: ; SPARC32: ! %bb.0: -; SPARC32-NEXT: save %sp, -248, %sp +; SPARC32-NEXT: save %sp, -272, %sp ; SPARC32-NEXT: mov %i0, %i1 ; SPARC32-NEXT: ld [%fp+64], %i0 ; SPARC32-NEXT: ldd [%i1], %f0 -; SPARC32-NEXT: std %f0, [%fp+-80] -; SPARC32-NEXT: std %f2, [%fp+-72] ! 16-byte Folded Spill +; SPARC32-NEXT: std %f0, [%fp+-144] +; SPARC32-NEXT: std %f2, [%fp+-136] ! 16-byte Folded Spill ; SPARC32-NEXT: ldd [%i1+8], %f0 -; SPARC32-NEXT: std %f0, [%fp+-88] ! 8-byte Folded Spill +; SPARC32-NEXT: std %f0, [%fp+-152] ! 8-byte Folded Spill ; SPARC32-NEXT: ldd [%i1+16], %f0 -; SPARC32-NEXT: std %f0, [%fp+-120] -; SPARC32-NEXT: std %f2, [%fp+-112] ! 16-byte Folded Spill +; SPARC32-NEXT: std %f0, [%fp+-176] +; SPARC32-NEXT: std %f2, [%fp+-168] ! 16-byte Folded Spill ; SPARC32-NEXT: ldd [%i1+24], %f4 -; SPARC32-NEXT: std %f4, [%fp+-104] ! 8-byte Folded Spill -; SPARC32-NEXT: add %fp, -64, %i1 +; SPARC32-NEXT: std %f4, [%fp+-160] ! 8-byte Folded Spill +; SPARC32-NEXT: add %fp, -112, %i1 ; SPARC32-NEXT: st %i1, [%sp+64] -; SPARC32-NEXT: std %f4, [%sp+100] +; SPARC32-NEXT: std %f4, [%fp+-120] +; SPARC32-NEXT: add %fp, -128, %o0 ; SPARC32-NEXT: call sinl -; SPARC32-NEXT: std %f0, [%sp+92] +; SPARC32-NEXT: std %f0, [%fp+-128] ; SPARC32-NEXT: unimp 16 ; SPARC32-NEXT: add %fp, -16, %i1 ; SPARC32-NEXT: st %i1, [%sp+64] -; SPARC32-NEXT: ldd [%fp+-88], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%sp+100] -; SPARC32-NEXT: ldd [%fp+-80], %f0 -; SPARC32-NEXT: ldd [%fp+-72], %f2 ! 16-byte Folded Reload +; SPARC32-NEXT: ldd [%fp+-152], %f0 ! 8-byte Folded Reload +; SPARC32-NEXT: std %f0, [%fp+-24] +; SPARC32-NEXT: add %fp, -32, %o0 +; SPARC32-NEXT: ldd [%fp+-144], %f0 +; SPARC32-NEXT: ldd [%fp+-136], %f2 ! 16-byte Folded Reload ; SPARC32-NEXT: call cosl -; SPARC32-NEXT: std %f0, [%sp+92] +; SPARC32-NEXT: std %f0, [%fp+-32] ; SPARC32-NEXT: unimp 16 -; SPARC32-NEXT: add %fp, -32, %i1 +; SPARC32-NEXT: add %fp, -48, %i1 ; SPARC32-NEXT: st %i1, [%sp+64] -; SPARC32-NEXT: ldd [%fp+-88], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%sp+100] -; SPARC32-NEXT: ldd [%fp+-80], %f0 -; SPARC32-NEXT: ldd [%fp+-72], %f2 ! 16-byte Folded Reload +; SPARC32-NEXT: ldd [%fp+-152], %f0 ! 8-byte Folded Reload +; SPARC32-NEXT: std %f0, [%fp+-56] +; SPARC32-NEXT: add %fp, -64, %o0 +; SPARC32-NEXT: ldd [%fp+-144], %f0 +; SPARC32-NEXT: ldd [%fp+-136], %f2 ! 16-byte Folded Reload ; SPARC32-NEXT: call sinl -; SPARC32-NEXT: std %f0, [%sp+92] +; SPARC32-NEXT: std %f0, [%fp+-64] ; SPARC32-NEXT: unimp 16 -; SPARC32-NEXT: add %fp, -48, %i1 +; SPARC32-NEXT: add %fp, -80, %i1 ; SPARC32-NEXT: st %i1, [%sp+64] -; SPARC32-NEXT: ldd [%fp+-104], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%sp+100] -; SPARC32-NEXT: ldd [%fp+-120], %f0 -; SPARC32-NEXT: ldd [%fp+-112], %f2 ! 16-byte Folded Reload -; SPARC32-NEXT: std %f0, [%sp+92] -; SPARC32-NEXT: ldd [%fp+-32], %f0 -; SPARC32-NEXT: std %f0, [%fp+-80] -; SPARC32-NEXT: std %f2, [%fp+-72] ! 16-byte Folded Spill -; SPARC32-NEXT: ldd [%fp+-24], %f0 -; SPARC32-NEXT: std %f0, [%fp+-88] ! 8-byte Folded Spill -; SPARC32-NEXT: ldd [%fp+-64], %f0 -; SPARC32-NEXT: std %f0, [%fp+-104] -; SPARC32-NEXT: std %f2, [%fp+-96] ! 16-byte Folded Spill -; SPARC32-NEXT: ldd [%fp+-56], %f0 -; SPARC32-NEXT: std %f0, [%fp+-120] ! 8-byte Folded Spill -; SPARC32-NEXT: ldd [%fp+-16], %f0 -; SPARC32-NEXT: std %f0, [%fp+-136] -; SPARC32-NEXT: std %f2, [%fp+-128] ! 16-byte Folded Spill -; SPARC32-NEXT: ldd [%fp+-8], %f0 +; SPARC32-NEXT: ldd [%fp+-160], %f0 ! 8-byte Folded Reload +; SPARC32-NEXT: std %f0, [%fp+-88] +; SPARC32-NEXT: add %fp, -96, %o0 +; SPARC32-NEXT: ldd [%fp+-176], %f0 +; SPARC32-NEXT: ldd [%fp+-168], %f2 ! 16-byte Folded Reload ; SPARC32-NEXT: call cosl -; SPARC32-NEXT: std %f0, [%fp+-144] +; SPARC32-NEXT: std %f0, [%fp+-96] ; SPARC32-NEXT: unimp 16 -; SPARC32-NEXT: ldd [%fp+-40], %f0 -; SPARC32-NEXT: ldd [%fp+-48], %f4 -; SPARC32-NEXT: std %f0, [%i0+56] -; SPARC32-NEXT: std %f4, [%i0+48] -; SPARC32-NEXT: ldd [%fp+-144], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%i0+40] -; SPARC32-NEXT: ldd [%fp+-136], %f0 -; SPARC32-NEXT: ldd [%fp+-128], %f2 ! 16-byte Folded Reload -; SPARC32-NEXT: std %f0, [%i0+32] -; SPARC32-NEXT: ldd [%fp+-120], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%i0+24] -; SPARC32-NEXT: ldd [%fp+-104], %f0 -; SPARC32-NEXT: ldd [%fp+-96], %f2 ! 16-byte Folded Reload -; SPARC32-NEXT: std %f0, [%i0+16] -; SPARC32-NEXT: ldd [%fp+-88], %f0 ! 8-byte Folded Reload -; SPARC32-NEXT: std %f0, [%i0+8] -; SPARC32-NEXT: ldd [%fp+-80], %f0 -; SPARC32-NEXT: ldd [%fp+-72], %f2 ! 16-byte Folded Reload +; SPARC32-NEXT: ldd [%fp+-48], %f0 +; SPARC32-NEXT: ldd [%fp+-40], %f8 +; SPARC32-NEXT: ldd [%fp+-112], %f4 +; SPARC32-NEXT: ldd [%fp+-104], %f10 +; SPARC32-NEXT: ldd [%fp+-72], %f12 +; SPARC32-NEXT: ldd [%fp+-80], %f16 +; SPARC32-NEXT: ldd [%fp+-8], %f14 +; SPARC32-NEXT: ldd [%fp+-16], %f20 +; SPARC32-NEXT: std %f12, [%i0+56] +; SPARC32-NEXT: std %f16, [%i0+48] +; SPARC32-NEXT: std %f14, [%i0+40] +; SPARC32-NEXT: std %f20, [%i0+32] +; SPARC32-NEXT: std %f10, [%i0+24] +; SPARC32-NEXT: std %f4, [%i0+16] +; SPARC32-NEXT: std %f8, [%i0+8] ; SPARC32-NEXT: std %f0, [%i0] ; SPARC32-NEXT: jmp %i7+12 ; SPARC32-NEXT: restore @@ -1147,37 +1130,39 @@ define void @test_sincos_v2f128(ptr sret({ <2 x fp128>, <2 x fp128> }) %ret, ptr ; ; GNU32-LABEL: test_sincos_v2f128: ; GNU32: ! %bb.0: -; GNU32-NEXT: save %sp, -192, %sp +; GNU32-NEXT: save %sp, -216, %sp ; GNU32-NEXT: mov %i0, %i1 ; GNU32-NEXT: ld [%fp+64], %i0 ; GNU32-NEXT: ldd [%i1+16], %f0 -; GNU32-NEXT: std %f0, [%fp+-80] -; GNU32-NEXT: std %f2, [%fp+-72] ! 16-byte Folded Spill +; GNU32-NEXT: std %f0, [%fp+-112] +; GNU32-NEXT: std %f2, [%fp+-104] ! 16-byte Folded Spill ; GNU32-NEXT: ldd [%i1+24], %f0 -; GNU32-NEXT: std %f0, [%fp+-88] ! 8-byte Folded Spill +; GNU32-NEXT: std %f0, [%fp+-120] ! 8-byte Folded Spill ; GNU32-NEXT: ldd [%i1], %f0 ; GNU32-NEXT: ldd [%i1+8], %f4 -; GNU32-NEXT: std %f4, [%sp+100] -; GNU32-NEXT: add %fp, -48, %o0 +; GNU32-NEXT: std %f4, [%fp+-88] +; GNU32-NEXT: add %fp, -96, %o0 ; GNU32-NEXT: add %fp, -64, %o1 +; GNU32-NEXT: add %fp, -80, %o2 ; GNU32-NEXT: call sincosl -; GNU32-NEXT: std %f0, [%sp+92] -; GNU32-NEXT: ldd [%fp+-88], %f0 ! 8-byte Folded Reload -; GNU32-NEXT: std %f0, [%sp+100] -; GNU32-NEXT: add %fp, -16, %o0 -; GNU32-NEXT: add %fp, -32, %o1 -; GNU32-NEXT: ldd [%fp+-80], %f0 -; GNU32-NEXT: ldd [%fp+-72], %f2 ! 16-byte Folded Reload +; GNU32-NEXT: std %f0, [%fp+-96] +; GNU32-NEXT: ldd [%fp+-120], %f0 ! 8-byte Folded Reload +; GNU32-NEXT: std %f0, [%fp+-40] +; GNU32-NEXT: add %fp, -48, %o0 +; GNU32-NEXT: add %fp, -16, %o1 +; GNU32-NEXT: add %fp, -32, %o2 +; GNU32-NEXT: ldd [%fp+-112], %f0 +; GNU32-NEXT: ldd [%fp+-104], %f2 ! 16-byte Folded Reload ; GNU32-NEXT: call sincosl -; GNU32-NEXT: std %f0, [%sp+92] -; GNU32-NEXT: ldd [%fp+-48], %f0 -; GNU32-NEXT: ldd [%fp+-40], %f8 +; GNU32-NEXT: std %f0, [%fp+-48] +; GNU32-NEXT: ldd [%fp+-64], %f0 +; GNU32-NEXT: ldd [%fp+-56], %f8 ; GNU32-NEXT: ldd [%fp+-16], %f4 ; GNU32-NEXT: ldd [%fp+-8], %f10 ; GNU32-NEXT: ldd [%fp+-24], %f12 ; GNU32-NEXT: ldd [%fp+-32], %f16 -; GNU32-NEXT: ldd [%fp+-56], %f14 -; GNU32-NEXT: ldd [%fp+-64], %f20 +; GNU32-NEXT: ldd [%fp+-72], %f14 +; GNU32-NEXT: ldd [%fp+-80], %f20 ; GNU32-NEXT: std %f12, [%i0+56] ; GNU32-NEXT: std %f16, [%i0+48] ; GNU32-NEXT: std %f14, [%i0+40] >From 04a8c1fba538ebfe46719e8ac2c07408df1fa2a2 Mon Sep 17 00:00:00 2001 From: Koakuma <[email protected]> Date: Thu, 4 Dec 2025 03:38:48 +0700 Subject: [PATCH 2/2] [SPARC] Remove CCIfConsecutiveRegs for f128 returns (#170133) It appears that using it will result in callers mistakenly thinking that complex f128 returns is done the sret-way, when it should be returned in registers. (cherry picked from commit 3d598c33350a6691807441666f9c5014c18aff39) --- llvm/lib/Target/Sparc/SparcCallingConv.td | 2 +- llvm/test/CodeGen/SPARC/fp128-abi.ll | 75 +++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td b/llvm/lib/Target/Sparc/SparcCallingConv.td index d9c50483a029c..6214000ddce5b 100644 --- a/llvm/lib/Target/Sparc/SparcCallingConv.td +++ b/llvm/lib/Target/Sparc/SparcCallingConv.td @@ -37,7 +37,7 @@ def RetCC_Sparc32 : CallingConv<[ CCIfType<[f32], CCAssignToReg<[F0, F1, F2, F3]>>, CCIfType<[f64], CCAssignToReg<[D0, D1]>>, // FIXME GCC in soft-float mode passes f128 as if 2xi64 values. - CCIfType<[f128], CCIfInReg<CCIfConsecutiveRegs<CCAssignToReg<[Q0, Q1]>>>>, + CCIfType<[f128], CCIfInReg<CCAssignToReg<[Q0, Q1]>>>, CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Ret_Split_64">> ]>; diff --git a/llvm/test/CodeGen/SPARC/fp128-abi.ll b/llvm/test/CodeGen/SPARC/fp128-abi.ll index 341e05d80e71e..b598d1b004832 100644 --- a/llvm/test/CodeGen/SPARC/fp128-abi.ll +++ b/llvm/test/CodeGen/SPARC/fp128-abi.ll @@ -87,3 +87,78 @@ define fp128 @f128_direct_spill(i32 %o0, i32 %o1, i32 %o2, i32 %o3, i32 %o4, i32 ret fp128 %ret } declare fp128 @f128_callee_spill(i32 %o0, i32 %o1, i32 %o2, i32 %o3, i32 %o4, i32 %o5, fp128 %a) + +define inreg { fp128, fp128 } @f128_complex(fp128 %num) nounwind { +; SPARC32-LABEL: f128_complex: +; SPARC32: ! %bb.0: +; SPARC32-NEXT: save %sp, -192, %sp +; SPARC32-NEXT: ldd [%i0], %f0 +; SPARC32-NEXT: ldd [%i0+8], %f4 +; SPARC32-NEXT: std %f4, [%fp+-24] +; SPARC32-NEXT: std %f0, [%fp+-32] +; SPARC32-NEXT: std %f4, [%fp+-8] +; SPARC32-NEXT: add %fp, -16, %o0 +; SPARC32-NEXT: add %fp, -32, %o1 +; SPARC32-NEXT: call f128_complex_callee +; SPARC32-NEXT: std %f0, [%fp+-16] +; SPARC32-NEXT: sethi %hi(.LCPI2_0), %i0 +; SPARC32-NEXT: ldd [%i0+%lo(.LCPI2_0)], %f8 +; SPARC32-NEXT: add %i0, %lo(.LCPI2_0), %i0 +; SPARC32-NEXT: ldd [%i0+8], %f12 +; SPARC32-NEXT: std %f4, [%fp+-96] +; SPARC32-NEXT: std %f6, [%fp+-88] ! 16-byte Folded Spill +; SPARC32-NEXT: std %f8, [%fp+-80] +; SPARC32-NEXT: std %f12, [%fp+-72] +; SPARC32-NEXT: std %f2, [%fp+-56] +; SPARC32-NEXT: std %f0, [%fp+-64] +; SPARC32-NEXT: add %fp, -48, %i0 +; SPARC32-NEXT: add %fp, -64, %o0 +; SPARC32-NEXT: add %fp, -80, %o1 +; SPARC32-NEXT: call _Q_add +; SPARC32-NEXT: st %i0, [%sp+64] +; SPARC32-NEXT: unimp 16 +; SPARC32-NEXT: ldd [%fp+-48], %f0 +; SPARC32-NEXT: ldd [%fp+-40], %f2 +; SPARC32-NEXT: ldd [%fp+-96], %f4 +; SPARC32-NEXT: ldd [%fp+-88], %f6 ! 16-byte Folded Reload +; SPARC32-NEXT: ret +; SPARC32-NEXT: restore +; +; SPARC64-LABEL: f128_complex: +; SPARC64: ! %bb.0: +; SPARC64-NEXT: save %sp, -240, %sp +; SPARC64-NEXT: fmovd %f0, %f4 +; SPARC64-NEXT: fmovd %f2, %f6 +; SPARC64-NEXT: call f128_complex_callee +; SPARC64-NEXT: nop +; SPARC64-NEXT: std %f4, [%fp+1983] +; SPARC64-NEXT: std %f6, [%fp+1991] ! 16-byte Folded Spill +; SPARC64-NEXT: sethi %h44(.LCPI2_0), %i0 +; SPARC64-NEXT: add %i0, %m44(.LCPI2_0), %i0 +; SPARC64-NEXT: sllx %i0, 12, %i0 +; SPARC64-NEXT: ldd [%i0+%l44(.LCPI2_0)], %f4 +; SPARC64-NEXT: add %i0, %l44(.LCPI2_0), %i0 +; SPARC64-NEXT: ldd [%i0+8], %f8 +; SPARC64-NEXT: std %f2, [%fp+2023] +; SPARC64-NEXT: std %f0, [%fp+2015] +; SPARC64-NEXT: std %f4, [%fp+1999] +; SPARC64-NEXT: std %f8, [%fp+2007] +; SPARC64-NEXT: add %fp, 2031, %o0 +; SPARC64-NEXT: add %fp, 2015, %o1 +; SPARC64-NEXT: call _Qp_add +; SPARC64-NEXT: add %fp, 1999, %o2 +; SPARC64-NEXT: ldd [%fp+2031], %f0 +; SPARC64-NEXT: ldd [%fp+2039], %f2 +; SPARC64-NEXT: ldd [%fp+1983], %f4 +; SPARC64-NEXT: ldd [%fp+1991], %f6 ! 16-byte Folded Reload +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore + %call = call inreg { fp128, fp128 } @f128_complex_callee(fp128 %num, fp128 %num) + %real = extractvalue { fp128, fp128 } %call, 0 + %imag = extractvalue { fp128, fp128 } %call, 1 + %add = fadd fp128 %real, 0xL00000000000000003FFF000000000000 + %tmp = insertvalue { fp128, fp128 } poison, fp128 %add, 0 + %ret = insertvalue { fp128, fp128 } %tmp, fp128 %imag, 1 + ret { fp128, fp128 } %ret +} +declare inreg { fp128, fp128 } @f128_complex_callee(fp128 %a, fp128 %b) _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
