Skip to content

Commit ca0fe2f

Browse files
committed
[Sparc] Add support for leaf functions in sparc backend.
llvm-svn: 182822
1 parent d7bf293 commit ca0fe2f

7 files changed

+180
-28
lines changed

llvm/lib/Target/Sparc/DelaySlotFiller.cpp

+19-9
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,22 @@ Filler::findDelayInstr(MachineBasicBlock &MBB,
135135
bool sawLoad = false;
136136
bool sawStore = false;
137137

138-
MachineBasicBlock::iterator I = slot;
138+
if (slot == MBB.begin())
139+
return MBB.end();
139140

140141
if (slot->getOpcode() == SP::RET)
141142
return MBB.end();
142143

143144
if (slot->getOpcode() == SP::RETL) {
144-
--I;
145-
if (I->getOpcode() != SP::RESTORErr)
146-
return MBB.end();
147-
//change retl to ret
148-
slot->setDesc(TII->get(SP::RET));
149-
return I;
145+
MachineBasicBlock::iterator J = slot;
146+
--J;
147+
148+
if (J->getOpcode() == SP::RESTORErr
149+
|| J->getOpcode() == SP::RESTOREri) {
150+
//change retl to ret
151+
slot->setDesc(TII->get(SP::RET));
152+
return J;
153+
}
150154
}
151155

152156
//Call's delay filler can def some of call's uses.
@@ -157,6 +161,8 @@ Filler::findDelayInstr(MachineBasicBlock &MBB,
157161

158162
bool done = false;
159163

164+
MachineBasicBlock::iterator I = slot;
165+
160166
while (!done) {
161167
done = (I == MBB.begin());
162168

@@ -274,9 +280,13 @@ void Filler::insertDefsUses(MachineBasicBlock::iterator MI,
274280
continue;
275281
if (MO.isDef())
276282
RegDefs.insert(Reg);
277-
if (MO.isUse())
283+
if (MO.isUse()) {
284+
//Implicit register uses of retl are return values and
285+
//retl does not use them.
286+
if (MO.isImplicit() && MI->getOpcode() == SP::RETL)
287+
continue;
278288
RegUses.insert(Reg);
279-
289+
}
280290
}
281291
}
282292

llvm/lib/Target/Sparc/SparcFrameLowering.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,18 @@
2626

2727
using namespace llvm;
2828

29+
static cl::opt<bool>
30+
DisableLeafProc("disable-sparc-leaf-proc",
31+
cl::init(true),
32+
cl::desc("Disable Sparc leaf procedure optimization."),
33+
cl::Hidden);
34+
35+
2936
void SparcFrameLowering::emitPrologue(MachineFunction &MF) const {
37+
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
38+
if (FuncInfo->isLeafProc())
39+
return;
40+
3041
MachineBasicBlock &MBB = MF.front();
3142
MachineFrameInfo *MFI = MF.getFrameInfo();
3243
const SparcInstrInfo &TII =
@@ -97,6 +108,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
97108

98109
void SparcFrameLowering::emitEpilogue(MachineFunction &MF,
99110
MachineBasicBlock &MBB) const {
111+
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
112+
if (FuncInfo->isLeafProc())
113+
return;
100114
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
101115
const SparcInstrInfo &TII =
102116
*static_cast<const SparcInstrInfo*>(MF.getTarget().getInstrInfo());
@@ -121,3 +135,65 @@ bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
121135
MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken();
122136
}
123137

138+
139+
static bool verifyLeafProcRegUse(MachineRegisterInfo *MRI)
140+
{
141+
142+
for (unsigned reg = SP::I0; reg <= SP::I7; ++reg)
143+
if (MRI->isPhysRegUsed(reg))
144+
return false;
145+
146+
for (unsigned reg = SP::L0; reg <= SP::L7; ++reg)
147+
if (MRI->isPhysRegUsed(reg))
148+
return false;
149+
150+
return true;
151+
}
152+
153+
bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const
154+
{
155+
156+
MachineRegisterInfo &MRI = MF.getRegInfo();
157+
MachineFrameInfo *MFI = MF.getFrameInfo();
158+
159+
return !(MFI->hasCalls() // has calls
160+
|| MRI.isPhysRegUsed(SP::L0) // Too many registers needed
161+
|| MRI.isPhysRegUsed(SP::O6) // %SP is used
162+
|| hasFP(MF)); // need %FP
163+
}
164+
165+
void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
166+
167+
MachineRegisterInfo &MRI = MF.getRegInfo();
168+
169+
//remap %i[0-7] to %o[0-7]
170+
for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
171+
if (!MRI.isPhysRegUsed(reg))
172+
continue;
173+
unsigned mapped_reg = (reg - SP::I0 + SP::O0);
174+
assert(!MRI.isPhysRegUsed(mapped_reg));
175+
176+
//Replace I register with O register
177+
MRI.replaceRegWith(reg, mapped_reg);
178+
179+
//mark the reg unused.
180+
MRI.setPhysRegUnused(reg);
181+
}
182+
183+
assert(verifyLeafProcRegUse(&MRI));
184+
#ifdef XDEBUG
185+
MF.verify(0, "After LeafProc Remapping");
186+
#endif
187+
}
188+
189+
void SparcFrameLowering::processFunctionBeforeCalleeSavedScan
190+
(MachineFunction &MF, RegScavenger *RS) const {
191+
192+
if (!DisableLeafProc && isLeafProc(MF)) {
193+
SparcMachineFunctionInfo *MFI = MF.getInfo<SparcMachineFunctionInfo>();
194+
MFI->setLeafProc(true);
195+
196+
remapRegsForLeafProc(MF);
197+
}
198+
199+
}

llvm/lib/Target/Sparc/SparcFrameLowering.h

+9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ class SparcFrameLowering : public TargetFrameLowering {
4040

4141
bool hasReservedCallFrame(const MachineFunction &MF) const;
4242
bool hasFP(const MachineFunction &MF) const;
43+
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
44+
RegScavenger *RS = NULL) const;
45+
46+
private:
47+
//Remap input registers to output registers for leaf procedure.
48+
void remapRegsForLeafProc(MachineFunction &MF) const;
49+
50+
//Returns true if MF is a leaf procedure.
51+
bool isLeafProc(MachineFunction &MF) const;
4352
};
4453

4554
} // End llvm namespace

llvm/lib/Target/Sparc/SparcMachineFunctionInfo.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,16 @@ namespace llvm {
2828
/// SRetReturnReg - Holds the virtual register into which the sret
2929
/// argument is passed.
3030
unsigned SRetReturnReg;
31+
32+
/// IsLeafProc - True if the function is a leaf procedure.
33+
bool IsLeafProc;
3134
public:
3235
SparcMachineFunctionInfo()
33-
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0) {}
36+
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
37+
IsLeafProc(false) {}
3438
explicit SparcMachineFunctionInfo(MachineFunction &MF)
35-
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0) {}
39+
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
40+
IsLeafProc(false) {}
3641

3742
unsigned getGlobalBaseReg() const { return GlobalBaseReg; }
3843
void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; }
@@ -42,6 +47,9 @@ namespace llvm {
4247

4348
unsigned getSRetReturnReg() const { return SRetReturnReg; }
4449
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
50+
51+
void setLeafProc(bool rhs) { IsLeafProc = rhs; }
52+
bool isLeafProc() const { return IsLeafProc; }
4553
};
4654
}
4755

llvm/lib/Target/Sparc/SparcRegisterInfo.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "SparcRegisterInfo.h"
1515
#include "Sparc.h"
16+
#include "SparcMachineFunctionInfo.h"
1617
#include "SparcSubtarget.h"
1718
#include "llvm/ADT/BitVector.h"
1819
#include "llvm/ADT/STLExtras.h"
@@ -89,12 +90,13 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
8990
int64_t Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
9091
MI.getOperand(FIOperandNum + 1).getImm() +
9192
Subtarget.getStackPointerBias();
92-
93+
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
94+
unsigned FramePtr = (FuncInfo->isLeafProc()) ? SP::O6 : SP::I6;
9395
// Replace frame index with a frame pointer reference.
9496
if (Offset >= -4096 && Offset <= 4095) {
9597
// If the offset is small enough to fit in the immediate field, directly
9698
// encode it.
97-
MI.getOperand(FIOperandNum).ChangeToRegister(SP::I6, false);
99+
MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false);
98100
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
99101
} else {
100102
// Otherwise, emit a G1 = SETHI %hi(offset). FIXME: it would be better to
@@ -103,7 +105,7 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
103105
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1).addImm(OffHi);
104106
// Emit G1 = G1 + I6
105107
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
106-
.addReg(SP::I6);
108+
.addReg(FramePtr);
107109
// Insert: G1+%lo(offset) into the user.
108110
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
109111
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset & ((1 << 10)-1));

llvm/lib/Target/Sparc/SparcRegisterInfo.td

+4-14
Original file line numberDiff line numberDiff line change
@@ -144,20 +144,10 @@ def D15 : Rd<30, "F30", [F30, F31]>, DwarfRegNum<[87]>;
144144
// register class for that. The i64 type is included here to allow i64 patterns
145145
// using the integer instructions.
146146
def IntRegs : RegisterClass<"SP", [i32, i64], 32,
147-
(add I0, I1, I2, I3, I4, I5,
148-
G1,
149-
G2, G3, G4, // OK for use only in
150-
// applications, not libraries.
151-
G5, // OK for use in 64 bit mode.
152-
L0, L1, L2, L3, L4, L5, L6, L7,
153-
O0, O1, O2, O3, O4, O5, O7,
154-
// Non-allocatable regs:
155-
O6, // stack ptr
156-
I6, // frame ptr
157-
I7, // return address
158-
G0, // constant zero
159-
G6, G7 // reserved for kernel
160-
)>;
147+
(add (sequence "I%u", 0, 7),
148+
(sequence "G%u", 0, 7),
149+
(sequence "L%u", 0, 7),
150+
(sequence "O%u", 0, 7))>;
161151

162152
// Register class for 64-bit mode, with a 64-bit spill slot size.
163153
// These are the same as the 32-bit registers, so TableGen will consider this

llvm/test/CodeGen/SPARC/leafproc.ll

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
; RUN: llc -march=sparc -disable-sparc-leaf-proc=0 < %s | FileCheck %s
2+
3+
; CHECK: func_nobody:
4+
; CHECK: jmp %o7+8
5+
; CHECK-NEXT: nop
6+
define void @func_nobody() {
7+
entry:
8+
ret void
9+
}
10+
11+
12+
; CHECK: return_int_const:
13+
; CHECK: jmp %o7+8
14+
; CHECK-NEXT: or %g0, 1729, %o0
15+
define i32 @return_int_const() {
16+
entry:
17+
ret i32 1729
18+
}
19+
20+
; CHECK: return_double_const:
21+
; CHECK: sethi
22+
; CHECK: jmp %o7+8
23+
; CHECK-NEXT: ldd {{.*}}, %f0
24+
25+
define double @return_double_const() {
26+
entry:
27+
ret double 0.000000e+00
28+
}
29+
30+
; CHECK: leaf_proc_with_args:
31+
; CHECK: add {{%o[0-1]}}, {{%o[0-1]}}, [[R:%[go][0-7]]]
32+
; CHECK: jmp %o7+8
33+
; CHECK-NEXT: add [[R]], %o2, %o0
34+
35+
define i32 @leaf_proc_with_args(i32 %a, i32 %b, i32 %c) {
36+
entry:
37+
%0 = add nsw i32 %b, %a
38+
%1 = add nsw i32 %0, %c
39+
ret i32 %1
40+
}
41+
42+
; CHECK: leaf_proc_with_args_in_stack:
43+
; CHECK-DAG: ld [%sp+92], {{%[go][0-7]}}
44+
; CHECK-DAG: ld [%sp+96], {{%[go][0-7]}}
45+
; CHECK: jmp %o7+8
46+
; CHECK-NEXT: add {{.*}}, %o0
47+
define i32 @leaf_proc_with_args_in_stack(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
48+
entry:
49+
%0 = add nsw i32 %b, %a
50+
%1 = add nsw i32 %0, %c
51+
%2 = add nsw i32 %1, %d
52+
%3 = add nsw i32 %2, %e
53+
%4 = add nsw i32 %3, %f
54+
%5 = add nsw i32 %4, %g
55+
%6 = add nsw i32 %5, %h
56+
ret i32 %6
57+
}

0 commit comments

Comments
 (0)