#include "PHIEliminationUtils.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <iterator>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "phi-node-elimination"
static cl::opt<bool>
DisableEdgeSplitting("disable-phi-elim-edge-splitting", cl::init(false),
cl::Hidden, cl::desc("Disable critical edge splitting "
"during PHI elimination"));
static cl::opt<bool>
SplitAllCriticalEdges("phi-elim-split-all-critical-edges", cl::init(false),
cl::Hidden, cl::desc("Split all critical edges during "
"PHI elimination"));
static cl::opt<bool> NoPhiElimLiveOutEarlyExit(
"no-phi-elim-live-out-early-exit", cl::init(false), cl::Hidden,
cl::desc("Do not use an early exit if isLiveOutPastPHIs returns true."));
namespace {
class PHIElimination : public MachineFunctionPass {
MachineRegisterInfo *MRI; LiveVariables *LV;
LiveIntervals *LIS;
public:
static char ID;
PHIElimination() : MachineFunctionPass(ID) {
initializePHIEliminationPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
private:
bool EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB);
void LowerPHINode(MachineBasicBlock &MBB,
MachineBasicBlock::iterator LastPHIIt);
void analyzePHINodes(const MachineFunction& MF);
bool SplitPHIEdges(MachineFunction &MF, MachineBasicBlock &MBB,
MachineLoopInfo *MLI,
std::vector<SparseBitVector<>> *LiveInSets);
bool isLiveIn(Register Reg, const MachineBasicBlock *MBB);
bool isLiveOutPastPHIs(Register Reg, const MachineBasicBlock *MBB);
using BBVRegPair = std::pair<unsigned, Register>;
using VRegPHIUse = DenseMap<BBVRegPair, unsigned>;
VRegPHIUse VRegPHIUseCount;
SmallPtrSet<MachineInstr*, 4> ImpDefs;
using LoweredPHIMap =
DenseMap<MachineInstr*, unsigned, MachineInstrExpressionTrait>;
LoweredPHIMap LoweredPHIs;
};
}
STATISTIC(NumLowered, "Number of phis lowered");
STATISTIC(NumCriticalEdgesSplit, "Number of critical edges split");
STATISTIC(NumReused, "Number of reused lowered phis");
char PHIElimination::ID = 0;
char& llvm::PHIEliminationID = PHIElimination::ID;
INITIALIZE_PASS_BEGIN(PHIElimination, DEBUG_TYPE,
"Eliminate PHI nodes for register allocation",
false, false)
INITIALIZE_PASS_DEPENDENCY(LiveVariables)
INITIALIZE_PASS_END(PHIElimination, DEBUG_TYPE,
"Eliminate PHI nodes for register allocation", false, false)
void PHIElimination::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addUsedIfAvailable<LiveVariables>();
AU.addPreserved<LiveVariables>();
AU.addPreserved<SlotIndexes>();
AU.addPreserved<LiveIntervals>();
AU.addPreserved<MachineDominatorTree>();
AU.addPreserved<MachineLoopInfo>();
MachineFunctionPass::getAnalysisUsage(AU);
}
bool PHIElimination::runOnMachineFunction(MachineFunction &MF) {
MRI = &MF.getRegInfo();
LV = getAnalysisIfAvailable<LiveVariables>();
LIS = getAnalysisIfAvailable<LiveIntervals>();
bool Changed = false;
if (!DisableEdgeSplitting && (LV || LIS)) {
std::vector<SparseBitVector<>> LiveInSets;
if (LV) {
LiveInSets.resize(MF.size());
for (unsigned Index = 0, e = MRI->getNumVirtRegs(); Index != e; ++Index) {
unsigned VirtReg = Register::index2VirtReg(Index);
MachineInstr *DefMI = MRI->getVRegDef(VirtReg);
if (!DefMI)
continue;
LiveVariables::VarInfo &VI = LV->getVarInfo(VirtReg);
SparseBitVector<>::iterator AliveBlockItr = VI.AliveBlocks.begin();
SparseBitVector<>::iterator EndItr = VI.AliveBlocks.end();
while (AliveBlockItr != EndItr) {
unsigned BlockNum = *(AliveBlockItr++);
LiveInSets[BlockNum].set(Index);
}
MachineBasicBlock *DefMBB = DefMI->getParent();
if (VI.Kills.size() > 1 ||
(!VI.Kills.empty() && VI.Kills.front()->getParent() != DefMBB))
for (auto *MI : VI.Kills)
LiveInSets[MI->getParent()->getNumber()].set(Index);
}
}
MachineLoopInfo *MLI = getAnalysisIfAvailable<MachineLoopInfo>();
for (auto &MBB : MF)
Changed |= SplitPHIEdges(MF, MBB, MLI, (LV ? &LiveInSets : nullptr));
}
MRI->leaveSSA();
analyzePHINodes(MF);
for (auto &MBB : MF)
Changed |= EliminatePHINodes(MF, MBB);
for (MachineInstr *DefMI : ImpDefs) {
Register DefReg = DefMI->getOperand(0).getReg();
if (MRI->use_nodbg_empty(DefReg)) {
if (LIS)
LIS->RemoveMachineInstrFromMaps(*DefMI);
DefMI->eraseFromParent();
}
}
for (auto &I : LoweredPHIs) {
if (LIS)
LIS->RemoveMachineInstrFromMaps(*I.first);
MF.deleteMachineInstr(I.first);
}
if (Changed)
if (auto *MDT = getAnalysisIfAvailable<MachineDominatorTree>())
MDT->getBase().recalculate(MF);
LoweredPHIs.clear();
ImpDefs.clear();
VRegPHIUseCount.clear();
MF.getProperties().set(MachineFunctionProperties::Property::NoPHIs);
return Changed;
}
bool PHIElimination::EliminatePHINodes(MachineFunction &MF,
MachineBasicBlock &MBB) {
if (MBB.empty() || !MBB.front().isPHI())
return false;
MachineBasicBlock::iterator LastPHIIt =
std::prev(MBB.SkipPHIsAndLabels(MBB.begin()));
while (MBB.front().isPHI())
LowerPHINode(MBB, LastPHIIt);
return true;
}
static bool isImplicitlyDefined(unsigned VirtReg,
const MachineRegisterInfo &MRI) {
for (MachineInstr &DI : MRI.def_instructions(VirtReg))
if (!DI.isImplicitDef())
return false;
return true;
}
static bool allPhiOperandsUndefined(const MachineInstr &MPhi,
const MachineRegisterInfo &MRI) {
for (unsigned I = 1, E = MPhi.getNumOperands(); I != E; I += 2) {
const MachineOperand &MO = MPhi.getOperand(I);
if (!isImplicitlyDefined(MO.getReg(), MRI) && !MO.isUndef())
return false;
}
return true;
}
void PHIElimination::LowerPHINode(MachineBasicBlock &MBB,
MachineBasicBlock::iterator LastPHIIt) {
++NumLowered;
MachineBasicBlock::iterator AfterPHIsIt = std::next(LastPHIIt);
MachineInstr *MPhi = MBB.remove(&*MBB.begin());
unsigned NumSrcs = (MPhi->getNumOperands() - 1) / 2;
Register DestReg = MPhi->getOperand(0).getReg();
assert(MPhi->getOperand(0).getSubReg() == 0 && "Can't handle sub-reg PHIs");
bool isDead = MPhi->getOperand(0).isDead();
MachineFunction &MF = *MBB.getParent();
unsigned IncomingReg = 0;
bool reusedIncoming = false;
MachineInstr *PHICopy = nullptr;
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
if (allPhiOperandsUndefined(*MPhi, *MRI))
PHICopy = BuildMI(MBB, AfterPHIsIt, MPhi->getDebugLoc(),
TII->get(TargetOpcode::IMPLICIT_DEF), DestReg);
else {
unsigned &entry = LoweredPHIs[MPhi];
if (entry) {
IncomingReg = entry;
reusedIncoming = true;
++NumReused;
LLVM_DEBUG(dbgs() << "Reusing " << printReg(IncomingReg) << " for "
<< *MPhi);
} else {
const TargetRegisterClass *RC = MF.getRegInfo().getRegClass(DestReg);
entry = IncomingReg = MF.getRegInfo().createVirtualRegister(RC);
}
PHICopy = TII->createPHIDestinationCopy(MBB, AfterPHIsIt, MPhi->getDebugLoc(),
IncomingReg, DestReg);
}
if (MPhi->peekDebugInstrNum()) {
MachineFunction *MF = MBB.getParent();
unsigned ID = MPhi->peekDebugInstrNum();
auto P = MachineFunction::DebugPHIRegallocPos(&MBB, IncomingReg, 0);
auto Res = MF->DebugPHIPositions.insert({ID, P});
assert(Res.second);
(void)Res;
}
if (LV) {
if (IncomingReg) {
LiveVariables::VarInfo &VI = LV->getVarInfo(IncomingReg);
LV->setPHIJoin(IncomingReg);
MachineInstr *OldKill = nullptr;
bool IsPHICopyAfterOldKill = false;
if (reusedIncoming && (OldKill = VI.findKill(&MBB))) {
for (auto I = MBB.SkipPHIsAndLabels(MBB.begin()), E = MBB.end();
I != E; ++I) {
if (I == PHICopy)
break;
if (I == OldKill) {
IsPHICopyAfterOldKill = true;
break;
}
}
}
if (IsPHICopyAfterOldKill) {
LLVM_DEBUG(dbgs() << "Remove old kill from " << *OldKill);
LV->removeVirtualRegisterKilled(IncomingReg, *OldKill);
LLVM_DEBUG(MBB.dump());
}
if (!OldKill || IsPHICopyAfterOldKill)
LV->addVirtualRegisterKilled(IncomingReg, *PHICopy);
}
LV->removeVirtualRegistersKilled(*MPhi);
if (isDead) {
LV->addVirtualRegisterDead(DestReg, *PHICopy);
LV->removeVirtualRegisterDead(DestReg, *MPhi);
}
}
if (LIS) {
SlotIndex DestCopyIndex = LIS->InsertMachineInstrInMaps(*PHICopy);
SlotIndex MBBStartIndex = LIS->getMBBStartIdx(&MBB);
if (IncomingReg) {
LiveInterval &IncomingLI = LIS->createEmptyInterval(IncomingReg);
VNInfo *IncomingVNI = IncomingLI.getVNInfoAt(MBBStartIndex);
if (!IncomingVNI)
IncomingVNI = IncomingLI.getNextValue(MBBStartIndex,
LIS->getVNInfoAllocator());
IncomingLI.addSegment(LiveInterval::Segment(MBBStartIndex,
DestCopyIndex.getRegSlot(),
IncomingVNI));
}
LiveInterval &DestLI = LIS->getInterval(DestReg);
assert(!DestLI.empty() && "PHIs should have nonempty LiveIntervals.");
if (DestLI.endIndex().isDead()) {
VNInfo *OrigDestVNI = DestLI.getVNInfoAt(MBBStartIndex);
assert(OrigDestVNI && "PHI destination should be live at block entry.");
DestLI.removeSegment(MBBStartIndex, MBBStartIndex.getDeadSlot());
DestLI.createDeadDef(DestCopyIndex.getRegSlot(),
LIS->getVNInfoAllocator());
DestLI.removeValNo(OrigDestVNI);
} else {
DestLI.removeSegment(MBBStartIndex, DestCopyIndex.getRegSlot());
VNInfo *DestVNI = DestLI.getVNInfoAt(DestCopyIndex.getRegSlot());
assert(DestVNI && "PHI destination should be live at its definition.");
DestVNI->def = DestCopyIndex.getRegSlot();
}
}
for (unsigned i = 1; i != MPhi->getNumOperands(); i += 2) {
if (!MPhi->getOperand(i).isUndef()) {
--VRegPHIUseCount[BBVRegPair(
MPhi->getOperand(i + 1).getMBB()->getNumber(),
MPhi->getOperand(i).getReg())];
}
}
SmallPtrSet<MachineBasicBlock*, 8> MBBsInsertedInto;
for (int i = NumSrcs - 1; i >= 0; --i) {
Register SrcReg = MPhi->getOperand(i * 2 + 1).getReg();
unsigned SrcSubReg = MPhi->getOperand(i*2+1).getSubReg();
bool SrcUndef = MPhi->getOperand(i*2+1).isUndef() ||
isImplicitlyDefined(SrcReg, *MRI);
assert(Register::isVirtualRegister(SrcReg) &&
"Machine PHI Operands must all be virtual registers!");
MachineBasicBlock &opBlock = *MPhi->getOperand(i*2+2).getMBB();
if (!MBBsInsertedInto.insert(&opBlock).second)
continue;
MachineInstr *SrcRegDef = MRI->getVRegDef(SrcReg);
if (SrcRegDef && TII->isUnspillableTerminator(SrcRegDef)) {
assert(SrcRegDef->getOperand(0).isReg() &&
SrcRegDef->getOperand(0).isDef() &&
"Expected operand 0 to be a reg def!");
assert(MRI->use_empty(SrcReg) &&
"Expected a single use from UnspillableTerminator");
SrcRegDef->getOperand(0).setReg(IncomingReg);
if (LV) {
LiveVariables::VarInfo &SrcVI = LV->getVarInfo(SrcReg);
LiveVariables::VarInfo &IncomingVI = LV->getVarInfo(IncomingReg);
IncomingVI.AliveBlocks = std::move(SrcVI.AliveBlocks);
SrcVI.AliveBlocks.clear();
}
continue;
}
MachineBasicBlock::iterator InsertPos =
findPHICopyInsertPoint(&opBlock, &MBB, SrcReg);
MachineInstr *NewSrcInstr = nullptr;
if (!reusedIncoming && IncomingReg) {
if (SrcUndef) {
NewSrcInstr = BuildMI(opBlock, InsertPos, MPhi->getDebugLoc(),
TII->get(TargetOpcode::IMPLICIT_DEF),
IncomingReg);
if (MachineInstr *DefMI = MRI->getVRegDef(SrcReg))
if (DefMI->isImplicitDef())
ImpDefs.insert(DefMI);
} else {
NewSrcInstr = TII->createPHISourceCopy(opBlock, InsertPos, nullptr,
SrcReg, SrcSubReg, IncomingReg);
}
}
if (LV && !SrcUndef &&
!VRegPHIUseCount[BBVRegPair(opBlock.getNumber(), SrcReg)] &&
!LV->isLiveOut(SrcReg, opBlock)) {
MachineBasicBlock::iterator KillInst = opBlock.end();
for (MachineBasicBlock::iterator Term = InsertPos; Term != opBlock.end();
++Term) {
if (Term->readsRegister(SrcReg))
KillInst = Term;
}
if (KillInst == opBlock.end()) {
if (reusedIncoming || !IncomingReg) {
KillInst = InsertPos;
while (KillInst != opBlock.begin()) {
--KillInst;
if (KillInst->isDebugInstr())
continue;
if (KillInst->readsRegister(SrcReg))
break;
}
} else {
KillInst = NewSrcInstr;
}
}
assert(KillInst->readsRegister(SrcReg) && "Cannot find kill instruction");
LV->addVirtualRegisterKilled(SrcReg, *KillInst);
unsigned opBlockNum = opBlock.getNumber();
LV->getVarInfo(SrcReg).AliveBlocks.reset(opBlockNum);
}
if (LIS) {
if (NewSrcInstr) {
LIS->InsertMachineInstrInMaps(*NewSrcInstr);
LIS->addSegmentToEndOfBlock(IncomingReg, *NewSrcInstr);
}
if (!SrcUndef &&
!VRegPHIUseCount[BBVRegPair(opBlock.getNumber(), SrcReg)]) {
LiveInterval &SrcLI = LIS->getInterval(SrcReg);
bool isLiveOut = false;
for (MachineBasicBlock *Succ : opBlock.successors()) {
SlotIndex startIdx = LIS->getMBBStartIdx(Succ);
VNInfo *VNI = SrcLI.getVNInfoAt(startIdx);
if (VNI && VNI->def != startIdx) {
isLiveOut = true;
break;
}
}
if (!isLiveOut) {
MachineBasicBlock::iterator KillInst = opBlock.end();
for (MachineBasicBlock::iterator Term = InsertPos;
Term != opBlock.end(); ++Term) {
if (Term->readsRegister(SrcReg))
KillInst = Term;
}
if (KillInst == opBlock.end()) {
if (reusedIncoming || !IncomingReg) {
KillInst = InsertPos;
while (KillInst != opBlock.begin()) {
--KillInst;
if (KillInst->isDebugInstr())
continue;
if (KillInst->readsRegister(SrcReg))
break;
}
} else {
KillInst = std::prev(InsertPos);
}
}
assert(KillInst->readsRegister(SrcReg) &&
"Cannot find kill instruction");
SlotIndex LastUseIndex = LIS->getInstructionIndex(*KillInst);
SrcLI.removeSegment(LastUseIndex.getRegSlot(),
LIS->getMBBEndIdx(&opBlock));
}
}
}
}
if (reusedIncoming || !IncomingReg) {
if (LIS)
LIS->RemoveMachineInstrFromMaps(*MPhi);
MF.deleteMachineInstr(MPhi);
}
}
void PHIElimination::analyzePHINodes(const MachineFunction& MF) {
for (const auto &MBB : MF) {
for (const auto &BBI : MBB) {
if (!BBI.isPHI())
break;
for (unsigned i = 1, e = BBI.getNumOperands(); i != e; i += 2) {
if (!BBI.getOperand(i).isUndef()) {
++VRegPHIUseCount[BBVRegPair(
BBI.getOperand(i + 1).getMBB()->getNumber(),
BBI.getOperand(i).getReg())];
}
}
}
}
}
bool PHIElimination::SplitPHIEdges(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineLoopInfo *MLI,
std::vector<SparseBitVector<>> *LiveInSets) {
if (MBB.empty() || !MBB.front().isPHI() || MBB.isEHPad())
return false;
const MachineLoop *CurLoop = MLI ? MLI->getLoopFor(&MBB) : nullptr;
bool IsLoopHeader = CurLoop && &MBB == CurLoop->getHeader();
bool Changed = false;
for (MachineBasicBlock::iterator BBI = MBB.begin(), BBE = MBB.end();
BBI != BBE && BBI->isPHI(); ++BBI) {
for (unsigned i = 1, e = BBI->getNumOperands(); i != e; i += 2) {
Register Reg = BBI->getOperand(i).getReg();
MachineBasicBlock *PreMBB = BBI->getOperand(i+1).getMBB();
if (PreMBB->succ_size() == 1)
continue;
if (PreMBB == &MBB && !SplitAllCriticalEdges)
continue;
const MachineLoop *PreLoop = MLI ? MLI->getLoopFor(PreMBB) : nullptr;
if (IsLoopHeader && PreLoop == CurLoop && !SplitAllCriticalEdges)
continue;
bool ShouldSplit = isLiveOutPastPHIs(Reg, PreMBB);
if (!ShouldSplit && !NoPhiElimLiveOutEarlyExit)
continue;
if (ShouldSplit) {
LLVM_DEBUG(dbgs() << printReg(Reg) << " live-out before critical edge "
<< printMBBReference(*PreMBB) << " -> "
<< printMBBReference(MBB) << ": " << *BBI);
}
ShouldSplit = ShouldSplit && !isLiveIn(Reg, &MBB);
if (!ShouldSplit && CurLoop != PreLoop) {
LLVM_DEBUG({
dbgs() << "Split wouldn't help, maybe avoid loop copies?\n";
if (PreLoop)
dbgs() << "PreLoop: " << *PreLoop;
if (CurLoop)
dbgs() << "CurLoop: " << *CurLoop;
});
ShouldSplit = PreLoop && !PreLoop->contains(CurLoop);
}
if (!ShouldSplit && !SplitAllCriticalEdges)
continue;
if (!PreMBB->SplitCriticalEdge(&MBB, *this, LiveInSets)) {
LLVM_DEBUG(dbgs() << "Failed to split critical edge.\n");
continue;
}
Changed = true;
++NumCriticalEdgesSplit;
}
}
return Changed;
}
bool PHIElimination::isLiveIn(Register Reg, const MachineBasicBlock *MBB) {
assert((LV || LIS) &&
"isLiveIn() requires either LiveVariables or LiveIntervals");
if (LIS)
return LIS->isLiveInToMBB(LIS->getInterval(Reg), MBB);
else
return LV->isLiveIn(Reg, *MBB);
}
bool PHIElimination::isLiveOutPastPHIs(Register Reg,
const MachineBasicBlock *MBB) {
assert((LV || LIS) &&
"isLiveOutPastPHIs() requires either LiveVariables or LiveIntervals");
if (LIS) {
const LiveInterval &LI = LIS->getInterval(Reg);
for (const MachineBasicBlock *SI : MBB->successors())
if (LI.liveAt(LIS->getMBBStartIdx(SI)))
return true;
return false;
} else {
return LV->isLiveOut(Reg, *MBB);
}
}