[llvm] [SPARC] Preserve liveins after leaf register remapping (PR #213359)

Kirill A. Korinsky via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 8 15:41:53 PDT 2026


https://github.com/catap updated https://github.com/llvm/llvm-project/pull/213359

>From 6848ec2bd15abbe5eb5a78149e02d454aa9c01a1 Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill at korins.ky>
Date: Sun, 9 Aug 2026 00:40:19 +0200
Subject: [PATCH] [SPARC] Preserve liveins after leaf register remapping

Leaf procedure lowering maps I registers to O registers.
llvm.read_register calls for reserved registers do not add machine
liveins, so mapping i7 to unreserved o7 leaves an undefined physical
register use.

The issue predates the reverted named register alias commit
cee7b71929312666c5cf48eb79873893811b99a7, which exposed it.

Classify leaf procedures after instruction selection, before reserved
registers are frozen, instead of modifying the function from
determineCalleeSaves. Reserve input and local registers and their
physical aliases before register allocation, then remap operands and
liveins to their output register counterparts.

Emit the corresponding CFA offset for leaf procedures with stack frames.
---
 llvm/lib/Target/Sparc/SparcFrameLowering.cpp  | 98 +++++++++----------
 llvm/lib/Target/Sparc/SparcFrameLowering.h    |  7 +-
 llvm/lib/Target/Sparc/SparcISelLowering.cpp   | 36 +++++++
 llvm/lib/Target/Sparc/SparcISelLowering.h     |  3 +
 llvm/lib/Target/Sparc/SparcRegisterInfo.cpp   | 17 ++++
 llvm/lib/Target/Sparc/SparcRegisterInfo.td    | 30 +++++-
 llvm/lib/Target/Sparc/SparcSubtarget.h        |  2 +-
 llvm/test/CodeGen/SPARC/2011-01-11-CC.ll      | 24 ++---
 .../CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll  |  4 +-
 llvm/test/CodeGen/SPARC/fp128-select.ll       |  8 +-
 llvm/test/CodeGen/SPARC/leafproc-reg-pair.mir | 24 +++++
 llvm/test/CodeGen/SPARC/leafproc.ll           | 18 ++++
 .../test/CodeGen/SPARC/reserved-regs-named.ll | 65 +++++++++++-
 llvm/test/CodeGen/SPARC/reserved-regs.ll      | 44 ++++++---
 .../SPARC/smulo-128-legalisation-lowering.ll  |  4 +-
 .../SPARC/umulo-128-legalisation-lowering.ll  |  4 +-
 16 files changed, 288 insertions(+), 100 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPARC/leafproc-reg-pair.mir

diff --git a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
index fa08d4474f39e..c53fc1ac9346e 100644
--- a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
@@ -14,6 +14,7 @@
 #include "SparcInstrInfo.h"
 #include "SparcMachineFunctionInfo.h"
 #include "SparcSubtarget.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/CodeGen/CFIInstBuilder.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
@@ -137,9 +138,13 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF,
 
   if (MF.needsFrameMoves()) {
     CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::NoFlags);
-    CFIBuilder.buildDefCFARegister(SP::I6);
-    CFIBuilder.buildWindowSave();
-    CFIBuilder.buildRegister(SP::O7, SP::I7);
+    if (FuncInfo->isLeafProc()) {
+      CFIBuilder.buildDefCFAOffset(NumBytes + Subtarget.getStackPointerBias());
+    } else {
+      CFIBuilder.buildDefCFARegister(SP::I6);
+      CFIBuilder.buildWindowSave();
+      CFIBuilder.buildRegister(SP::O7, SP::I7);
+    }
   }
 }
 
@@ -259,53 +264,53 @@ SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
   return true;
 }
 
-bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const
-{
-
-  MachineRegisterInfo &MRI = MF.getRegInfo();
-  MachineFrameInfo    &MFI = MF.getFrameInfo();
-
-  return !(MFI.hasCalls()               // has calls
-           || MRI.isPhysRegUsed(SP::L0) // Too many registers needed
-           || MRI.isPhysRegUsed(SP::O6) // %sp is used
-           || hasFP(MF)                 // need %fp
-           || MF.hasInlineAsm());       // has inline assembly
+bool SparcFrameLowering::isLeafProc(MachineFunction &MF,
+                                    bool UsesLocalRegister) const {
+  if (MF.getFrameInfo().hasCalls() || MF.getRegInfo().isPhysRegUsed(SP::O6) ||
+      hasFP(MF) || MF.hasInlineAsm() || UsesLocalRegister)
+    return false;
+  return true;
 }
 
 void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
   MachineRegisterInfo &MRI = MF.getRegInfo();
-  // Remap %i[0-7] to %o[0-7].
-  for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
-    if (!MRI.isPhysRegUsed(reg))
-      continue;
-
-    unsigned mapped_reg = reg - SP::I0 + SP::O0;
-
-    // Replace I register with O register.
-    MRI.replaceRegWith(reg, mapped_reg);
+  const SparcRegisterInfo *TRI =
+      MF.getSubtarget<SparcSubtarget>().getRegisterInfo();
+  DenseMap<MCRegister, MCRegister> RegMap;
+  auto RemapReg = [&](MCRegister Reg, MCRegister MappedReg) {
+    auto [It, Inserted] = RegMap.try_emplace(Reg, MappedReg);
+    assert((Inserted || It->second == MappedReg) &&
+           "inconsistent leaf register mapping");
+    if (!Inserted)
+      return;
+    MRI.replaceRegWith(Reg, MappedReg);
+  };
 
-    // Also replace register pair super-registers.
-    if ((reg - SP::I0) % 2 == 0) {
-      unsigned preg = (reg - SP::I0) / 2 + SP::I0_I1;
-      unsigned mapped_preg = preg - SP::I0_I1 + SP::O0_O1;
-      MRI.replaceRegWith(preg, mapped_preg);
+  // Remap %i[0-7] to %o[0-7].
+  for (unsigned Reg = SP::I0; Reg <= SP::I7; ++Reg) {
+    MCRegister MappedReg = Reg - SP::I0 + SP::O0;
+    RemapReg(Reg, MappedReg);
+    for (MCRegAliasIterator AI(Reg, TRI, false); AI.isValid(); ++AI) {
+      unsigned SubRegIndex = TRI->getSubRegIndex(*AI, Reg);
+      if (!SubRegIndex)
+        continue;
+      MCRegister MappedAlias = TRI->getMatchingSuperReg(MappedReg, SubRegIndex,
+                                                        &SP::IntPairRegClass);
+      assert(MappedAlias);
+      RemapReg(*AI, MappedAlias);
     }
   }
 
   // Rewrite MBB's Live-ins.
   for (MachineBasicBlock &MBB : MF) {
-    for (unsigned reg = SP::I0_I1; reg <= SP::I6_I7; ++reg) {
-      if (!MBB.isLiveIn(reg))
-        continue;
-      MBB.removeLiveIn(reg);
-      MBB.addLiveIn(reg - SP::I0_I1 + SP::O0_O1);
-    }
-    for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
-      if (!MBB.isLiveIn(reg))
-        continue;
-      MBB.removeLiveIn(reg);
-      MBB.addLiveIn(reg - SP::I0 + SP::O0);
+    std::vector<MachineBasicBlock::RegisterMaskPair> LiveIns;
+    MBB.clearLiveIns(LiveIns);
+    for (const auto &LiveIn : LiveIns) {
+      auto It = RegMap.find(LiveIn.PhysReg);
+      MBB.addLiveIn(It == RegMap.end() ? LiveIn.PhysReg : It->second,
+                    LiveIn.LaneMask);
     }
+    MBB.sortUniqueLiveIns();
   }
 
   assert(verifyLeafProcRegUse(&MRI));
@@ -314,15 +319,10 @@ void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
 #endif
 }
 
-void SparcFrameLowering::determineCalleeSaves(MachineFunction &MF,
-                                              BitVector &SavedRegs,
-                                              RegScavenger *RS) const {
-  TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
-  if (!DisableLeafProc && isLeafProc(MF)) {
-    SparcMachineFunctionInfo *MFI = MF.getInfo<SparcMachineFunctionInfo>();
-    MFI->setLeafProc(true);
-
+void SparcFrameLowering::finalizeLeafProc(MachineFunction &MF,
+                                          bool UsesLocalRegister) const {
+  bool IsLeafProc = !DisableLeafProc && isLeafProc(MF, UsesLocalRegister);
+  MF.getInfo<SparcMachineFunctionInfo>()->setLeafProc(IsLeafProc);
+  if (IsLeafProc)
     remapRegsForLeafProc(MF);
-  }
-
 }
diff --git a/llvm/lib/Target/Sparc/SparcFrameLowering.h b/llvm/lib/Target/Sparc/SparcFrameLowering.h
index 803856811969b..42e0981c381ef 100644
--- a/llvm/lib/Target/Sparc/SparcFrameLowering.h
+++ b/llvm/lib/Target/Sparc/SparcFrameLowering.h
@@ -35,8 +35,8 @@ class SparcFrameLowering : public TargetFrameLowering {
                                 MachineBasicBlock::iterator I) const override;
 
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
-  void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
-                            RegScavenger *RS = nullptr) const override;
+
+  void finalizeLeafProc(MachineFunction &MF, bool UsesLocalRegister) const;
 
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
@@ -54,8 +54,7 @@ class SparcFrameLowering : public TargetFrameLowering {
   void remapRegsForLeafProc(MachineFunction &MF) const;
 
   // Returns true if MF is a leaf procedure.
-  bool isLeafProc(MachineFunction &MF) const;
-
+  bool isLeafProc(MachineFunction &MF, bool UsesLocalRegister) const;
 
   // Emits code for adjusting SP in function prologue/epilogue.
   void emitSPAdjustment(MachineFunction &MF,
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 66638f599559a..f0c11ae6c7d47 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -13,6 +13,7 @@
 
 #include "SparcISelLowering.h"
 #include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "SparcFrameLowering.h"
 #include "SparcMachineFunctionInfo.h"
 #include "SparcRegisterInfo.h"
 #include "SparcSelectionDAGInfo.h"
@@ -34,6 +35,8 @@
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/KnownBits.h"
@@ -1206,6 +1209,33 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
   return Chain;
 }
 
+bool SparcTargetLowering::usesNamedLocalRegister(
+    const MachineFunction &MF) const {
+  for (const Instruction &I : instructions(MF.getFunction())) {
+    const auto *II = dyn_cast<IntrinsicInst>(&I);
+    if (!II)
+      continue;
+
+    switch (II->getIntrinsicID()) {
+    case Intrinsic::read_register:
+    case Intrinsic::read_volatile_register:
+    case Intrinsic::write_register:
+    case Intrinsic::write_volatile_register:
+      break;
+    default:
+      continue;
+    }
+
+    const auto *MD = cast<MDNode>(
+        cast<MetadataAsValue>(II->getArgOperand(0))->getMetadata());
+    Register Reg = getRegisterByName(
+        cast<MDString>(MD->getOperand(0))->getString().data(), LLT(), MF);
+    if (Reg >= SP::L0 && Reg <= SP::L7)
+      return true;
+  }
+  return false;
+}
+
 // FIXME? Maybe this could be a TableGen attribute on some registers and
 // this table could be generated automatically from RegInfo.
 Register SparcTargetLowering::getRegisterByName(const char* RegName, LLT VT,
@@ -2050,6 +2080,12 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
   computeRegisterProperties(Subtarget->getRegisterInfo());
 }
 
+void SparcTargetLowering::finalizeLowering(MachineFunction &MF) const {
+  Subtarget->getFrameLowering()->finalizeLeafProc(MF,
+                                                  usesNamedLocalRegister(MF));
+  TargetLoweringBase::finalizeLowering(MF);
+}
+
 bool SparcTargetLowering::useSoftFloat() const {
   return Subtarget->useSoftFloat();
 }
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h
index 5098480e192a6..a53612f3b3cd7 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.h
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.h
@@ -22,9 +22,12 @@ namespace llvm {
 
   class SparcTargetLowering : public TargetLowering {
     const SparcSubtarget *Subtarget;
+    bool usesNamedLocalRegister(const MachineFunction &MF) const;
+
   public:
     SparcTargetLowering(const TargetMachine &TM, const SparcSubtarget &STI);
     SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
+    void finalizeLowering(MachineFunction &MF) const override;
 
     bool useSoftFloat() const override;
 
diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
index 0a14746f587bb..be7f561386fef 100644
--- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
+++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
@@ -12,6 +12,7 @@
 
 #include "SparcRegisterInfo.h"
 #include "Sparc.h"
+#include "SparcMachineFunctionInfo.h"
 #include "SparcSubtarget.h"
 #include "llvm/ADT/BitVector.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
@@ -103,6 +104,22 @@ BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
       markSuperRegs(Reserved, *i);
   }
 
+  if (MF.getInfo<SparcMachineFunctionInfo>()->isLeafProc()) {
+    auto ReserveAliases = [&](MCRegister Reg) {
+      for (MCRegAliasIterator AI(Reg, this, true); AI.isValid(); ++AI)
+        Reserved.set(*AI);
+    };
+
+    for (unsigned Reg = SP::I0; Reg <= SP::I7; ++Reg)
+      if (Reserved.test(Reg))
+        ReserveAliases(Reg - SP::I0 + SP::O0);
+
+    for (unsigned Reg = SP::I0; Reg <= SP::I7; ++Reg)
+      ReserveAliases(Reg);
+    for (unsigned Reg = SP::L0; Reg <= SP::L7; ++Reg)
+      ReserveAliases(Reg);
+  }
+
   assert(checkAllSuperRegsMarked(Reserved));
   return Reserved;
 }
diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.td b/llvm/lib/Target/Sparc/SparcRegisterInfo.td
index d8319a8d41dda..f607701de5b6b 100644
--- a/llvm/lib/Target/Sparc/SparcRegisterInfo.td
+++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.td
@@ -343,20 +343,44 @@ def IntRegs : RegisterClass<"SP", [i32, i64], 32,
                             (add (sequence "I%u", 0, 7),
                                  (sequence "G%u", 0, 7),
                                  (sequence "L%u", 0, 7),
-                                 (sequence "O%u", 0, 7))>;
+                                 (sequence "O%u", 0, 7))> {
+  let AltOrders = [(add (sequence "O%u", 0, 7),
+                        (sequence "G%u", 0, 7),
+                        (sequence "L%u", 0, 7),
+                        (sequence "I%u", 0, 7))];
+  let AltOrderSelect = [{
+    return MF.getInfo<SparcMachineFunctionInfo>()->isLeafProc();
+  }];
+}
 
 // Should be in the same order as IntRegs.
 def IntPair : RegisterClass<"SP", [v2i32], 64,
     (add I0_I1, I2_I3, I4_I5, I6_I7,
          G0_G1, G2_G3, G4_G5, G6_G7,
          L0_L1, L2_L3, L4_L5, L6_L7,
-         O0_O1, O2_O3, O4_O5, O6_O7)>;
+         O0_O1, O2_O3, O4_O5, O6_O7)> {
+  let AltOrders = [(add O0_O1, O2_O3, O4_O5, O6_O7,
+                        G0_G1, G2_G3, G4_G5, G6_G7,
+                        L0_L1, L2_L3, L4_L5, L6_L7,
+                        I0_I1, I2_I3, I4_I5, I6_I7)];
+  let AltOrderSelect = [{
+    return MF.getInfo<SparcMachineFunctionInfo>()->isLeafProc();
+  }];
+}
 
 // Register class for 64-bit mode, with a 64-bit spill slot size.
 // These are the same as the 32-bit registers, so TableGen will consider this
 // to be a sub-class of IntRegs. That works out because requiring a 64-bit
 // spill slot is a stricter constraint than only requiring a 32-bit spill slot.
-def I64Regs : RegisterClass<"SP", [i64], 64, (add IntRegs)>;
+def I64Regs : RegisterClass<"SP", [i64], 64, (add IntRegs)> {
+  let AltOrders = [(add (sequence "O%u", 0, 7),
+                        (sequence "G%u", 0, 7),
+                        (sequence "L%u", 0, 7),
+                        (sequence "I%u", 0, 7))];
+  let AltOrderSelect = [{
+    return MF.getInfo<SparcMachineFunctionInfo>()->isLeafProc();
+  }];
+}
 
 // Floating point register classes.
 def FPRegs : RegisterClass<"SP", [f32], 32, (sequence "F%u", 0, 31)>;
diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h
index 02d56eb8f3000..121e5096117f8 100644
--- a/llvm/lib/Target/Sparc/SparcSubtarget.h
+++ b/llvm/lib/Target/Sparc/SparcSubtarget.h
@@ -51,7 +51,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
   ~SparcSubtarget() override;
 
   const SparcInstrInfo *getInstrInfo() const override { return &InstrInfo; }
-  const TargetFrameLowering *getFrameLowering() const override {
+  const SparcFrameLowering *getFrameLowering() const override {
     return &FrameLowering;
   }
   const SparcRegisterInfo *getRegisterInfo() const override {
diff --git a/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll b/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll
index e05c47bfee766..b62e7c30f71f1 100644
--- a/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll
+++ b/llvm/test/CodeGen/SPARC/2011-01-11-CC.ll
@@ -167,14 +167,14 @@ define double @test_select_dfp_icc(i32 %a, double %f1, double %f2) nounwind {
 ; V8-LABEL: test_select_dfp_icc:
 ; V8:       ! %bb.0: ! %entry
 ; V8-NEXT:    add %sp, -112, %sp
-; V8-NEXT:    mov %o4, %o5
-; V8-NEXT:    mov %o2, %g3
-; V8-NEXT:    mov %o3, %o4
-; V8-NEXT:    std %o4, [%sp+96]
+; V8-NEXT:    mov %o4, %g3
+; V8-NEXT:    mov %o2, %o5
+; V8-NEXT:    mov %o3, %g2
+; V8-NEXT:    std %g2, [%sp+96]
 ; V8-NEXT:    cmp %o0, 0
-; V8-NEXT:    mov %o1, %g2
+; V8-NEXT:    mov %o1, %o4
 ; V8-NEXT:    be .LBB3_2
-; V8-NEXT:    std %g2, [%sp+104]
+; V8-NEXT:    std %o4, [%sp+104]
 ; V8-NEXT:  ! %bb.1: ! %entry
 ; V8-NEXT:    ldd [%sp+96], %f0
 ; V8-NEXT:    retl
@@ -187,12 +187,12 @@ define double @test_select_dfp_icc(i32 %a, double %f1, double %f2) nounwind {
 ; V9-LABEL: test_select_dfp_icc:
 ; V9:       ! %bb.0: ! %entry
 ; V9-NEXT:    add %sp, -112, %sp
-; V9-NEXT:    mov %o4, %o5
-; V9-NEXT:    mov %o2, %g3
-; V9-NEXT:    mov %o3, %o4
-; V9-NEXT:    std %o4, [%sp+96]
-; V9-NEXT:    mov %o1, %g2
-; V9-NEXT:    std %g2, [%sp+104]
+; V9-NEXT:    mov %o4, %g3
+; V9-NEXT:    mov %o2, %o5
+; V9-NEXT:    mov %o3, %g2
+; V9-NEXT:    std %g2, [%sp+96]
+; V9-NEXT:    mov %o1, %o4
+; V9-NEXT:    std %o4, [%sp+104]
 ; V9-NEXT:    ldd [%sp+96], %f0
 ; V9-NEXT:    ldd [%sp+104], %f2
 ; V9-NEXT:    cmp %o0, 0
diff --git a/llvm/test/CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll b/llvm/test/CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll
index 7b4db4d3034cc..11d2a72d4ce4b 100644
--- a/llvm/test/CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll
+++ b/llvm/test/CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll
@@ -7,9 +7,7 @@ define float @ld_float_test() #0 {
 ; CHECK:         .cfi_startproc
 ; CHECK-NEXT:  ! %bb.0: ! %entry
 ; CHECK-NEXT:    add %sp, -96, %sp
-; CHECK-NEXT:    .cfi_def_cfa_register %fp
-; CHECK-NEXT:    .cfi_window_save
-; CHECK-NEXT:    .cfi_register %o7, %i7
+; CHECK-NEXT:    .cfi_def_cfa_offset 96
 ; CHECK-NEXT:    sethi 1042305, %o0
 ; CHECK-NEXT:    or %o0, 25, %o0
 ; CHECK-NEXT:    st %o0, [%sp+92]
diff --git a/llvm/test/CodeGen/SPARC/fp128-select.ll b/llvm/test/CodeGen/SPARC/fp128-select.ll
index 2868896dd83b3..cb56f740dd583 100644
--- a/llvm/test/CodeGen/SPARC/fp128-select.ll
+++ b/llvm/test/CodeGen/SPARC/fp128-select.ll
@@ -6,9 +6,7 @@ define fp128 @f128_select_soft(fp128 %a, fp128 %b) #0 {
 ; V9:         .cfi_startproc
 ; V9-NEXT:  ! %bb.0: ! %entry
 ; V9-NEXT:    add %sp, -144, %sp
-; V9-NEXT:    .cfi_def_cfa_register %fp
-; V9-NEXT:    .cfi_window_save
-; V9-NEXT:    .cfi_register %o7, %i7
+; V9-NEXT:    .cfi_def_cfa_offset 2191
 ; V9-NEXT:    add %sp, 2175, %o0
 ; V9-NEXT:    or %o0, 8, %o0
 ; V9-NEXT:    std %f6, [%o0]
@@ -48,9 +46,7 @@ define fp128 @f128_select_hard(fp128 %a, fp128 %b) #1 {
 ; V9:         .cfi_startproc
 ; V9-NEXT:  ! %bb.0: ! %entry
 ; V9-NEXT:    add %sp, -144, %sp
-; V9-NEXT:    .cfi_def_cfa_register %fp
-; V9-NEXT:    .cfi_window_save
-; V9-NEXT:    .cfi_register %o7, %i7
+; V9-NEXT:    .cfi_def_cfa_offset 2191
 ; V9-NEXT:    stq %f4, [%sp+2175]
 ; V9-NEXT:    add %sp, 2175, %o0
 ; V9-NEXT:    or %o0, 8, %o0
diff --git a/llvm/test/CodeGen/SPARC/leafproc-reg-pair.mir b/llvm/test/CodeGen/SPARC/leafproc-reg-pair.mir
new file mode 100644
index 0000000000000..4c69801590ada
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/leafproc-reg-pair.mir
@@ -0,0 +1,24 @@
+# RUN: llc -mtriple=sparc -run-pass=finalize-isel -verify-machineinstrs -o - %s | FileCheck %s
+
+--- |
+  define void @pair() { ret void }
+...
+---
+name: pair
+# CHECK-LABEL: name: pair
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: intpair }
+liveins:
+  - { reg: '$i0_i1', virtual-reg: '%0' }
+# CHECK: bb.0:
+# CHECK-NEXT: liveins: $o0_o1
+# CHECK: %0:intpair = COPY $o0_o1
+# CHECK-NOT: $i0_i1
+body: |
+  bb.0:
+    liveins: $i0_i1
+    %0:intpair = COPY $i0_i1
+    $o0_o1 = COPY %0
+    RETL 8, implicit $o0, implicit $o1
+...
diff --git a/llvm/test/CodeGen/SPARC/leafproc.ll b/llvm/test/CodeGen/SPARC/leafproc.ll
index 3998ef26f7b20..70e0e2d633fab 100644
--- a/llvm/test/CodeGen/SPARC/leafproc.ll
+++ b/llvm/test/CodeGen/SPARC/leafproc.ll
@@ -1,4 +1,5 @@
 ; RUN: llc -mtriple=sparc -disable-sparc-leaf-proc=0 < %s | FileCheck %s
+; RUN: llc -mtriple=sparcv9 -disable-sparc-leaf-proc=0 < %s | FileCheck %s --check-prefix=V9
 
 ; CHECK-LABEL:      func_nobody:
 ; CHECK:      retl
@@ -39,6 +40,16 @@ entry:
   ret i32 %1
 }
 
+; CHECK-LABEL: leaf_proc_with_i64_arg:
+; CHECK:       addcc %o1, 1, %o1
+; CHECK:       retl
+; CHECK-NEXT:  addxcc %o0, 0, %o0
+define i64 @leaf_proc_with_i64_arg(i64 %x) {
+entry:
+  %value = add i64 %x, 1
+  ret i64 %value
+}
+
 ; CHECK-LABEL:     leaf_proc_with_args_in_stack:
 ; CHECK-DAG: ld [%sp+92], {{%[go][0-7]}}
 ; CHECK-DAG: ld [%sp+96], {{%[go][0-7]}}
@@ -58,6 +69,8 @@ entry:
 
 ; CHECK-LABEL:      leaf_proc_with_local_array:
 ; CHECK:      add %sp, -104, %sp
+; CHECK-NEXT: .cfi_def_cfa_offset 104
+; CHECK-NOT:  .cfi_window_save
 ; CHECK:      mov 1, [[R1:%[go][0-7]]]
 ; CHECK:      st [[R1]], [%sp+96]
 ; CHECK:      mov 2, [[R2:%[go][0-7]]]
@@ -67,6 +80,11 @@ entry:
 ; CHECK-NEXT: add %sp, 104, %sp
 
 define i32 @leaf_proc_with_local_array(i32 %a, i32 %b, i32 %c) {
+; V9-LABEL: leaf_proc_with_local_array:
+; V9:       add %sp, -144, %sp
+; V9-NEXT:  .cfi_def_cfa_offset 2191
+; V9-NOT:   .cfi_window_save
+; V9:       retl
 entry:
   %array = alloca [2 x i32], align 4
   %0 = sub nsw i32 %b, %c
diff --git a/llvm/test/CodeGen/SPARC/reserved-regs-named.ll b/llvm/test/CodeGen/SPARC/reserved-regs-named.ll
index 91808be156c55..c287c83ae7a28 100644
--- a/llvm/test/CodeGen/SPARC/reserved-regs-named.ll
+++ b/llvm/test/CodeGen/SPARC/reserved-regs-named.ll
@@ -1,13 +1,74 @@
-; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-l0 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-L0
+; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-l0 -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-L0
+; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-l0 -verify-machineinstrs -stop-after=finalize-isel -o - %s | FileCheck %s --check-prefix=NAMES
+; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-l0 -verify-machineinstrs -stop-after=prolog-epilog -simplify-mir -o - %s | FileCheck %s --check-prefix=LIVEINS
 
 ;; Ensure explicit register references are catched as well.
 
-; CHECK-RESERVED-L0: %l0
+; CHECK-RESERVED-L0-LABEL: set_reg:
+; CHECK-RESERVED-L0: save %sp
+; CHECK-RESERVED-L0: mov %i0, %l0
 define void @set_reg(i32 zeroext %x) {
 entry:
   tail call void @llvm.write_register.i32(metadata !0, i32 %x)
   ret void
 }
 
+; NAMES-LABEL: name: {{ *}}read_o6
+; NAMES: {{%[0-9]+}}:i64regs = COPY $o6
+; CHECK-RESERVED-L0-LABEL: read_o6:
+; CHECK-RESERVED-L0: save %sp
+define i64 @read_o6() {
+entry:
+  %value = call i64 @llvm.read_register.i64(metadata !1)
+  ret i64 %value
+}
+
+; LIVEINS-LABEL: name: {{ *}}read_i7
+; LIVEINS-NOT: liveins:
+; LIVEINS: bb.0.entry:
+; LIVEINS-NOT: liveins:
+; LIVEINS: $o0 = COPY $o7
+define i64 @read_i7() {
+entry:
+  %value = call i64 @llvm.read_register.i64(metadata !2)
+  ret i64 %value
+}
+
+; LIVEINS-LABEL: name: {{ *}}read_i7_nonentry
+; LIVEINS: bb.0.entry:
+; LIVEINS: liveins: $o0, $o1{{$}}
+; LIVEINS: bb.{{[0-9]+}}.read:
+; LIVEINS-NOT: liveins:
+; LIVEINS: $o0 = COPY $o7
+define i64 @read_i7_nonentry(i64 %zero_value, i1 %cond) {
+entry:
+  br i1 %cond, label %read, label %zero
+
+read:
+  %value = call i64 @llvm.read_register.i64(metadata !2)
+  ret i64 %value
+
+zero:
+  ret i64 %zero_value
+}
+
+; NAMES-LABEL: name: {{ *}}read_i7_nonleaf
+; NAMES: {{%[0-9]+}}:i64regs = COPY $i7
+; CHECK-RESERVED-L0-LABEL: read_i7_nonleaf:
+; CHECK-RESERVED-L0: save %sp
+; CHECK-RESERVED-L0: call callee
+; CHECK-RESERVED-L0: ret
+define i64 @read_i7_nonleaf() {
+entry:
+  call void @callee()
+  %value = call i64 @llvm.read_register.i64(metadata !2)
+  ret i64 %value
+}
+
 declare void @llvm.write_register.i32(metadata, i32)
+declare i64 @llvm.read_register.i64(metadata)
+declare void @callee()
+
 !0 = !{!"l0"}
+!1 = !{!"o6"}
+!2 = !{!"i7"}
diff --git a/llvm/test/CodeGen/SPARC/reserved-regs.ll b/llvm/test/CodeGen/SPARC/reserved-regs.ll
index 6bb4e1245589d..1e247ba187658 100644
--- a/llvm/test/CodeGen/SPARC/reserved-regs.ll
+++ b/llvm/test/CodeGen/SPARC/reserved-regs.ll
@@ -1,13 +1,15 @@
 ; RUN: llc -mtriple=sparc -verify-machineinstrs < %s | FileCheck %s
 
 ;; Test reserve-* options.
-; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-g1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-G1
-; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-o1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-O1
-; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-l1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-L1
-; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-I1
+; RUN: llc -mtriple=sparc64-linux-gnu -disable-sparc-leaf-proc -mattr=+reserve-g1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-G1
+; RUN: llc -mtriple=sparc64-linux-gnu -disable-sparc-leaf-proc -mattr=+reserve-o1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-O1
+; RUN: llc -mtriple=sparc64-linux-gnu -disable-sparc-leaf-proc -mattr=+reserve-l1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-L1
+; RUN: llc -mtriple=sparc64-linux-gnu -disable-sparc-leaf-proc -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-I1
+; RUN: llc -mtriple=sparc64-linux-gnu -verify-machineinstrs -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=LEAF-RESERVED-I1
+; RUN: llc -mtriple=sparc -verify-machineinstrs -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=LEAF32-RESERVED-I1
 
 ;; Test multiple reserve-* options together.
-; RUN: llc -mtriple=sparc64-linux-gnu -mattr=+reserve-g1 -mattr=+reserve-o1 -mattr=+reserve-l1 -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-G1,CHECK-RESERVED-O1,CHECK-RESERVED-L1,CHECK-RESERVED-I1
+; RUN: llc -mtriple=sparc64-linux-gnu -disable-sparc-leaf-proc -mattr=+reserve-g1 -mattr=+reserve-o1 -mattr=+reserve-l1 -mattr=+reserve-i1 -o - %s | FileCheck %s --check-prefixes=CHECK-RESERVED-G1,CHECK-RESERVED-O1,CHECK-RESERVED-L1,CHECK-RESERVED-I1
 
 @g = common global [32 x i32] zeroinitializer, align 16
 @h = common global [16 x i64] zeroinitializer, align 16
@@ -15,21 +17,25 @@
 ;; Ensures that we don't use registers which are supposed to be reserved.
 
 ; CHECK-LABEL: use_all_i32_regs:
-; CHECK: save %sp
-; CHECK: .cfi_register %o7, %i7
+; CHECK: add %sp, -{{[0-9]+}}, %sp
+; CHECK-NOT: .cfi_window_save
 ; CHECK-NOT: %g0
 ; CHECK-NOT: %g1
 ; CHECK-NOT: %g5
 ; CHECK-NOT: %g6
 ; CHECK-NOT: %g7
 ; CHECK-NOT: %o6
-; CHECK-NOT: %i6
-; CHECK-NOT: %i7
+; CHECK-NOT: %i{{[0-7]}}
+; CHECK-NOT: %l{{[0-7]}}
+; CHECK-NOT: %fp
 ; CHECK-RESERVED-G1-NOT: %g1
 ; CHECK-RESERVED-O1-NOT: %o1
 ; CHECK-RESERVED-L1-NOT: %l1
 ; CHECK-RESERVED-I1-NOT: %i1
-; CHECK: ret
+; CHECK: retl
+; LEAF-RESERVED-I1-LABEL: use_all_i32_regs:
+; LEAF-RESERVED-I1-NOT: %o1
+; LEAF-RESERVED-I1: retl
 define void @use_all_i32_regs() {
 entry:
   %0 = load volatile i32, ptr @g, align 16
@@ -101,23 +107,29 @@ entry:
 
 
 ; CHECK-LABEL: use_all_i64_regs:
-; CHECK: save %sp
-; CHECK: .cfi_register %o7, %i7
+; CHECK: add %sp, -{{[0-9]+}}, %sp
+; CHECK-NOT: .cfi_window_save
 ; CHECK-NOT: %g0
 ; CHECK-NOT: %g1
-; CHECK-NOT: %g4
 ; CHECK-NOT: %g5
+; CHECK-NOT: ldd {{.*}}, %g4
+; CHECK-NOT: std %g4
 ; CHECK-NOT: %g6
 ; CHECK-NOT: %g7
 ; CHECK-NOT: %o6
 ; CHECK-NOT: %o7
-; CHECK-NOT: %i6
-; CHECK-NOT: %i7
+; CHECK-NOT: %i{{[0-7]}}
+; CHECK-NOT: %l{{[0-7]}}
+; CHECK-NOT: %fp
 ; CHECK-RESERVED-G1-NOT: %g1
 ; CHECK-RESERVED-O1-NOT: %o1
 ; CHECK-RESERVED-L1-NOT: %l1
 ; CHECK-RESERVED-I1-NOT: %i1
-; CHECK: ret
+; CHECK: retl
+; LEAF32-RESERVED-I1-LABEL: use_all_i64_regs:
+; LEAF32-RESERVED-I1-NOT: ldd {{.*}}, %o0
+; LEAF32-RESERVED-I1-NOT: std %o0
+; LEAF32-RESERVED-I1: retl
 define void @use_all_i64_regs() {
 entry:
   %0 = load volatile i64, ptr @h, align 16
diff --git a/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll b/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll
index e0c7032b1d9d4..904625dc1a37d 100644
--- a/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll
+++ b/llvm/test/CodeGen/SPARC/smulo-128-legalisation-lowering.ll
@@ -1,7 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=sparc-unknown-linux-gnu | FileCheck %s --check-prefixes=SPARC
+; RUN: llc < %s -mtriple=sparc-unknown-linux-gnu -disable-sparc-leaf-proc | FileCheck %s --check-prefixes=SPARC
 ; RUN: llc < %s -mtriple=sparc64-unknown-linux-gnu | FileCheck %s --check-prefixes=SPARC64
-; RUN: llc < %s -mtriple=sparc64-unknown-linux-gnu -mattr=vis3 | FileCheck %s --check-prefixes=SPARC64-VIS3
+; RUN: llc < %s -mtriple=sparc64-unknown-linux-gnu -mattr=vis3 -disable-sparc-leaf-proc | FileCheck %s --check-prefixes=SPARC64-VIS3
 
 define { i128, i8 } @muloti_test(i128 %l, i128 %r) nounwind {
 ; SPARC-LABEL: muloti_test:
diff --git a/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll b/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll
index 40e90d6bdd6af..9295fdb3e1f55 100644
--- a/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll
+++ b/llvm/test/CodeGen/SPARC/umulo-128-legalisation-lowering.ll
@@ -1,7 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=sparc-unknown-linux-gnu | FileCheck %s --check-prefixes=SPARC
+; RUN: llc < %s -mtriple=sparc-unknown-linux-gnu -disable-sparc-leaf-proc | FileCheck %s --check-prefixes=SPARC
 ; RUN: llc < %s -mtriple=sparc64-unknown-linux-gnu | FileCheck %s --check-prefixes=SPARC64
-; RUN: llc < %s -mtriple=sparc64-unknown-linux-gnu -mattr=vis3 | FileCheck %s --check-prefixes=SPARC64-VIS3
+; RUN: llc < %s -mtriple=sparc64-unknown-linux-gnu -mattr=vis3 -disable-sparc-leaf-proc | FileCheck %s --check-prefixes=SPARC64-VIS3
 
 define { i128, i8 } @muloti_test(i128 %l, i128 %r) nounwind {
 ; SPARC-LABEL: muloti_test:



More information about the llvm-commits mailing list