#include "llvm/Transforms/Scalar/ADCE.h"
#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#define DEBUG_TYPE "adce"
STATISTIC(NumRemoved, "Number of instructions removed");
+STATISTIC(NumBranchesRemoved, "Number of branch instructions removed");
// This is a tempoary option until we change the interface
// to this pass based on optimization level.
static cl::opt<bool> RemoveControlFlowFlag("adce-remove-control-flow",
- cl::init(false), cl::Hidden);
+ cl::init(true), cl::Hidden);
+
+// This option enables removing of may-be-infinite loops which have no other
+// effect.
+static cl::opt<bool> RemoveLoops("adce-remove-loops", cl::init(false),
+ cl::Hidden);
namespace {
/// Information about Instructions
/// Corresponding BasicBlock.
BasicBlock *BB = nullptr;
- /// Cache of BB->getTerminator()
+ /// Cache of BB->getTerminator().
TerminatorInst *Terminator = nullptr;
+
+ /// Post-order numbering of reverse control flow graph.
+ unsigned PostOrder;
};
class AggressiveDeadCodeElimination {
/// Set of blocks with not known to have live terminators.
SmallPtrSet<BasicBlock *, 16> BlocksWithDeadTerminators;
- /// The set of blocks which we have determined are live in the
- /// most recent iteration of propagating liveness.
+ /// The set of blocks which we have determined whose control
+ /// dependence sources must be live and which have not had
+ /// those dependences analyized.
SmallPtrSet<BasicBlock *, 16> NewLiveBlocks;
/// Set up auxiliary data structures for Instructions and BasicBlocks and
void markLiveInstructions();
/// Mark an instruction as live.
void markLive(Instruction *I);
-
+ /// Mark a block as live.
+ void markLive(BlockInfoType &BB);
+ void markLive(BasicBlock *BB) { markLive(BlockInfo[BB]); }
+
/// Mark terminators of control predecessors of a PHI node live.
void markPhiLive(PHINode *PN);
/// was removed.
bool removeDeadInstructions();
+ /// Identify connected sections of the control flow grap which have
+ /// dead terminators and rewrite the control flow graph to remove them.
+ void updateDeadRegions();
+
+ /// Set the BlockInfo::PostOrder field based on a post-order
+ /// numbering of the reverse control flow graph.
+ void computeReversePostOrder();
+
+ /// Make the terminator of this block an unconditional branch to \p Target.
+ void makeUnconditional(BasicBlock *BB, BasicBlock *Target);
+
public:
AggressiveDeadCodeElimination(Function &F, PostDominatorTree &PDT)
: F(F), PDT(PDT) {}
}
static bool isUnconditionalBranch(TerminatorInst *Term) {
- auto BR = dyn_cast<BranchInst>(Term);
+ auto *BR = dyn_cast<BranchInst>(Term);
return BR && BR->isUnconditional();
}
if (!RemoveControlFlowFlag)
return;
- // This is temporary: will update with post order traveral to
- // find loop bottoms
- SmallPtrSet<BasicBlock *, 16> Seen;
- for (auto &BB : F) {
- Seen.insert(&BB);
- TerminatorInst *Term = BB.getTerminator();
- if (isLive(Term))
- continue;
+ if (!RemoveLoops) {
+ // This stores state for the depth-first iterator. In addition
+ // to recording which nodes have been visited we also record whether
+ // a node is currently on the "stack" of active ancestors of the current
+ // node.
+ typedef DenseMap<BasicBlock *, bool> StatusMap ;
+ class DFState : public StatusMap {
+ public:
+ std::pair<StatusMap::iterator, bool> insert(BasicBlock *BB) {
+ return StatusMap::insert(std::make_pair(BB, true));
+ }
+
+ // Invoked after we have visited all children of a node.
+ void completed(BasicBlock *BB) { (*this)[BB] = false; }
- for (auto Succ : successors(&BB))
- if (Seen.count(Succ)) {
- // back edge....
- markLive(Term);
+ // Return true if \p BB is currently on the active stack
+ // of ancestors.
+ bool onStack(BasicBlock *BB) {
+ auto Iter = find(BB);
+ return Iter != end() && Iter->second;
+ }
+ } State;
+
+ State.reserve(F.size());
+ // Iterate over blocks in depth-first pre-order and
+ // treat all edges to a block already seen as loop back edges
+ // and mark the branch live it if there is a back edge.
+ for (auto *BB: depth_first_ext(&F.getEntryBlock(), State)) {
+ TerminatorInst *Term = BB->getTerminator();
+ if (isLive(Term))
+ continue;
+
+ for (auto *Succ : successors(BB))
+ if (State.onStack(Succ)) {
+ // back edge....
+ markLive(Term);
+ break;
+ }
+ }
+ }
+
+ // Mark blocks live if there is no path from the block to the
+ // return of the function or a successor for which this is true.
+ // This protects IDFCalculator which cannot handle such blocks.
+ for (auto &BBInfoPair : BlockInfo) {
+ auto &BBInfo = BBInfoPair.second;
+ if (BBInfo.terminatorIsLive())
+ continue;
+ auto *BB = BBInfo.BB;
+ if (!PDT.getNode(BB)) {
+ markLive(BBInfo.Terminator);
+ continue;
+ }
+ for (auto *Succ : successors(BB))
+ if (!PDT.getNode(Succ)) {
+ markLive(BBInfo.Terminator);
break;
}
}
- // End temporary handling of loops.
// Mark blocks live if there is no path from the block to the
// return of the function or a successor for which this is true.
markLive(BBInfo.Terminator);
continue;
}
- for (auto Succ : successors(BB))
+ for (auto *Succ : successors(BB))
if (!PDT.getNode(Succ)) {
DEBUG(dbgs() << "Successor not post-dominated by return: "
<< BB->getName() << '\n';);
Instruction *LiveInst = Worklist.pop_back_val();
DEBUG(dbgs() << "work live: "; LiveInst->dump(););
- // Collect the live debug info scopes attached to this instruction.
- if (const DILocation *DL = LiveInst->getDebugLoc())
- collectLiveScopes(*DL);
-
for (Use &OI : LiveInst->operands())
if (Instruction *Inst = dyn_cast<Instruction>(OI))
markLive(Inst);
-
+
if (auto *PN = dyn_cast<PHINode>(LiveInst))
markPhiLive(PN);
}
+
+ // After data flow liveness has been identified, examine which branch
+ // decisions are required to determine live instructions are executed.
markLiveBranchesFromControlDependences();
- if (Worklist.empty()) {
- // Temporary until we can actually delete branches.
- SmallVector<TerminatorInst *, 16> DeadTerminators;
- for (auto *BB : BlocksWithDeadTerminators)
- DeadTerminators.push_back(BB->getTerminator());
- for (auto *I : DeadTerminators)
- markLive(I);
- assert(BlocksWithDeadTerminators.empty());
- // End temporary.
- }
} while (!Worklist.empty());
-
- assert(BlocksWithDeadTerminators.empty());
}
void AggressiveDeadCodeElimination::markLive(Instruction *I) {
Info.Live = true;
Worklist.push_back(I);
+ // Collect the live debug info scopes attached to this instruction.
+ if (const DILocation *DL = I->getDebugLoc())
+ collectLiveScopes(*DL);
+
// Mark the containing block live
auto &BBInfo = *Info.Block;
- if (BBInfo.Terminator == I)
+ if (BBInfo.Terminator == I) {
BlocksWithDeadTerminators.erase(BBInfo.BB);
+ // For live terminators, mark destination blocks
+ // live to preserve this control flow edges.
+ if (!BBInfo.UnconditionalBranch)
+ for (auto *BB : successors(I->getParent()))
+ markLive(BB);
+ }
+ markLive(BBInfo);
+}
+
+void AggressiveDeadCodeElimination::markLive(BlockInfoType &BBInfo) {
if (BBInfo.Live)
return;
-
DEBUG(dbgs() << "mark block live: " << BBInfo.BB->getName() << '\n');
BBInfo.Live = true;
if (!BBInfo.CFLive) {
// Mark unconditional branches at the end of live
// blocks as live since there is no work to do for them later
- if (BBInfo.UnconditionalBranch && I != BBInfo.Terminator)
+ if (BBInfo.UnconditionalBranch)
markLive(BBInfo.Terminator);
}
NewLiveBlocks.clear();
// Dead terminators which control live blocks are now marked live.
- for (auto BB : IDFBlocks) {
+ for (auto *BB : IDFBlocks) {
DEBUG(dbgs() << "live control in: " << BB->getName() << '\n');
markLive(BB->getTerminator());
}
//===----------------------------------------------------------------------===//
bool AggressiveDeadCodeElimination::removeDeadInstructions() {
+ // Updates control and dataflow around dead blocks
+ updateDeadRegions();
+
+ DEBUG({
+ for (Instruction &I : instructions(F)) {
+ // Check if the instruction is alive.
+ if (isLive(&I))
+ continue;
+
+ if (auto *DII = dyn_cast<DbgInfoIntrinsic>(&I)) {
+ // Check if the scope of this variable location is alive.
+ if (AliveScopes.count(DII->getDebugLoc()->getScope()))
+ continue;
+
+ // If intrinsic is pointing at a live SSA value, there may be an
+ // earlier optimization bug: if we know the location of the variable,
+ // why isn't the scope of the location alive?
+ if (Value *V = DII->getVariableLocation())
+ if (Instruction *II = dyn_cast<Instruction>(V))
+ if (isLive(II))
+ dbgs() << "Dropping debug info for " << *DII << "\n";
+ }
+ }
+ });
+
// The inverse of the live set is the dead set. These are those instructions
- // which have no side effects and do not influence the control flow or return
+ // that have no side effects and do not influence the control flow or return
// value of the function, and may therefore be deleted safely.
// NOTE: We reuse the Worklist vector here for memory efficiency.
for (Instruction &I : instructions(F)) {
if (isLive(&I))
continue;
- assert(!I.isTerminator() && "NYI: Removing Control Flow");
-
if (auto *DII = dyn_cast<DbgInfoIntrinsic>(&I)) {
// Check if the scope of this variable location is alive.
if (AliveScopes.count(DII->getDebugLoc()->getScope()))
continue;
// Fallthrough and drop the intrinsic.
- DEBUG({
- // If intrinsic is pointing at a live SSA value, there may be an
- // earlier optimization bug: if we know the location of the variable,
- // why isn't the scope of the location alive?
- if (Value *V = DII->getVariableLocation())
- if (Instruction *II = dyn_cast<Instruction>(V))
- if (isLive(II))
- dbgs() << "Dropping debug info for " << *DII << "\n";
- });
}
// Prepare to delete.
return !Worklist.empty();
}
+// A dead region is the set of dead blocks with a common live post-dominator.
+void AggressiveDeadCodeElimination::updateDeadRegions() {
+
+ DEBUG({
+ dbgs() << "final dead terminator blocks: " << '\n';
+ for (auto *BB : BlocksWithDeadTerminators)
+ dbgs() << '\t' << BB->getName()
+ << (BlockInfo[BB].Live ? " LIVE\n" : "\n");
+ });
+
+ // Don't compute the post ordering unless we needed it.
+ bool HavePostOrder = false;
+
+ for (auto *BB : BlocksWithDeadTerminators) {
+ auto &Info = BlockInfo[BB];
+ if (Info.UnconditionalBranch) {
+ InstInfo[Info.Terminator].Live = true;
+ continue;
+ }
+
+ if (!HavePostOrder) {
+ computeReversePostOrder();
+ HavePostOrder = true;
+ }
+
+ // Add an unconditional branch to the successor closest to the
+ // end of the function which insures a path to the exit for each
+ // live edge.
+ BlockInfoType *PreferredSucc = nullptr;
+ for (auto *Succ : successors(BB)) {
+ auto *Info = &BlockInfo[Succ];
+ if (!PreferredSucc || PreferredSucc->PostOrder < Info->PostOrder)
+ PreferredSucc = Info;
+ }
+ assert((PreferredSucc && PreferredSucc->PostOrder > 0) &&
+ "Failed to find safe successor for dead branc");
+ bool First = true;
+ for (auto *Succ : successors(BB)) {
+ if (!First || Succ != PreferredSucc->BB)
+ Succ->removePredecessor(BB);
+ else
+ First = false;
+ }
+ makeUnconditional(BB, PreferredSucc->BB);
+ NumBranchesRemoved += 1;
+ }
+}
+
+// reverse top-sort order
+void AggressiveDeadCodeElimination::computeReversePostOrder() {
+
+ // This provides a post-order numbering of the reverse conrtol flow graph
+ // Note that it is incomplete in the presence of infinite loops but we don't
+ // need numbers blocks which don't reach the end of the functions since
+ // all branches in those blocks are forced live.
+
+ // For each block without successors, extend the DFS from the bloack
+ // backward through the graph
+ SmallPtrSet<BasicBlock*, 16> Visited;
+ unsigned PostOrder = 0;
+ for (auto &BB : F) {
+ if (succ_begin(&BB) != succ_end(&BB))
+ continue;
+ for (BasicBlock *Block : inverse_post_order_ext(&BB,Visited))
+ BlockInfo[Block].PostOrder = PostOrder++;
+ }
+}
+
+void AggressiveDeadCodeElimination::makeUnconditional(BasicBlock *BB,
+ BasicBlock *Target) {
+ TerminatorInst *PredTerm = BB->getTerminator();
+ // Collect the live debug info scopes attached to this instruction.
+ if (const DILocation *DL = PredTerm->getDebugLoc())
+ collectLiveScopes(*DL);
+
+ // Just mark live an existing unconditional branch
+ if (isUnconditionalBranch(PredTerm)) {
+ PredTerm->setSuccessor(0, Target);
+ InstInfo[PredTerm].Live = true;
+ return;
+ }
+ DEBUG(dbgs() << "making unconditional " << BB->getName() << '\n');
+ NumBranchesRemoved += 1;
+ IRBuilder<> Builder(PredTerm);
+ auto *NewTerm = Builder.CreateBr(Target);
+ InstInfo[NewTerm].Live = true;
+ if (const DILocation *DL = PredTerm->getDebugLoc())
+ NewTerm->setDebugLoc(DL);
+}
+
//===----------------------------------------------------------------------===//
//
// Pass Manager integration code
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<PostDominatorTreeWrapperPass>();
- AU.setPreservesCFG(); // TODO -- will remove when we start removing branches
+ if (!RemoveControlFlowFlag)
+ AU.setPreservesCFG();
AU.addPreserved<GlobalsAAWrapperPass>();
}
};