PrologEpilogInserter.cpp [plain text]
#define DEBUG_TYPE "pei"
#include "PrologEpilogInserter.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include <climits>
using namespace llvm;
char PEI::ID = 0;
char &llvm::PrologEpilogCodeInserterID = PEI::ID;
static cl::opt<unsigned>
WarnStackSize("warn-stack-size", cl::Hidden, cl::init((unsigned)-1),
cl::desc("Warn for stack size bigger than the given"
" number"));
INITIALIZE_PASS_BEGIN(PEI, "prologepilog",
"Prologue/Epilogue Insertion", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(PEI, "prologepilog",
"Prologue/Epilogue Insertion & Frame Finalization",
false, false)
STATISTIC(NumVirtualFrameRegs, "Number of virtual frame regs encountered");
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
STATISTIC(NumBytesStackSpace,
"Number of bytes used for stack in all functions");
bool PEI::runOnMachineFunction(MachineFunction &Fn) {
const Function* F = Fn.getFunction();
const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo();
const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering();
assert(!Fn.getRegInfo().getNumVirtRegs() && "Regalloc must assign all vregs");
RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : NULL;
FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn);
calculateCallsInformation(Fn);
TFI->processFunctionBeforeCalleeSavedScan(Fn, RS);
calculateCalleeSavedRegisters(Fn);
placeCSRSpillsAndRestores(Fn);
if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::Naked))
insertCSRSpillsAndRestores(Fn);
TFI->processFunctionBeforeFrameFinalized(Fn);
calculateFrameObjectOffsets(Fn);
if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::Naked))
insertPrologEpilogCode(Fn);
replaceFrameIndices(Fn);
if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging)
scavengeFrameVirtualRegs(Fn);
Fn.getRegInfo().clearVirtRegs();
MachineFrameInfo *MFI = Fn.getFrameInfo();
if (WarnStackSize.getNumOccurrences() > 0 &&
WarnStackSize < MFI->getStackSize())
errs() << "warning: Stack size limit exceeded (" << MFI->getStackSize()
<< ") in " << Fn.getName() << ".\n";
delete RS;
clearAllSets();
return true;
}
void PEI::calculateCallsInformation(MachineFunction &Fn) {
const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering();
MachineFrameInfo *MFI = Fn.getFrameInfo();
unsigned MaxCallFrameSize = 0;
bool AdjustsStack = MFI->adjustsStack();
int FrameSetupOpcode = TII.getCallFrameSetupOpcode();
int FrameDestroyOpcode = TII.getCallFrameDestroyOpcode();
if (FrameSetupOpcode == -1 && FrameDestroyOpcode == -1)
return;
std::vector<MachineBasicBlock::iterator> FrameSDOps;
for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I)
if (I->getOpcode() == FrameSetupOpcode ||
I->getOpcode() == FrameDestroyOpcode) {
assert(I->getNumOperands() >= 1 && "Call Frame Setup/Destroy Pseudo"
" instructions should have a single immediate argument!");
unsigned Size = I->getOperand(0).getImm();
if (Size > MaxCallFrameSize) MaxCallFrameSize = Size;
AdjustsStack = true;
FrameSDOps.push_back(I);
} else if (I->isInlineAsm()) {
unsigned ExtraInfo = I->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
if (ExtraInfo & InlineAsm::Extra_IsAlignStack)
AdjustsStack = true;
}
MFI->setAdjustsStack(AdjustsStack);
MFI->setMaxCallFrameSize(MaxCallFrameSize);
for (std::vector<MachineBasicBlock::iterator>::iterator
i = FrameSDOps.begin(), e = FrameSDOps.end(); i != e; ++i) {
MachineBasicBlock::iterator I = *i;
if (TFI->canSimplifyCallFramePseudos(Fn))
RegInfo->eliminateCallFramePseudoInstr(Fn, *I->getParent(), I);
}
}
void PEI::calculateCalleeSavedRegisters(MachineFunction &F) {
const TargetRegisterInfo *RegInfo = F.getTarget().getRegisterInfo();
const TargetFrameLowering *TFI = F.getTarget().getFrameLowering();
MachineFrameInfo *MFI = F.getFrameInfo();
const uint16_t *CSRegs = RegInfo->getCalleeSavedRegs(&F);
MinCSFrameIndex = INT_MAX;
MaxCSFrameIndex = 0;
if (CSRegs == 0 || CSRegs[0] == 0)
return;
if (F.getFunction()->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::Naked))
return;
std::vector<CalleeSavedInfo> CSI;
for (unsigned i = 0; CSRegs[i]; ++i) {
unsigned Reg = CSRegs[i];
if (F.getRegInfo().isPhysRegUsed(Reg)) {
CSI.push_back(CalleeSavedInfo(Reg));
}
}
if (CSI.empty())
return;
unsigned NumFixedSpillSlots;
const TargetFrameLowering::SpillSlot *FixedSpillSlots =
TFI->getCalleeSavedSpillSlots(NumFixedSpillSlots);
for (std::vector<CalleeSavedInfo>::iterator
I = CSI.begin(), E = CSI.end(); I != E; ++I) {
unsigned Reg = I->getReg();
const TargetRegisterClass *RC = RegInfo->getMinimalPhysRegClass(Reg);
int FrameIdx;
if (RegInfo->hasReservedSpillSlot(F, Reg, FrameIdx)) {
I->setFrameIdx(FrameIdx);
continue;
}
const TargetFrameLowering::SpillSlot *FixedSlot = FixedSpillSlots;
while (FixedSlot != FixedSpillSlots+NumFixedSpillSlots &&
FixedSlot->Reg != Reg)
++FixedSlot;
if (FixedSlot == FixedSpillSlots + NumFixedSpillSlots) {
unsigned Align = RC->getAlignment();
unsigned StackAlign = TFI->getStackAlignment();
Align = std::min(Align, StackAlign);
FrameIdx = MFI->CreateStackObject(RC->getSize(), Align, true);
if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx;
if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx;
} else {
FrameIdx = MFI->CreateFixedObject(RC->getSize(), FixedSlot->Offset, true);
}
I->setFrameIdx(FrameIdx);
}
MFI->setCalleeSavedInfo(CSI);
}
void PEI::insertCSRSpillsAndRestores(MachineFunction &Fn) {
MachineFrameInfo *MFI = Fn.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
MFI->setCalleeSavedInfoValid(true);
if (CSI.empty())
return;
const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering();
const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo();
MachineBasicBlock::iterator I;
if (!ShrinkWrapThisFunction) {
I = EntryBlock->begin();
if (!TFI->spillCalleeSavedRegisters(*EntryBlock, I, CSI, TRI)) {
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
EntryBlock->addLiveIn(CSI[i].getReg());
unsigned Reg = CSI[i].getReg();
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(*EntryBlock, I, Reg, true,
CSI[i].getFrameIdx(), RC, TRI);
}
}
for (unsigned ri = 0, re = ReturnBlocks.size(); ri != re; ++ri) {
MachineBasicBlock* MBB = ReturnBlocks[ri];
I = MBB->end(); --I;
MachineBasicBlock::iterator I2 = I;
while (I2 != MBB->begin() && (--I2)->isTerminator())
I = I2;
bool AtStart = I == MBB->begin();
MachineBasicBlock::iterator BeforeI = I;
if (!AtStart)
--BeforeI;
if (!TFI->restoreCalleeSavedRegisters(*MBB, I, CSI, TRI)) {
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
unsigned Reg = CSI[i].getReg();
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.loadRegFromStackSlot(*MBB, I, Reg,
CSI[i].getFrameIdx(),
RC, TRI);
assert(I != MBB->begin() &&
"loadRegFromStackSlot didn't insert any code!");
if (AtStart)
I = MBB->begin();
else {
I = BeforeI;
++I;
}
}
}
}
return;
}
std::vector<CalleeSavedInfo> blockCSI;
for (CSRegBlockMap::iterator BI = CSRSave.begin(),
BE = CSRSave.end(); BI != BE; ++BI) {
MachineBasicBlock* MBB = BI->first;
CSRegSet save = BI->second;
if (save.empty())
continue;
blockCSI.clear();
for (CSRegSet::iterator RI = save.begin(),
RE = save.end(); RI != RE; ++RI) {
blockCSI.push_back(CSI[*RI]);
}
assert(blockCSI.size() > 0 &&
"Could not collect callee saved register info");
I = MBB->begin();
for (unsigned i = 0, e = blockCSI.size(); i != e; ++i) {
MBB->addLiveIn(blockCSI[i].getReg());
unsigned Reg = blockCSI[i].getReg();
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(*MBB, I, Reg,
true,
blockCSI[i].getFrameIdx(),
RC, TRI);
}
}
for (CSRegBlockMap::iterator BI = CSRRestore.begin(),
BE = CSRRestore.end(); BI != BE; ++BI) {
MachineBasicBlock* MBB = BI->first;
CSRegSet restore = BI->second;
if (restore.empty())
continue;
blockCSI.clear();
for (CSRegSet::iterator RI = restore.begin(),
RE = restore.end(); RI != RE; ++RI) {
blockCSI.push_back(CSI[*RI]);
}
assert(blockCSI.size() > 0 &&
"Could not find callee saved register info");
if (MBB->empty()) {
I = MBB->begin();
} else {
I = MBB->end();
--I;
if (! I->isTerminator()) {
++I;
} else {
MachineBasicBlock::iterator I2 = I;
while (I2 != MBB->begin() && (--I2)->isTerminator())
I = I2;
}
}
bool AtStart = I == MBB->begin();
MachineBasicBlock::iterator BeforeI = I;
if (!AtStart)
--BeforeI;
for (unsigned i = 0, e = blockCSI.size(); i != e; ++i) {
unsigned Reg = blockCSI[i].getReg();
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.loadRegFromStackSlot(*MBB, I, Reg,
blockCSI[i].getFrameIdx(),
RC, TRI);
assert(I != MBB->begin() &&
"loadRegFromStackSlot didn't insert any code!");
if (AtStart)
I = MBB->begin();
else {
I = BeforeI;
++I;
}
}
}
}
static inline void
AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx,
bool StackGrowsDown, int64_t &Offset,
unsigned &MaxAlign) {
if (StackGrowsDown)
Offset += MFI->getObjectSize(FrameIdx);
unsigned Align = MFI->getObjectAlignment(FrameIdx);
MaxAlign = std::max(MaxAlign, Align);
Offset = (Offset + Align - 1) / Align * Align;
if (StackGrowsDown) {
DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << -Offset << "]\n");
MFI->setObjectOffset(FrameIdx, -Offset); } else {
DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << Offset << "]\n");
MFI->setObjectOffset(FrameIdx, Offset);
Offset += MFI->getObjectSize(FrameIdx);
}
}
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering();
bool StackGrowsDown =
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
MachineFrameInfo *MFI = Fn.getFrameInfo();
int LocalAreaOffset = TFI.getOffsetOfLocalArea();
if (StackGrowsDown)
LocalAreaOffset = -LocalAreaOffset;
assert(LocalAreaOffset >= 0
&& "Local area offset should be in direction of stack growth");
int64_t Offset = LocalAreaOffset;
for (int i = MFI->getObjectIndexBegin(); i != 0; ++i) {
int64_t FixedOff;
if (StackGrowsDown) {
FixedOff = -MFI->getObjectOffset(i);
} else {
FixedOff = MFI->getObjectOffset(i) + MFI->getObjectSize(i);
}
if (FixedOff > Offset) Offset = FixedOff;
}
if (StackGrowsDown) {
for (unsigned i = MinCSFrameIndex; i <= MaxCSFrameIndex; ++i) {
Offset += MFI->getObjectSize(i);
unsigned Align = MFI->getObjectAlignment(i);
Offset = (Offset+Align-1)/Align*Align;
MFI->setObjectOffset(i, -Offset); }
} else {
int MaxCSFI = MaxCSFrameIndex, MinCSFI = MinCSFrameIndex;
for (int i = MaxCSFI; i >= MinCSFI ; --i) {
unsigned Align = MFI->getObjectAlignment(i);
Offset = (Offset+Align-1)/Align*Align;
MFI->setObjectOffset(i, Offset);
Offset += MFI->getObjectSize(i);
}
}
unsigned MaxAlign = MFI->getMaxAlignment();
const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
if (RS && TFI.hasFP(Fn) && RegInfo->useFPForScavengingIndex(Fn) &&
!RegInfo->needsStackRealignment(Fn)) {
int SFI = RS->getScavengingFrameIndex();
if (SFI >= 0)
AdjustStackOffset(MFI, SFI, StackGrowsDown, Offset, MaxAlign);
}
if (MFI->getUseLocalStackAllocationBlock()) {
unsigned Align = MFI->getLocalFrameMaxAlign();
Offset = (Offset + Align - 1) / Align * Align;
DEBUG(dbgs() << "Local frame base offset: " << Offset << "\n");
for (unsigned i = 0, e = MFI->getLocalFrameObjectCount(); i != e; ++i) {
std::pair<int, int64_t> Entry = MFI->getLocalFrameObjectMap(i);
int64_t FIOffset = (StackGrowsDown ? -Offset : Offset) + Entry.second;
DEBUG(dbgs() << "alloc FI(" << Entry.first << ") at SP[" <<
FIOffset << "]\n");
MFI->setObjectOffset(Entry.first, FIOffset);
}
Offset += MFI->getLocalFrameSize();
MaxAlign = std::max(Align, MaxAlign);
}
SmallSet<int, 16> LargeStackObjs;
if (MFI->getStackProtectorIndex() >= 0) {
AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), StackGrowsDown,
Offset, MaxAlign);
for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
if (MFI->isObjectPreAllocated(i) &&
MFI->getUseLocalStackAllocationBlock())
continue;
if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex)
continue;
if (RS && (int)i == RS->getScavengingFrameIndex())
continue;
if (MFI->isDeadObjectIndex(i))
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
if (!MFI->MayNeedStackProtector(i))
continue;
AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
LargeStackObjs.insert(i);
}
}
for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
if (MFI->isObjectPreAllocated(i) &&
MFI->getUseLocalStackAllocationBlock())
continue;
if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex)
continue;
if (RS && (int)i == RS->getScavengingFrameIndex())
continue;
if (MFI->isDeadObjectIndex(i))
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
if (LargeStackObjs.count(i))
continue;
AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
}
if (RS && (!TFI.hasFP(Fn) || RegInfo->needsStackRealignment(Fn) ||
!RegInfo->useFPForScavengingIndex(Fn))) {
int SFI = RS->getScavengingFrameIndex();
if (SFI >= 0)
AdjustStackOffset(MFI, SFI, StackGrowsDown, Offset, MaxAlign);
}
if (!TFI.targetHandlesStackFrameRounding()) {
if (MFI->adjustsStack() && TFI.hasReservedCallFrame(Fn))
Offset += MFI->getMaxCallFrameSize();
unsigned StackAlign;
if (MFI->adjustsStack() || MFI->hasVarSizedObjects() ||
(RegInfo->needsStackRealignment(Fn) && MFI->getObjectIndexEnd() != 0))
StackAlign = TFI.getStackAlignment();
else
StackAlign = TFI.getTransientStackAlignment();
StackAlign = std::max(StackAlign, MaxAlign);
unsigned AlignMask = StackAlign - 1;
Offset = (Offset + AlignMask) & ~uint64_t(AlignMask);
}
int64_t StackSize = Offset - LocalAreaOffset;
MFI->setStackSize(StackSize);
NumBytesStackSpace += StackSize;
}
void PEI::insertPrologEpilogCode(MachineFunction &Fn) {
const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering();
TFI.emitPrologue(Fn);
for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
if (!I->empty() && I->back().isReturn())
TFI.emitEpilogue(Fn, *I);
}
if (Fn.getTarget().Options.EnableSegmentedStacks)
TFI.adjustForSegmentedStacks(Fn);
}
void PEI::replaceFrameIndices(MachineFunction &Fn) {
if (!Fn.getFrameInfo()->hasStackObjects()) return;
const TargetMachine &TM = Fn.getTarget();
assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!");
const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
const TargetRegisterInfo &TRI = *TM.getRegisterInfo();
const TargetFrameLowering *TFI = TM.getFrameLowering();
bool StackGrowsDown =
TFI->getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
int FrameSetupOpcode = TII.getCallFrameSetupOpcode();
int FrameDestroyOpcode = TII.getCallFrameDestroyOpcode();
for (MachineFunction::iterator BB = Fn.begin(),
E = Fn.end(); BB != E; ++BB) {
#ifndef NDEBUG
int SPAdjCount = 0; #endif
int SPAdj = 0; if (RS && !FrameIndexVirtualScavenging) RS->enterBasicBlock(BB);
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) {
if (I->getOpcode() == FrameSetupOpcode ||
I->getOpcode() == FrameDestroyOpcode) {
#ifndef NDEBUG
SPAdjCount += I->getOpcode() == FrameSetupOpcode ? 1 : -1;
#endif
int Size = I->getOperand(0).getImm();
if ((!StackGrowsDown && I->getOpcode() == FrameSetupOpcode) ||
(StackGrowsDown && I->getOpcode() == FrameDestroyOpcode))
Size = -Size;
SPAdj += Size;
MachineBasicBlock::iterator PrevI = BB->end();
if (I != BB->begin()) PrevI = prior(I);
TRI.eliminateCallFramePseudoInstr(Fn, *BB, I);
if (PrevI == BB->end())
I = BB->begin(); else
I = llvm::next(PrevI);
continue;
}
MachineInstr *MI = I;
bool DoIncr = true;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i)
if (MI->getOperand(i).isFI()) {
bool AtBeginning = (I == BB->begin());
if (!AtBeginning) --I;
TRI.eliminateFrameIndex(MI, SPAdj, i,
FrameIndexVirtualScavenging ? NULL : RS);
if (AtBeginning) {
I = BB->begin();
DoIncr = false;
}
MI = 0;
break;
}
if (DoIncr && I != BB->end()) ++I;
if (RS && !FrameIndexVirtualScavenging && MI) RS->forward(MI);
}
assert((SPAdjCount || SPAdj == 0) &&
"Unbalanced call frame setup / destroy pairs?");
}
}
void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
for (MachineFunction::iterator BB = Fn.begin(),
E = Fn.end(); BB != E; ++BB) {
RS->enterBasicBlock(BB);
unsigned VirtReg = 0;
unsigned ScratchReg = 0;
int SPAdj = 0;
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) {
MachineInstr *MI = I;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
if (MI->getOperand(i).isReg()) {
MachineOperand &MO = MI->getOperand(i);
unsigned Reg = MO.getReg();
if (Reg == 0)
continue;
if (!TargetRegisterInfo::isVirtualRegister(Reg))
continue;
++NumVirtualFrameRegs;
if (Reg != VirtReg) {
assert(MI->getOperand(i).isDef() &&
"frame index virtual missing def!");
VirtReg = Reg;
const TargetRegisterClass *RC = Fn.getRegInfo().getRegClass(Reg);
ScratchReg = RS->scavengeRegister(RC, I, SPAdj);
++NumScavengedRegs;
}
assert (ScratchReg && "Missing scratch register!");
MI->getOperand(i).setReg(ScratchReg);
}
}
RS->forward(I);
++I;
}
}
}