#include "SparcFrameLowering.h"
#include "SparcInstrInfo.h"
#include "SparcMachineFunctionInfo.h"
#include "SparcSubtarget.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
static cl::opt<bool>
DisableLeafProc("disable-sparc-leaf-proc",
cl::init(false),
cl::desc("Disable Sparc leaf procedure optimization."),
cl::Hidden);
SparcFrameLowering::SparcFrameLowering(const SparcSubtarget &ST)
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
ST.is64Bit() ? Align(16) : Align(8), 0,
ST.is64Bit() ? Align(16) : Align(8)) {}
void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
int NumBytes,
unsigned ADDrr,
unsigned ADDri) const {
DebugLoc dl;
const SparcInstrInfo &TII =
*static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
if (NumBytes >= -4096 && NumBytes < 4096) {
BuildMI(MBB, MBBI, dl, TII.get(ADDri), SP::O6)
.addReg(SP::O6).addImm(NumBytes);
return;
}
if (NumBytes >= 0) {
BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HI22(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(SP::ORri), SP::G1)
.addReg(SP::G1).addImm(LO10(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
.addReg(SP::O6).addReg(SP::G1);
return ;
}
BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HIX22(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(SP::XORri), SP::G1)
.addReg(SP::G1).addImm(LOX10(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
.addReg(SP::O6).addReg(SP::G1);
}
void SparcFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
MachineFrameInfo &MFI = MF.getFrameInfo();
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
const SparcInstrInfo &TII =
*static_cast<const SparcInstrInfo *>(Subtarget.getInstrInfo());
const SparcRegisterInfo &RegInfo =
*static_cast<const SparcRegisterInfo *>(Subtarget.getRegisterInfo());
MachineBasicBlock::iterator MBBI = MBB.begin();
DebugLoc dl;
bool NeedsStackRealignment = RegInfo.shouldRealignStack(MF);
if (NeedsStackRealignment && !RegInfo.canRealignStack(MF))
report_fatal_error("Function \"" + Twine(MF.getName()) + "\" required "
"stack re-alignment, but LLVM couldn't handle it "
"(probably because it has a dynamic alloca).");
int NumBytes = (int) MFI.getStackSize();
unsigned SAVEri = SP::SAVEri;
unsigned SAVErr = SP::SAVErr;
if (FuncInfo->isLeafProc()) {
if (NumBytes == 0)
return;
SAVEri = SP::ADDri;
SAVErr = SP::ADDrr;
}
if (MFI.adjustsStack() && hasReservedCallFrame(MF))
NumBytes += MFI.getMaxCallFrameSize();
NumBytes = Subtarget.getAdjustedFrameSize(NumBytes);
NumBytes = alignTo(NumBytes, MFI.getMaxAlign());
MFI.setStackSize(NumBytes);
emitSPAdjustment(MF, MBB, MBBI, -NumBytes, SAVErr, SAVEri);
unsigned regFP = RegInfo.getDwarfRegNum(SP::I6, true);
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(nullptr, regFP));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
CFIIndex = MF.addFrameInst(MCCFIInstruction::createWindowSave(nullptr));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
unsigned regInRA = RegInfo.getDwarfRegNum(SP::I7, true);
unsigned regOutRA = RegInfo.getDwarfRegNum(SP::O7, true);
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createRegister(nullptr, regOutRA, regInRA));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
if (NeedsStackRealignment) {
int64_t Bias = Subtarget.getStackPointerBias();
unsigned regUnbiased;
if (Bias) {
regUnbiased = SP::G1;
BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), regUnbiased)
.addReg(SP::O6).addImm(Bias);
} else
regUnbiased = SP::O6;
Align MaxAlign = MFI.getMaxAlign();
BuildMI(MBB, MBBI, dl, TII.get(SP::ANDNri), regUnbiased)
.addReg(regUnbiased)
.addImm(MaxAlign.value() - 1U);
if (Bias) {
BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), SP::O6)
.addReg(regUnbiased).addImm(-Bias);
}
}
}
MachineBasicBlock::iterator SparcFrameLowering::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
if (!hasReservedCallFrame(MF)) {
MachineInstr &MI = *I;
int Size = MI.getOperand(0).getImm();
if (MI.getOpcode() == SP::ADJCALLSTACKDOWN)
Size = -Size;
if (Size)
emitSPAdjustment(MF, MBB, I, Size, SP::ADDrr, SP::ADDri);
}
return MBB.erase(I);
}
void SparcFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
const SparcInstrInfo &TII =
*static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
DebugLoc dl = MBBI->getDebugLoc();
assert((MBBI->getOpcode() == SP::RETL || MBBI->getOpcode() == SP::TAIL_CALL ||
MBBI->getOpcode() == SP::TAIL_CALLri) &&
"Can only put epilog before 'retl' or 'tail_call' instruction!");
if (!FuncInfo->isLeafProc()) {
BuildMI(MBB, MBBI, dl, TII.get(SP::RESTORErr), SP::G0).addReg(SP::G0)
.addReg(SP::G0);
return;
}
MachineFrameInfo &MFI = MF.getFrameInfo();
int NumBytes = (int) MFI.getStackSize();
if (NumBytes != 0)
emitSPAdjustment(MF, MBB, MBBI, NumBytes, SP::ADDrr, SP::ADDri);
if (MBBI->getOpcode() == SP::TAIL_CALL) {
MBB.addLiveIn(SP::O7);
BuildMI(MBB, MBBI, dl, TII.get(SP::ORrr), SP::G1)
.addReg(SP::G0)
.addReg(SP::O7);
BuildMI(MBB, MBBI, dl, TII.get(SP::ORrr), SP::O7)
.addReg(SP::G0)
.addReg(SP::G1);
}
}
bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
return !MF.getFrameInfo().hasVarSizedObjects();
}
bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
const MachineFrameInfo &MFI = MF.getFrameInfo();
return MF.getTarget().Options.DisableFramePointerElim(MF) ||
RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
MFI.isFrameAddressTaken();
}
StackOffset
SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const {
const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
const MachineFrameInfo &MFI = MF.getFrameInfo();
const SparcRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
const SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
bool isFixed = MFI.isFixedObjectIndex(FI);
bool UseFP;
if (FuncInfo->isLeafProc()) {
UseFP = false;
} else if (isFixed) {
UseFP = true;
} else if (RegInfo->hasStackRealignment(MF)) {
UseFP = false;
} else {
UseFP = true;
}
int64_t FrameOffset = MF.getFrameInfo().getObjectOffset(FI) +
Subtarget.getStackPointerBias();
if (UseFP) {
FrameReg = RegInfo->getFrameRegister(MF);
return StackOffset::getFixed(FrameOffset);
} else {
FrameReg = SP::O6; return StackOffset::getFixed(FrameOffset + MF.getFrameInfo().getStackSize());
}
}
static bool LLVM_ATTRIBUTE_UNUSED 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() || MRI.isPhysRegUsed(SP::L0) || MRI.isPhysRegUsed(SP::O6) || hasFP(MF) || MF.hasInlineAsm()); }
void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
MachineRegisterInfo &MRI = MF.getRegInfo();
for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
if (!MRI.isPhysRegUsed(reg))
continue;
unsigned mapped_reg = reg - SP::I0 + SP::O0;
MRI.replaceRegWith(reg, mapped_reg);
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);
}
}
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);
}
}
assert(verifyLeafProcRegUse(&MRI));
#ifdef EXPENSIVE_CHECKS
MF.verify(0, "After LeafProc Remapping");
#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);
remapRegsForLeafProc(MF);
}
}