PrologEpilogInserter.cpp [plain text]
#include "PrologEpilogInserter.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/STLExtras.h"
#include <climits>
using namespace llvm;
char PEI::ID = 0;
static RegisterPass<PEI>
X("prologepilog", "Prologue/Epilogue Insertion");
FunctionPass *llvm::createPrologEpilogCodeInserter() { return new PEI(); }
bool PEI::runOnMachineFunction(MachineFunction &Fn) {
const Function* F = Fn.getFunction();
const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo();
RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : NULL;
FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn);
FrameConstantRegMap.clear();
if (MachineModuleInfo *MMI = getAnalysisIfAvailable<MachineModuleInfo>())
Fn.getFrameInfo()->setMachineModuleInfo(MMI);
calculateCallsInformation(Fn);
TRI->processFunctionBeforeCalleeSavedScan(Fn, RS);
calculateCalleeSavedRegisters(Fn);
placeCSRSpillsAndRestores(Fn);
if (!F->hasFnAttr(Attribute::Naked))
insertCSRSpillsAndRestores(Fn);
TRI->processFunctionBeforeFrameFinalized(Fn);
calculateFrameObjectOffsets(Fn);
if (!F->hasFnAttr(Attribute::Naked))
insertPrologEpilogCode(Fn);
replaceFrameIndices(Fn);
if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging)
scavengeFrameVirtualRegs(Fn);
delete RS;
clearAllSets();
return true;
}
#if 0
void PEI::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
if (ShrinkWrapping || ShrinkWrapFunc != "") {
AU.addRequired<MachineLoopInfo>();
AU.addRequired<MachineDominatorTree>();
}
AU.addPreserved<MachineLoopInfo>();
AU.addPreserved<MachineDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU);
}
#endif
void PEI::calculateCallsInformation(MachineFunction &Fn) {
const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
MachineFrameInfo *FFI = Fn.getFrameInfo();
unsigned MaxCallFrameSize = 0;
bool AdjustsStack = FFI->adjustsStack();
int FrameSetupOpcode = RegInfo->getCallFrameSetupOpcode();
int FrameDestroyOpcode = RegInfo->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()) {
if (I->getOperand(1).getImm())
AdjustsStack = true;
}
FFI->setAdjustsStack(AdjustsStack);
FFI->setMaxCallFrameSize(MaxCallFrameSize);
for (std::vector<MachineBasicBlock::iterator>::iterator
i = FrameSDOps.begin(), e = FrameSDOps.end(); i != e; ++i) {
MachineBasicBlock::iterator I = *i;
if (RegInfo->canSimplifyCallFramePseudos(Fn))
RegInfo->eliminateCallFramePseudoInstr(Fn, *I->getParent(), I);
}
}
void PEI::calculateCalleeSavedRegisters(MachineFunction &Fn) {
const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
const TargetFrameInfo *TFI = Fn.getTarget().getFrameInfo();
MachineFrameInfo *FFI = Fn.getFrameInfo();
const unsigned *CSRegs = RegInfo->getCalleeSavedRegs(&Fn);
MinCSFrameIndex = INT_MAX;
MaxCSFrameIndex = 0;
if (CSRegs == 0 || CSRegs[0] == 0)
return;
if (Fn.getFunction()->hasFnAttr(Attribute::Naked))
return;
const TargetRegisterClass * const *CSRegClasses =
RegInfo->getCalleeSavedRegClasses(&Fn);
std::vector<CalleeSavedInfo> CSI;
for (unsigned i = 0; CSRegs[i]; ++i) {
unsigned Reg = CSRegs[i];
if (Fn.getRegInfo().isPhysRegUsed(Reg)) {
CSI.push_back(CalleeSavedInfo(Reg, CSRegClasses[i]));
} else {
for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
*AliasSet; ++AliasSet) { if (Fn.getRegInfo().isPhysRegUsed(*AliasSet)) {
CSI.push_back(CalleeSavedInfo(Reg, CSRegClasses[i]));
break;
}
}
}
}
if (CSI.empty())
return;
unsigned NumFixedSpillSlots;
const TargetFrameInfo::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 = I->getRegClass();
int FrameIdx;
if (RegInfo->hasReservedSpillSlot(Fn, Reg, FrameIdx)) {
I->setFrameIdx(FrameIdx);
continue;
}
const TargetFrameInfo::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 = FFI->CreateStackObject(RC->getSize(), Align, true);
if ((unsigned)FrameIdx < MinCSFrameIndex) MinCSFrameIndex = FrameIdx;
if ((unsigned)FrameIdx > MaxCSFrameIndex) MaxCSFrameIndex = FrameIdx;
} else {
FrameIdx = FFI->CreateFixedObject(RC->getSize(), FixedSlot->Offset,
true, false);
}
I->setFrameIdx(FrameIdx);
}
FFI->setCalleeSavedInfo(CSI);
}
void PEI::insertCSRSpillsAndRestores(MachineFunction &Fn) {
MachineFrameInfo *FFI = Fn.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = FFI->getCalleeSavedInfo();
FFI->setCalleeSavedInfoValid(true);
if (CSI.empty())
return;
const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo();
MachineBasicBlock::iterator I;
if (! ShrinkWrapThisFunction) {
I = EntryBlock->begin();
if (!TII.spillCalleeSavedRegisters(*EntryBlock, I, CSI, TRI)) {
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
EntryBlock->addLiveIn(CSI[i].getReg());
TII.storeRegToStackSlot(*EntryBlock, I, CSI[i].getReg(), true,
CSI[i].getFrameIdx(), CSI[i].getRegClass());
}
}
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)->getDesc().isTerminator())
I = I2;
bool AtStart = I == MBB->begin();
MachineBasicBlock::iterator BeforeI = I;
if (!AtStart)
--BeforeI;
if (!TII.restoreCalleeSavedRegisters(*MBB, I, CSI, TRI)) {
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
TII.loadRegFromStackSlot(*MBB, I, CSI[i].getReg(),
CSI[i].getFrameIdx(),
CSI[i].getRegClass());
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());
TII.storeRegToStackSlot(*MBB, I, blockCSI[i].getReg(),
true,
blockCSI[i].getFrameIdx(),
blockCSI[i].getRegClass());
}
}
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->getDesc().isTerminator()) {
++I;
} else {
MachineBasicBlock::iterator I2 = I;
while (I2 != MBB->begin() && (--I2)->getDesc().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) {
TII.loadRegFromStackSlot(*MBB, I, blockCSI[i].getReg(),
blockCSI[i].getFrameIdx(),
blockCSI[i].getRegClass());
assert(I != MBB->begin() &&
"loadRegFromStackSlot didn't insert any code!");
if (AtStart)
I = MBB->begin();
else {
I = BeforeI;
++I;
}
}
}
}
static inline void
AdjustStackOffset(MachineFrameInfo *FFI, int FrameIdx,
bool StackGrowsDown, int64_t &Offset,
unsigned &MaxAlign) {
if (StackGrowsDown)
Offset += FFI->getObjectSize(FrameIdx);
unsigned Align = FFI->getObjectAlignment(FrameIdx);
MaxAlign = std::max(MaxAlign, Align);
Offset = (Offset + Align - 1) / Align * Align;
if (StackGrowsDown) {
FFI->setObjectOffset(FrameIdx, -Offset); } else {
FFI->setObjectOffset(FrameIdx, Offset);
Offset += FFI->getObjectSize(FrameIdx);
}
}
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo();
bool StackGrowsDown =
TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;
MachineFrameInfo *FFI = 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 = FFI->getObjectIndexBegin(); i != 0; ++i) {
int64_t FixedOff;
if (StackGrowsDown) {
FixedOff = -FFI->getObjectOffset(i);
} else {
FixedOff = FFI->getObjectOffset(i) + FFI->getObjectSize(i);
}
if (FixedOff > Offset) Offset = FixedOff;
}
if (StackGrowsDown) {
for (unsigned i = MinCSFrameIndex; i <= MaxCSFrameIndex; ++i) {
Offset += FFI->getObjectSize(i);
unsigned Align = FFI->getObjectAlignment(i);
Offset = (Offset+Align-1)/Align*Align;
FFI->setObjectOffset(i, -Offset); }
} else {
int MaxCSFI = MaxCSFrameIndex, MinCSFI = MinCSFrameIndex;
for (int i = MaxCSFI; i >= MinCSFI ; --i) {
unsigned Align = FFI->getObjectAlignment(i);
Offset = (Offset+Align-1)/Align*Align;
FFI->setObjectOffset(i, Offset);
Offset += FFI->getObjectSize(i);
}
}
unsigned MaxAlign = FFI->getMaxAlignment();
const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
if (RS && RegInfo->hasFP(Fn) && !RegInfo->needsStackRealignment(Fn)) {
int SFI = RS->getScavengingFrameIndex();
if (SFI >= 0)
AdjustStackOffset(FFI, SFI, StackGrowsDown, Offset, MaxAlign);
}
SmallSet<int, 16> LargeStackObjs;
if (FFI->getStackProtectorIndex() >= 0) {
AdjustStackOffset(FFI, FFI->getStackProtectorIndex(), StackGrowsDown,
Offset, MaxAlign);
for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) {
if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex)
continue;
if (RS && (int)i == RS->getScavengingFrameIndex())
continue;
if (FFI->isDeadObjectIndex(i))
continue;
if (FFI->getStackProtectorIndex() == (int)i)
continue;
if (!FFI->MayNeedStackProtector(i))
continue;
AdjustStackOffset(FFI, i, StackGrowsDown, Offset, MaxAlign);
LargeStackObjs.insert(i);
}
}
for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) {
if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex)
continue;
if (RS && (int)i == RS->getScavengingFrameIndex())
continue;
if (FFI->isDeadObjectIndex(i))
continue;
if (FFI->getStackProtectorIndex() == (int)i)
continue;
if (LargeStackObjs.count(i))
continue;
AdjustStackOffset(FFI, i, StackGrowsDown, Offset, MaxAlign);
}
if (RS && (!RegInfo->hasFP(Fn) || RegInfo->needsStackRealignment(Fn))) {
int SFI = RS->getScavengingFrameIndex();
if (SFI >= 0)
AdjustStackOffset(FFI, SFI, StackGrowsDown, Offset, MaxAlign);
}
if (!RegInfo->targetHandlesStackFrameRounding()) {
if (FFI->adjustsStack() && RegInfo->hasReservedCallFrame(Fn))
Offset += FFI->getMaxCallFrameSize();
unsigned StackAlign;
if (FFI->adjustsStack() || FFI->hasVarSizedObjects() ||
(RegInfo->needsStackRealignment(Fn) && FFI->getObjectIndexEnd() != 0))
StackAlign = TFI.getStackAlignment();
else
StackAlign = TFI.getTransientStackAlignment();
StackAlign = std::max(StackAlign, MaxAlign);
unsigned AlignMask = StackAlign - 1;
Offset = (Offset + AlignMask) & ~uint64_t(AlignMask);
}
FFI->setStackSize(Offset - LocalAreaOffset);
}
void PEI::insertPrologEpilogCode(MachineFunction &Fn) {
const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo();
TRI->emitPrologue(Fn);
for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
if (!I->empty() && I->back().getDesc().isReturn())
TRI->emitEpilogue(Fn, *I);
}
}
void PEI::replaceFrameIndices(MachineFunction &Fn) {
if (!Fn.getFrameInfo()->hasStackObjects()) return;
const TargetMachine &TM = Fn.getTarget();
assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!");
const TargetRegisterInfo &TRI = *TM.getRegisterInfo();
const TargetFrameInfo *TFI = TM.getFrameInfo();
bool StackGrowsDown =
TFI->getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;
int FrameSetupOpcode = TRI.getCallFrameSetupOpcode();
int FrameDestroyOpcode = TRI.getCallFrameDestroyOpcode();
for (MachineFunction::iterator BB = Fn.begin(),
E = Fn.end(); BB != E; ++BB) {
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) {
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;
TargetRegisterInfo::FrameIndexValue Value;
unsigned VReg =
TRI.eliminateFrameIndex(MI, SPAdj, &Value,
FrameIndexVirtualScavenging ? NULL : RS);
if (VReg) {
assert (FrameIndexVirtualScavenging &&
"Not scavenging, but virtual returned from "
"eliminateFrameIndex()!");
FrameConstantRegMap[VReg] = FrameConstantEntry(Value, SPAdj);
}
if (AtBeginning) {
I = BB->begin();
DoIncr = false;
}
MI = 0;
break;
}
if (DoIncr && I != BB->end()) ++I;
if (RS && !FrameIndexVirtualScavenging && MI) RS->forward(MI);
}
assert(SPAdj == 0 && "Unbalanced call frame setup / destroy pairs?");
}
}
static MachineBasicBlock::iterator
findLastUseReg(MachineBasicBlock::iterator I, MachineBasicBlock::iterator ME,
unsigned Reg) {
for (++I; I != ME; ++I) {
MachineInstr *MI = I;
bool isDefInsn = false;
bool isKillInsn = false;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i)
if (MI->getOperand(i).isReg()) {
unsigned OpReg = MI->getOperand(i).getReg();
if (OpReg == 0 || !TargetRegisterInfo::isVirtualRegister(OpReg))
continue;
assert (OpReg == Reg
&& "overlapping use of scavenged index register!");
if (MI->getOperand(i).isKill())
isKillInsn = true;
else if (MI->getOperand(i).isDef())
isDefInsn = true;
}
if (isKillInsn && !isDefInsn)
return I;
}
assert (0 && "scavenged index register never killed!");
return ME;
}
void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
for (MachineFunction::iterator BB = Fn.begin(),
E = Fn.end(); BB != E; ++BB) {
RS->enterBasicBlock(BB);
unsigned CurrentVirtReg = 0;
unsigned CurrentScratchReg = 0;
bool havePrevValue = false;
TargetRegisterInfo::FrameIndexValue PrevValue(0,0);
TargetRegisterInfo::FrameIndexValue Value(0,0);
MachineInstr *PrevLastUseMI = NULL;
unsigned PrevLastUseOp = 0;
bool trackingCurrentValue = false;
int SPAdj = 0;
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) {
MachineInstr *MI = I;
bool isDefInsn = false;
bool isKillInsn = false;
bool clobbersScratchReg = false;
bool DoIncr = true;
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)) {
if (Reg == CurrentScratchReg) {
if (MO.isUse()) {
if (MO.isKill() || MI->isRegTiedToDefOperand(i))
clobbersScratchReg = true;
} else {
assert (MO.isDef());
clobbersScratchReg = true;
}
}
continue;
}
if (MO.isDef())
isDefInsn = true;
if (Reg != CurrentVirtReg) {
assert(MI->getOperand(i).isDef() &&
"frame index virtual missing def!");
assert (CurrentVirtReg == 0 &&
"overlapping frame index virtual registers!");
DenseMap<unsigned, FrameConstantEntry>::iterator Entry =
FrameConstantRegMap.find(Reg);
trackingCurrentValue = Entry != FrameConstantRegMap.end();
if (trackingCurrentValue) {
SPAdj = (*Entry).second.second;
Value = (*Entry).second.first;
} else {
SPAdj = 0;
Value.first = 0;
Value.second = 0;
}
if (trackingCurrentValue && havePrevValue && PrevValue == Value) {
MachineBasicBlock::iterator LastUseMI =
findLastUseReg(I, BB->end(), Reg);
BB->erase(I, LastUseMI);
I = LastUseMI;
PrevLastUseMI->getOperand(PrevLastUseOp).setIsKill(false);
RS->setUsed(CurrentScratchReg);
CurrentVirtReg = Reg;
DoIncr = false;
break;
}
CurrentVirtReg = Reg;
const TargetRegisterClass *RC = Fn.getRegInfo().getRegClass(Reg);
CurrentScratchReg = RS->FindUnusedReg(RC);
if (CurrentScratchReg == 0)
CurrentScratchReg = RS->scavengeRegister(RC, I, SPAdj);
PrevValue = Value;
}
assert (CurrentScratchReg && "Missing scratch register!");
MI->getOperand(i).setReg(CurrentScratchReg);
if (MI->getOperand(i).isKill()) {
isKillInsn = true;
PrevLastUseOp = i;
PrevLastUseMI = MI;
}
}
}
if (isKillInsn && !isDefInsn) {
CurrentVirtReg = 0;
havePrevValue = trackingCurrentValue;
}
if (clobbersScratchReg) {
havePrevValue = false;
CurrentScratchReg = 0;
}
if (DoIncr) {
RS->forward(I);
++I;
}
}
}
}