mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-09 11:25:55 +00:00
Teach jump threading some more simple tricks:
1) have it fold "br undef", which does occur with surprising frequency as jump threading iterates. 2) teach j-t to delete dead blocks. This removes the successor edges, reducing the in-edges of other blocks, allowing recursive simplification. 3) Fold things like: br COND, BBX, BBY BBX: br COND, BBZ, BBW which also happens because jump threading iterates. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@60470 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -67,6 +67,7 @@ namespace {
|
|||||||
bool ProcessBlock(BasicBlock *BB);
|
bool ProcessBlock(BasicBlock *BB);
|
||||||
void ThreadEdge(BasicBlock *BB, BasicBlock *PredBB, BasicBlock *SuccBB);
|
void ThreadEdge(BasicBlock *BB, BasicBlock *PredBB, BasicBlock *SuccBB);
|
||||||
BasicBlock *FactorCommonPHIPreds(PHINode *PN, Constant *CstVal);
|
BasicBlock *FactorCommonPHIPreds(PHINode *PN, Constant *CstVal);
|
||||||
|
bool ProcessBranchOnDuplicateCond(BasicBlock *PredBB, BasicBlock *DestBB);
|
||||||
|
|
||||||
bool ProcessJumpOnPHI(PHINode *PN);
|
bool ProcessJumpOnPHI(PHINode *PN);
|
||||||
bool ProcessBranchOnLogical(Value *V, BasicBlock *BB, bool isAnd);
|
bool ProcessBranchOnLogical(Value *V, BasicBlock *BB, bool isAnd);
|
||||||
@@ -93,9 +94,23 @@ bool JumpThreading::runOnFunction(Function &F) {
|
|||||||
while (AnotherIteration) {
|
while (AnotherIteration) {
|
||||||
AnotherIteration = false;
|
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;) {
|
||||||
while (ProcessBlock(I))
|
BasicBlock *BB = I;
|
||||||
|
while (ProcessBlock(BB))
|
||||||
Changed = true;
|
Changed = true;
|
||||||
|
|
||||||
|
++I;
|
||||||
|
|
||||||
|
// If the block is trivially dead, zap it. This eliminates the successor
|
||||||
|
// edges which simplifies the CFG.
|
||||||
|
if (pred_begin(BB) == pred_end(BB) &&
|
||||||
|
BB != &BB->getParent()->getEntryBlock()) {
|
||||||
|
DOUT << " JT: Deleting dead block '" << BB->getNameStart()
|
||||||
|
<< "' with terminator: " << *BB->getTerminator();
|
||||||
|
DeleteDeadBlock(BB);
|
||||||
|
Changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
AnotherIteration = Changed;
|
AnotherIteration = Changed;
|
||||||
EverChanged |= Changed;
|
EverChanged |= Changed;
|
||||||
}
|
}
|
||||||
@@ -209,29 +224,80 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the terminator is branching on an undef, we can pick any of the
|
||||||
|
// successors to branch to. Since this is arbitrary, we pick the successor
|
||||||
|
// with the fewest predecessors. This should reduce the in-degree of the
|
||||||
|
// others.
|
||||||
|
if (isa<UndefValue>(Condition)) {
|
||||||
|
TerminatorInst *BBTerm = BB->getTerminator();
|
||||||
|
unsigned MinSucc = 0;
|
||||||
|
BasicBlock *TestBB = BBTerm->getSuccessor(MinSucc);
|
||||||
|
// Compute the successor with the minimum number of predecessors.
|
||||||
|
unsigned MinNumPreds = std::distance(pred_begin(TestBB), pred_end(TestBB));
|
||||||
|
for (unsigned i = 1, e = BBTerm->getNumSuccessors(); i != e; ++i) {
|
||||||
|
TestBB = BBTerm->getSuccessor(i);
|
||||||
|
unsigned NumPreds = std::distance(pred_begin(TestBB), pred_end(TestBB));
|
||||||
|
if (NumPreds < MinNumPreds)
|
||||||
|
MinSucc = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fold the branch/switch.
|
||||||
|
for (unsigned i = 0, e = BBTerm->getNumSuccessors(); i != e; ++i) {
|
||||||
|
if (i == MinSucc) continue;
|
||||||
|
BBTerm->getSuccessor(i)->removePredecessor(BB);
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUT << " In block '" << BB->getNameStart()
|
||||||
|
<< "' folding undef terminator: " << *BBTerm;
|
||||||
|
BranchInst::Create(BBTerm->getSuccessor(MinSucc), BBTerm);
|
||||||
|
BBTerm->eraseFromParent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction *CondInst = dyn_cast<Instruction>(Condition);
|
||||||
|
|
||||||
|
// If the condition is an instruction defined in another block, see if a
|
||||||
|
// predecessor has the same condition:
|
||||||
|
// br COND, BBX, BBY
|
||||||
|
// BBX:
|
||||||
|
// br COND, BBZ, BBW
|
||||||
|
if (!Condition->hasOneUse() && // Multiple uses.
|
||||||
|
(CondInst == 0 || CondInst->getParent() != BB)) { // Non-local definition.
|
||||||
|
pred_iterator PI = pred_begin(BB), E = pred_end(BB);
|
||||||
|
if (isa<BranchInst>(BB->getTerminator())) {
|
||||||
|
for (; PI != E; ++PI)
|
||||||
|
if (BranchInst *PBI = dyn_cast<BranchInst>((*PI)->getTerminator()))
|
||||||
|
if (PBI->isConditional() && PBI->getCondition() == Condition &&
|
||||||
|
ProcessBranchOnDuplicateCond(*PI, BB))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If there is only a single predecessor of this block, nothing to fold.
|
// If there is only a single predecessor of this block, nothing to fold.
|
||||||
if (BB->getSinglePredecessor())
|
if (BB->getSinglePredecessor())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// All the rest of our checks depend on the condition being an instruction.
|
||||||
|
if (CondInst == 0)
|
||||||
|
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);
|
if (PHINode *PN = dyn_cast<PHINode>(CondInst))
|
||||||
if (PN && PN->getParent() == BB)
|
if (PN->getParent() == BB)
|
||||||
return ProcessJumpOnPHI(PN);
|
return ProcessJumpOnPHI(PN);
|
||||||
|
|
||||||
// If this is a conditional branch whose condition is and/or of a phi, try to
|
// If this is a conditional branch whose condition is and/or of a phi, try to
|
||||||
// simplify it.
|
// simplify it.
|
||||||
if (BinaryOperator *CondI = dyn_cast<BinaryOperator>(Condition)) {
|
if ((CondInst->getOpcode() == Instruction::And ||
|
||||||
if ((CondI->getOpcode() == Instruction::And ||
|
CondInst->getOpcode() == Instruction::Or) &&
|
||||||
CondI->getOpcode() == Instruction::Or) &&
|
isa<BranchInst>(BB->getTerminator()) &&
|
||||||
isa<BranchInst>(BB->getTerminator()) &&
|
ProcessBranchOnLogical(CondInst, BB,
|
||||||
ProcessBranchOnLogical(CondI, BB,
|
CondInst->getOpcode() == Instruction::And))
|
||||||
CondI->getOpcode() == Instruction::And))
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have "br (phi != 42)" and the phi node has any constant values as
|
// If we have "br (phi != 42)" and the phi node has any constant values as
|
||||||
// operands, we can thread through this block.
|
// operands, we can thread through this block.
|
||||||
if (CmpInst *CondCmp = dyn_cast<CmpInst>(Condition))
|
if (CmpInst *CondCmp = dyn_cast<CmpInst>(CondInst))
|
||||||
if (isa<PHINode>(CondCmp->getOperand(0)) &&
|
if (isa<PHINode>(CondCmp->getOperand(0)) &&
|
||||||
isa<Constant>(CondCmp->getOperand(1)) &&
|
isa<Constant>(CondCmp->getOperand(1)) &&
|
||||||
ProcessBranchOnCompare(CondCmp, BB))
|
ProcessBranchOnCompare(CondCmp, BB))
|
||||||
@@ -244,7 +310,7 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) {
|
|||||||
//
|
//
|
||||||
// This is particularly important because reg2mem inserts loads and stores all
|
// This is particularly important because reg2mem inserts loads and stores all
|
||||||
// over the place, and this blocks jump threading if we don't zap them.
|
// over the place, and this blocks jump threading if we don't zap them.
|
||||||
Value *SimplifyValue = Condition;
|
Value *SimplifyValue = CondInst;
|
||||||
if (CmpInst *CondCmp = dyn_cast<CmpInst>(SimplifyValue))
|
if (CmpInst *CondCmp = dyn_cast<CmpInst>(SimplifyValue))
|
||||||
if (isa<Constant>(CondCmp->getOperand(1)))
|
if (isa<Constant>(CondCmp->getOperand(1)))
|
||||||
SimplifyValue = CondCmp->getOperand(0);
|
SimplifyValue = CondCmp->getOperand(0);
|
||||||
@@ -259,6 +325,80 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ProcessBranchOnDuplicateCond - We found a block and a predecessor of that
|
||||||
|
/// block that jump on exactly the same condition. This means that we almost
|
||||||
|
/// always know the direction of the edge in the DESTBB:
|
||||||
|
/// PREDBB:
|
||||||
|
/// br COND, DESTBB, BBY
|
||||||
|
/// DESTBB:
|
||||||
|
/// br COND, BBZ, BBW
|
||||||
|
///
|
||||||
|
/// If DESTBB has multiple predecessors, we can't just constant fold the branch
|
||||||
|
/// in DESTBB, we have to thread over it.
|
||||||
|
bool JumpThreading::ProcessBranchOnDuplicateCond(BasicBlock *PredBB,
|
||||||
|
BasicBlock *BB) {
|
||||||
|
BranchInst *PredBI = cast<BranchInst>(PredBB->getTerminator());
|
||||||
|
|
||||||
|
// If both successors of PredBB go to DESTBB, we don't know anything. We can
|
||||||
|
// fold the branch to an unconditional one, which allows other recursive
|
||||||
|
// simplifications.
|
||||||
|
bool BranchDir;
|
||||||
|
if (PredBI->getSuccessor(1) != BB)
|
||||||
|
BranchDir = true;
|
||||||
|
else if (PredBI->getSuccessor(0) != BB)
|
||||||
|
BranchDir = false;
|
||||||
|
else {
|
||||||
|
DOUT << " In block '" << PredBB->getNameStart()
|
||||||
|
<< "' folding terminator: " << *PredBB->getTerminator();
|
||||||
|
++NumFolds;
|
||||||
|
ConstantFoldTerminator(PredBB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BranchInst *DestBI = cast<BranchInst>(BB->getTerminator());
|
||||||
|
|
||||||
|
// If the dest block has one predecessor, just fix the branch condition to a
|
||||||
|
// constant and fold it.
|
||||||
|
if (BB->getSinglePredecessor()) {
|
||||||
|
DOUT << " In block '" << BB->getNameStart()
|
||||||
|
<< "' folding condition to '" << BranchDir << "': "
|
||||||
|
<< *BB->getTerminator();
|
||||||
|
++NumFolds;
|
||||||
|
DestBI->setCondition(ConstantInt::get(Type::Int1Ty, BranchDir));
|
||||||
|
ConstantFoldTerminator(BB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we need to thread from PredBB to DestBB's successor which
|
||||||
|
// involves code duplication. Check to see if it is worth it.
|
||||||
|
unsigned JumpThreadCost = getJumpThreadDuplicationCost(BB);
|
||||||
|
if (JumpThreadCost > Threshold) {
|
||||||
|
DOUT << " Not threading BB '" << BB->getNameStart()
|
||||||
|
<< "' - Cost is too high: " << JumpThreadCost << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, figure out which successor we are threading to.
|
||||||
|
BasicBlock *SuccBB = DestBI->getSuccessor(!BranchDir);
|
||||||
|
|
||||||
|
// If threading to the same block as we come from, we would infinite loop.
|
||||||
|
if (SuccBB == BB) {
|
||||||
|
DOUT << " Not threading BB '" << BB->getNameStart()
|
||||||
|
<< "' - would thread to self!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And finally, do it!
|
||||||
|
DOUT << " Threading edge from '" << PredBB->getNameStart() << "' to '"
|
||||||
|
<< SuccBB->getNameStart() << "' with cost: " << JumpThreadCost
|
||||||
|
<< ", across block:\n "
|
||||||
|
<< *BB << "\n";
|
||||||
|
|
||||||
|
ThreadEdge(BB, PredBB, SuccBB);
|
||||||
|
++NumThreads;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// SimplifyPartiallyRedundantLoad - If LI is an obviously partially redundant
|
/// SimplifyPartiallyRedundantLoad - If LI is an obviously partially redundant
|
||||||
/// load instruction, eliminate it by replacing it with a PHI node. This is an
|
/// load instruction, eliminate it by replacing it with a PHI node. This is an
|
||||||
/// important optimization that encourages jump threading, and needs to be run
|
/// important optimization that encourages jump threading, and needs to be run
|
||||||
|
@@ -29,3 +29,25 @@ T2:
|
|||||||
F2:
|
F2:
|
||||||
ret i32 %B
|
ret i32 %B
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
;; cond is known false on Entry -> F1 edge!
|
||||||
|
define i32 @test2(i1 %cond) {
|
||||||
|
Entry:
|
||||||
|
br i1 %cond, label %T1, label %F1
|
||||||
|
|
||||||
|
T1:
|
||||||
|
%v1 = call i32 @f1()
|
||||||
|
br label %Merge
|
||||||
|
|
||||||
|
F1:
|
||||||
|
br i1 %cond, label %Merge, label %F2
|
||||||
|
|
||||||
|
Merge:
|
||||||
|
%B = phi i32 [47, %T1], [192, %F1]
|
||||||
|
ret i32 %B
|
||||||
|
|
||||||
|
F2:
|
||||||
|
call void @f3()
|
||||||
|
ret i32 12
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user