[llvm] [SPARC] Preserve liveins after leaf register remapping (PR #213359)
Kirill A. Korinsky via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 1 16:39:57 PDT 2026
https://github.com/catap updated https://github.com/llvm/llvm-project/pull/213359
>From a3a01bce11bb3ee967f55dfdeb6694fa24cc74db Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill at korins.ky>
Date: Sun, 2 Aug 2026 01:37:47 +0200
Subject: [PATCH] [SPARC] Preserve liveins after leaf register remapping
Leaf procedure lowering maps I registers to O registers. Named reserved
register reads do not add liveins, so mapping i7 to unreserved o7 leaves
an undefined physical register use.
Seems that exists for a while and cee7b71929312666c5cf48eb79873893811b99a7
just makes it more probably.
---
.../llvm/CodeGen/MachineRegisterInfo.h | 4 +
llvm/lib/CodeGen/MachineRegisterInfo.cpp | 15 +++
llvm/lib/Target/Sparc/SparcFrameLowering.cpp | 99 ++++++++++---------
llvm/lib/Target/Sparc/SparcFrameLowering.h | 5 +-
llvm/lib/Target/Sparc/SparcISelLowering.cpp | 8 +-
llvm/lib/Target/Sparc/SparcISelLowering.h | 1 +
llvm/lib/Target/Sparc/SparcRegisterInfo.cpp | 17 ++++
llvm/lib/Target/Sparc/SparcRegisterInfo.td | 30 +++++-
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 | 27 +++++
llvm/test/CodeGen/SPARC/leafproc.ll | 18 ++++
.../test/CodeGen/SPARC/reserved-regs-named.ll | 58 +++++++++--
llvm/test/CodeGen/SPARC/reserved-regs.ll | 44 ++++++---
.../SPARC/smulo-128-legalisation-lowering.ll | 4 +-
llvm/test/CodeGen/SPARC/stackaddress.ll | 12 +--
.../SPARC/umulo-128-legalisation-lowering.ll | 4 +-
18 files changed, 273 insertions(+), 109 deletions(-)
create mode 100644 llvm/test/CodeGen/SPARC/leafproc-reg-pair.mir
diff --git a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
index e6fc300d19672..610d4c95f01c0 100644
--- a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h
@@ -1021,6 +1021,10 @@ class MachineRegisterInfo {
LiveIns.push_back(std::make_pair(Reg, vreg));
}
+ /// Replace a physical register in the function livein list. ToReg must not
+ /// already be a livein.
+ LLVM_ABI void replaceLiveInPhysReg(MCRegister FromReg, MCRegister ToReg);
+
// Iteration support for the live-ins set. It's kept in sorted order
// by register number.
using livein_iterator =
diff --git a/llvm/lib/CodeGen/MachineRegisterInfo.cpp b/llvm/lib/CodeGen/MachineRegisterInfo.cpp
index dbba413548018..35250c1e959f4 100644
--- a/llvm/lib/CodeGen/MachineRegisterInfo.cpp
+++ b/llvm/lib/CodeGen/MachineRegisterInfo.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -462,6 +463,20 @@ bool MachineRegisterInfo::isLiveIn(Register Reg) const {
return false;
}
+void MachineRegisterInfo::replaceLiveInPhysReg(MCRegister FromReg,
+ MCRegister ToReg) {
+ assert(FromReg.isPhysical() && ToReg.isPhysical() && FromReg != ToReg);
+ auto From = llvm::find_if(LiveIns, [FromReg](const auto &LiveIn) {
+ return LiveIn.first == FromReg;
+ });
+ if (From == LiveIns.end())
+ return;
+ assert(llvm::none_of(
+ LiveIns, [ToReg](const auto &LiveIn) { return LiveIn.first == ToReg; }));
+ From->first = ToReg;
+ llvm::sort(LiveIns);
+}
+
/// getLiveInPhysReg - If VReg is a live-in virtual register, return the
/// corresponding live-in physical register.
MCRegister MachineRegisterInfo::getLiveInPhysReg(Register VReg) const {
diff --git a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
index fa08d4474f39e..df374ba8cb6f7 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,57 @@ SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
return true;
}
-bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const
-{
-
- MachineRegisterInfo &MRI = MF.getRegInfo();
- MachineFrameInfo &MFI = MF.getFrameInfo();
+bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const {
+ if (MF.getFrameInfo().hasCalls() || hasFP(MF) || MF.hasInlineAsm())
+ return false;
- 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
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+ for (unsigned Reg = SP::L0; Reg <= SP::L7; ++Reg)
+ if (MRI.isPhysRegUsed(Reg))
+ 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);
+ MRI.replaceLiveInPhysReg(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 +323,9 @@ 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) const {
+ bool IsLeafProc = !DisableLeafProc && isLeafProc(MF);
+ 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..d1bcd2b85303b 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) const;
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;
@@ -56,7 +56,6 @@ class SparcFrameLowering : public TargetFrameLowering {
// Returns true if MF is a leaf procedure.
bool isLeafProc(MachineFunction &MF) const;
-
// Emits code for adjusting SP in function prologue/epilogue.
void emitSPAdjustment(MachineFunction &MF,
MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 488cc2f8e900f..2c4e0033d280e 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"
@@ -39,7 +40,6 @@
#include "llvm/Support/KnownBits.h"
using namespace llvm;
-
//===----------------------------------------------------------------------===//
// Calling Convention Implementation
//===----------------------------------------------------------------------===//
@@ -2071,6 +2071,12 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
computeRegisterProperties(Subtarget->getRegisterInfo());
}
+void SparcTargetLowering::finalizeLowering(MachineFunction &MF) const {
+ static_cast<const SparcFrameLowering *>(Subtarget->getFrameLowering())
+ ->finalizeLeafProc(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..e716eac668b61 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.h
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.h
@@ -25,6 +25,7 @@ namespace llvm {
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/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..c918f5cf8d813
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/leafproc-reg-pair.mir
@@ -0,0 +1,27 @@
+# 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:
+# CHECK: liveins:
+# CHECK-NEXT: - { reg: '$o0_o1', virtual-reg: '%0' }
+# CHECK-NOT: reg: '$i0_i1'
+ - { 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 0904d8ed74ef1..6b1a29bf9193f 100644
--- a/llvm/test/CodeGen/SPARC/reserved-regs-named.ll
+++ b/llvm/test/CodeGen/SPARC/reserved-regs-named.ll
@@ -1,5 +1,6 @@
-; 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 -stop-after=finalize-isel -o - %s | FileCheck %s --check-prefix=NAMES
+; 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.
@@ -38,7 +39,7 @@ entry:
}
; NAMES-LABEL: name: {{ *}}read_percent_fp
-; NAMES: {{%[0-9]+}}:i64regs = COPY $i6
+; NAMES: {{%[0-9]+}}:i64regs = COPY $o6
define i64 @read_percent_fp() {
entry:
%value = call i64 @llvm.read_register.i64(metadata !4)
@@ -46,7 +47,7 @@ entry:
}
; NAMES-LABEL: name: {{ *}}read_fp
-; NAMES: {{%[0-9]+}}:i64regs = COPY $i6
+; NAMES: {{%[0-9]+}}:i64regs = COPY $o6
define i64 @read_fp() {
entry:
%value = call i64 @llvm.read_register.i64(metadata !5)
@@ -54,7 +55,7 @@ entry:
}
; NAMES-LABEL: name: {{ *}}read_r30
-; NAMES: {{%[0-9]+}}:i64regs = COPY $i6
+; NAMES: {{%[0-9]+}}:i64regs = COPY $o6
define i64 @read_r30() {
entry:
%value = call i64 @llvm.read_register.i64(metadata !6)
@@ -79,21 +80,63 @@ entry:
; NAMES-LABEL: name: {{ *}}read_r16
; NAMES: {{%[0-9]+}}:i64regs = COPY $l0
+; CHECK-RESERVED-L0-LABEL: read_r16:
+; CHECK-RESERVED-L0: save %sp
+; CHECK-RESERVED-L0: restore {{.*}}%l0
define i64 @read_r16() {
entry:
%value = call i64 @llvm.read_register.i64(metadata !9)
ret i64 %value
}
-; NAMES-LABEL: name: {{ *}}read_r31
-; NAMES: {{%[0-9]+}}:i64regs = COPY $i7
+; LIVEINS-LABEL: name: {{ *}}read_r31
+; LIVEINS-NOT: liveins:
+; LIVEINS: bb.0.entry:
+; LIVEINS-NOT: liveins:
+; LIVEINS: $o0 = COPY $o7
define i64 @read_r31() {
entry:
%value = call i64 @llvm.read_register.i64(metadata !10)
ret i64 %value
}
+; LIVEINS-LABEL: name: {{ *}}read_i7_nonentry
+; LIVEINS: liveins:
+; LIVEINS-NEXT: - { reg: '$o0' }
+; LIVEINS-NEXT: - { reg: '$o1' }
+; LIVEINS-NOT: reg: '$i{{[01]}}'
+; 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 !11)
+ 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 !11)
+ ret i64 %value
+}
+
declare i64 @llvm.read_register.i64(metadata)
+declare void @callee()
!1 = !{!"%sp"}
!2 = !{!"sp"}
@@ -105,3 +148,4 @@ declare i64 @llvm.read_register.i64(metadata)
!8 = !{!"r0"}
!9 = !{!"r16"}
!10 = !{!"r31"}
+!11 = !{!"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/stackaddress.ll b/llvm/test/CodeGen/SPARC/stackaddress.ll
index fce5f1cba8fb1..0580527c86dd2 100644
--- a/llvm/test/CodeGen/SPARC/stackaddress.ll
+++ b/llvm/test/CodeGen/SPARC/stackaddress.ll
@@ -4,13 +4,13 @@
declare ptr @llvm.stackaddress.p0()
define ptr @test() {
-; sparc32: save %sp, -96, %sp
-; sparc32: ret
-; sparc32: restore %sp, 68, %o0
+; sparc32-LABEL: test:
+; sparc32: retl
+; sparc32-NEXT: add %sp, 68, %o0
;
-; sparc64: save %sp, -128, %sp
-; sparc64: ret
-; sparc64: restore %sp, 2175, %o0
+; sparc64-LABEL: test:
+; sparc64: retl
+; sparc64-NEXT: add %sp, 2175, %o0
%sp = call ptr @llvm.stackaddress.p0()
ret ptr %sp
}
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