https://github.com/koachan updated 
https://github.com/llvm/llvm-project/pull/162226

>From ff3ad98dfe826048a60b035269e85e9b196085d4 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Tue, 7 Oct 2025 12:55:39 +0700
Subject: [PATCH 01/15] [WIP][SPARC] Properly handle CC for long double on
 sparc32

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.
---
 clang/lib/Basic/Targets/Sparc.h             |  7 +++++
 clang/lib/CodeGen/Targets/Sparc.cpp         | 30 ++++++++++++++++++---
 compiler-rt/lib/builtins/CMakeLists.txt     |  4 +--
 compiler-rt/test/builtins/CMakeLists.txt    |  2 +-
 llvm/lib/Target/Sparc/SparcCallingConv.td   |  4 +--
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 19 ++++++-------
 6 files changed, 48 insertions(+), 18 deletions(-)

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 38dbebdec2429..4259c8bbfdcae 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -26,6 +26,7 @@ class SparcV8ABIInfo : public DefaultABIInfo {
 
 private:
   ABIArgInfo classifyReturnType(QualType RetTy) const;
+  ABIArgInfo classifyArgumentType(QualType Ty) const;
   void computeInfo(CGFunctionInfo &FI) const override;
 };
 } // end anonymous namespace
@@ -33,12 +34,33 @@ class SparcV8ABIInfo : public DefaultABIInfo {
 
 ABIArgInfo
 SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
+  if (Ty->isRealFloatingType() && getContext().getTypeSize(Ty) == 128)
+    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
+
   if (Ty->isAnyComplexType()) {
-    return ABIArgInfo::getDirect();
-  }
-  else {
-    return DefaultABIInfo::classifyReturnType(Ty);
+    auto AI = ABIArgInfo::getDirect();
+    AI.setInReg(true);
+    return AI;
   }
+
+  return DefaultABIInfo::classifyReturnType(Ty);
+}
+
+ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const {
+  const BuiltinType *BT = Ty->getAs<BuiltinType>();
+  bool IsF128 = false;
+
+  if (Ty->isRealFloatingType() && getContext().getTypeSize(Ty) == 128)
+    IsF128 = true;
+
+  // FIXME not sure if redundant
+  if (BT && BT->getKind() == BuiltinType::LongDouble)
+    IsF128 = true;
+
+  if (IsF128)
+    return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
+
+  return DefaultABIInfo::classifyArgumentType(Ty);
 }
 
 void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const {
diff --git a/compiler-rt/lib/builtins/CMakeLists.txt 
b/compiler-rt/lib/builtins/CMakeLists.txt
index e781c2460e488..01f9c38766be5 100644
--- a/compiler-rt/lib/builtins/CMakeLists.txt
+++ b/compiler-rt/lib/builtins/CMakeLists.txt
@@ -1009,9 +1009,9 @@ 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 8e3cb35183ba7..cef23ba557b9e 100644
--- a/compiler-rt/test/builtins/CMakeLists.txt
+++ b/compiler-rt/test/builtins/CMakeLists.txt
@@ -48,7 +48,7 @@ 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/llvm/lib/Target/Sparc/SparcCallingConv.td 
b/llvm/lib/Target/Sparc/SparcCallingConv.td
index 8afd0a7fc09ad..55be696c14a78 100644
--- a/llvm/lib/Target/Sparc/SparcCallingConv.td
+++ b/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -24,8 +24,8 @@ 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">>,
-
-
+  // f128 arguments are passed indirectly.
+  CCIfType<[f128], CCPassIndirect<i32>>,
   // Alternatively, they are assigned to the stack in 4-byte aligned units.
   CCAssignToStack<4, 4>
 ]>;
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp 
b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index dc1196127e3d4..001e4a39b20fd 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -555,20 +555,19 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
       continue;
     }
 
-    int FI = MF.getFrameInfo().CreateFixedObject(4,
-                                                 Offset,
-                                                 true);
-    SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
-    SDValue Load ;
+    int FI;
     if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
-      Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, 
MachinePointerInfo());
+      FI = MF.getFrameInfo().CreateFixedObject(4, Offset, true);
     } else if (VA.getValVT() == MVT::f128) {
-      report_fatal_error("SPARCv8 does not handle f128 in calls; "
-                         "pass indirectly");
+      FI = MF.getFrameInfo().CreateFixedObject(16, Offset, false);
     } else {
       // We shouldn't see any other value types here.
       llvm_unreachable("Unexpected ValVT encountered in frame lowering.");
     }
+
+    SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
+    SDValue Load =
+        DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo());
     InVals.push_back(Load);
   }
 
@@ -914,7 +913,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;

>From 84b1b6dfcdc093b082e7e2ababe5ffffd54afb43 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 13 Oct 2025 22:30:53 +0700
Subject: [PATCH 02/15] Implement indirect argument handling in
 LowerCall/FormalArguments

---
 clang/lib/CodeGen/Targets/Sparc.cpp         |  10 +
 clang/test/CodeGen/Sparc/sparcv8-abi.c      |   7 +
 llvm/lib/Target/Sparc/SparcISelLowering.cpp |  73 ++++++-
 llvm/test/CodeGen/SPARC/fp128.ll            |   6 +
 llvm/test/CodeGen/SPARC/fp16-promote.ll     |  24 ++-
 llvm/test/CodeGen/SPARC/llvm.sincos.ll      | 200 +++++++++++---------
 6 files changed, 218 insertions(+), 102 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index 4259c8bbfdcae..80a2b3d6c0085 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -34,7 +34,17 @@ class SparcV8ABIInfo : public DefaultABIInfo {
 
 ABIArgInfo
 SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
+  const BuiltinType *BT = Ty->getAs<BuiltinType>();
+  bool IsF128 = false;
+
   if (Ty->isRealFloatingType() && getContext().getTypeSize(Ty) == 128)
+    IsF128 = true;
+
+  // FIXME not sure if redundant
+  if (BT && BT->getKind() == BuiltinType::LongDouble)
+    IsF128 = true;
+
+  if (IsF128)
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
 
   if (Ty->isAnyComplexType()) {
diff --git a/clang/test/CodeGen/Sparc/sparcv8-abi.c 
b/clang/test/CodeGen/Sparc/sparcv8-abi.c
index c5faf130890f8..07a90cd8087df 100644
--- a/clang/test/CodeGen/Sparc/sparcv8-abi.c
+++ b/clang/test/CodeGen/Sparc/sparcv8-abi.c
@@ -20,3 +20,10 @@ r (long long __complex__  a, long long __complex__  b)
 {
   return 0;
 }
+
+// CHECK-LABEL: define{{.*}} void @s(ptr dead_on_unwind noalias writable 
sret(fp128) align 8 %agg.result, ptr noundef byval(fp128) align 8 %0) #0
+long double
+s(long double a)
+{
+    return 0;
+}
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp 
b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 001e4a39b20fd..beaf63afb1e98 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -555,11 +555,34 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
       continue;
     }
 
+    if (VA.getLocInfo() == CCValAssign::Indirect) {
+      EVT LocVT = VA.getLocVT();
+      int FI = MF.getFrameInfo().CreateFixedObject(
+          LocVT.getFixedSizeInBits() / 8, Offset, true);
+      SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
+      SDValue ArgValue = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,
+                                     MachinePointerInfo::getFixedStack(MF, 
FI));
+      InVals.push_back(ArgValue);
+
+      unsigned ArgIndex = Ins[InIdx].OrigArgIndex;
+      unsigned ArgPartOffset = Ins[InIdx].PartOffset;
+      assert(ArgPartOffset == 0);
+      while (i + 1 != e && Ins[InIdx + 1].OrigArgIndex == ArgIndex) {
+        CCValAssign &PartVA = ArgLocs[i + 1];
+        unsigned PartOffset = Ins[InIdx + 1].PartOffset - ArgPartOffset;
+        SDValue Offset = DAG.getIntPtrConstant(PartOffset, dl);
+        SDValue Address = DAG.getNode(ISD::ADD, dl, PtrVT, ArgValue, Offset);
+        InVals.push_back(DAG.getLoad(PartVA.getValVT(), dl, Chain, Address,
+                                     MachinePointerInfo()));
+        ++i;
+        ++InIdx;
+      }
+      continue;
+    }
+
     int FI;
     if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
       FI = MF.getFrameInfo().CreateFixedObject(4, Offset, true);
-    } else if (VA.getValVT() == MVT::f128) {
-      FI = MF.getFrameInfo().CreateFixedObject(16, Offset, false);
     } else {
       // We shouldn't see any other value types here.
       llvm_unreachable("Unexpected ValVT encountered in frame lowering.");
@@ -835,6 +858,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;
@@ -1028,6 +1053,50 @@ 
SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
 
     assert(VA.isMemLoc());
 
+    if (VA.getLocInfo() == CCValAssign::Indirect) {
+      // Store the argument in a stack slot and pass its address.
+      unsigned ArgIndex = Outs[realArgIdx].OrigArgIndex;
+      unsigned ArgPartOffset = Outs[realArgIdx].PartOffset;
+      assert(ArgPartOffset == 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. i128), 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.getNode(ISD::ADD, dl, PtrVT, SpillSlot,
+                                      DAG.getIntPtrConstant(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;
+    }
+
     // Create a store off the stack pointer for this argument.
     SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
     SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset() + StackOffset,
diff --git a/llvm/test/CodeGen/SPARC/fp128.ll b/llvm/test/CodeGen/SPARC/fp128.ll
index 99bfb8d742711..fbdc99394eb9e 100644
--- a/llvm/test/CodeGen/SPARC/fp128.ll
+++ b/llvm/test/CodeGen/SPARC/fp128.ll
@@ -241,3 +241,9 @@ entry:
   store fp128 %1, ptr %scalar.result, align 8
   ret void
 }
+
+define fp128 @f128_direct(fp128 %num) {
+    %ret = call fp128 @f128_callee(fp128 %num, fp128 %num)
+    ret fp128 %ret
+}
+declare fp128 @f128_callee(fp128 %a, fp128 %b)
diff --git a/llvm/test/CodeGen/SPARC/fp16-promote.ll 
b/llvm/test/CodeGen/SPARC/fp16-promote.ll
index 64873b744de50..ed956eb807be7 100644
--- a/llvm/test/CodeGen/SPARC/fp16-promote.ll
+++ b/llvm/test/CodeGen/SPARC/fp16-promote.ll
@@ -268,19 +268,21 @@ 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, -120, %sp
 ; V8-OPT-NEXT:    ldd [%i0], %f0
 ; V8-OPT-NEXT:    ldd [%i0+8], %f4
-; V8-OPT-NEXT:    std %f4, [%sp+100]
+; V8-OPT-NEXT:    add %fp, -16, %i0
+; V8-OPT-NEXT:    st %i0, [%sp+92]
+; V8-OPT-NEXT:    std %f4, [%fp+-8]
 ; 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, -120, %sp
 ; V8-UNOPT-NEXT:    ldd [%i0], %f4
 ; V8-UNOPT-NEXT:    ! implicit-def: $q0
 ; V8-UNOPT-NEXT:    fmovs %f4, %f0
@@ -288,24 +290,28 @@ define void @test_fptrunc_fp128(ptr %dp, ptr %p) nounwind 
{
 ; V8-UNOPT-NEXT:    ldd [%i0+8], %f4
 ; V8-UNOPT-NEXT:    fmovs %f4, %f2
 ; V8-UNOPT-NEXT:    fmovs %f5, %f3
+; V8-UNOPT-NEXT:    add %fp, -16, %i0
+; V8-UNOPT-NEXT:    st %i0, [%sp+92]
 ; 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:    call __trunctfhf2
-; V8-UNOPT-NEXT:    std %f0, [%sp+92]
+; V8-UNOPT-NEXT:    std %f0, [%fp+-16]
 ; 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, -120, %sp
 ; V9-NEXT:    ldd [%i0], %f0
 ; V9-NEXT:    ldd [%i0+8], %f4
-; V9-NEXT:    std %f4, [%sp+100]
+; V9-NEXT:    add %fp, -16, %i0
+; V9-NEXT:    st %i0, [%sp+92]
+; V9-NEXT:    std %f4, [%fp+-8]
 ; 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 8d0d50f67e3f5..cc4ceb20a4651 100644
--- a/llvm/test/CodeGen/SPARC/llvm.sincos.ll
+++ b/llvm/test/CodeGen/SPARC/llvm.sincos.ll
@@ -943,41 +943,45 @@ 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, -200, %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+-96]
+; SPARC32-NEXT:    std %f2, [%fp+-88] ! 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+-80] ! 8-byte Folded Spill
+; SPARC32-NEXT:    add %fp, -64, %i0
+; SPARC32-NEXT:    st %i0, [%sp+92]
+; 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:    call sinl
-; SPARC32-NEXT:    std %f0, [%sp+92]
+; SPARC32-NEXT:    std %f0, [%fp+-64]
 ; SPARC32-NEXT:    unimp 16
+; 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:    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+-80], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-24]
+; SPARC32-NEXT:    ldd [%fp+-96], %f0
+; SPARC32-NEXT:    ldd [%fp+-88], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-32]
+; SPARC32-NEXT:    ldd [%fp+-48], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-80]
+; SPARC32-NEXT:    std %f2, [%fp+-72] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-40], %f0
 ; SPARC32-NEXT:    call cosl
-; SPARC32-NEXT:    std %f0, [%fp+-64]
+; SPARC32-NEXT:    std %f0, [%fp+-96]
 ; SPARC32-NEXT:    unimp 16
 ; SPARC32-NEXT:    ldd [%fp+-8], %f0
 ; SPARC32-NEXT:    ldd [%fp+-16], %f4
 ; SPARC32-NEXT:    std %f0, [%i1+24]
 ; SPARC32-NEXT:    std %f4, [%i1+16]
-; SPARC32-NEXT:    ldd [%fp+-64], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-96], %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:    ldd [%fp+-80], %f0
+; SPARC32-NEXT:    ldd [%fp+-72], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i1]
 ; SPARC32-NEXT:    jmp %i7+12
 ; SPARC32-NEXT:    restore %g0, %i1, %o0
@@ -1006,15 +1010,17 @@ 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, -152, %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, -48, %i0
+; GNU32-NEXT:    st %i0, [%sp+92]
+; GNU32-NEXT:    std %f4, [%fp+-40]
 ; GNU32-NEXT:    add %fp, -16, %o0
 ; GNU32-NEXT:    add %fp, -32, %o1
 ; 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
@@ -1057,85 +1063,93 @@ 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, -312, %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+-184]
+; SPARC32-NEXT:    std %f2, [%fp+-176] ! 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+-168] ! 8-byte Folded Spill
+; SPARC32-NEXT:    add %fp, -128, %i1
+; SPARC32-NEXT:    st %i1, [%sp+92]
+; 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:    call sinl
-; SPARC32-NEXT:    std %f0, [%sp+92]
+; SPARC32-NEXT:    std %f0, [%fp+-128]
 ; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    add %fp, -32, %i1
+; SPARC32-NEXT:    st %i1, [%sp+92]
 ; 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:    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, -64, %i1
+; SPARC32-NEXT:    st %i1, [%sp+92]
+; 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:    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, -96, %i1
+; SPARC32-NEXT:    st %i1, [%sp+92]
+; 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+-168], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-88]
+; SPARC32-NEXT:    ldd [%fp+-184], %f0
+; SPARC32-NEXT:    ldd [%fp+-176], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-96]
+; SPARC32-NEXT:    ldd [%fp+-48], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-144]
+; SPARC32-NEXT:    std %f2, [%fp+-136] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-40], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-152] ! 8-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-112], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-168]
+; SPARC32-NEXT:    std %f2, [%fp+-160] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-104], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-184] ! 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:    std %f0, [%fp+-200]
+; SPARC32-NEXT:    std %f2, [%fp+-192] ! 16-byte Folded Spill
 ; SPARC32-NEXT:    ldd [%fp+-8], %f0
 ; SPARC32-NEXT:    call cosl
-; SPARC32-NEXT:    std %f0, [%fp+-144]
+; SPARC32-NEXT:    std %f0, [%fp+-208]
 ; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    ldd [%fp+-40], %f0
-; SPARC32-NEXT:    ldd [%fp+-48], %f4
+; SPARC32-NEXT:    ldd [%fp+-72], %f0
+; SPARC32-NEXT:    ldd [%fp+-80], %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:    ldd [%fp+-208], %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:    ldd [%fp+-200], %f0
+; SPARC32-NEXT:    ldd [%fp+-192], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i0+32]
-; SPARC32-NEXT:    ldd [%fp+-120], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-184], %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:    ldd [%fp+-168], %f0
+; SPARC32-NEXT:    ldd [%fp+-160], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i0+16]
-; SPARC32-NEXT:    ldd [%fp+-88], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-152], %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+-144], %f0
+; SPARC32-NEXT:    ldd [%fp+-136], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i0]
 ; SPARC32-NEXT:    jmp %i7+12
 ; SPARC32-NEXT:    restore
@@ -1186,37 +1200,41 @@ 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, -224, %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:    add %fp, -64, %o1
+; GNU32-NEXT:    add %fp, -96, %i1
+; GNU32-NEXT:    st %i1, [%sp+92]
+; GNU32-NEXT:    std %f4, [%fp+-88]
+; GNU32-NEXT:    add %fp, -64, %o0
+; GNU32-NEXT:    add %fp, -80, %o1
 ; 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:    std %f0, [%fp+-96]
+; GNU32-NEXT:    add %fp, -48, %i1
+; GNU32-NEXT:    st %i1, [%sp+92]
+; GNU32-NEXT:    ldd [%fp+-120], %f0 ! 8-byte Folded Reload
+; GNU32-NEXT:    std %f0, [%fp+-40]
 ; 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:    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 0c673aea9fe784b5fedc4a4c6cfec1daa8a456a9 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Tue, 14 Oct 2025 08:46:19 +0700
Subject: [PATCH 03/15] Update tests

---
 clang/test/Preprocessor/init.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c
index 4dea1b583a089..32c758699120e 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

>From aee28958addc855b75011f8817afe9a5da410256 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Wed, 15 Oct 2025 13:05:14 +0700
Subject: [PATCH 04/15] Remove redundant checks

---
 clang/lib/CodeGen/Targets/Sparc.cpp | 24 +-----------------------
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index 80a2b3d6c0085..f67b794f80491 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -31,20 +31,8 @@ class SparcV8ABIInfo : public DefaultABIInfo {
 };
 } // end anonymous namespace
 
-
-ABIArgInfo
-SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
-  const BuiltinType *BT = Ty->getAs<BuiltinType>();
-  bool IsF128 = false;
-
+ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
   if (Ty->isRealFloatingType() && getContext().getTypeSize(Ty) == 128)
-    IsF128 = true;
-
-  // FIXME not sure if redundant
-  if (BT && BT->getKind() == BuiltinType::LongDouble)
-    IsF128 = true;
-
-  if (IsF128)
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
 
   if (Ty->isAnyComplexType()) {
@@ -57,17 +45,7 @@ SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
 }
 
 ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const {
-  const BuiltinType *BT = Ty->getAs<BuiltinType>();
-  bool IsF128 = false;
-
   if (Ty->isRealFloatingType() && getContext().getTypeSize(Ty) == 128)
-    IsF128 = true;
-
-  // FIXME not sure if redundant
-  if (BT && BT->getKind() == BuiltinType::LongDouble)
-    IsF128 = true;
-
-  if (IsF128)
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
 
   return DefaultABIInfo::classifyArgumentType(Ty);

>From f62d4df9d6141e92530ce6bb08bb69a074aeef35 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 20 Oct 2025 14:37:12 +0700
Subject: [PATCH 05/15] Un-xfail tests that are now passing

---
 compiler-rt/test/sanitizer_common/TestCases/printf-ldbl.c | 3 ---
 compiler-rt/test/sanitizer_common/TestCases/scanf-ldbl.c  | 3 ---
 compiler-rt/test/ubsan/TestCases/Float/cast-overflow.cpp  | 3 ---
 compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp   | 3 ---
 4 files changed, 12 deletions(-)

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 4773884cb4cc0..3fd02957a6903 100644
--- a/compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp
+++ b/compiler-rt/test/ubsan/TestCases/Misc/log-path_test.cpp
@@ -24,9 +24,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[]) {

>From b283fee20a8d96084fdecb88efa2483876ae52ed Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Wed, 29 Oct 2025 19:07:34 +0700
Subject: [PATCH 06/15] Fix long double __Complex returns

---
 llvm/lib/Target/Sparc/SparcCallingConv.td |   1 +
 llvm/test/CodeGen/SPARC/llvm.sincos.ll    | 170 +++++++++-------------
 2 files changed, 67 insertions(+), 104 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td 
b/llvm/lib/Target/Sparc/SparcCallingConv.td
index 55be696c14a78..1cc73688185c1 100644
--- a/llvm/lib/Target/Sparc/SparcCallingConv.td
+++ b/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -34,6 +34,7 @@ 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]>>,
+  CCIfType<[f128], CCAssignToReg<[Q0, Q1]>>,
   CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Ret_Split_64">>
 ]>;
 
diff --git a/llvm/test/CodeGen/SPARC/llvm.sincos.ll 
b/llvm/test/CodeGen/SPARC/llvm.sincos.ll
index cc4ceb20a4651..bbb8906974fb5 100644
--- a/llvm/test/CodeGen/SPARC/llvm.sincos.ll
+++ b/llvm/test/CodeGen/SPARC/llvm.sincos.ll
@@ -943,45 +943,33 @@ 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, -200, %sp
+; SPARC32-NEXT:    save %sp, -176, %sp
 ; SPARC32-NEXT:    ld [%fp+64], %i1
 ; SPARC32-NEXT:    ldd [%i0], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-96]
-; SPARC32-NEXT:    std %f2, [%fp+-88] ! 16-byte Folded Spill
+; SPARC32-NEXT:    std %f0, [%fp+-72]
+; SPARC32-NEXT:    std %f2, [%fp+-64] ! 16-byte Folded Spill
 ; SPARC32-NEXT:    ldd [%i0+8], %f4
-; SPARC32-NEXT:    std %f4, [%fp+-80] ! 8-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -64, %i0
-; SPARC32-NEXT:    st %i0, [%sp+92]
-; SPARC32-NEXT:    add %fp, -48, %i0
-; SPARC32-NEXT:    st %i0, [%sp+64]
-; SPARC32-NEXT:    std %f4, [%fp+-56]
-; SPARC32-NEXT:    call sinl
-; SPARC32-NEXT:    std %f0, [%fp+-64]
-; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    std %f4, [%fp+-56] ! 8-byte Folded Spill
 ; 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:    ldd [%fp+-80], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-24]
-; SPARC32-NEXT:    ldd [%fp+-96], %f0
-; SPARC32-NEXT:    ldd [%fp+-88], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f4, [%fp+-24]
+; SPARC32-NEXT:    call sinl
 ; SPARC32-NEXT:    std %f0, [%fp+-32]
-; SPARC32-NEXT:    ldd [%fp+-48], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-80]
-; SPARC32-NEXT:    std %f2, [%fp+-72] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-40], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-48]
+; SPARC32-NEXT:    std %f2, [%fp+-40] ! 16-byte Folded Spill
+; SPARC32-NEXT:    add %fp, -16, %i0
+; SPARC32-NEXT:    st %i0, [%sp+92]
+; SPARC32-NEXT:    ldd [%fp+-56], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-8]
+; SPARC32-NEXT:    ldd [%fp+-72], %f0
+; SPARC32-NEXT:    ldd [%fp+-64], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    call cosl
-; SPARC32-NEXT:    std %f0, [%fp+-96]
-; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    ldd [%fp+-8], %f0
-; SPARC32-NEXT:    ldd [%fp+-16], %f4
-; SPARC32-NEXT:    std %f0, [%i1+24]
-; SPARC32-NEXT:    std %f4, [%i1+16]
-; SPARC32-NEXT:    ldd [%fp+-96], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i1+8]
-; SPARC32-NEXT:    ldd [%fp+-80], %f0
-; SPARC32-NEXT:    ldd [%fp+-72], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-16]
+; SPARC32-NEXT:    std %f2, [%i1+24]
+; SPARC32-NEXT:    std %f0, [%i1+16]
+; SPARC32-NEXT:    ldd [%fp+-48], %f0
+; SPARC32-NEXT:    ldd [%fp+-40], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f2, [%i1+8]
 ; SPARC32-NEXT:    std %f0, [%i1]
 ; SPARC32-NEXT:    jmp %i7+12
 ; SPARC32-NEXT:    restore %g0, %i1, %o0
@@ -1063,93 +1051,67 @@ 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, -312, %sp
+; SPARC32-NEXT:    save %sp, -256, %sp
 ; SPARC32-NEXT:    mov %i0, %i1
 ; SPARC32-NEXT:    ld [%fp+64], %i0
-; SPARC32-NEXT:    ldd [%i1], %f0
-; 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+-152] ! 8-byte Folded Spill
 ; SPARC32-NEXT:    ldd [%i1+16], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-184]
-; SPARC32-NEXT:    std %f2, [%fp+-176] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%i1+24], %f4
-; SPARC32-NEXT:    std %f4, [%fp+-168] ! 8-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -128, %i1
-; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    add %fp, -112, %i1
-; SPARC32-NEXT:    st %i1, [%sp+64]
-; SPARC32-NEXT:    std %f4, [%fp+-120]
-; SPARC32-NEXT:    call sinl
-; SPARC32-NEXT:    std %f0, [%fp+-128]
-; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    std %f0, [%fp+-80]
+; SPARC32-NEXT:    std %f2, [%fp+-72] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%i1+24], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-88] ! 8-byte Folded Spill
+; SPARC32-NEXT:    ldd [%i1], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-152]
+; SPARC32-NEXT:    std %f2, [%fp+-144] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%i1+8], %f4
+; SPARC32-NEXT:    std %f4, [%fp+-136] ! 8-byte Folded Spill
 ; SPARC32-NEXT:    add %fp, -32, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    add %fp, -16, %i1
-; SPARC32-NEXT:    st %i1, [%sp+64]
-; SPARC32-NEXT:    ldd [%fp+-152], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-24]
-; SPARC32-NEXT:    ldd [%fp+-144], %f0
-; SPARC32-NEXT:    ldd [%fp+-136], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    call cosl
+; SPARC32-NEXT:    std %f4, [%fp+-24]
+; SPARC32-NEXT:    call sinl
 ; SPARC32-NEXT:    std %f0, [%fp+-32]
-; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    std %f0, [%fp+-104]
+; SPARC32-NEXT:    std %f2, [%fp+-96] ! 16-byte Folded Spill
 ; SPARC32-NEXT:    add %fp, -64, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    add %fp, -48, %i1
-; SPARC32-NEXT:    st %i1, [%sp+64]
-; SPARC32-NEXT:    ldd [%fp+-152], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-88], %f0 ! 8-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%fp+-56]
-; SPARC32-NEXT:    ldd [%fp+-144], %f0
-; SPARC32-NEXT:    ldd [%fp+-136], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-80], %f0
+; SPARC32-NEXT:    ldd [%fp+-72], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    call sinl
 ; SPARC32-NEXT:    std %f0, [%fp+-64]
-; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    add %fp, -96, %i1
+; SPARC32-NEXT:    std %f0, [%fp+-120]
+; SPARC32-NEXT:    std %f2, [%fp+-112] ! 16-byte Folded Spill
+; SPARC32-NEXT:    add %fp, -16, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    add %fp, -80, %i1
-; SPARC32-NEXT:    st %i1, [%sp+64]
-; SPARC32-NEXT:    ldd [%fp+-168], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-88]
-; SPARC32-NEXT:    ldd [%fp+-184], %f0
-; SPARC32-NEXT:    ldd [%fp+-176], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-96]
-; SPARC32-NEXT:    ldd [%fp+-48], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-144]
-; SPARC32-NEXT:    std %f2, [%fp+-136] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-40], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-152] ! 8-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-112], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-168]
-; SPARC32-NEXT:    std %f2, [%fp+-160] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-104], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-184] ! 8-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-16], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-200]
-; SPARC32-NEXT:    std %f2, [%fp+-192] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-8], %f0
+; SPARC32-NEXT:    ldd [%fp+-136], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-8]
+; SPARC32-NEXT:    ldd [%fp+-152], %f0
+; SPARC32-NEXT:    ldd [%fp+-144], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    call cosl
-; SPARC32-NEXT:    std %f0, [%fp+-208]
-; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    ldd [%fp+-72], %f0
-; SPARC32-NEXT:    ldd [%fp+-80], %f4
-; SPARC32-NEXT:    std %f0, [%i0+56]
-; SPARC32-NEXT:    std %f4, [%i0+48]
-; SPARC32-NEXT:    ldd [%fp+-208], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+40]
-; SPARC32-NEXT:    ldd [%fp+-200], %f0
-; SPARC32-NEXT:    ldd [%fp+-192], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-16]
+; SPARC32-NEXT:    std %f0, [%fp+-136]
+; SPARC32-NEXT:    std %f2, [%fp+-128] ! 16-byte Folded Spill
+; SPARC32-NEXT:    add %fp, -48, %i1
+; SPARC32-NEXT:    st %i1, [%sp+92]
+; SPARC32-NEXT:    ldd [%fp+-88], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-40]
+; SPARC32-NEXT:    ldd [%fp+-80], %f0
+; SPARC32-NEXT:    ldd [%fp+-72], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    call cosl
+; SPARC32-NEXT:    std %f0, [%fp+-48]
+; SPARC32-NEXT:    std %f2, [%i0+56]
+; SPARC32-NEXT:    std %f0, [%i0+48]
+; SPARC32-NEXT:    ldd [%fp+-136], %f0
+; SPARC32-NEXT:    ldd [%fp+-128], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f2, [%i0+40]
 ; SPARC32-NEXT:    std %f0, [%i0+32]
-; SPARC32-NEXT:    ldd [%fp+-184], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+24]
-; SPARC32-NEXT:    ldd [%fp+-168], %f0
-; SPARC32-NEXT:    ldd [%fp+-160], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-120], %f0
+; SPARC32-NEXT:    ldd [%fp+-112], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f2, [%i0+24]
 ; SPARC32-NEXT:    std %f0, [%i0+16]
-; SPARC32-NEXT:    ldd [%fp+-152], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+8]
-; SPARC32-NEXT:    ldd [%fp+-144], %f0
-; SPARC32-NEXT:    ldd [%fp+-136], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-104], %f0
+; SPARC32-NEXT:    ldd [%fp+-96], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f2, [%i0+8]
 ; SPARC32-NEXT:    std %f0, [%i0]
 ; SPARC32-NEXT:    jmp %i7+12
 ; SPARC32-NEXT:    restore

>From 8724a592352026ace068a2c9c74f92e864038b5a Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 10 Nov 2025 10:34:57 +0700
Subject: [PATCH 07/15] Apply suggestions

---
 clang/lib/CodeGen/Targets/Sparc.cpp     |  5 +----
 clang/test/CodeGen/Sparc/sparcv8-abi.c  |  7 +++++++
 compiler-rt/lib/builtins/CMakeLists.txt |  2 +-
 llvm/test/CodeGen/SPARC/fp128.ll        | 18 +++++++++++++++++-
 4 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index f67b794f80491..7f7eb959d8809 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -36,9 +36,7 @@ ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) 
const {
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
 
   if (Ty->isAnyComplexType()) {
-    auto AI = ABIArgInfo::getDirect();
-    AI.setInReg(true);
-    return AI;
+    return ABIArgInfo::getDirectInReg();
   }
 
   return DefaultABIInfo::classifyReturnType(Ty);
@@ -52,7 +50,6 @@ ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) 
const {
 }
 
 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/Sparc/sparcv8-abi.c 
b/clang/test/CodeGen/Sparc/sparcv8-abi.c
index 07a90cd8087df..4e53e50cd2c0d 100644
--- a/clang/test/CodeGen/Sparc/sparcv8-abi.c
+++ b/clang/test/CodeGen/Sparc/sparcv8-abi.c
@@ -27,3 +27,10 @@ s(long double a)
 {
     return 0;
 }
+
+// CHECK-LABEL: define{{.*}} { fp128, fp128 } @t(ptr noundef byval({ fp128, 
fp128 }) align 8 %a) #0
+long double _Complex
+t(long double _Complex a)
+{
+    return 0;
+}
diff --git a/compiler-rt/lib/builtins/CMakeLists.txt 
b/compiler-rt/lib/builtins/CMakeLists.txt
index 01f9c38766be5..93d9e4b9242c5 100644
--- a/compiler-rt/lib/builtins/CMakeLists.txt
+++ b/compiler-rt/lib/builtins/CMakeLists.txt
@@ -1011,7 +1011,7 @@ else ()
 
       # For RISCV32 and 32-bit SPARC, we must force enable int128 for 
compiling long
       # double routines.
-      if(COMPILER_RT_ENABLE_SOFTWARE_INT128 OR "${arch}" MATCHES 
"riscv32|sparc$" AND NOT CMAKE_COMPILER_IS_GNUCC)
+      if(COMPILER_RT_ENABLE_SOFTWARE_INT128 OR "${arch}" STREQUAL "riscv32" OR 
("${arch}" STREQUAL "sparc" AND NOT CMAKE_COMPILER_IS_GNUCC))
         list(APPEND BUILTIN_CFLAGS_${arch} -fforce-enable-int128)
       endif()
 
diff --git a/llvm/test/CodeGen/SPARC/fp128.ll b/llvm/test/CodeGen/SPARC/fp128.ll
index fbdc99394eb9e..5a0c7031b7a15 100644
--- a/llvm/test/CodeGen/SPARC/fp128.ll
+++ b/llvm/test/CodeGen/SPARC/fp128.ll
@@ -242,7 +242,23 @@ entry:
   ret void
 }
 
-define fp128 @f128_direct(fp128 %num) {
+define fp128 @f128_direct(fp128 %num) nounwind {
+; CHECK-LABEL: f128_direct:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -136, %sp
+; CHECK-NEXT:    ldd [%fp+92], %f0
+; CHECK-NEXT:    ldd [%fp+100], %f4
+; CHECK-NEXT:    add %fp, -32, %i0
+; CHECK-NEXT:    st %i0, [%sp+96]
+; CHECK-NEXT:    add %fp, -16, %i0
+; CHECK-NEXT:    st %i0, [%sp+92]
+; CHECK-NEXT:    std %f4, [%fp+-24]
+; CHECK-NEXT:    std %f0, [%fp+-32]
+; CHECK-NEXT:    std %f4, [%fp+-8]
+; CHECK-NEXT:    call f128_callee
+; CHECK-NEXT:    std %f0, [%fp+-16]
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore
     %ret = call fp128 @f128_callee(fp128 %num, fp128 %num)
     ret fp128 %ret
 }

>From 5e8aa4a1871d12ef53f3be1eebbd44b597317c15 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Tue, 18 Nov 2025 22:45:05 +0700
Subject: [PATCH 08/15] Try to make complex f128 work

---
 clang/test/CodeGen/Sparc/sparcv8-abi.c      |   2 +-
 llvm/lib/Target/Sparc/SparcCallingConv.td   |   2 +-
 llvm/lib/Target/Sparc/SparcISelLowering.cpp |  20 ++-
 llvm/test/CodeGen/SPARC/fp128.ll            |  24 ++-
 llvm/test/CodeGen/SPARC/llvm.sincos.ll      | 170 ++++++++++++--------
 5 files changed, 140 insertions(+), 78 deletions(-)

diff --git a/clang/test/CodeGen/Sparc/sparcv8-abi.c 
b/clang/test/CodeGen/Sparc/sparcv8-abi.c
index 4e53e50cd2c0d..67f0dea611aef 100644
--- a/clang/test/CodeGen/Sparc/sparcv8-abi.c
+++ b/clang/test/CodeGen/Sparc/sparcv8-abi.c
@@ -28,7 +28,7 @@ s(long double a)
     return 0;
 }
 
-// CHECK-LABEL: define{{.*}} { fp128, fp128 } @t(ptr noundef byval({ fp128, 
fp128 }) align 8 %a) #0
+// CHECK-LABEL: define{{.*}}inreg{{.*}} { fp128, fp128 } @t(ptr noundef 
byval({ fp128, fp128 }) align 8 %a) #0
 long double _Complex
 t(long double _Complex a)
 {
diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td 
b/llvm/lib/Target/Sparc/SparcCallingConv.td
index 1cc73688185c1..d50aa2cf449b6 100644
--- a/llvm/lib/Target/Sparc/SparcCallingConv.td
+++ b/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -34,7 +34,7 @@ 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]>>,
-  CCIfType<[f128], CCAssignToReg<[Q0, Q1]>>,
+  CCIfType<[f128], CCCustom<"CC_Sparc_Assign_Ret_F128">>,
   CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Ret_Split_64">>
 ]>;
 
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp 
b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index beaf63afb1e98..1a315a190a3bf 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -106,6 +106,23 @@ static bool CC_Sparc_Assign_Ret_Split_64(unsigned &ValNo, 
MVT &ValVT,
   return true;
 }
 
+static bool CC_Sparc_Assign_Ret_F128(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
+                                     CCValAssign::LocInfo &LocInfo,
+                                     ISD::ArgFlagsTy &ArgFlags,
+                                     CCState &State) {
+  static const MCPhysReg RegList[] = {SP::Q0, SP::Q1};
+
+  if (!ArgFlags.isInReg())
+    return false;
+
+  if (Register Reg = State.AllocateReg(RegList))
+    State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+  else
+    return false;
+
+  return true;
+}
+
 // Allocate a full-sized argument for the 64-bit ABI.
 static bool Analyze_CC_Sparc64_Full(bool IsReturn, unsigned &ValNo, MVT &ValVT,
                                     MVT &LocVT, CCValAssign::LocInfo &LocInfo,
@@ -289,8 +306,7 @@ SparcTargetLowering::LowerReturn_32(SDValue Chain, 
CallingConv::ID CallConv,
 
     SDValue Arg = OutVals[realRVLocIdx];
 
-    if (VA.needsCustom()) {
-      assert(VA.getLocVT() == MVT::v2i32);
+    if (VA.needsCustom() && VA.getLocVT() == MVT::v2i32) {
       // Legalize ret v2i32 -> ret 2 x i32 (Basically: do what would
       // happen by default if this wasn't a legal type)
 
diff --git a/llvm/test/CodeGen/SPARC/fp128.ll b/llvm/test/CodeGen/SPARC/fp128.ll
index 5a0c7031b7a15..3529d091145a6 100644
--- a/llvm/test/CodeGen/SPARC/fp128.ll
+++ b/llvm/test/CodeGen/SPARC/fp128.ll
@@ -245,18 +245,26 @@ entry:
 define fp128 @f128_direct(fp128 %num) nounwind {
 ; CHECK-LABEL: f128_direct:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -136, %sp
+; CHECK-NEXT:    save %sp, -152, %sp
 ; CHECK-NEXT:    ldd [%fp+92], %f0
 ; CHECK-NEXT:    ldd [%fp+100], %f4
-; CHECK-NEXT:    add %fp, -32, %i0
-; CHECK-NEXT:    st %i0, [%sp+96]
-; CHECK-NEXT:    add %fp, -16, %i0
-; CHECK-NEXT:    st %i0, [%sp+92]
+; CHECK-NEXT:    ld [%fp+64], %i0
+; CHECK-NEXT:    add %fp, -48, %i1
+; CHECK-NEXT:    st %i1, [%sp+96]
+; CHECK-NEXT:    add %fp, -32, %i1
+; CHECK-NEXT:    st %i1, [%sp+92]
+; CHECK-NEXT:    add %fp, -16, %i1
+; CHECK-NEXT:    st %i1, [%sp+64]
+; CHECK-NEXT:    std %f4, [%fp+-40]
+; CHECK-NEXT:    std %f0, [%fp+-48]
 ; CHECK-NEXT:    std %f4, [%fp+-24]
-; CHECK-NEXT:    std %f0, [%fp+-32]
-; CHECK-NEXT:    std %f4, [%fp+-8]
 ; CHECK-NEXT:    call f128_callee
-; CHECK-NEXT:    std %f0, [%fp+-16]
+; CHECK-NEXT:    std %f0, [%fp+-32]
+; CHECK-NEXT:    unimp 16
+; CHECK-NEXT:    ldd [%fp+-8], %f0
+; CHECK-NEXT:    ldd [%fp+-16], %f4
+; CHECK-NEXT:    std %f0, [%i0+8]
+; CHECK-NEXT:    std %f4, [%i0]
 ; CHECK-NEXT:    ret
 ; CHECK-NEXT:    restore
     %ret = call fp128 @f128_callee(fp128 %num, fp128 %num)
diff --git a/llvm/test/CodeGen/SPARC/llvm.sincos.ll 
b/llvm/test/CodeGen/SPARC/llvm.sincos.ll
index bbb8906974fb5..cc4ceb20a4651 100644
--- a/llvm/test/CodeGen/SPARC/llvm.sincos.ll
+++ b/llvm/test/CodeGen/SPARC/llvm.sincos.ll
@@ -943,33 +943,45 @@ 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, -176, %sp
+; SPARC32-NEXT:    save %sp, -200, %sp
 ; SPARC32-NEXT:    ld [%fp+64], %i1
 ; SPARC32-NEXT:    ldd [%i0], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-72]
-; SPARC32-NEXT:    std %f2, [%fp+-64] ! 16-byte Folded Spill
+; SPARC32-NEXT:    std %f0, [%fp+-96]
+; SPARC32-NEXT:    std %f2, [%fp+-88] ! 16-byte Folded Spill
 ; SPARC32-NEXT:    ldd [%i0+8], %f4
-; SPARC32-NEXT:    std %f4, [%fp+-56] ! 8-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -32, %i0
+; SPARC32-NEXT:    std %f4, [%fp+-80] ! 8-byte Folded Spill
+; SPARC32-NEXT:    add %fp, -64, %i0
 ; SPARC32-NEXT:    st %i0, [%sp+92]
-; SPARC32-NEXT:    std %f4, [%fp+-24]
+; SPARC32-NEXT:    add %fp, -48, %i0
+; SPARC32-NEXT:    st %i0, [%sp+64]
+; SPARC32-NEXT:    std %f4, [%fp+-56]
 ; SPARC32-NEXT:    call sinl
-; SPARC32-NEXT:    std %f0, [%fp+-32]
-; SPARC32-NEXT:    std %f0, [%fp+-48]
-; SPARC32-NEXT:    std %f2, [%fp+-40] ! 16-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -16, %i0
+; SPARC32-NEXT:    std %f0, [%fp+-64]
+; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    add %fp, -32, %i0
 ; SPARC32-NEXT:    st %i0, [%sp+92]
-; SPARC32-NEXT:    ldd [%fp+-56], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-8]
-; SPARC32-NEXT:    ldd [%fp+-72], %f0
-; SPARC32-NEXT:    ldd [%fp+-64], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    call cosl
-; SPARC32-NEXT:    std %f0, [%fp+-16]
-; SPARC32-NEXT:    std %f2, [%i1+24]
-; SPARC32-NEXT:    std %f0, [%i1+16]
+; SPARC32-NEXT:    add %fp, -16, %i0
+; SPARC32-NEXT:    st %i0, [%sp+64]
+; SPARC32-NEXT:    ldd [%fp+-80], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-24]
+; SPARC32-NEXT:    ldd [%fp+-96], %f0
+; SPARC32-NEXT:    ldd [%fp+-88], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-32]
 ; SPARC32-NEXT:    ldd [%fp+-48], %f0
-; SPARC32-NEXT:    ldd [%fp+-40], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f2, [%i1+8]
+; SPARC32-NEXT:    std %f0, [%fp+-80]
+; SPARC32-NEXT:    std %f2, [%fp+-72] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-40], %f0
+; SPARC32-NEXT:    call cosl
+; SPARC32-NEXT:    std %f0, [%fp+-96]
+; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    ldd [%fp+-8], %f0
+; SPARC32-NEXT:    ldd [%fp+-16], %f4
+; SPARC32-NEXT:    std %f0, [%i1+24]
+; SPARC32-NEXT:    std %f4, [%i1+16]
+; SPARC32-NEXT:    ldd [%fp+-96], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%i1+8]
+; SPARC32-NEXT:    ldd [%fp+-80], %f0
+; SPARC32-NEXT:    ldd [%fp+-72], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i1]
 ; SPARC32-NEXT:    jmp %i7+12
 ; SPARC32-NEXT:    restore %g0, %i1, %o0
@@ -1051,67 +1063,93 @@ 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, -256, %sp
+; SPARC32-NEXT:    save %sp, -312, %sp
 ; SPARC32-NEXT:    mov %i0, %i1
 ; SPARC32-NEXT:    ld [%fp+64], %i0
-; SPARC32-NEXT:    ldd [%i1+16], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-80]
-; SPARC32-NEXT:    std %f2, [%fp+-72] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%i1+24], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-88] ! 8-byte Folded Spill
 ; SPARC32-NEXT:    ldd [%i1], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-152]
-; SPARC32-NEXT:    std %f2, [%fp+-144] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%i1+8], %f4
-; SPARC32-NEXT:    std %f4, [%fp+-136] ! 8-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -32, %i1
+; 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+-152] ! 8-byte Folded Spill
+; SPARC32-NEXT:    ldd [%i1+16], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-184]
+; SPARC32-NEXT:    std %f2, [%fp+-176] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%i1+24], %f4
+; SPARC32-NEXT:    std %f4, [%fp+-168] ! 8-byte Folded Spill
+; SPARC32-NEXT:    add %fp, -128, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    std %f4, [%fp+-24]
+; SPARC32-NEXT:    add %fp, -112, %i1
+; SPARC32-NEXT:    st %i1, [%sp+64]
+; SPARC32-NEXT:    std %f4, [%fp+-120]
 ; SPARC32-NEXT:    call sinl
+; SPARC32-NEXT:    std %f0, [%fp+-128]
+; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    add %fp, -32, %i1
+; SPARC32-NEXT:    st %i1, [%sp+92]
+; SPARC32-NEXT:    add %fp, -16, %i1
+; SPARC32-NEXT:    st %i1, [%sp+64]
+; SPARC32-NEXT:    ldd [%fp+-152], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-24]
+; SPARC32-NEXT:    ldd [%fp+-144], %f0
+; SPARC32-NEXT:    ldd [%fp+-136], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    call cosl
 ; SPARC32-NEXT:    std %f0, [%fp+-32]
-; SPARC32-NEXT:    std %f0, [%fp+-104]
-; SPARC32-NEXT:    std %f2, [%fp+-96] ! 16-byte Folded Spill
+; SPARC32-NEXT:    unimp 16
 ; SPARC32-NEXT:    add %fp, -64, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    ldd [%fp+-88], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    add %fp, -48, %i1
+; SPARC32-NEXT:    st %i1, [%sp+64]
+; SPARC32-NEXT:    ldd [%fp+-152], %f0 ! 8-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%fp+-56]
-; SPARC32-NEXT:    ldd [%fp+-80], %f0
-; SPARC32-NEXT:    ldd [%fp+-72], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-144], %f0
+; SPARC32-NEXT:    ldd [%fp+-136], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    call sinl
 ; SPARC32-NEXT:    std %f0, [%fp+-64]
-; SPARC32-NEXT:    std %f0, [%fp+-120]
-; SPARC32-NEXT:    std %f2, [%fp+-112] ! 16-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -16, %i1
-; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    ldd [%fp+-136], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-8]
-; SPARC32-NEXT:    ldd [%fp+-152], %f0
-; SPARC32-NEXT:    ldd [%fp+-144], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    call cosl
-; SPARC32-NEXT:    std %f0, [%fp+-16]
-; SPARC32-NEXT:    std %f0, [%fp+-136]
-; SPARC32-NEXT:    std %f2, [%fp+-128] ! 16-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -48, %i1
+; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    add %fp, -96, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+92]
-; SPARC32-NEXT:    ldd [%fp+-88], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-40]
-; SPARC32-NEXT:    ldd [%fp+-80], %f0
-; SPARC32-NEXT:    ldd [%fp+-72], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    add %fp, -80, %i1
+; SPARC32-NEXT:    st %i1, [%sp+64]
+; SPARC32-NEXT:    ldd [%fp+-168], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-88]
+; SPARC32-NEXT:    ldd [%fp+-184], %f0
+; SPARC32-NEXT:    ldd [%fp+-176], %f2 ! 16-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%fp+-96]
+; SPARC32-NEXT:    ldd [%fp+-48], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-144]
+; SPARC32-NEXT:    std %f2, [%fp+-136] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-40], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-152] ! 8-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-112], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-168]
+; SPARC32-NEXT:    std %f2, [%fp+-160] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-104], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-184] ! 8-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-16], %f0
+; SPARC32-NEXT:    std %f0, [%fp+-200]
+; SPARC32-NEXT:    std %f2, [%fp+-192] ! 16-byte Folded Spill
+; SPARC32-NEXT:    ldd [%fp+-8], %f0
 ; SPARC32-NEXT:    call cosl
-; SPARC32-NEXT:    std %f0, [%fp+-48]
-; SPARC32-NEXT:    std %f2, [%i0+56]
-; SPARC32-NEXT:    std %f0, [%i0+48]
-; SPARC32-NEXT:    ldd [%fp+-136], %f0
-; SPARC32-NEXT:    ldd [%fp+-128], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f2, [%i0+40]
+; SPARC32-NEXT:    std %f0, [%fp+-208]
+; SPARC32-NEXT:    unimp 16
+; SPARC32-NEXT:    ldd [%fp+-72], %f0
+; SPARC32-NEXT:    ldd [%fp+-80], %f4
+; SPARC32-NEXT:    std %f0, [%i0+56]
+; SPARC32-NEXT:    std %f4, [%i0+48]
+; SPARC32-NEXT:    ldd [%fp+-208], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%i0+40]
+; SPARC32-NEXT:    ldd [%fp+-200], %f0
+; SPARC32-NEXT:    ldd [%fp+-192], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i0+32]
-; SPARC32-NEXT:    ldd [%fp+-120], %f0
-; SPARC32-NEXT:    ldd [%fp+-112], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f2, [%i0+24]
+; SPARC32-NEXT:    ldd [%fp+-184], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%i0+24]
+; SPARC32-NEXT:    ldd [%fp+-168], %f0
+; SPARC32-NEXT:    ldd [%fp+-160], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i0+16]
-; SPARC32-NEXT:    ldd [%fp+-104], %f0
-; SPARC32-NEXT:    ldd [%fp+-96], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f2, [%i0+8]
+; SPARC32-NEXT:    ldd [%fp+-152], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    std %f0, [%i0+8]
+; SPARC32-NEXT:    ldd [%fp+-144], %f0
+; SPARC32-NEXT:    ldd [%fp+-136], %f2 ! 16-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%i0]
 ; SPARC32-NEXT:    jmp %i7+12
 ; SPARC32-NEXT:    restore

>From f9ed024a6e9a53d2cd5622a98fe334979a532ce6 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Tue, 18 Nov 2025 23:02:52 +0700
Subject: [PATCH 09/15] Apply suggestions

---
 clang/lib/CodeGen/Targets/Sparc.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index 7f7eb959d8809..df497d2b47b6c 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -32,7 +32,8 @@ class SparcV8ABIInfo : public DefaultABIInfo {
 } // end anonymous namespace
 
 ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
-  if (Ty->isRealFloatingType() && getContext().getTypeSize(Ty) == 128)
+  if (const auto *BT = Ty->getAs<BuiltinType>();
+      BT && BT->getKind() == BuiltinType::LongDouble)
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
 
   if (Ty->isAnyComplexType()) {
@@ -43,7 +44,8 @@ ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) 
const {
 }
 
 ABIArgInfo SparcV8ABIInfo::classifyArgumentType(QualType Ty) const {
-  if (Ty->isRealFloatingType() && getContext().getTypeSize(Ty) == 128)
+  if (const auto *BT = Ty->getAs<BuiltinType>();
+      BT && BT->getKind() == BuiltinType::LongDouble)
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
 
   return DefaultABIInfo::classifyArgumentType(Ty);

>From ff6e10e262158f53518fc7317f757e22c00c2ab7 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Sun, 23 Nov 2025 10:21:16 +0700
Subject: [PATCH 10/15] Apply suggestions

---
 clang/lib/CodeGen/Targets/Sparc.cpp         |  3 +--
 llvm/lib/Target/Sparc/SparcCallingConv.td   |  2 +-
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 20 ++------------------
 3 files changed, 4 insertions(+), 21 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index df497d2b47b6c..1aa370cead357 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -36,9 +36,8 @@ ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) 
const {
       BT && BT->getKind() == BuiltinType::LongDouble)
     return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
 
-  if (Ty->isAnyComplexType()) {
+  if (Ty->isAnyComplexType())
     return ABIArgInfo::getDirectInReg();
-  }
 
   return DefaultABIInfo::classifyReturnType(Ty);
 }
diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td 
b/llvm/lib/Target/Sparc/SparcCallingConv.td
index d50aa2cf449b6..2782aecdc1101 100644
--- a/llvm/lib/Target/Sparc/SparcCallingConv.td
+++ b/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -34,7 +34,7 @@ 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]>>,
-  CCIfType<[f128], CCCustom<"CC_Sparc_Assign_Ret_F128">>,
+  CCIfType<[f128], CCIfInReg<CCAssignToReg<[Q0, Q1]>>>,
   CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Ret_Split_64">>
 ]>;
 
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp 
b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 1a315a190a3bf..beaf63afb1e98 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -106,23 +106,6 @@ static bool CC_Sparc_Assign_Ret_Split_64(unsigned &ValNo, 
MVT &ValVT,
   return true;
 }
 
-static bool CC_Sparc_Assign_Ret_F128(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
-                                     CCValAssign::LocInfo &LocInfo,
-                                     ISD::ArgFlagsTy &ArgFlags,
-                                     CCState &State) {
-  static const MCPhysReg RegList[] = {SP::Q0, SP::Q1};
-
-  if (!ArgFlags.isInReg())
-    return false;
-
-  if (Register Reg = State.AllocateReg(RegList))
-    State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
-  else
-    return false;
-
-  return true;
-}
-
 // Allocate a full-sized argument for the 64-bit ABI.
 static bool Analyze_CC_Sparc64_Full(bool IsReturn, unsigned &ValNo, MVT &ValVT,
                                     MVT &LocVT, CCValAssign::LocInfo &LocInfo,
@@ -306,7 +289,8 @@ SparcTargetLowering::LowerReturn_32(SDValue Chain, 
CallingConv::ID CallConv,
 
     SDValue Arg = OutVals[realRVLocIdx];
 
-    if (VA.needsCustom() && VA.getLocVT() == MVT::v2i32) {
+    if (VA.needsCustom()) {
+      assert(VA.getLocVT() == MVT::v2i32);
       // Legalize ret v2i32 -> ret 2 x i32 (Basically: do what would
       // happen by default if this wasn't a legal type)
 

>From e38af2a622ac5387804d9ce33f9181f127b98f9c Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 24 Nov 2025 09:03:02 +0700
Subject: [PATCH 11/15] Use CCIfConsecutiveRegs

---
 llvm/lib/Target/Sparc/SparcCallingConv.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td 
b/llvm/lib/Target/Sparc/SparcCallingConv.td
index 2782aecdc1101..a87680ab36c48 100644
--- a/llvm/lib/Target/Sparc/SparcCallingConv.td
+++ b/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -34,7 +34,7 @@ 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]>>,
-  CCIfType<[f128], CCIfInReg<CCAssignToReg<[Q0, Q1]>>>,
+  CCIfType<[f128], CCIfInReg<CCIfConsecutiveRegs<CCAssignToReg<[Q0, Q1]>>>>,
   CCIfType<[v2i32], CCCustom<"CC_Sparc_Assign_Ret_Split_64">>
 ]>;
 

>From cb69bc66f8a9c649e348747573ee060d02a61e47 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 24 Nov 2025 09:47:26 +0700
Subject: [PATCH 12/15] inreg should only apply to long double _Complex

---
 clang/lib/CodeGen/Targets/Sparc.cpp | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp 
b/clang/lib/CodeGen/Targets/Sparc.cpp
index 1aa370cead357..17fe26222c29d 100644
--- a/clang/lib/CodeGen/Targets/Sparc.cpp
+++ b/clang/lib/CodeGen/Targets/Sparc.cpp
@@ -32,13 +32,20 @@ class SparcV8ABIInfo : public DefaultABIInfo {
 } // end anonymous namespace
 
 ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const {
-  if (const auto *BT = Ty->getAs<BuiltinType>();
-      BT && BT->getKind() == BuiltinType::LongDouble)
+  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;
+
+  // 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());
 
-  if (Ty->isAnyComplexType())
-    return ABIArgInfo::getDirectInReg();
-
   return DefaultABIInfo::classifyReturnType(Ty);
 }
 

>From 34bfc88ff4b9d284d97f6c4bd5405d0696b5b17d Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 24 Nov 2025 13:18:57 +0700
Subject: [PATCH 13/15] Use autogenerated tests

---
 clang/test/CodeGen/Sparc/sparcv8-abi.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/clang/test/CodeGen/Sparc/sparcv8-abi.c 
b/clang/test/CodeGen/Sparc/sparcv8-abi.c
index 67f0dea611aef..7beddd20e5e4d 100644
--- a/clang/test/CodeGen/Sparc/sparcv8-abi.c
+++ b/clang/test/CodeGen/Sparc/sparcv8-abi.c
@@ -1,35 +1,51 @@
+// 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;
 }
 
-// CHECK-LABEL: define{{.*}} void @s(ptr dead_on_unwind noalias writable 
sret(fp128) align 8 %agg.result, ptr noundef byval(fp128) align 8 %0) #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;
 }
 
-// CHECK-LABEL: define{{.*}}inreg{{.*}} { fp128, fp128 } @t(ptr noundef 
byval({ fp128, fp128 }) align 8 %a) #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;

>From 69e93a865e33f74648715d3403fa0f4d62a03976 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 24 Nov 2025 15:32:22 +0700
Subject: [PATCH 14/15] Fix direct fp128 arg passing

---
 llvm/lib/Target/Sparc/SparcCallingConv.td   |   5 +-
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 180 ++++++++++----------
 llvm/test/CodeGen/SPARC/fp128.ll            |  43 +++--
 llvm/test/CodeGen/SPARC/fp16-promote.ll     |  17 +-
 llvm/test/CodeGen/SPARC/llvm.sincos.ll      | 137 ++++++---------
 5 files changed, 171 insertions(+), 211 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td 
b/llvm/lib/Target/Sparc/SparcCallingConv.td
index a87680ab36c48..e829935a3dfb3 100644
--- a/llvm/lib/Target/Sparc/SparcCallingConv.td
+++ b/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -17,6 +17,8 @@
 def CC_Sparc32 : CallingConv<[
   // Custom assign SRet to [sp+64].
   CCIfSRet<CCCustom<"CC_Sparc_Assign_SRet">>,
+  // f128 arguments are passed indirectly, using i32 pointers.
+  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,12 +26,11 @@ 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">>,
-  // f128 arguments are passed indirectly.
-  CCIfType<[f128], CCPassIndirect<i32>>,
   // 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]>>,
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp 
b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index beaf63afb1e98..a4a498cc81776 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -440,6 +440,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;
@@ -466,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);
@@ -500,98 +502,92 @@ 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;
+      if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
+        FI = MF.getFrameInfo().CreateFixedObject(4, Offset, true);
+      } else {
+        // We shouldn't see any other value types here.
+        llvm_unreachable("Unexpected ValVT encountered in frame lowering.");
+      }
 
-    if (VA.getLocInfo() == CCValAssign::Indirect) {
-      EVT LocVT = VA.getLocVT();
-      int FI = MF.getFrameInfo().CreateFixedObject(
-          LocVT.getFixedSizeInBits() / 8, Offset, true);
       SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
-      SDValue ArgValue = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,
-                                     MachinePointerInfo::getFixedStack(MF, 
FI));
-      InVals.push_back(ArgValue);
-
-      unsigned ArgIndex = Ins[InIdx].OrigArgIndex;
-      unsigned ArgPartOffset = Ins[InIdx].PartOffset;
-      assert(ArgPartOffset == 0);
-      while (i + 1 != e && Ins[InIdx + 1].OrigArgIndex == ArgIndex) {
-        CCValAssign &PartVA = ArgLocs[i + 1];
-        unsigned PartOffset = Ins[InIdx + 1].PartOffset - ArgPartOffset;
-        SDValue Offset = DAG.getIntPtrConstant(PartOffset, dl);
-        SDValue Address = DAG.getNode(ISD::ADD, dl, PtrVT, ArgValue, Offset);
-        InVals.push_back(DAG.getLoad(PartVA.getValVT(), dl, Chain, Address,
-                                     MachinePointerInfo()));
-        ++i;
-        ++InIdx;
+      SDValue Load =
+          DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo());
+      if (VA.getLocInfo() != CCValAssign::Indirect) {
+        InVals.push_back(Load);
+        continue;
       }
-      continue;
+      Arg = Load;
     }
 
-    int FI;
-    if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
-      FI = MF.getFrameInfo().CreateFixedObject(4, Offset, true);
-    } 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;
+    unsigned ArgPartOffset = Ins[InIdx].PartOffset;
+    assert(ArgPartOffset == 0);
+    while (i + 1 != e && Ins[InIdx + 1].OrigArgIndex == ArgIndex) {
+      CCValAssign &PartVA = ArgLocs[i + 1];
+      unsigned PartOffset = Ins[InIdx + 1].PartOffset - ArgPartOffset;
+      SDValue Offset = DAG.getIntPtrConstant(PartOffset, dl);
+      SDValue Address = DAG.getNode(ISD::ADD, dl, PtrVT, ArgValue, Offset);
+      InVals.push_back(DAG.getLoad(PartVA.getValVT(), dl, Chain, Address,
+                                   MachinePointerInfo()));
+      ++i;
+      ++InIdx;
     }
-
-    SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
-    SDValue Load =
-        DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo());
-    InVals.push_back(Load);
   }
 
   if (MF.getFunction().hasStructRetAttr()) {
@@ -1039,20 +1035,6 @@ 
SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
       continue;
     }
 
-    // Arguments that can be passed on register must be kept at
-    // RegsToPass vector
-    if (VA.isRegLoc()) {
-      if (VA.getLocVT() != MVT::f32) {
-        RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
-        continue;
-      }
-      Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg);
-      RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
-      continue;
-    }
-
-    assert(VA.isMemLoc());
-
     if (VA.getLocInfo() == CCValAssign::Indirect) {
       // Store the argument in a stack slot and pass its address.
       unsigned ArgIndex = Outs[realArgIdx].OrigArgIndex;
@@ -1077,7 +1059,7 @@ 
SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
       MemOpChains.push_back(
           DAG.getStore(Chain, dl, Arg, SpillSlot,
                        MachinePointerInfo::getFixedStack(MF, FI)));
-      // If the original argument was split (e.g. i128), we need
+      // 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];
@@ -1097,6 +1079,20 @@ 
SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
       Arg = SpillSlot;
     }
 
+    // Arguments that can be passed on register must be kept at
+    // RegsToPass vector
+    if (VA.isRegLoc()) {
+      if (VA.getLocVT() != MVT::f32) {
+        RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+        continue;
+      }
+      Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg);
+      RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+      continue;
+    }
+
+    assert(VA.isMemLoc());
+
     // Create a store off the stack pointer for this argument.
     SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
     SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset() + StackOffset,
diff --git a/llvm/test/CodeGen/SPARC/fp128.ll b/llvm/test/CodeGen/SPARC/fp128.ll
index 3529d091145a6..0ff84bdc0067e 100644
--- a/llvm/test/CodeGen/SPARC/fp128.ll
+++ b/llvm/test/CodeGen/SPARC/fp128.ll
@@ -245,28 +245,27 @@ entry:
 define fp128 @f128_direct(fp128 %num) nounwind {
 ; CHECK-LABEL: f128_direct:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -152, %sp
-; CHECK-NEXT:    ldd [%fp+92], %f0
-; CHECK-NEXT:    ldd [%fp+100], %f4
-; CHECK-NEXT:    ld [%fp+64], %i0
-; CHECK-NEXT:    add %fp, -48, %i1
-; CHECK-NEXT:    st %i1, [%sp+96]
-; CHECK-NEXT:    add %fp, -32, %i1
-; CHECK-NEXT:    st %i1, [%sp+92]
-; CHECK-NEXT:    add %fp, -16, %i1
-; CHECK-NEXT:    st %i1, [%sp+64]
-; CHECK-NEXT:    std %f4, [%fp+-40]
-; CHECK-NEXT:    std %f0, [%fp+-48]
-; CHECK-NEXT:    std %f4, [%fp+-24]
-; CHECK-NEXT:    call f128_callee
-; CHECK-NEXT:    std %f0, [%fp+-32]
-; CHECK-NEXT:    unimp 16
-; CHECK-NEXT:    ldd [%fp+-8], %f0
-; CHECK-NEXT:    ldd [%fp+-16], %f4
-; CHECK-NEXT:    std %f0, [%i0+8]
-; CHECK-NEXT:    std %f4, [%i0]
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore
+; CHECK-NEXT:  save %sp, -144, %sp
+; CHECK-NEXT:  ldd [%i0], %f0
+; CHECK-NEXT:  ldd [%i0+8], %f4
+; CHECK-NEXT:  ld [%fp+64], %i0
+; CHECK-NEXT:  add %fp, -16, %i1
+; CHECK-NEXT:  st %i1, [%sp+64]
+; CHECK-NEXT:  std %f4, [%fp+-40]
+; CHECK-NEXT:  std %f0, [%fp+-48]
+; CHECK-NEXT:  std %f4, [%fp+-24]
+; CHECK-NEXT:  add %fp, -32, %o0
+; CHECK-NEXT:  add %fp, -48, %o1
+; CHECK-NEXT:  call f128_callee
+; CHECK-NEXT:  std %f0, [%fp+-32]
+; CHECK-NEXT:  unimp 16
+; CHECK-NEXT:  ldd [%fp+-8], %f0
+; CHECK-NEXT:  ldd [%fp+-16], %f4
+; CHECK-NEXT:  std %f0, [%i0+8]
+; CHECK-NEXT:  std %f4, [%i0]
+; CHECK-NEXT:  ret
+; CHECK-NEXT:  restore
+
     %ret = call fp128 @f128_callee(fp128 %num, fp128 %num)
     ret fp128 %ret
 }
diff --git a/llvm/test/CodeGen/SPARC/fp16-promote.ll 
b/llvm/test/CodeGen/SPARC/fp16-promote.ll
index ed956eb807be7..4e46fd073923e 100644
--- a/llvm/test/CodeGen/SPARC/fp16-promote.ll
+++ b/llvm/test/CodeGen/SPARC/fp16-promote.ll
@@ -268,12 +268,11 @@ 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, -120, %sp
+; V8-OPT-NEXT:    save %sp, -112, %sp
 ; V8-OPT-NEXT:    ldd [%i0], %f0
 ; V8-OPT-NEXT:    ldd [%i0+8], %f4
-; V8-OPT-NEXT:    add %fp, -16, %i0
-; V8-OPT-NEXT:    st %i0, [%sp+92]
 ; V8-OPT-NEXT:    std %f4, [%fp+-8]
+; V8-OPT-NEXT:    add %fp, -16, %o0
 ; V8-OPT-NEXT:    call __trunctfhf2
 ; V8-OPT-NEXT:    std %f0, [%fp+-16]
 ; V8-OPT-NEXT:    sth %o0, [%i1]
@@ -282,7 +281,7 @@ define void @test_fptrunc_fp128(ptr %dp, ptr %p) nounwind {
 ;
 ; V8-UNOPT-LABEL: test_fptrunc_fp128:
 ; V8-UNOPT:       ! %bb.0:
-; V8-UNOPT-NEXT:    save %sp, -120, %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,26 +289,24 @@ define void @test_fptrunc_fp128(ptr %dp, ptr %p) nounwind 
{
 ; V8-UNOPT-NEXT:    ldd [%i0+8], %f4
 ; V8-UNOPT-NEXT:    fmovs %f4, %f2
 ; V8-UNOPT-NEXT:    fmovs %f5, %f3
-; V8-UNOPT-NEXT:    add %fp, -16, %i0
-; V8-UNOPT-NEXT:    st %i0, [%sp+92]
 ; V8-UNOPT-NEXT:    fmovs %f2, %f4
 ; V8-UNOPT-NEXT:    fmovs %f3, %f5
 ; V8-UNOPT-NEXT:    std %f4, [%fp+-8]
 ; V8-UNOPT-NEXT:    ! kill: def $d0 killed $d0 killed $q0
-; V8-UNOPT-NEXT:    call __trunctfhf2
 ; V8-UNOPT-NEXT:    std %f0, [%fp+-16]
+; V8-UNOPT-NEXT:    call __trunctfhf2
+; 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, -120, %sp
+; V9-NEXT:    save %sp, -112, %sp
 ; V9-NEXT:    ldd [%i0], %f0
 ; V9-NEXT:    ldd [%i0+8], %f4
-; V9-NEXT:    add %fp, -16, %i0
-; V9-NEXT:    st %i0, [%sp+92]
 ; V9-NEXT:    std %f4, [%fp+-8]
+; V9-NEXT:    add %fp, -16, %o0
 ; V9-NEXT:    call __trunctfhf2
 ; V9-NEXT:    std %f0, [%fp+-16]
 ; V9-NEXT:    sth %o0, [%i1]
diff --git a/llvm/test/CodeGen/SPARC/llvm.sincos.ll 
b/llvm/test/CodeGen/SPARC/llvm.sincos.ll
index cc4ceb20a4651..ea5de64607042 100644
--- a/llvm/test/CodeGen/SPARC/llvm.sincos.ll
+++ b/llvm/test/CodeGen/SPARC/llvm.sincos.ll
@@ -943,46 +943,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, -200, %sp
+; SPARC32-NEXT:    save %sp, -184, %sp
 ; SPARC32-NEXT:    ld [%fp+64], %i1
 ; SPARC32-NEXT:    ldd [%i0], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-96]
-; SPARC32-NEXT:    std %f2, [%fp+-88] ! 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+-80] ! 8-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -64, %i0
-; SPARC32-NEXT:    st %i0, [%sp+92]
+; 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, [%fp+-56]
+; SPARC32-NEXT:    add %fp, -64, %o0
 ; SPARC32-NEXT:    call sinl
 ; SPARC32-NEXT:    std %f0, [%fp+-64]
 ; SPARC32-NEXT:    unimp 16
-; 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:    ldd [%fp+-80], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-72], %f0 ! 8-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%fp+-24]
-; SPARC32-NEXT:    ldd [%fp+-96], %f0
-; SPARC32-NEXT:    ldd [%fp+-88], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-32]
-; SPARC32-NEXT:    ldd [%fp+-48], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-80]
-; SPARC32-NEXT:    std %f2, [%fp+-72] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-40], %f0
+; 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+-96]
+; 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+-96], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i1+8]
-; SPARC32-NEXT:    ldd [%fp+-80], %f0
-; SPARC32-NEXT:    ldd [%fp+-72], %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
 ;
@@ -1010,15 +1002,14 @@ 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, -152, %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:    add %fp, -48, %i0
-; GNU32-NEXT:    st %i0, [%sp+92]
 ; GNU32-NEXT:    std %f4, [%fp+-40]
-; GNU32-NEXT:    add %fp, -16, %o0
-; GNU32-NEXT:    add %fp, -32, %o1
+; 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, [%fp+-48]
 ; GNU32-NEXT:    ldd [%fp+-24], %f0
@@ -1063,7 +1054,7 @@ 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, -312, %sp
+; SPARC32-NEXT:    save %sp, -272, %sp
 ; SPARC32-NEXT:    mov %i0, %i1
 ; SPARC32-NEXT:    ld [%fp+64], %i0
 ; SPARC32-NEXT:    ldd [%i1], %f0
@@ -1072,84 +1063,62 @@ define void @test_sincos_v2f128(ptr sret({ <2 x fp128>, 
<2 x fp128> }) %ret, ptr
 ; SPARC32-NEXT:    ldd [%i1+8], %f0
 ; SPARC32-NEXT:    std %f0, [%fp+-152] ! 8-byte Folded Spill
 ; SPARC32-NEXT:    ldd [%i1+16], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-184]
-; SPARC32-NEXT:    std %f2, [%fp+-176] ! 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+-168] ! 8-byte Folded Spill
-; SPARC32-NEXT:    add %fp, -128, %i1
-; SPARC32-NEXT:    st %i1, [%sp+92]
+; 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, [%fp+-120]
+; SPARC32-NEXT:    add %fp, -128, %o0
 ; SPARC32-NEXT:    call sinl
 ; SPARC32-NEXT:    std %f0, [%fp+-128]
 ; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    add %fp, -32, %i1
-; SPARC32-NEXT:    st %i1, [%sp+92]
 ; SPARC32-NEXT:    add %fp, -16, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+64]
 ; 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, [%fp+-32]
 ; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    add %fp, -64, %i1
-; SPARC32-NEXT:    st %i1, [%sp+92]
 ; SPARC32-NEXT:    add %fp, -48, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+64]
 ; 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, [%fp+-64]
 ; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    add %fp, -96, %i1
-; SPARC32-NEXT:    st %i1, [%sp+92]
 ; SPARC32-NEXT:    add %fp, -80, %i1
 ; SPARC32-NEXT:    st %i1, [%sp+64]
-; SPARC32-NEXT:    ldd [%fp+-168], %f0 ! 8-byte Folded Reload
+; SPARC32-NEXT:    ldd [%fp+-160], %f0 ! 8-byte Folded Reload
 ; SPARC32-NEXT:    std %f0, [%fp+-88]
-; SPARC32-NEXT:    ldd [%fp+-184], %f0
-; SPARC32-NEXT:    ldd [%fp+-176], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%fp+-96]
-; SPARC32-NEXT:    ldd [%fp+-48], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-144]
-; SPARC32-NEXT:    std %f2, [%fp+-136] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-40], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-152] ! 8-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-112], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-168]
-; SPARC32-NEXT:    std %f2, [%fp+-160] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-104], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-184] ! 8-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-16], %f0
-; SPARC32-NEXT:    std %f0, [%fp+-200]
-; SPARC32-NEXT:    std %f2, [%fp+-192] ! 16-byte Folded Spill
-; SPARC32-NEXT:    ldd [%fp+-8], %f0
+; 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+-208]
+; SPARC32-NEXT:    std %f0, [%fp+-96]
 ; SPARC32-NEXT:    unimp 16
-; SPARC32-NEXT:    ldd [%fp+-72], %f0
-; SPARC32-NEXT:    ldd [%fp+-80], %f4
-; SPARC32-NEXT:    std %f0, [%i0+56]
-; SPARC32-NEXT:    std %f4, [%i0+48]
-; SPARC32-NEXT:    ldd [%fp+-208], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+40]
-; SPARC32-NEXT:    ldd [%fp+-200], %f0
-; SPARC32-NEXT:    ldd [%fp+-192], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+32]
-; SPARC32-NEXT:    ldd [%fp+-184], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+24]
-; SPARC32-NEXT:    ldd [%fp+-168], %f0
-; SPARC32-NEXT:    ldd [%fp+-160], %f2 ! 16-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+16]
-; SPARC32-NEXT:    ldd [%fp+-152], %f0 ! 8-byte Folded Reload
-; SPARC32-NEXT:    std %f0, [%i0+8]
-; SPARC32-NEXT:    ldd [%fp+-144], %f0
-; SPARC32-NEXT:    ldd [%fp+-136], %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
@@ -1200,7 +1169,7 @@ 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, -224, %sp
+; GNU32-NEXT:    save %sp, -216, %sp
 ; GNU32-NEXT:    mov %i0, %i1
 ; GNU32-NEXT:    ld [%fp+64], %i0
 ; GNU32-NEXT:    ldd [%i1+16], %f0
@@ -1210,19 +1179,17 @@ define void @test_sincos_v2f128(ptr sret({ <2 x fp128>, 
<2 x fp128> }) %ret, ptr
 ; GNU32-NEXT:    std %f0, [%fp+-120] ! 8-byte Folded Spill
 ; GNU32-NEXT:    ldd [%i1], %f0
 ; GNU32-NEXT:    ldd [%i1+8], %f4
-; GNU32-NEXT:    add %fp, -96, %i1
-; GNU32-NEXT:    st %i1, [%sp+92]
 ; GNU32-NEXT:    std %f4, [%fp+-88]
-; GNU32-NEXT:    add %fp, -64, %o0
-; GNU32-NEXT:    add %fp, -80, %o1
+; 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, [%fp+-96]
-; GNU32-NEXT:    add %fp, -48, %i1
-; GNU32-NEXT:    st %i1, [%sp+92]
 ; GNU32-NEXT:    ldd [%fp+-120], %f0 ! 8-byte Folded Reload
 ; GNU32-NEXT:    std %f0, [%fp+-40]
-; GNU32-NEXT:    add %fp, -16, %o0
-; GNU32-NEXT:    add %fp, -32, %o1
+; 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

>From 16391d0e7e5fd8f6b16c304f75281aef3f802830 Mon Sep 17 00:00:00 2001
From: Koakuma <[email protected]>
Date: Mon, 24 Nov 2025 20:43:45 +0700
Subject: [PATCH 15/15] Add FIXME note and stack argument test

---
 llvm/lib/Target/Sparc/SparcCallingConv.td   |  3 +-
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 17 ++++-------
 llvm/test/CodeGen/SPARC/fp128.ll            | 34 +++++++++++++++++++++
 3 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcCallingConv.td 
b/llvm/lib/Target/Sparc/SparcCallingConv.td
index e829935a3dfb3..d9c50483a029c 100644
--- a/llvm/lib/Target/Sparc/SparcCallingConv.td
+++ b/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -18,6 +18,7 @@ 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]>>,
@@ -35,11 +36,11 @@ 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 a4a498cc81776..d995eaab47ef8 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -454,6 +454,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)
@@ -551,17 +552,11 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
         continue;
       }
 
-      int FI;
-      if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
-        FI = MF.getFrameInfo().CreateFixedObject(4, Offset, true);
-      } else {
-        // We shouldn't see any other value types here.
-        llvm_unreachable("Unexpected ValVT encountered in frame lowering.");
-      }
-
+      int FI = MF.getFrameInfo().CreateFixedObject(LocVT.getSizeInBits() / 8,
+                                                   Offset, true);
       SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT);
-      SDValue Load =
-          DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo());
+      SDValue Load = DAG.getLoad(LocVT, dl, Chain, FIPtr,
+                                 MachinePointerInfo::getFixedStack(MF, FI));
       if (VA.getLocInfo() != CCValAssign::Indirect) {
         InVals.push_back(Load);
         continue;
@@ -580,7 +575,7 @@ SDValue SparcTargetLowering::LowerFormalArguments_32(
     assert(ArgPartOffset == 0);
     while (i + 1 != e && Ins[InIdx + 1].OrigArgIndex == ArgIndex) {
       CCValAssign &PartVA = ArgLocs[i + 1];
-      unsigned PartOffset = Ins[InIdx + 1].PartOffset - ArgPartOffset;
+      unsigned PartOffset = Ins[InIdx + 1].PartOffset;
       SDValue Offset = DAG.getIntPtrConstant(PartOffset, dl);
       SDValue Address = DAG.getNode(ISD::ADD, dl, PtrVT, ArgValue, Offset);
       InVals.push_back(DAG.getLoad(PartVA.getValVT(), dl, Chain, Address,
diff --git a/llvm/test/CodeGen/SPARC/fp128.ll b/llvm/test/CodeGen/SPARC/fp128.ll
index 0ff84bdc0067e..ca99f12468910 100644
--- a/llvm/test/CodeGen/SPARC/fp128.ll
+++ b/llvm/test/CodeGen/SPARC/fp128.ll
@@ -270,3 +270,37 @@ define fp128 @f128_direct(fp128 %num) nounwind {
     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 {
+; CHECK-LABEL: f128_direct_spill:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:  save %sp, -136, %sp
+; CHECK-NEXT:  ld [%fp+96], %g2
+; CHECK-NEXT:  ldd [%g2], %f0
+; CHECK-NEXT:  ldd [%g2+8], %f4
+; CHECK-NEXT:  ld [%fp+64], %l0
+; CHECK-NEXT:  mov %i5, %o5
+; CHECK-NEXT:  mov %i4, %o4
+; CHECK-NEXT:  mov %i3, %o3
+; CHECK-NEXT:  mov %i2, %o2
+; CHECK-NEXT:  mov %i1, %o1
+; CHECK-NEXT:  mov %i0, %o0
+; CHECK-NEXT:  add %fp, -32, %i0
+; CHECK-NEXT:  st %i0, [%sp+92]
+; CHECK-NEXT:  add %fp, -16, %i0
+; CHECK-NEXT:  st %i0, [%sp+64]
+; CHECK-NEXT:  std %f4, [%fp+-24]
+; CHECK-NEXT:  call f128_callee_spill
+; CHECK-NEXT:  std %f0, [%fp+-32]
+; CHECK-NEXT:  unimp 16
+; CHECK-NEXT:  ldd [%fp+-8], %f0
+; CHECK-NEXT:  ldd [%fp+-16], %f4
+; CHECK-NEXT:  std %f0, [%l0+8]
+; CHECK-NEXT:  std %f4, [%l0]
+; CHECK-NEXT:  ret
+; CHECK-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)

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

Reply via email to