mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-26 07:24:25 +00:00
finish the first cut of a jump threading pass implementation.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@50006 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -15,13 +15,16 @@
|
|||||||
#include "llvm/Transforms/Scalar.h"
|
#include "llvm/Transforms/Scalar.h"
|
||||||
#include "llvm/IntrinsicInst.h"
|
#include "llvm/IntrinsicInst.h"
|
||||||
#include "llvm/Pass.h"
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/Transforms/Utils/Local.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
//STATISTIC(NumThreads, "Number of jumps threaded");
|
STATISTIC(NumThreads, "Number of jumps threaded");
|
||||||
|
STATISTIC(NumFolds, "Number of terminators folded");
|
||||||
|
|
||||||
static cl::opt<unsigned>
|
static cl::opt<unsigned>
|
||||||
Threshold("jump-threading-threshold",
|
Threshold("jump-threading-threshold",
|
||||||
@ -51,7 +54,8 @@ namespace {
|
|||||||
JumpThreading() : FunctionPass((intptr_t)&ID) {}
|
JumpThreading() : FunctionPass((intptr_t)&ID) {}
|
||||||
|
|
||||||
bool runOnFunction(Function &F);
|
bool runOnFunction(Function &F);
|
||||||
bool ThreadBlock(BasicBlock &BB);
|
bool ThreadBlock(BasicBlock *BB);
|
||||||
|
void ThreadEdge(BasicBlock *BB, BasicBlock *PredBB, BasicBlock *SuccBB);
|
||||||
};
|
};
|
||||||
char JumpThreading::ID = 0;
|
char JumpThreading::ID = 0;
|
||||||
RegisterPass<JumpThreading> X("jump-threading", "Jump Threading");
|
RegisterPass<JumpThreading> X("jump-threading", "Jump Threading");
|
||||||
@ -64,16 +68,24 @@ FunctionPass *llvm::createJumpThreadingPass() { return new JumpThreading(); }
|
|||||||
///
|
///
|
||||||
bool JumpThreading::runOnFunction(Function &F) {
|
bool JumpThreading::runOnFunction(Function &F) {
|
||||||
DOUT << "Jump threading on function '" << F.getNameStart() << "'\n";
|
DOUT << "Jump threading on function '" << F.getNameStart() << "'\n";
|
||||||
|
|
||||||
|
bool AnotherIteration = true, EverChanged = false;
|
||||||
|
while (AnotherIteration) {
|
||||||
|
AnotherIteration = false;
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
|
for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
|
||||||
Changed |= ThreadBlock(*I);
|
while (ThreadBlock(I))
|
||||||
return Changed;
|
Changed = true;
|
||||||
|
AnotherIteration = Changed;
|
||||||
|
EverChanged |= Changed;
|
||||||
|
}
|
||||||
|
return EverChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getJumpThreadDuplicationCost - Return the cost of duplicating this block to
|
/// getJumpThreadDuplicationCost - Return the cost of duplicating this block to
|
||||||
/// thread across it.
|
/// thread across it.
|
||||||
static unsigned getJumpThreadDuplicationCost(const BasicBlock &BB) {
|
static unsigned getJumpThreadDuplicationCost(const BasicBlock *BB) {
|
||||||
BasicBlock::const_iterator I = BB.begin();
|
BasicBlock::const_iterator I = BB->begin();
|
||||||
/// Ignore PHI nodes, these will be flattened when duplication happens.
|
/// Ignore PHI nodes, these will be flattened when duplication happens.
|
||||||
while (isa<PHINode>(*I)) ++I;
|
while (isa<PHINode>(*I)) ++I;
|
||||||
|
|
||||||
@ -114,31 +126,45 @@ static unsigned getJumpThreadDuplicationCost(const BasicBlock &BB) {
|
|||||||
|
|
||||||
/// ThreadBlock - If there are any predecessors whose control can be threaded
|
/// ThreadBlock - If there are any predecessors whose control can be threaded
|
||||||
/// through to a successor, transform them now.
|
/// through to a successor, transform them now.
|
||||||
bool JumpThreading::ThreadBlock(BasicBlock &BB) {
|
bool JumpThreading::ThreadBlock(BasicBlock *BB) {
|
||||||
// If there is only one predecessor or successor, then there is nothing to do.
|
|
||||||
if (BB.getTerminator()->getNumSuccessors() == 1 || BB.getSinglePredecessor())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// See if this block ends with a branch of switch. If so, see if the
|
// See if this block ends with a branch of switch. If so, see if the
|
||||||
// condition is a phi node. If so, and if an entry of the phi node is a
|
// condition is a phi node. If so, and if an entry of the phi node is a
|
||||||
// constant, we can thread the block.
|
// constant, we can thread the block.
|
||||||
Value *Condition;
|
Value *Condition;
|
||||||
if (BranchInst *BI = dyn_cast<BranchInst>(BB.getTerminator()))
|
if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
|
||||||
|
// Can't thread an unconditional jump.
|
||||||
|
if (BI->isUnconditional()) return false;
|
||||||
Condition = BI->getCondition();
|
Condition = BI->getCondition();
|
||||||
else if (SwitchInst *SI = dyn_cast<SwitchInst>(BB.getTerminator()))
|
} else if (SwitchInst *SI = dyn_cast<SwitchInst>(BB->getTerminator()))
|
||||||
Condition = SI->getCondition();
|
Condition = SI->getCondition();
|
||||||
else
|
else
|
||||||
return false; // Must be an invoke.
|
return false; // Must be an invoke.
|
||||||
|
|
||||||
|
// If the terminator of this block is branching on a constant, simplify the
|
||||||
|
// terminator to an unconditional branch. This can occur do to threading in
|
||||||
|
// other blocks.
|
||||||
|
if (isa<ConstantInt>(Condition)) {
|
||||||
|
DOUT << " In block '" << BB->getNameStart()
|
||||||
|
<< "' folding terminator: " << *BB->getTerminator();
|
||||||
|
++NumFolds;
|
||||||
|
ConstantFoldTerminator(BB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is only a single predecessor of this block, nothing to fold.
|
||||||
|
if (BB->getSinglePredecessor())
|
||||||
|
return false;
|
||||||
|
|
||||||
// See if this is a phi node in the current block.
|
// See if this is a phi node in the current block.
|
||||||
PHINode *PN = dyn_cast<PHINode>(Condition);
|
PHINode *PN = dyn_cast<PHINode>(Condition);
|
||||||
if (!PN || PN->getParent() != &BB) return false;
|
if (!PN || PN->getParent() != BB) return false;
|
||||||
|
|
||||||
// See if the phi node has any constant values. If so, we can determine where
|
// See if the phi node has any constant values. If so, we can determine where
|
||||||
// the corresponding predecessor will branch.
|
// the corresponding predecessor will branch.
|
||||||
unsigned PredNo = ~0U;
|
unsigned PredNo = ~0U;
|
||||||
|
ConstantInt *PredCst = 0;
|
||||||
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
|
||||||
if (isa<ConstantInt>(PN->getIncomingValue(i))) {
|
if ((PredCst = dyn_cast<ConstantInt>(PN->getIncomingValue(i)))) {
|
||||||
PredNo = i;
|
PredNo = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -152,13 +178,107 @@ bool JumpThreading::ThreadBlock(BasicBlock &BB) {
|
|||||||
// See if the cost of duplicating this block is low enough.
|
// See if the cost of duplicating this block is low enough.
|
||||||
unsigned JumpThreadCost = getJumpThreadDuplicationCost(BB);
|
unsigned JumpThreadCost = getJumpThreadDuplicationCost(BB);
|
||||||
if (JumpThreadCost > Threshold) {
|
if (JumpThreadCost > Threshold) {
|
||||||
DOUT << " Not threading BB '" << BB.getNameStart()
|
DOUT << " Not threading BB '" << BB->getNameStart()
|
||||||
<< "' - Cost is too high: " << JumpThreadCost << "\n";
|
<< "' - Cost is too high: " << JumpThreadCost << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOUT << " Threading BB '" << BB.getNameStart() << "'. Cost is: "
|
// If so, we can actually do this threading. Figure out which predecessor and
|
||||||
<< JumpThreadCost << "\n";
|
// which successor we are threading for.
|
||||||
|
BasicBlock *PredBB = PN->getIncomingBlock(PredNo);
|
||||||
|
BasicBlock *SuccBB;
|
||||||
|
if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator()))
|
||||||
|
SuccBB = BI->getSuccessor(PredCst == ConstantInt::getFalse());
|
||||||
|
else {
|
||||||
|
SwitchInst *SI = cast<SwitchInst>(BB->getTerminator());
|
||||||
|
SuccBB = SI->getSuccessor(SI->findCaseValue(PredCst));
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
// TODO: If there are multiple preds with the same incoming value for the PHI,
|
||||||
|
// factor them together so we get one thread block for the whole group. This
|
||||||
|
// is important for things like "phi i1 [true, true, false, true, x]" where
|
||||||
|
// we only need to clone the block for the true blocks once.
|
||||||
|
|
||||||
|
DOUT << " Threading edge from '" << PredBB->getNameStart() << "' to '"
|
||||||
|
<< SuccBB->getNameStart() << "' with cost: " << JumpThreadCost
|
||||||
|
<< ", across block:\n "
|
||||||
|
<< *BB;
|
||||||
|
|
||||||
|
ThreadEdge(BB, PredBB, SuccBB);
|
||||||
|
++NumThreads;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ThreadEdge - We have decided that it is safe and profitable to thread an
|
||||||
|
/// edge from PredBB to SuccBB across BB. Transform the IR to reflect this
|
||||||
|
/// change.
|
||||||
|
void JumpThreading::ThreadEdge(BasicBlock *BB, BasicBlock *PredBB,
|
||||||
|
BasicBlock *SuccBB) {
|
||||||
|
|
||||||
|
// Jump Threading can not update SSA properties correctly if the values
|
||||||
|
// defined in the duplicated block are used outside of the block itself. For
|
||||||
|
// this reason, we spill all values that are used outside of BB to the stack.
|
||||||
|
for (BasicBlock::iterator I = BB->begin(); I != BB->end(); ++I)
|
||||||
|
if (I->isUsedOutsideOfBlock(BB)) {
|
||||||
|
// We found a use of I outside of BB. Create a new stack slot to
|
||||||
|
// break this inter-block usage pattern.
|
||||||
|
DemoteRegToStack(*I);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are going to have to map operands from the original BB block to the new
|
||||||
|
// copy of the block 'NewBB'. If there are PHI nodes in BB, evaluate them to
|
||||||
|
// account for entry from PredBB.
|
||||||
|
DenseMap<Instruction*, Value*> ValueMapping;
|
||||||
|
|
||||||
|
BasicBlock *NewBB =
|
||||||
|
BasicBlock::Create(BB->getName()+".thread", BB->getParent(), BB);
|
||||||
|
NewBB->moveAfter(PredBB);
|
||||||
|
|
||||||
|
BasicBlock::iterator BI = BB->begin();
|
||||||
|
for (; PHINode *PN = dyn_cast<PHINode>(BI); ++BI)
|
||||||
|
ValueMapping[PN] = PN->getIncomingValueForBlock(PredBB);
|
||||||
|
|
||||||
|
// Clone the non-phi instructions of BB into NewBB, keeping track of the
|
||||||
|
// mapping and using it to remap operands in the cloned instructions.
|
||||||
|
for (; !isa<TerminatorInst>(BI); ++BI) {
|
||||||
|
Instruction *New = BI->clone();
|
||||||
|
New->setName(BI->getNameStart());
|
||||||
|
NewBB->getInstList().push_back(New);
|
||||||
|
ValueMapping[BI] = New;
|
||||||
|
|
||||||
|
// Remap operands to patch up intra-block references.
|
||||||
|
for (unsigned i = 0, e = New->getNumOperands(); i != e; ++i)
|
||||||
|
if (Instruction *Inst = dyn_cast<Instruction>(New->getOperand(i)))
|
||||||
|
if (Value *Remapped = ValueMapping[Inst])
|
||||||
|
New->setOperand(i, Remapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We didn't copy the terminator from BB over to NewBB, because there is now
|
||||||
|
// an unconditional jump to SuccBB. Insert the unconditional jump.
|
||||||
|
BranchInst::Create(SuccBB, NewBB);
|
||||||
|
|
||||||
|
// Check to see if SuccBB has PHI nodes. If so, we need to add entries to the
|
||||||
|
// PHI nodes for NewBB now.
|
||||||
|
for (BasicBlock::iterator PNI = SuccBB->begin(); isa<PHINode>(PNI); ++PNI) {
|
||||||
|
PHINode *PN = cast<PHINode>(PNI);
|
||||||
|
// Ok, we have a PHI node. Figure out what the incoming value was for the
|
||||||
|
// DestBlock.
|
||||||
|
Value *IV = PN->getIncomingValueForBlock(BB);
|
||||||
|
|
||||||
|
// Remap the value if necessary.
|
||||||
|
if (Instruction *Inst = dyn_cast<Instruction>(IV))
|
||||||
|
if (Value *MappedIV = ValueMapping[Inst])
|
||||||
|
IV = MappedIV;
|
||||||
|
PN->addIncoming(IV, NewBB);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, NewBB is good to go. Update the terminator of PredBB to jump to
|
||||||
|
// NewBB instead of BB. This eliminates predecessors from BB, which requires
|
||||||
|
// us to simplify any PHI nodes in BB.
|
||||||
|
TerminatorInst *PredTerm = PredBB->getTerminator();
|
||||||
|
for (unsigned i = 0, e = PredTerm->getNumSuccessors(); i != e; ++i)
|
||||||
|
if (PredTerm->getSuccessor(i) == BB) {
|
||||||
|
BB->removePredecessor(PredBB);
|
||||||
|
PredTerm->setSuccessor(i, NewBB);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user