[Sparc] Add support for leaf functions in sparc backend.

llvm-svn: 182822
This commit is contained in:
Venkatraman Govindaraju 2013-05-29 04:46:31 +00:00
parent d7bf293eb7
commit ca0fe2f57e
7 changed files with 180 additions and 28 deletions

View File

@ -135,18 +135,22 @@ Filler::findDelayInstr(MachineBasicBlock &MBB,
bool sawLoad = false;
bool sawStore = false;
MachineBasicBlock::iterator I = slot;
if (slot == MBB.begin())
return MBB.end();
if (slot->getOpcode() == SP::RET)
return MBB.end();
if (slot->getOpcode() == SP::RETL) {
--I;
if (I->getOpcode() != SP::RESTORErr)
return MBB.end();
//change retl to ret
slot->setDesc(TII->get(SP::RET));
return I;
MachineBasicBlock::iterator J = slot;
--J;
if (J->getOpcode() == SP::RESTORErr
|| J->getOpcode() == SP::RESTOREri) {
//change retl to ret
slot->setDesc(TII->get(SP::RET));
return J;
}
}
//Call's delay filler can def some of call's uses.
@ -157,6 +161,8 @@ Filler::findDelayInstr(MachineBasicBlock &MBB,
bool done = false;
MachineBasicBlock::iterator I = slot;
while (!done) {
done = (I == MBB.begin());
@ -274,9 +280,13 @@ void Filler::insertDefsUses(MachineBasicBlock::iterator MI,
continue;
if (MO.isDef())
RegDefs.insert(Reg);
if (MO.isUse())
if (MO.isUse()) {
//Implicit register uses of retl are return values and
//retl does not use them.
if (MO.isImplicit() && MI->getOpcode() == SP::RETL)
continue;
RegUses.insert(Reg);
}
}
}

View File

@ -26,7 +26,18 @@
using namespace llvm;
static cl::opt<bool>
DisableLeafProc("disable-sparc-leaf-proc",
cl::init(true),
cl::desc("Disable Sparc leaf procedure optimization."),
cl::Hidden);
void SparcFrameLowering::emitPrologue(MachineFunction &MF) const {
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
if (FuncInfo->isLeafProc())
return;
MachineBasicBlock &MBB = MF.front();
MachineFrameInfo *MFI = MF.getFrameInfo();
const SparcInstrInfo &TII =
@ -97,6 +108,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
void SparcFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
if (FuncInfo->isLeafProc())
return;
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
const SparcInstrInfo &TII =
*static_cast<const SparcInstrInfo*>(MF.getTarget().getInstrInfo());
@ -121,3 +135,65 @@ bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken();
}
static bool verifyLeafProcRegUse(MachineRegisterInfo *MRI)
{
for (unsigned reg = SP::I0; reg <= SP::I7; ++reg)
if (MRI->isPhysRegUsed(reg))
return false;
for (unsigned reg = SP::L0; reg <= SP::L7; ++reg)
if (MRI->isPhysRegUsed(reg))
return false;
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
}
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);
assert(!MRI.isPhysRegUsed(mapped_reg));
//Replace I register with O register
MRI.replaceRegWith(reg, mapped_reg);
//mark the reg unused.
MRI.setPhysRegUnused(reg);
}
assert(verifyLeafProcRegUse(&MRI));
#ifdef XDEBUG
MF.verify(0, "After LeafProc Remapping");
#endif
}
void SparcFrameLowering::processFunctionBeforeCalleeSavedScan
(MachineFunction &MF, RegScavenger *RS) const {
if (!DisableLeafProc && isLeafProc(MF)) {
SparcMachineFunctionInfo *MFI = MF.getInfo<SparcMachineFunctionInfo>();
MFI->setLeafProc(true);
remapRegsForLeafProc(MF);
}
}

View File

@ -40,6 +40,15 @@ public:
bool hasReservedCallFrame(const MachineFunction &MF) const;
bool hasFP(const MachineFunction &MF) const;
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS = NULL) const;
private:
//Remap input registers to output registers for leaf procedure.
void remapRegsForLeafProc(MachineFunction &MF) const;
//Returns true if MF is a leaf procedure.
bool isLeafProc(MachineFunction &MF) const;
};
} // End llvm namespace

View File

@ -28,11 +28,16 @@ namespace llvm {
/// SRetReturnReg - Holds the virtual register into which the sret
/// argument is passed.
unsigned SRetReturnReg;
/// IsLeafProc - True if the function is a leaf procedure.
bool IsLeafProc;
public:
SparcMachineFunctionInfo()
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0) {}
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
IsLeafProc(false) {}
explicit SparcMachineFunctionInfo(MachineFunction &MF)
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0) {}
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
IsLeafProc(false) {}
unsigned getGlobalBaseReg() const { return GlobalBaseReg; }
void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; }
@ -42,6 +47,9 @@ namespace llvm {
unsigned getSRetReturnReg() const { return SRetReturnReg; }
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
void setLeafProc(bool rhs) { IsLeafProc = rhs; }
bool isLeafProc() const { return IsLeafProc; }
};
}

View File

@ -13,6 +13,7 @@
#include "SparcRegisterInfo.h"
#include "Sparc.h"
#include "SparcMachineFunctionInfo.h"
#include "SparcSubtarget.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
@ -89,12 +90,13 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int64_t Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
MI.getOperand(FIOperandNum + 1).getImm() +
Subtarget.getStackPointerBias();
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
unsigned FramePtr = (FuncInfo->isLeafProc()) ? SP::O6 : SP::I6;
// Replace frame index with a frame pointer reference.
if (Offset >= -4096 && Offset <= 4095) {
// If the offset is small enough to fit in the immediate field, directly
// encode it.
MI.getOperand(FIOperandNum).ChangeToRegister(SP::I6, false);
MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
} else {
// Otherwise, emit a G1 = SETHI %hi(offset). FIXME: it would be better to
@ -103,7 +105,7 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1).addImm(OffHi);
// Emit G1 = G1 + I6
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
.addReg(SP::I6);
.addReg(FramePtr);
// Insert: G1+%lo(offset) into the user.
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset & ((1 << 10)-1));

View File

@ -144,20 +144,10 @@ def D15 : Rd<30, "F30", [F30, F31]>, DwarfRegNum<[87]>;
// register class for that. The i64 type is included here to allow i64 patterns
// using the integer instructions.
def IntRegs : RegisterClass<"SP", [i32, i64], 32,
(add I0, I1, I2, I3, I4, I5,
G1,
G2, G3, G4, // OK for use only in
// applications, not libraries.
G5, // OK for use in 64 bit mode.
L0, L1, L2, L3, L4, L5, L6, L7,
O0, O1, O2, O3, O4, O5, O7,
// Non-allocatable regs:
O6, // stack ptr
I6, // frame ptr
I7, // return address
G0, // constant zero
G6, G7 // reserved for kernel
)>;
(add (sequence "I%u", 0, 7),
(sequence "G%u", 0, 7),
(sequence "L%u", 0, 7),
(sequence "O%u", 0, 7))>;
// 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

View File

@ -0,0 +1,57 @@
; RUN: llc -march=sparc -disable-sparc-leaf-proc=0 < %s | FileCheck %s
; CHECK: func_nobody:
; CHECK: jmp %o7+8
; CHECK-NEXT: nop
define void @func_nobody() {
entry:
ret void
}
; CHECK: return_int_const:
; CHECK: jmp %o7+8
; CHECK-NEXT: or %g0, 1729, %o0
define i32 @return_int_const() {
entry:
ret i32 1729
}
; CHECK: return_double_const:
; CHECK: sethi
; CHECK: jmp %o7+8
; CHECK-NEXT: ldd {{.*}}, %f0
define double @return_double_const() {
entry:
ret double 0.000000e+00
}
; CHECK: leaf_proc_with_args:
; CHECK: add {{%o[0-1]}}, {{%o[0-1]}}, [[R:%[go][0-7]]]
; CHECK: jmp %o7+8
; CHECK-NEXT: add [[R]], %o2, %o0
define i32 @leaf_proc_with_args(i32 %a, i32 %b, i32 %c) {
entry:
%0 = add nsw i32 %b, %a
%1 = add nsw i32 %0, %c
ret i32 %1
}
; CHECK: leaf_proc_with_args_in_stack:
; CHECK-DAG: ld [%sp+92], {{%[go][0-7]}}
; CHECK-DAG: ld [%sp+96], {{%[go][0-7]}}
; CHECK: jmp %o7+8
; CHECK-NEXT: add {{.*}}, %o0
define i32 @leaf_proc_with_args_in_stack(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
entry:
%0 = add nsw i32 %b, %a
%1 = add nsw i32 %0, %c
%2 = add nsw i32 %1, %d
%3 = add nsw i32 %2, %e
%4 = add nsw i32 %3, %f
%5 = add nsw i32 %4, %g
%6 = add nsw i32 %5, %h
ret i32 %6
}