Run early if-conversion in domtree post-order.

This ordering allows nested if-conversion without using a work list, and
it makes it possible to update the dominator tree on the fly as well.

Any erased basic blocks will always be dominated by the current
post-order position, so the domtree can be pruned without invalidating
the iterator.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160025 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jakob Stoklund Olesen 2012-07-10 22:18:23 +00:00
parent 2b02688b6e
commit 1f523dc45e

View File

@ -19,10 +19,12 @@
#define DEBUG_TYPE "early-ifcvt" #define DEBUG_TYPE "early-ifcvt"
#include "llvm/Function.h" #include "llvm/Function.h"
#include "llvm/ADT/BitVector.h" #include "llvm/ADT/BitVector.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SparseSet.h" #include "llvm/ADT/SparseSet.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" #include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h"
@ -74,6 +76,7 @@ class SSAIfConv {
const TargetRegisterInfo *TRI; const TargetRegisterInfo *TRI;
MachineRegisterInfo *MRI; MachineRegisterInfo *MRI;
public:
/// The block containing the conditional branch. /// The block containing the conditional branch.
MachineBasicBlock *Head; MachineBasicBlock *Head;
@ -90,9 +93,6 @@ class SSAIfConv {
/// equal to Tail. /// equal to Tail.
bool isTriangle() const { return TBB == Tail || FBB == Tail; } bool isTriangle() const { return TBB == Tail || FBB == Tail; }
/// The branch condition determined by AnalyzeBranch.
SmallVector<MachineOperand, 4> Cond;
/// Information about each phi in the Tail block. /// Information about each phi in the Tail block.
struct PHIInfo { struct PHIInfo {
MachineInstr *PHI; MachineInstr *PHI;
@ -106,6 +106,10 @@ class SSAIfConv {
SmallVector<PHIInfo, 8> PHIs; SmallVector<PHIInfo, 8> PHIs;
private:
/// The branch condition determined by AnalyzeBranch.
SmallVector<MachineOperand, 4> Cond;
/// Instructions in Head that define values used by the conditional blocks. /// Instructions in Head that define values used by the conditional blocks.
/// The hoisted instructions must be inserted after these instructions. /// The hoisted instructions must be inserted after these instructions.
SmallPtrSet<MachineInstr*, 8> InsertAfter; SmallPtrSet<MachineInstr*, 8> InsertAfter;
@ -144,8 +148,8 @@ public:
bool canConvertIf(MachineBasicBlock *MBB); bool canConvertIf(MachineBasicBlock *MBB);
/// convertIf - If-convert the last block passed to canConvertIf(), assuming /// convertIf - If-convert the last block passed to canConvertIf(), assuming
/// it is possible. Remove any erased blocks from WorkList /// it is possible. Add any erased blocks to RemovedBlocks.
void convertIf(BlockSetVector &WorkList); void convertIf(SmallVectorImpl<MachineBasicBlock*> &RemovedBlocks);
}; };
} // end anonymous namespace } // end anonymous namespace
@ -425,18 +429,12 @@ bool SSAIfConv::canConvertIf(MachineBasicBlock *MBB) {
} }
static void eraseBlock(BlockSetVector &WorkList, MachineBasicBlock *MBB) {
WorkList.remove(MBB);
MBB->eraseFromParent();
}
/// convertIf - Execute the if conversion after canConvertIf has determined the /// convertIf - Execute the if conversion after canConvertIf has determined the
/// feasibility. /// feasibility.
/// ///
/// Any basic blocks erased will also be removed from WorkList. /// Any basic blocks erased will be added to RemovedBlocks.
/// ///
void SSAIfConv::convertIf(BlockSetVector &WorkList) { void SSAIfConv::convertIf(SmallVectorImpl<MachineBasicBlock*> &RemovedBlocks) {
assert(Head && Tail && TBB && FBB && "Call canConvertIf first."); assert(Head && Tail && TBB && FBB && "Call canConvertIf first.");
// Move all instructions into Head, except for the terminators. // Move all instructions into Head, except for the terminators.
@ -475,10 +473,14 @@ void SSAIfConv::convertIf(BlockSetVector &WorkList) {
// Erase the now empty conditional blocks. It is likely that Head can fall // Erase the now empty conditional blocks. It is likely that Head can fall
// through to Tail, and we can join the two blocks. // through to Tail, and we can join the two blocks.
if (TBB != Tail) if (TBB != Tail) {
eraseBlock(WorkList, TBB); RemovedBlocks.push_back(TBB);
if (FBB != Tail) TBB->eraseFromParent();
eraseBlock(WorkList, FBB); }
if (FBB != Tail) {
RemovedBlocks.push_back(FBB);
FBB->eraseFromParent();
}
assert(Head->succ_empty() && "Additional head successors?"); assert(Head->succ_empty() && "Additional head successors?");
if (Head->isLayoutSuccessor(Tail)) { if (Head->isLayoutSuccessor(Tail)) {
@ -488,8 +490,8 @@ void SSAIfConv::convertIf(BlockSetVector &WorkList) {
Head->splice(Head->end(), Tail, Head->splice(Head->end(), Tail,
Tail->begin(), Tail->end()); Tail->begin(), Tail->end());
Head->transferSuccessorsAndUpdatePHIs(Tail); Head->transferSuccessorsAndUpdatePHIs(Tail);
eraseBlock(WorkList, Tail); RemovedBlocks.push_back(Tail);
Tail->eraseFromParent();
} else { } else {
// We need a branch to Tail, let code placement work it out later. // We need a branch to Tail, let code placement work it out later.
DEBUG(dbgs() << "Converting to unconditional branch.\n"); DEBUG(dbgs() << "Converting to unconditional branch.\n");
@ -510,11 +512,9 @@ class EarlyIfConverter : public MachineFunctionPass {
const TargetInstrInfo *TII; const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI; const TargetRegisterInfo *TRI;
MachineRegisterInfo *MRI; MachineRegisterInfo *MRI;
MachineDominatorTree *DomTree;
SSAIfConv IfConv; SSAIfConv IfConv;
// Worklist of head blocks to try for if-conversion.
BlockSetVector WorkList;
public: public:
static char ID; static char ID;
EarlyIfConverter() : MachineFunctionPass(ID) {} EarlyIfConverter() : MachineFunctionPass(ID) {}
@ -523,6 +523,7 @@ public:
private: private:
bool tryConvertIf(MachineBasicBlock*); bool tryConvertIf(MachineBasicBlock*);
void updateDomTree(ArrayRef<MachineBasicBlock*> Removed);
}; };
} // end anonymous namespace } // end anonymous namespace
@ -532,34 +533,47 @@ char &llvm::EarlyIfConverterID = EarlyIfConverter::ID;
INITIALIZE_PASS_BEGIN(EarlyIfConverter, INITIALIZE_PASS_BEGIN(EarlyIfConverter,
"early-ifcvt", "Early If Converter", false, false) "early-ifcvt", "Early If Converter", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo) INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_END(EarlyIfConverter, INITIALIZE_PASS_END(EarlyIfConverter,
"early-ifcvt", "Early If Converter", false, false) "early-ifcvt", "Early If Converter", false, false)
void EarlyIfConverter::getAnalysisUsage(AnalysisUsage &AU) const { void EarlyIfConverter::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<MachineBranchProbabilityInfo>(); AU.addRequired<MachineBranchProbabilityInfo>();
AU.addRequired<MachineDominatorTree>();
AU.addPreserved<MachineDominatorTree>();
MachineFunctionPass::getAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU);
} }
/// Attempt repeated if-conversion on MBB, return true if successful. /// Update the dominator tree after if-conversion erased some blocks.
/// Update WorkList with new opportunities. void EarlyIfConverter::updateDomTree(ArrayRef<MachineBasicBlock*> Removed) {
/// // convertIf can remove TBB, FBB, and Tail can be merged into Head.
bool EarlyIfConverter::tryConvertIf(MachineBasicBlock *MBB) { // TBB and FBB should not dominate any blocks.
if (!IfConv.canConvertIf(MBB)) // Tail children should be transferred to Head.
return false; MachineDomTreeNode *HeadNode = DomTree->getNode(IfConv.Head);
for (unsigned i = 0, e = Removed.size(); i != e; ++i) {
// Repeatedly if-convert MBB, joining Head and Tail may expose more MachineDomTreeNode *Node = DomTree->getNode(Removed[i]);
// opportunities. assert(Node != HeadNode && "Cannot erase the head node");
do IfConv.convertIf(WorkList); while (Node->getNumChildren()) {
while (IfConv.canConvertIf(MBB)); assert(Node->getBlock() == IfConv.Tail && "Unexpected children");
DomTree->changeImmediateDominator(Node->getChildren().back(), HeadNode);
// It is possible that MBB is now itself a conditional block that can be }
// if-converted. DomTree->eraseNode(Removed[i]);
if (MBB->pred_size() == 1 && MBB->succ_size() == 1) }
WorkList.insert(MBB->pred_begin()[0]);
WorkList.remove(MBB);
return true;
} }
/// Attempt repeated if-conversion on MBB, return true if successful.
///
bool EarlyIfConverter::tryConvertIf(MachineBasicBlock *MBB) {
bool Changed = false;
while (IfConv.canConvertIf(MBB)) {
// If-convert MBB and update analyses.
SmallVector<MachineBasicBlock*, 4> RemovedBlocks;
IfConv.convertIf(RemovedBlocks);
Changed = true;
updateDomTree(RemovedBlocks);
}
return Changed;
}
bool EarlyIfConverter::runOnMachineFunction(MachineFunction &MF) { bool EarlyIfConverter::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "********** EARLY IF-CONVERSION **********\n" DEBUG(dbgs() << "********** EARLY IF-CONVERSION **********\n"
@ -568,23 +582,20 @@ bool EarlyIfConverter::runOnMachineFunction(MachineFunction &MF) {
TII = MF.getTarget().getInstrInfo(); TII = MF.getTarget().getInstrInfo();
TRI = MF.getTarget().getRegisterInfo(); TRI = MF.getTarget().getRegisterInfo();
MRI = &MF.getRegInfo(); MRI = &MF.getRegInfo();
DomTree = &getAnalysis<MachineDominatorTree>();
bool Changed = false; bool Changed = false;
IfConv.runOnMachineFunction(MF); IfConv.runOnMachineFunction(MF);
// Initially visit blocks in layout order. The tryConvertIf() function may // Visit blocks in dominator tree post-order. The post-order enables nested
// erase blocks, but never the head block passed as MFI. // if-conversion in a single pass. The tryConvertIf() function may erase
for (MachineFunction::iterator MFI = MF.begin(), MFE = MF.end(); MFI != MFE; // blocks, but only blocks dominated by the head block. This makes it safe to
++MFI) // update the dominator tree while the post-order iterator is still active.
if (tryConvertIf(MFI)) for (po_iterator<MachineDominatorTree*>
I = po_begin(DomTree), E = po_end(DomTree); I != E; ++I)
if (tryConvertIf(I->getBlock()))
Changed = true; Changed = true;
// Revisit blocks identified by tryConvertIf() as candidates for nested
// if-conversion.
DEBUG(dbgs() << "Revisiting " << WorkList.size() << " blocks.\n");
while (!WorkList.empty())
tryConvertIf(WorkList.pop_back_val());
MF.verify(this, "After early if-conversion"); MF.verify(this, "After early if-conversion");
return Changed; return Changed;
} }