[llvm] [SPARC] Use hardware byteswapper when we have V9 (PR #191720)

via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 19 00:59:11 PDT 2026


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

>From 76d56e710d19bc8fa23a8b6df6790b303b0e24e4 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sat, 11 Apr 2026 22:54:59 +0700
Subject: [PATCH 1/3] [SPARC] Use hardware byteswapper when we have V9

On V9 processors we have endianness-adjusted memory operations, that can be
used to implement BSWAPs. Use those instructions whenever possible to reduce
code size.
---
 llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp |  15 ++
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 137 +++++++++-
 llvm/lib/Target/Sparc/SparcISelLowering.h   |   4 +
 llvm/lib/Target/Sparc/SparcInstr64Bit.td    |  12 +
 llvm/lib/Target/Sparc/SparcInstrInfo.td     |  46 +++-
 llvm/test/CodeGen/SPARC/bswap.ll            | 265 ++++++++++++++++++++
 6 files changed, 475 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPARC/bswap.ll

diff --git a/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
index 55bf40e185ff4..db45fa0c509bb 100644
--- a/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
@@ -49,6 +49,7 @@ class SparcDAGToDAGISel : public SelectionDAGISel {
   // Complex Pattern Selectors.
   bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
   bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
+  bool SelectForceADDRrr(SDValue N, SDValue &R1, SDValue &R2);
 
   /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
   /// inline asm expressions.
@@ -152,6 +153,20 @@ bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
   return true;
 }
 
+bool SparcDAGToDAGISel::SelectForceADDRrr(SDValue Addr, SDValue &Base,
+                                          SDValue &Offset) {
+  // If it's already in R+R form then hand it over to regular ADDRrr handling.
+  if (Addr.getNumOperands() == 2 &&
+      !isa<ConstantSDNode>(Addr.getOperand(0).getNode()) &&
+      !isa<ConstantSDNode>(Addr.getOperand(1).getNode()))
+    return SelectADDRrr(Addr, Base, Offset);
+
+  // Otherwise we'll use the full address in base and set the offset part to
+  // zero.
+  Base = Addr;
+  Offset = CurDAG->getRegister(SP::G0, Addr.getValueType());
+  return true;
+}
 
 // Re-assemble i64 arguments split up in SelectionDAGBuilder's
 // visitInlineAsm / GetRegistersForValue functions.
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index bfca95c9b1a38..2af28dae44268 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1807,7 +1807,7 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
 
     setOperationAction(ISD::CTPOP, MVT::i64,
                        Subtarget->usePopc() ? Legal : Expand);
-    setOperationAction(ISD::BSWAP, MVT::i64, Expand);
+    setOperationAction(ISD::BSWAP, MVT::i64, Custom);
     setOperationAction(ISD::ROTL , MVT::i64, Expand);
     setOperationAction(ISD::ROTR , MVT::i64, Expand);
     setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
@@ -1871,7 +1871,7 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
                      Subtarget->isUA2007() ? Legal : Expand);
   setOperationAction(ISD::ROTL , MVT::i32, Expand);
   setOperationAction(ISD::ROTR , MVT::i32, Expand);
-  setOperationAction(ISD::BSWAP, MVT::i32, Expand);
+  setOperationAction(ISD::BSWAP, MVT::i32, Subtarget->isV9() ? Custom : Expand);
   setOperationAction(ISD::FCOPYSIGN, MVT::f128, Expand);
   setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
   setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
@@ -1984,6 +1984,9 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
   if (!Subtarget->is64Bit())
     setTargetDAGCombine(ISD::BITCAST);
 
+  if (Subtarget->isV9())
+    setTargetDAGCombine({ISD::BSWAP, ISD::STORE});
+
   if (Subtarget->hasLeonCycleCounter())
     setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom);
 
@@ -3001,6 +3004,37 @@ static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG)
   return DAG.getMergeValues(Ops, dl);
 }
 
+SDValue SparcTargetLowering::LowerBSWAP(SDValue Op, SelectionDAG &DAG) const {
+  // We don't have an in-register bswap, so expand bswap(x) into
+  // load(store-swapped(x)). The reason the swap is done during the store is
+  // that on some implementations (mainly older ones) ASI-tagged memory
+  // operations are not pipelined, and generally stores finish faster than
+  // loads.
+
+  MachineFunction &MF = DAG.getMachineFunction();
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+  auto PtrVT = getPointerTy(DAG.getDataLayout());
+  SDValue Chain = DAG.getEntryNode();
+  bool IsLittleEndian = DAG.getDataLayout().isLittleEndian();
+  SDLoc DL(Op);
+
+  SDValue BSwapOp = Op.getOperand(0);
+  EVT BSwapVT = BSwapOp.getValueType();
+
+  // Create a stack object to serve as temporary storage.
+  int BSwapFI = MFI.CreateStackObject(BSwapVT.getStoreSize(), Align(8), false);
+  SDValue BSwapPtr = DAG.getFrameIndex(BSwapFI, PtrVT);
+
+  // Store-swap the value, then load it back.
+  SDValue Ops[] = {Chain, BSwapOp, BSwapPtr, DAG.getValueType(BSwapVT)};
+  SDValue SwappedMem = DAG.getMemIntrinsicNode(
+      IsLittleEndian ? SPISD::STORE_BIG : SPISD::STORE_LITTLE, DL,
+      DAG.getVTList(MVT::Other), Ops, BSwapVT, MachinePointerInfo(), Align(8),
+      MachineMemOperand::MOStore);
+  return DAG.getLoad(BSwapVT, DL, SwappedMem, BSwapPtr, MachinePointerInfo(),
+                     Align(8));
+}
+
 static SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG)
 {
   LoadSDNode *LdNode = cast<LoadSDNode>(Op.getNode());
@@ -3173,6 +3207,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   case ISD::STACKADDRESS:
     return LowerSTACKADDRESS(Op, DAG, *Subtarget);
 
+  case ISD::BSWAP:
+    return LowerBSWAP(Op, DAG);
+
   case ISD::LOAD:               return LowerLOAD(Op, DAG);
   case ISD::STORE:              return LowerSTORE(Op, DAG);
   case ISD::FADD:
@@ -3218,6 +3255,98 @@ SDValue SparcTargetLowering::PerformBITCASTCombine(SDNode *N,
   return SDValue();
 }
 
+SDValue SparcTargetLowering::PerformBSWAPCombine(SDNode *N,
+                                                 DAGCombinerInfo &DCI) const {
+  SDLoc DL(N);
+  SelectionDAG &DAG = DCI.DAG;
+  SDValue Op0 = N->getOperand(0);
+  EVT Op0VT = N->getValueType(0);
+  bool IsLittleEndian = DAG.getDataLayout().isLittleEndian();
+
+  // Turn BSWAP (LOAD) -> ld*a #ASI_P(_L) on V9.
+  if (Subtarget->isV9() && ISD::isNormalLoad(Op0.getNode()) &&
+      Op0.getNode()->hasOneUse() &&
+      (Op0VT == MVT::i16 || Op0VT == MVT::i32 ||
+       (Subtarget->is64Bit() && Op0VT == MVT::i64))) {
+    SDValue Load = Op0;
+    LoadSDNode *LD = cast<LoadSDNode>(Load);
+
+    // Create the byte-swapping load.
+    SDValue Ops[] = {
+        LD->getChain(),         // Chain
+        LD->getBasePtr(),       // Ptr
+        DAG.getValueType(Op0VT) // VT
+    };
+
+    SDValue BSLoad = DAG.getMemIntrinsicNode(
+        IsLittleEndian ? SPISD::LOAD_BIG : SPISD::LOAD_LITTLE, DL,
+        DAG.getVTList(Op0VT == MVT::i64 ? MVT::i64 : MVT::i32, MVT::Other), Ops,
+        LD->getMemoryVT(), LD->getMemOperand());
+
+    // If this is an i16 load, insert the truncate.
+    SDValue ResVal = BSLoad;
+    if (Op0VT == MVT::i16)
+      ResVal = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, BSLoad);
+
+    // First, combine the bswap away.  This makes the value produced by the
+    // load dead.
+    DCI.CombineTo(N, ResVal);
+
+    // Next, combine the load away, we give it a bogus result value but a real
+    // chain result.  The result value is dead because the bswap is dead.
+    DCI.CombineTo(Load.getNode(), ResVal, BSLoad.getValue(1));
+
+    // Return N so it doesn't get rechecked!
+    return SDValue(N, 0);
+  }
+
+  return SDValue();
+}
+
+SDValue SparcTargetLowering::PerformSTORECombine(SDNode *N,
+                                                 DAGCombinerInfo &DCI) const {
+  SDLoc DL(N);
+  SelectionDAG &DAG = DCI.DAG;
+  EVT Op1VT = N->getOperand(1).getValueType();
+  unsigned Opcode = N->getOperand(1).getOpcode();
+  bool IsLittleEndian = DAG.getDataLayout().isLittleEndian();
+
+  // Turn STORE (BSWAP) -> st*a #ASI_P(_L) on V9.
+  if (Subtarget->isV9() && Opcode == ISD::BSWAP &&
+      N->getOperand(1).getNode()->hasOneUse() &&
+      (Op1VT == MVT::i16 || Op1VT == MVT::i32 ||
+       (Subtarget->is64Bit() && Op1VT == MVT::i64))) {
+
+    // st*a can only handle simple types and it makes no sense to store less
+    // than two bytes in byte-reversed order.
+    EVT MemVT = cast<StoreSDNode>(N)->getMemoryVT();
+    if (MemVT.isExtended() || MemVT.getSizeInBits() < 16)
+      return SDValue();
+
+    SDValue BSwapOp = N->getOperand(1).getOperand(0);
+    // Do an any-extend to 32-bits if this is a half-word input.
+    if (BSwapOp.getValueType() == MVT::i16)
+      BSwapOp = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, BSwapOp);
+
+    // If the type of BSWAP operand is wider than stored memory width
+    // it needs to be shifted to the right side before st*a.
+    if (Op1VT.bitsGT(MemVT)) {
+      int Shift = Op1VT.getSizeInBits() - MemVT.getSizeInBits();
+      BSwapOp = DAG.getNode(ISD::SRL, DL, Op1VT, BSwapOp,
+                            DAG.getConstant(Shift, DL, MVT::i32));
+    }
+
+    SDValue Ops[] = {N->getOperand(0), BSwapOp, N->getOperand(2),
+                     DAG.getValueType(MemVT)};
+    return DAG.getMemIntrinsicNode(
+        IsLittleEndian ? SPISD::STORE_BIG : SPISD::STORE_LITTLE, DL,
+        DAG.getVTList(MVT::Other), Ops, cast<StoreSDNode>(N)->getMemoryVT(),
+        cast<StoreSDNode>(N)->getMemOperand());
+  }
+
+  return SDValue();
+}
+
 SDValue SparcTargetLowering::PerformDAGCombine(SDNode *N,
                                                DAGCombinerInfo &DCI) const {
   switch (N->getOpcode()) {
@@ -3225,6 +3354,10 @@ SDValue SparcTargetLowering::PerformDAGCombine(SDNode *N,
     break;
   case ISD::BITCAST:
     return PerformBITCASTCombine(N, DCI);
+  case ISD::BSWAP:
+    return PerformBSWAPCombine(N, DCI);
+  case ISD::STORE:
+    return PerformSTORECombine(N, DCI);
   }
   return SDValue();
 }
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h
index f97b0ab9edd93..5098480e192a6 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.h
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.h
@@ -143,9 +143,13 @@ namespace llvm {
     SDValue LowerF128Compare(SDValue LHS, SDValue RHS, unsigned &SPCC,
                              const SDLoc &DL, SelectionDAG &DAG) const;
 
+    SDValue LowerBSWAP(SDValue Op, SelectionDAG &DAG) const;
+
     SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
 
     SDValue PerformBITCASTCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+    SDValue PerformBSWAPCombine(SDNode *N, DAGCombinerInfo &DCI) const;
+    SDValue PerformSTORECombine(SDNode *N, DAGCombinerInfo &DCI) const;
 
     SDValue bitcastConstantFPToInt(ConstantFPSDNode *C, const SDLoc &DL,
                                    SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
index d6d081d51e4bc..5680dcd81ce86 100644
--- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td
+++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td
@@ -500,3 +500,15 @@ def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)),  (ADDri $r, tconstpool:$in)>;
 def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)),
                         (ADDri $r, tblockaddress:$in)>;
 }
+
+// Endian adjusted memory operations.
+let Predicates = [HasV9, Is64Bit] in {
+  // LDSWA is only usable on 64-bit environment.
+  def : Pat<(sext (i32 (SPloadbig    ForceADDRrr:$src, i32))), (LDSWArr ForceADDRrr:$src, 0x80)>;
+  def : Pat<(sext (i32 (SPloadlittle ForceADDRrr:$src, i32))), (LDSWArr ForceADDRrr:$src, 0x88)>;
+
+  def : Pat<(SPloadbig    ForceADDRrr:$src, i64), (LDXArr ForceADDRrr:$src, 0x80)>;
+  def : Pat<(SPloadlittle ForceADDRrr:$src, i64), (LDXArr ForceADDRrr:$src, 0x88)>;
+  def : Pat<(SPstorebig    i64:$val, ForceADDRrr:$dst, i64), (STXArr ForceADDRrr:$dst, $val, 0x80)>;
+  def : Pat<(SPstorelittle i64:$val, ForceADDRrr:$dst, i64), (STXArr ForceADDRrr:$dst, $val, 0x88)>;
+}
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td
index 8717b9347210c..4686cd9f278ce 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -158,6 +158,7 @@ def SETHIimm_not : PatLeaf<(i32 imm), [{
 // Addressing modes.
 def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr", [], []>;
 def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [], []>;
+def ForceADDRrr : ComplexPattern<iPTR, 2, "SelectForceADDRrr", [], []>;
 
 // Constrained operands for the shift operations.
 class ShiftAmtImmAsmOperand<int Bits> : AsmOperandClass {
@@ -336,6 +337,11 @@ SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>;
 def SDTSPloadgdop :
 SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>;
 
+def SDTSPloadbig     : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
+def SDTSPloadlittle  : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
+def SDTSPstorebig    : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
+def SDTSPstorelittle : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
+
 def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>;
 def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>;
 def SPcmpfccv9 : SDNode<"SPISD::CMPFCC_V9", SDTSPcmpfcc, [SDNPOutGlue]>;
@@ -359,6 +365,24 @@ def SPselectxcc : SDNode<"SPISD::SELECT_XCC", SDTSPselectcc, [SDNPInGlue]>;
 def SPselectfcc : SDNode<"SPISD::SELECT_FCC", SDTSPselectcc, [SDNPInGlue]>;
 def SPselectreg : SDNode<"SPISD::SELECT_REG", SDTSPselectreg>;
 
+// GPRC, CHAIN = LOAD_BIG/LITTLE CHAIN, Ptr, Type
+// These are endianness-adjusted load instructions. They load the low "Type"
+// bits of the memory pointed by Ptr, possibly byte swapping it as necessary
+// to account for its in-memory endianness. Type can be i16, i32, or i64.
+def SPloadbig    : SDNode<"SPISD::LOAD_BIG", SDTSPloadbig,
+                           [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+def SPloadlittle : SDNode<"SPISD::LOAD_LITTLE", SDTSPloadlittle,
+                           [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
+// CHAIN = STORE_BIG/LITTLE CHAIN, GPRC, Ptr, Type
+// These are endianness-adjusted store instructions. They store the low "Type"
+// bits of the GPR input out through Ptr, possibly byte swapping it as necessary
+// to adjust its in-memory endianness. Type can be i16, i32, or i64.
+def SPstorebig    : SDNode<"SPISD::STORE_BIG", SDTSPstorebig,
+                           [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+def SPstorelittle : SDNode<"SPISD::STORE_LITTLE", SDTSPstorelittle,
+                           [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
+
 //  These are target-independent nodes, but have target-specific formats.
 def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>,
                                           SDTCisVT<1, i32> ]>;
@@ -546,8 +570,6 @@ multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
                  itin>;
 }
 
-// TODO: Instructions of the StoreASI class are currently asm only; hooking up
-// CodeGen's address spaces to use these is a future task.
 multiclass StoreASI<string OpcStr, bits<6> Op3Val, RegisterClass RC,
                InstrItinClass itin = IIC_st> {
   def rr : F3_1_asi<3, Op3Val, (outs), (ins (MEMrr $rs1, $rs2):$addr, RC:$rd, ASITag:$asi),
@@ -2050,6 +2072,26 @@ def : Pat<(build_vector (i32 IntRegs:$a1), (i32 IntRegs:$a2)),
 	    (INSERT_SUBREG (v2i32 (IMPLICIT_DEF)), (i32 IntRegs:$a1), sub_even),
             (i32 IntRegs:$a2), sub_odd)>;
 
+// Endian adjusted memory operations.
+let Predicates = [HasV9] in {
+  def : Pat<(i32 (SPloadbig    ForceADDRrr:$src, i16)), (LDUHArr ForceADDRrr:$src, 0x80)>;
+  def : Pat<(i32 (SPloadbig    ForceADDRrr:$src, i32)), (LDArr   ForceADDRrr:$src, 0x80)>;
+  def : Pat<(i32 (SPloadlittle ForceADDRrr:$src, i16)), (LDUHArr ForceADDRrr:$src, 0x88)>;
+  def : Pat<(i32 (SPloadlittle ForceADDRrr:$src, i32)), (LDArr   ForceADDRrr:$src, 0x88)>;
+
+  def : Pat<(zanyext (i32 (SPloadbig    ForceADDRrr:$src, i16))), (LDUHArr ForceADDRrr:$src, 0x80)>;
+  def : Pat<(zanyext (i32 (SPloadbig    ForceADDRrr:$src, i32))), (LDArr   ForceADDRrr:$src, 0x80)>;
+  def : Pat<(zanyext (i32 (SPloadlittle ForceADDRrr:$src, i16))), (LDUHArr ForceADDRrr:$src, 0x88)>;
+  def : Pat<(zanyext (i32 (SPloadlittle ForceADDRrr:$src, i32))), (LDArr   ForceADDRrr:$src, 0x88)>;
+
+  def : Pat<(sext    (i32 (SPloadbig    ForceADDRrr:$src, i16))), (LDSHArr ForceADDRrr:$src, 0x80)>;
+  def : Pat<(sext    (i32 (SPloadlittle ForceADDRrr:$src, i16))), (LDSHArr ForceADDRrr:$src, 0x88)>;
+
+  def : Pat<(SPstorebig    i32:$val, ForceADDRrr:$dst, i16), (STHArr ForceADDRrr:$dst, $val, 0x80)>;
+  def : Pat<(SPstorebig    i32:$val, ForceADDRrr:$dst, i32), (STArr  ForceADDRrr:$dst, $val, 0x80)>;
+  def : Pat<(SPstorelittle i32:$val, ForceADDRrr:$dst, i16), (STHArr ForceADDRrr:$dst, $val, 0x88)>;
+  def : Pat<(SPstorelittle i32:$val, ForceADDRrr:$dst, i32), (STArr  ForceADDRrr:$dst, $val, 0x88)>;
+}
 
 include "SparcInstr64Bit.td"
 include "SparcInstrVIS.td"
diff --git a/llvm/test/CodeGen/SPARC/bswap.ll b/llvm/test/CodeGen/SPARC/bswap.ll
new file mode 100644
index 0000000000000..b007d588f02c6
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/bswap.ll
@@ -0,0 +1,265 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=sparc   -mcpu=v9 | FileCheck %s --check-prefix=SPARC32
+; RUN: llc < %s -mtriple=sparcel -mcpu=v9 | FileCheck %s --check-prefix=SPARCEL
+; RUN: llc < %s -mtriple=sparc64 -mcpu=v9 | FileCheck %s --check-prefix=SPARC64
+
+;; On V9 processors we can use endian-adjusted memory accessess to implement
+;; byte swapping for more compact code.
+
+declare i16 @llvm.bswap.i16(i16)
+declare i32 @llvm.bswap.i32(i32)
+declare i64 @llvm.bswap.i64(i64)
+
+define i16 @u16_bswap(i16 %0) #0 {
+; SPARC32-LABEL: u16_bswap:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -104, %sp
+; SPARC32-NEXT:    add %sp, 96, %o1
+; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC32-NEXT:    lduh [%sp+96], %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 104, %sp
+;
+; SPARCEL-LABEL: u16_bswap:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -104, %sp
+; SPARCEL-NEXT:    add %sp, 96, %o1
+; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
+; SPARCEL-NEXT:    or %o1, 2, %o0
+; SPARCEL-NEXT:    lduh [%o0], %o0
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 104, %sp
+;
+; SPARC64-LABEL: u16_bswap:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    add %sp, 2183, %o1
+; SPARC64-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC64-NEXT:    lduh [%sp+2183], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %2 = tail call i16 @llvm.bswap.i16(i16 %0)
+  ret i16 %2
+}
+
+define i32 @u32_bswap(i32 %0) #0 {
+; SPARC32-LABEL: u32_bswap:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -104, %sp
+; SPARC32-NEXT:    add %sp, 96, %o1
+; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC32-NEXT:    ld [%sp+96], %o0
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 104, %sp
+;
+; SPARCEL-LABEL: u32_bswap:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -104, %sp
+; SPARCEL-NEXT:    add %sp, 96, %o1
+; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
+; SPARCEL-NEXT:    ld [%sp+96], %o0
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 104, %sp
+;
+; SPARC64-LABEL: u32_bswap:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    add %sp, 2183, %o1
+; SPARC64-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC64-NEXT:    ld [%sp+2183], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %2 = tail call i32 @llvm.bswap.i32(i32 %0)
+  ret i32 %2
+}
+
+define i64 @u64_bswap(i64 %0) #0 {
+; SPARC32-LABEL: u64_bswap:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -112, %sp
+; SPARC32-NEXT:    add %sp, 104, %o2
+; SPARC32-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC32-NEXT:    add %sp, 96, %o1
+; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
+; SPARC32-NEXT:    ld [%sp+104], %o0
+; SPARC32-NEXT:    ld [%sp+96], %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 112, %sp
+;
+; SPARCEL-LABEL: u64_bswap:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -112, %sp
+; SPARCEL-NEXT:    add %sp, 104, %o2
+; SPARCEL-NEXT:    sta %o1, [%o2] #ASI_P
+; SPARCEL-NEXT:    add %sp, 96, %o1
+; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
+; SPARCEL-NEXT:    ld [%sp+104], %o0
+; SPARCEL-NEXT:    ld [%sp+96], %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 112, %sp
+;
+; SPARC64-LABEL: u64_bswap:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    add %sp, -144, %sp
+; SPARC64-NEXT:    add %sp, 2183, %o1
+; SPARC64-NEXT:    stxa %o0, [%o1] #ASI_P_L
+; SPARC64-NEXT:    ldx [%sp+2183], %o0
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    add %sp, 144, %sp
+  %2 = tail call i64 @llvm.bswap.i64(i64 %0)
+  ret i64 %2
+}
+
+define i16 @u16_bswapload(ptr %0) #0 {
+; SPARC32-LABEL: u16_bswapload:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    lduha [%o0] #ASI_P_L, %o0
+;
+; SPARCEL-LABEL: u16_bswapload:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    lduha [%o0] #ASI_P, %o0
+;
+; SPARC64-LABEL: u16_bswapload:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    lduha [%o0] #ASI_P_L, %o0
+  %2 = load i16, ptr %0, align 2
+  %3 = tail call i16 @llvm.bswap.i16(i16 %2)
+  ret i16 %3
+}
+
+define i32 @u32_bswapload(ptr %0) #0 {
+; SPARC32-LABEL: u32_bswapload:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    lda [%o0] #ASI_P_L, %o0
+;
+; SPARCEL-LABEL: u32_bswapload:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    lda [%o0] #ASI_P, %o0
+;
+; SPARC64-LABEL: u32_bswapload:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    lda [%o0] #ASI_P_L, %o0
+  %2 = load i32, ptr %0, align 4
+  %3 = tail call i32 @llvm.bswap.i32(i32 %2)
+  ret i32 %3
+}
+
+define i64 @u64_bswapload(ptr %0) #0 {
+; SPARC32-LABEL: u64_bswapload:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -112, %sp
+; SPARC32-NEXT:    ldd [%o0], %o0
+; SPARC32-NEXT:    add %sp, 96, %o2
+; SPARC32-NEXT:    sta %o1, [%o2] #ASI_P_L
+; SPARC32-NEXT:    add %sp, 104, %o2
+; SPARC32-NEXT:    sta %o0, [%o2] #ASI_P_L
+; SPARC32-NEXT:    ld [%sp+96], %o0
+; SPARC32-NEXT:    ld [%sp+104], %o1
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 112, %sp
+;
+; SPARCEL-LABEL: u64_bswapload:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -112, %sp
+; SPARCEL-NEXT:    ldd [%o0], %o0
+; SPARCEL-NEXT:    add %sp, 96, %o2
+; SPARCEL-NEXT:    sta %o1, [%o2] #ASI_P
+; SPARCEL-NEXT:    add %sp, 104, %o2
+; SPARCEL-NEXT:    sta %o0, [%o2] #ASI_P
+; SPARCEL-NEXT:    ld [%sp+96], %o0
+; SPARCEL-NEXT:    ld [%sp+104], %o1
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 112, %sp
+;
+; SPARC64-LABEL: u64_bswapload:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    ldxa [%o0] #ASI_P_L, %o0
+  %2 = load i64, ptr %0, align 8
+  %3 = tail call i64 @llvm.bswap.i64(i64 %2)
+  ret i64 %3
+}
+
+define void @u16_bswapstore(ptr %0, i16 %1) #0 {
+; SPARC32-LABEL: u16_bswapstore:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    stha %o1, [%o0] #ASI_P_L
+;
+; SPARCEL-LABEL: u16_bswapstore:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    stha %o1, [%o0] #ASI_P
+;
+; SPARC64-LABEL: u16_bswapstore:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    stha %o1, [%o0] #ASI_P_L
+  %3 = tail call i16 @llvm.bswap.i16(i16 %1)
+  store i16 %3, ptr %0, align 2
+  ret void
+}
+
+define void @u32_bswapstore(ptr %0, i32 %1) #0 {
+; SPARC32-LABEL: u32_bswapstore:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    sta %o1, [%o0] #ASI_P_L
+;
+; SPARCEL-LABEL: u32_bswapstore:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    sta %o1, [%o0] #ASI_P
+;
+; SPARC64-LABEL: u32_bswapstore:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    sta %o1, [%o0] #ASI_P_L
+  %3 = tail call i32 @llvm.bswap.i32(i32 %1)
+  store i32 %3, ptr %0, align 4
+  ret void
+}
+
+define void @u64_bswapstore(ptr %0, i64 %1) #0 {
+; SPARC32-LABEL: u64_bswapstore:
+; SPARC32:       ! %bb.0:
+; SPARC32-NEXT:    add %sp, -112, %sp
+; SPARC32-NEXT:    add %sp, 96, %o3
+; SPARC32-NEXT:    sta %o1, [%o3] #ASI_P_L
+; SPARC32-NEXT:    add %sp, 104, %o1
+; SPARC32-NEXT:    sta %o2, [%o1] #ASI_P_L
+; SPARC32-NEXT:    ld [%sp+96], %o3
+; SPARC32-NEXT:    ld [%sp+104], %o2
+; SPARC32-NEXT:    std %o2, [%o0]
+; SPARC32-NEXT:    retl
+; SPARC32-NEXT:    add %sp, 112, %sp
+;
+; SPARCEL-LABEL: u64_bswapstore:
+; SPARCEL:       ! %bb.0:
+; SPARCEL-NEXT:    add %sp, -112, %sp
+; SPARCEL-NEXT:    add %sp, 96, %o3
+; SPARCEL-NEXT:    sta %o1, [%o3] #ASI_P
+; SPARCEL-NEXT:    add %sp, 104, %o1
+; SPARCEL-NEXT:    sta %o2, [%o1] #ASI_P
+; SPARCEL-NEXT:    ld [%sp+96], %o3
+; SPARCEL-NEXT:    ld [%sp+104], %o2
+; SPARCEL-NEXT:    std %o2, [%o0]
+; SPARCEL-NEXT:    retl
+; SPARCEL-NEXT:    add %sp, 112, %sp
+;
+; SPARC64-LABEL: u64_bswapstore:
+; SPARC64:       ! %bb.0:
+; SPARC64-NEXT:    retl
+; SPARC64-NEXT:    stxa %o1, [%o0] #ASI_P_L
+  %3 = tail call i64 @llvm.bswap.i64(i64 %1)
+  store i64 %3, ptr %0, align 8
+  ret void
+}
+
+attributes #0 = { nounwind }

>From 2fb812e990853591c761ec810c0d0523f4969690 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Tue, 14 Apr 2026 06:11:36 +0700
Subject: [PATCH 2/3] Use getPointerTy for SelectForceADDRrr

---
 llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
index db45fa0c509bb..8ed9c5222a3a1 100644
--- a/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
@@ -49,7 +49,7 @@ class SparcDAGToDAGISel : public SelectionDAGISel {
   // Complex Pattern Selectors.
   bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
   bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
-  bool SelectForceADDRrr(SDValue N, SDValue &R1, SDValue &R2);
+  bool SelectForceADDRrr(SDValue N, SDValue &Base, SDValue &Disp);
 
   /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
   /// inline asm expressions.
@@ -154,17 +154,18 @@ bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
 }
 
 bool SparcDAGToDAGISel::SelectForceADDRrr(SDValue Addr, SDValue &Base,
-                                          SDValue &Offset) {
+                                          SDValue &Disp) {
   // If it's already in R+R form then hand it over to regular ADDRrr handling.
   if (Addr.getNumOperands() == 2 &&
       !isa<ConstantSDNode>(Addr.getOperand(0).getNode()) &&
       !isa<ConstantSDNode>(Addr.getOperand(1).getNode()))
-    return SelectADDRrr(Addr, Base, Offset);
+    return SelectADDRrr(Addr, Base, Disp);
 
   // Otherwise we'll use the full address in base and set the offset part to
   // zero.
   Base = Addr;
-  Offset = CurDAG->getRegister(SP::G0, Addr.getValueType());
+  Disp =
+      CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
   return true;
 }
 

>From 7fe968551b9fa65e032ea485adb742d17086757e Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sun, 19 Apr 2026 14:48:27 +0700
Subject: [PATCH 3/3] Apply feedback

---
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 33 ++++----
 llvm/test/CodeGen/SPARC/bswap.ll            | 86 ++++++++++-----------
 2 files changed, 56 insertions(+), 63 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 2af28dae44268..4bacca06a9eb0 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -3013,26 +3013,28 @@ SDValue SparcTargetLowering::LowerBSWAP(SDValue Op, SelectionDAG &DAG) const {
 
   MachineFunction &MF = DAG.getMachineFunction();
   MachineFrameInfo &MFI = MF.getFrameInfo();
-  auto PtrVT = getPointerTy(DAG.getDataLayout());
+  MVT PtrVT = getPointerTy(DAG.getDataLayout());
   SDValue Chain = DAG.getEntryNode();
   bool IsLittleEndian = DAG.getDataLayout().isLittleEndian();
   SDLoc DL(Op);
 
   SDValue BSwapOp = Op.getOperand(0);
-  EVT BSwapVT = BSwapOp.getValueType();
+  EVT VT = BSwapOp.getValueType();
+  Type *Ty = VT.getTypeForEVT(*DAG.getContext());
+  Align Al = DAG.getDataLayout().getABITypeAlign(Ty);
 
   // Create a stack object to serve as temporary storage.
-  int BSwapFI = MFI.CreateStackObject(BSwapVT.getStoreSize(), Align(8), false);
-  SDValue BSwapPtr = DAG.getFrameIndex(BSwapFI, PtrVT);
+  int TmpFI = MFI.CreateStackObject(VT.getStoreSize(), Al, false);
+  SDValue TmpPtr = DAG.getFrameIndex(TmpFI, PtrVT);
 
   // Store-swap the value, then load it back.
-  SDValue Ops[] = {Chain, BSwapOp, BSwapPtr, DAG.getValueType(BSwapVT)};
-  SDValue SwappedMem = DAG.getMemIntrinsicNode(
+  SDValue Ops[] = {Chain, BSwapOp, TmpPtr, DAG.getValueType(VT)};
+  SDValue ST = DAG.getMemIntrinsicNode(
       IsLittleEndian ? SPISD::STORE_BIG : SPISD::STORE_LITTLE, DL,
-      DAG.getVTList(MVT::Other), Ops, BSwapVT, MachinePointerInfo(), Align(8),
-      MachineMemOperand::MOStore);
-  return DAG.getLoad(BSwapVT, DL, SwappedMem, BSwapPtr, MachinePointerInfo(),
-                     Align(8));
+      DAG.getVTList(MVT::Other), Ops, VT,
+      MachinePointerInfo::getFixedStack(MF, TmpFI));
+  return DAG.getLoad(VT, DL, ST, TmpPtr,
+                     MachinePointerInfo::getFixedStack(MF, TmpFI));
 }
 
 static SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG)
@@ -3288,16 +3290,7 @@ SDValue SparcTargetLowering::PerformBSWAPCombine(SDNode *N,
     if (Op0VT == MVT::i16)
       ResVal = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, BSLoad);
 
-    // First, combine the bswap away.  This makes the value produced by the
-    // load dead.
-    DCI.CombineTo(N, ResVal);
-
-    // Next, combine the load away, we give it a bogus result value but a real
-    // chain result.  The result value is dead because the bswap is dead.
-    DCI.CombineTo(Load.getNode(), ResVal, BSLoad.getValue(1));
-
-    // Return N so it doesn't get rechecked!
-    return SDValue(N, 0);
+    return DCI.CombineTo(N, ResVal);
   }
 
   return SDValue();
diff --git a/llvm/test/CodeGen/SPARC/bswap.ll b/llvm/test/CodeGen/SPARC/bswap.ll
index b007d588f02c6..b182862561752 100644
--- a/llvm/test/CodeGen/SPARC/bswap.ll
+++ b/llvm/test/CodeGen/SPARC/bswap.ll
@@ -13,29 +13,29 @@ declare i64 @llvm.bswap.i64(i64)
 define i16 @u16_bswap(i16 %0) #0 {
 ; SPARC32-LABEL: u16_bswap:
 ; SPARC32:       ! %bb.0:
-; SPARC32-NEXT:    add %sp, -104, %sp
-; SPARC32-NEXT:    add %sp, 96, %o1
+; SPARC32-NEXT:    add %sp, -96, %sp
+; SPARC32-NEXT:    add %sp, 92, %o1
 ; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
-; SPARC32-NEXT:    lduh [%sp+96], %o0
+; SPARC32-NEXT:    lduh [%sp+92], %o0
 ; SPARC32-NEXT:    retl
-; SPARC32-NEXT:    add %sp, 104, %sp
+; SPARC32-NEXT:    add %sp, 96, %sp
 ;
 ; SPARCEL-LABEL: u16_bswap:
 ; SPARCEL:       ! %bb.0:
-; SPARCEL-NEXT:    add %sp, -104, %sp
-; SPARCEL-NEXT:    add %sp, 96, %o1
+; SPARCEL-NEXT:    add %sp, -96, %sp
+; SPARCEL-NEXT:    add %sp, 92, %o1
 ; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
 ; SPARCEL-NEXT:    or %o1, 2, %o0
 ; SPARCEL-NEXT:    lduh [%o0], %o0
 ; SPARCEL-NEXT:    retl
-; SPARCEL-NEXT:    add %sp, 104, %sp
+; SPARCEL-NEXT:    add %sp, 96, %sp
 ;
 ; SPARC64-LABEL: u16_bswap:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %sp, -144, %sp
-; SPARC64-NEXT:    add %sp, 2183, %o1
+; SPARC64-NEXT:    add %sp, 2187, %o1
 ; SPARC64-NEXT:    sta %o0, [%o1] #ASI_P_L
-; SPARC64-NEXT:    lduh [%sp+2183], %o0
+; SPARC64-NEXT:    lduh [%sp+2187], %o0
 ; SPARC64-NEXT:    retl
 ; SPARC64-NEXT:    add %sp, 144, %sp
   %2 = tail call i16 @llvm.bswap.i16(i16 %0)
@@ -45,28 +45,28 @@ define i16 @u16_bswap(i16 %0) #0 {
 define i32 @u32_bswap(i32 %0) #0 {
 ; SPARC32-LABEL: u32_bswap:
 ; SPARC32:       ! %bb.0:
-; SPARC32-NEXT:    add %sp, -104, %sp
-; SPARC32-NEXT:    add %sp, 96, %o1
+; SPARC32-NEXT:    add %sp, -96, %sp
+; SPARC32-NEXT:    add %sp, 92, %o1
 ; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
-; SPARC32-NEXT:    ld [%sp+96], %o0
+; SPARC32-NEXT:    ld [%sp+92], %o0
 ; SPARC32-NEXT:    retl
-; SPARC32-NEXT:    add %sp, 104, %sp
+; SPARC32-NEXT:    add %sp, 96, %sp
 ;
 ; SPARCEL-LABEL: u32_bswap:
 ; SPARCEL:       ! %bb.0:
-; SPARCEL-NEXT:    add %sp, -104, %sp
-; SPARCEL-NEXT:    add %sp, 96, %o1
+; SPARCEL-NEXT:    add %sp, -96, %sp
+; SPARCEL-NEXT:    add %sp, 92, %o1
 ; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
-; SPARCEL-NEXT:    ld [%sp+96], %o0
+; SPARCEL-NEXT:    ld [%sp+92], %o0
 ; SPARCEL-NEXT:    retl
-; SPARCEL-NEXT:    add %sp, 104, %sp
+; SPARCEL-NEXT:    add %sp, 96, %sp
 ;
 ; SPARC64-LABEL: u32_bswap:
 ; SPARC64:       ! %bb.0:
 ; SPARC64-NEXT:    add %sp, -144, %sp
-; SPARC64-NEXT:    add %sp, 2183, %o1
+; SPARC64-NEXT:    add %sp, 2187, %o1
 ; SPARC64-NEXT:    sta %o0, [%o1] #ASI_P_L
-; SPARC64-NEXT:    ld [%sp+2183], %o0
+; SPARC64-NEXT:    ld [%sp+2187], %o0
 ; SPARC64-NEXT:    retl
 ; SPARC64-NEXT:    add %sp, 144, %sp
   %2 = tail call i32 @llvm.bswap.i32(i32 %0)
@@ -76,27 +76,27 @@ define i32 @u32_bswap(i32 %0) #0 {
 define i64 @u64_bswap(i64 %0) #0 {
 ; SPARC32-LABEL: u64_bswap:
 ; SPARC32:       ! %bb.0:
-; SPARC32-NEXT:    add %sp, -112, %sp
-; SPARC32-NEXT:    add %sp, 104, %o2
+; SPARC32-NEXT:    add %sp, -104, %sp
+; SPARC32-NEXT:    add %sp, 100, %o2
 ; SPARC32-NEXT:    sta %o1, [%o2] #ASI_P_L
 ; SPARC32-NEXT:    add %sp, 96, %o1
 ; SPARC32-NEXT:    sta %o0, [%o1] #ASI_P_L
-; SPARC32-NEXT:    ld [%sp+104], %o0
+; SPARC32-NEXT:    ld [%sp+100], %o0
 ; SPARC32-NEXT:    ld [%sp+96], %o1
 ; SPARC32-NEXT:    retl
-; SPARC32-NEXT:    add %sp, 112, %sp
+; SPARC32-NEXT:    add %sp, 104, %sp
 ;
 ; SPARCEL-LABEL: u64_bswap:
 ; SPARCEL:       ! %bb.0:
-; SPARCEL-NEXT:    add %sp, -112, %sp
-; SPARCEL-NEXT:    add %sp, 104, %o2
+; SPARCEL-NEXT:    add %sp, -104, %sp
+; SPARCEL-NEXT:    add %sp, 100, %o2
 ; SPARCEL-NEXT:    sta %o1, [%o2] #ASI_P
 ; SPARCEL-NEXT:    add %sp, 96, %o1
 ; SPARCEL-NEXT:    sta %o0, [%o1] #ASI_P
-; SPARCEL-NEXT:    ld [%sp+104], %o0
+; SPARCEL-NEXT:    ld [%sp+100], %o0
 ; SPARCEL-NEXT:    ld [%sp+96], %o1
 ; SPARCEL-NEXT:    retl
-; SPARCEL-NEXT:    add %sp, 112, %sp
+; SPARCEL-NEXT:    add %sp, 104, %sp
 ;
 ; SPARC64-LABEL: u64_bswap:
 ; SPARC64:       ! %bb.0:
@@ -153,29 +153,29 @@ define i32 @u32_bswapload(ptr %0) #0 {
 define i64 @u64_bswapload(ptr %0) #0 {
 ; SPARC32-LABEL: u64_bswapload:
 ; SPARC32:       ! %bb.0:
-; SPARC32-NEXT:    add %sp, -112, %sp
+; SPARC32-NEXT:    add %sp, -104, %sp
 ; SPARC32-NEXT:    ldd [%o0], %o0
 ; SPARC32-NEXT:    add %sp, 96, %o2
 ; SPARC32-NEXT:    sta %o1, [%o2] #ASI_P_L
-; SPARC32-NEXT:    add %sp, 104, %o2
+; SPARC32-NEXT:    add %sp, 100, %o2
 ; SPARC32-NEXT:    sta %o0, [%o2] #ASI_P_L
 ; SPARC32-NEXT:    ld [%sp+96], %o0
-; SPARC32-NEXT:    ld [%sp+104], %o1
+; SPARC32-NEXT:    ld [%sp+100], %o1
 ; SPARC32-NEXT:    retl
-; SPARC32-NEXT:    add %sp, 112, %sp
+; SPARC32-NEXT:    add %sp, 104, %sp
 ;
 ; SPARCEL-LABEL: u64_bswapload:
 ; SPARCEL:       ! %bb.0:
-; SPARCEL-NEXT:    add %sp, -112, %sp
+; SPARCEL-NEXT:    add %sp, -104, %sp
 ; SPARCEL-NEXT:    ldd [%o0], %o0
 ; SPARCEL-NEXT:    add %sp, 96, %o2
 ; SPARCEL-NEXT:    sta %o1, [%o2] #ASI_P
-; SPARCEL-NEXT:    add %sp, 104, %o2
+; SPARCEL-NEXT:    add %sp, 100, %o2
 ; SPARCEL-NEXT:    sta %o0, [%o2] #ASI_P
 ; SPARCEL-NEXT:    ld [%sp+96], %o0
-; SPARCEL-NEXT:    ld [%sp+104], %o1
+; SPARCEL-NEXT:    ld [%sp+100], %o1
 ; SPARCEL-NEXT:    retl
-; SPARCEL-NEXT:    add %sp, 112, %sp
+; SPARCEL-NEXT:    add %sp, 104, %sp
 ;
 ; SPARC64-LABEL: u64_bswapload:
 ; SPARC64:       ! %bb.0:
@@ -229,29 +229,29 @@ define void @u32_bswapstore(ptr %0, i32 %1) #0 {
 define void @u64_bswapstore(ptr %0, i64 %1) #0 {
 ; SPARC32-LABEL: u64_bswapstore:
 ; SPARC32:       ! %bb.0:
-; SPARC32-NEXT:    add %sp, -112, %sp
+; SPARC32-NEXT:    add %sp, -104, %sp
 ; SPARC32-NEXT:    add %sp, 96, %o3
 ; SPARC32-NEXT:    sta %o1, [%o3] #ASI_P_L
-; SPARC32-NEXT:    add %sp, 104, %o1
+; SPARC32-NEXT:    add %sp, 100, %o1
 ; SPARC32-NEXT:    sta %o2, [%o1] #ASI_P_L
 ; SPARC32-NEXT:    ld [%sp+96], %o3
-; SPARC32-NEXT:    ld [%sp+104], %o2
+; SPARC32-NEXT:    ld [%sp+100], %o2
 ; SPARC32-NEXT:    std %o2, [%o0]
 ; SPARC32-NEXT:    retl
-; SPARC32-NEXT:    add %sp, 112, %sp
+; SPARC32-NEXT:    add %sp, 104, %sp
 ;
 ; SPARCEL-LABEL: u64_bswapstore:
 ; SPARCEL:       ! %bb.0:
-; SPARCEL-NEXT:    add %sp, -112, %sp
+; SPARCEL-NEXT:    add %sp, -104, %sp
 ; SPARCEL-NEXT:    add %sp, 96, %o3
 ; SPARCEL-NEXT:    sta %o1, [%o3] #ASI_P
-; SPARCEL-NEXT:    add %sp, 104, %o1
+; SPARCEL-NEXT:    add %sp, 100, %o1
 ; SPARCEL-NEXT:    sta %o2, [%o1] #ASI_P
 ; SPARCEL-NEXT:    ld [%sp+96], %o3
-; SPARCEL-NEXT:    ld [%sp+104], %o2
+; SPARCEL-NEXT:    ld [%sp+100], %o2
 ; SPARCEL-NEXT:    std %o2, [%o0]
 ; SPARCEL-NEXT:    retl
-; SPARCEL-NEXT:    add %sp, 112, %sp
+; SPARCEL-NEXT:    add %sp, 104, %sp
 ;
 ; SPARC64-LABEL: u64_bswapstore:
 ; SPARC64:       ! %bb.0:



More information about the llvm-commits mailing list