mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-13 22:24:07 +00:00
Teach PHIElimination to split critical edges when -split-phi-edges is enabled.
Critical edges leading to a PHI node are split when the PHI source variable is live out from the predecessor block. This help the coalescer eliminate more PHI joins. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@86725 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -103,7 +103,10 @@ public:
|
|||||||
Kills.erase(I);
|
Kills.erase(I);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// findKill - Find a kill instruction in MBB. Return NULL if none is found.
|
||||||
|
MachineInstr *findKill(const MachineBasicBlock *MBB) const;
|
||||||
|
|
||||||
void dump() const;
|
void dump() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -263,6 +266,10 @@ public:
|
|||||||
void HandleVirtRegDef(unsigned reg, MachineInstr *MI);
|
void HandleVirtRegDef(unsigned reg, MachineInstr *MI);
|
||||||
void HandleVirtRegUse(unsigned reg, MachineBasicBlock *MBB,
|
void HandleVirtRegUse(unsigned reg, MachineBasicBlock *MBB,
|
||||||
MachineInstr *MI);
|
MachineInstr *MI);
|
||||||
|
|
||||||
|
/// addNewBlock - Add a new basic block A as an empty predecessor of B. All
|
||||||
|
/// variables that are live into B will be marked as passing live through A.
|
||||||
|
void addNewBlock(MachineBasicBlock *A, MachineBasicBlock *B);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
@ -50,6 +50,14 @@ void LiveVariables::getAnalysisUsage(AnalysisUsage &AU) const {
|
|||||||
MachineFunctionPass::getAnalysisUsage(AU);
|
MachineFunctionPass::getAnalysisUsage(AU);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MachineInstr *
|
||||||
|
LiveVariables::VarInfo::findKill(const MachineBasicBlock *MBB) const {
|
||||||
|
for (unsigned i = 0, e = Kills.size(); i != e; ++i)
|
||||||
|
if (Kills[i]->getParent() == MBB)
|
||||||
|
return Kills[i];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void LiveVariables::VarInfo::dump() const {
|
void LiveVariables::VarInfo::dump() const {
|
||||||
errs() << " Alive in blocks: ";
|
errs() << " Alive in blocks: ";
|
||||||
for (SparseBitVector<>::iterator I = AliveBlocks.begin(),
|
for (SparseBitVector<>::iterator I = AliveBlocks.begin(),
|
||||||
@ -641,3 +649,35 @@ void LiveVariables::analyzePHINodes(const MachineFunction& Fn) {
|
|||||||
PHIVarInfo[BBI->getOperand(i + 1).getMBB()->getNumber()]
|
PHIVarInfo[BBI->getOperand(i + 1).getMBB()->getNumber()]
|
||||||
.push_back(BBI->getOperand(i).getReg());
|
.push_back(BBI->getOperand(i).getReg());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LiveVariables::addNewBlock(MachineBasicBlock *A, MachineBasicBlock *B) {
|
||||||
|
unsigned NumA = A->getNumber();
|
||||||
|
unsigned NumB = B->getNumber();
|
||||||
|
|
||||||
|
// Update info for all live variables
|
||||||
|
for (unsigned i = 0, e = VirtRegInfo.size(); i != e; ++i) {
|
||||||
|
VarInfo &VI = VirtRegInfo[i];
|
||||||
|
|
||||||
|
// Anything live through B is also live through A.
|
||||||
|
if (VI.AliveBlocks.test(NumB)) {
|
||||||
|
VI.AliveBlocks.set(NumA);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're not killed in B, we are not live in
|
||||||
|
if (!VI.findKill(B))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
unsigned Reg = i+TargetRegisterInfo::FirstVirtualRegister;
|
||||||
|
|
||||||
|
// Find a def outside B
|
||||||
|
for (MachineRegisterInfo::def_iterator di = MRI->def_begin(Reg),
|
||||||
|
de=MRI->def_end(); di != de; ++di) {
|
||||||
|
if (di->getParent() != B) {
|
||||||
|
// Reg was defined outside B and killed in B - it must be live in.
|
||||||
|
VI.AliveBlocks.set(NumA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -27,12 +27,20 @@
|
|||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
STATISTIC(NumAtomic, "Number of atomic phis lowered");
|
STATISTIC(NumAtomic, "Number of atomic phis lowered");
|
||||||
|
STATISTIC(NumSplits, "Number of critical edges split on demand");
|
||||||
|
|
||||||
|
static cl::opt<bool>
|
||||||
|
SplitEdges("split-phi-edges",
|
||||||
|
cl::desc("Split critical edges during phi elimination"),
|
||||||
|
cl::init(false), cl::Hidden);
|
||||||
|
|
||||||
char PHIElimination::ID = 0;
|
char PHIElimination::ID = 0;
|
||||||
static RegisterPass<PHIElimination>
|
static RegisterPass<PHIElimination>
|
||||||
@ -41,10 +49,14 @@ X("phi-node-elimination", "Eliminate PHI nodes for register allocation");
|
|||||||
const PassInfo *const llvm::PHIEliminationID = &X;
|
const PassInfo *const llvm::PHIEliminationID = &X;
|
||||||
|
|
||||||
void llvm::PHIElimination::getAnalysisUsage(AnalysisUsage &AU) const {
|
void llvm::PHIElimination::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
AU.setPreservesCFG();
|
|
||||||
AU.addPreserved<LiveVariables>();
|
AU.addPreserved<LiveVariables>();
|
||||||
AU.addPreservedID(MachineLoopInfoID);
|
if (SplitEdges) {
|
||||||
AU.addPreservedID(MachineDominatorsID);
|
AU.addRequired<LiveVariables>();
|
||||||
|
} else {
|
||||||
|
AU.setPreservesCFG();
|
||||||
|
AU.addPreservedID(MachineLoopInfoID);
|
||||||
|
AU.addPreservedID(MachineDominatorsID);
|
||||||
|
}
|
||||||
MachineFunctionPass::getAnalysisUsage(AU);
|
MachineFunctionPass::getAnalysisUsage(AU);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +96,9 @@ bool llvm::PHIElimination::EliminatePHINodes(MachineFunction &MF,
|
|||||||
if (MBB.empty() || MBB.front().getOpcode() != TargetInstrInfo::PHI)
|
if (MBB.empty() || MBB.front().getOpcode() != TargetInstrInfo::PHI)
|
||||||
return false; // Quick exit for basic blocks without PHIs.
|
return false; // Quick exit for basic blocks without PHIs.
|
||||||
|
|
||||||
|
if (SplitEdges)
|
||||||
|
SplitPHIEdges(MF, MBB);
|
||||||
|
|
||||||
// Get an iterator to the first instruction after the last PHI node (this may
|
// Get an iterator to the first instruction after the last PHI node (this may
|
||||||
// also be the end of the basic block).
|
// also be the end of the basic block).
|
||||||
MachineBasicBlock::iterator AfterPHIsIt = SkipPHIsAndLabels(MBB, MBB.begin());
|
MachineBasicBlock::iterator AfterPHIsIt = SkipPHIsAndLabels(MBB, MBB.begin());
|
||||||
@ -277,7 +292,8 @@ void llvm::PHIElimination::LowerAtomicPHINode(
|
|||||||
|
|
||||||
// Okay, if we now know that the value is not live out of the block, we can
|
// Okay, if we now know that the value is not live out of the block, we can
|
||||||
// add a kill marker in this block saying that it kills the incoming value!
|
// add a kill marker in this block saying that it kills the incoming value!
|
||||||
if (!ValueIsUsed && !isLiveOut(SrcReg, opBlock, *LV)) {
|
// When SplitEdges is enabled, the value is never live out.
|
||||||
|
if (!ValueIsUsed && (SplitEdges || !isLiveOut(SrcReg, opBlock, *LV))) {
|
||||||
// In our final twist, we have to decide which instruction kills the
|
// In our final twist, we have to decide which instruction kills the
|
||||||
// register. In most cases this is the copy, however, the first
|
// register. In most cases this is the copy, however, the first
|
||||||
// terminator instruction at the end of the block may also use the value.
|
// terminator instruction at the end of the block may also use the value.
|
||||||
@ -329,6 +345,22 @@ void llvm::PHIElimination::analyzePHINodes(const MachineFunction& Fn) {
|
|||||||
BBI->getOperand(i).getReg())];
|
BBI->getOperand(i).getReg())];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void llvm::PHIElimination::SplitPHIEdges(MachineFunction &MF,
|
||||||
|
MachineBasicBlock &MBB) {
|
||||||
|
LiveVariables &LV = getAnalysis<LiveVariables>();
|
||||||
|
for (MachineBasicBlock::const_iterator BBI = MBB.begin(), BBE = MBB.end();
|
||||||
|
BBI != BBE && BBI->getOpcode() == TargetInstrInfo::PHI; ++BBI) {
|
||||||
|
for (unsigned i = 1, e = BBI->getNumOperands(); i != e; i += 2) {
|
||||||
|
unsigned Reg = BBI->getOperand(i).getReg();
|
||||||
|
MachineBasicBlock *PreMBB = BBI->getOperand(i+1).getMBB();
|
||||||
|
// We break edges when registers are live out from the predecessor block
|
||||||
|
// (not considering PHI nodes).
|
||||||
|
if (isLiveOut(Reg, *PreMBB, LV))
|
||||||
|
SplitCriticalEdge(PreMBB, &MBB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool llvm::PHIElimination::isLiveOut(unsigned Reg, const MachineBasicBlock &MBB,
|
bool llvm::PHIElimination::isLiveOut(unsigned Reg, const MachineBasicBlock &MBB,
|
||||||
LiveVariables &LV) {
|
LiveVariables &LV) {
|
||||||
LiveVariables::VarInfo &InRegVI = LV.getVarInfo(Reg);
|
LiveVariables::VarInfo &InRegVI = LV.getVarInfo(Reg);
|
||||||
@ -376,3 +408,43 @@ bool llvm::PHIElimination::isLiveOut(unsigned Reg, const MachineBasicBlock &MBB,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MachineBasicBlock *PHIElimination::SplitCriticalEdge(MachineBasicBlock *A,
|
||||||
|
MachineBasicBlock *B) {
|
||||||
|
assert(A && B && "Missing MBB end point");
|
||||||
|
++NumSplits;
|
||||||
|
|
||||||
|
MachineFunction *MF = A->getParent();
|
||||||
|
MachineBasicBlock *NMBB = MF->CreateMachineBasicBlock(B->getBasicBlock());
|
||||||
|
MF->push_back(NMBB);
|
||||||
|
const unsigned NewNum = NMBB->getNumber();
|
||||||
|
DEBUG(errs() << "PHIElimination splitting critical edge:"
|
||||||
|
" BB#" << A->getNumber()
|
||||||
|
<< " -- BB#" << NewNum
|
||||||
|
<< " -- BB#" << B->getNumber() << '\n');
|
||||||
|
|
||||||
|
A->ReplaceUsesOfBlockWith(B, NMBB);
|
||||||
|
NMBB->addSuccessor(B);
|
||||||
|
|
||||||
|
// Insert unconditional "jump B" instruction in NMBB.
|
||||||
|
SmallVector<MachineOperand, 4> Cond;
|
||||||
|
MF->getTarget().getInstrInfo()->InsertBranch(*NMBB, B, NULL, Cond);
|
||||||
|
|
||||||
|
LiveVariables *LV = getAnalysisIfAvailable<LiveVariables>();
|
||||||
|
if (LV)
|
||||||
|
LV->addNewBlock(NMBB, B);
|
||||||
|
|
||||||
|
// Fix PHI nodes in B so they refer to NMBB instead of A
|
||||||
|
for (MachineBasicBlock::iterator i = B->begin(), e = B->end();
|
||||||
|
i != e && i->getOpcode() == TargetInstrInfo::PHI; ++i)
|
||||||
|
for (unsigned ni = 1, ne = i->getNumOperands(); ni != ne; ni += 2)
|
||||||
|
if (i->getOperand(ni+1).getMBB() == A) {
|
||||||
|
i->getOperand(ni+1).setMBB(NMBB);
|
||||||
|
// Mark PHI sources as passing live through NMBB
|
||||||
|
if (LV)
|
||||||
|
LV->getVarInfo(i->getOperand(ni).getReg()).AliveBlocks.set(NewNum);
|
||||||
|
}
|
||||||
|
return NMBB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,12 +89,21 @@ namespace llvm {
|
|||||||
///
|
///
|
||||||
void analyzePHINodes(const MachineFunction& Fn);
|
void analyzePHINodes(const MachineFunction& Fn);
|
||||||
|
|
||||||
|
/// Split critical edges where necessary for good coalescer performance.
|
||||||
|
void SplitPHIEdges(MachineFunction &MF, MachineBasicBlock &MBB);
|
||||||
|
|
||||||
/// isLiveOut - Determine if Reg is live out from MBB, when not
|
/// isLiveOut - Determine if Reg is live out from MBB, when not
|
||||||
/// considering PHI nodes. This means that Reg is either killed by
|
/// considering PHI nodes. This means that Reg is either killed by
|
||||||
/// a successor block or passed through one.
|
/// a successor block or passed through one.
|
||||||
bool isLiveOut(unsigned Reg, const MachineBasicBlock &MBB,
|
bool isLiveOut(unsigned Reg, const MachineBasicBlock &MBB,
|
||||||
LiveVariables &LV);
|
LiveVariables &LV);
|
||||||
|
|
||||||
|
/// SplitCriticalEdge - Split a critical edge from A to B by
|
||||||
|
/// inserting a new MBB. Update branches in A and PHI instructions
|
||||||
|
/// in B. Return the new block.
|
||||||
|
MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *A,
|
||||||
|
MachineBasicBlock *B);
|
||||||
|
|
||||||
// FindCopyInsertPoint - Find a safe place in MBB to insert a copy from
|
// FindCopyInsertPoint - Find a safe place in MBB to insert a copy from
|
||||||
// SrcReg. This needs to be after any def or uses of SrcReg, but before
|
// SrcReg. This needs to be after any def or uses of SrcReg, but before
|
||||||
// any subsequent point where control flow might jump out of the basic
|
// any subsequent point where control flow might jump out of the basic
|
||||||
|
Reference in New Issue
Block a user