61#define DEBUG_TYPE "adce"
63STATISTIC(NumRemoved,
"Number of instructions removed");
64STATISTIC(NumBranchesRemoved,
"Number of branch instructions removed");
84 struct BlockInfoType *Block =
nullptr;
93 bool UnconditionalBranch =
false;
96 bool HasLivePhiNodes =
false;
103 InstInfoType *TerminatorLiveInfo =
nullptr;
114 bool terminatorIsLive()
const {
return TerminatorLiveInfo->Live; }
118 bool ChangedAnything =
false;
119 bool ChangedNonDebugInstr =
false;
120 bool ChangedControlFlow =
false;
123class AggressiveDeadCodeElimination {
134 bool isLive(
BasicBlock *BB) {
return BlockInfo[BB].Live; }
166 void markLiveInstructions();
172 void markLive(BlockInfoType &BB);
173 void markLive(
BasicBlock *BB) { markLive(BlockInfo[BB]); }
185 void markLiveBranchesFromControlDependences();
189 ADCEChanged removeDeadInstructions();
193 bool updateDeadRegions();
197 void computeReversePostOrder();
205 :
F(
F), DT(DT), PDT(PDT) {}
207 ADCEChanged performDeadCodeElimination();
212ADCEChanged AggressiveDeadCodeElimination::performDeadCodeElimination() {
214 markLiveInstructions();
215 return removeDeadInstructions();
219 auto *BR = dyn_cast<BranchInst>(Term);
220 return BR && BR->isUnconditional();
223void AggressiveDeadCodeElimination::initialize() {
224 auto NumBlocks =
F.size();
228 BlockInfo.reserve(NumBlocks);
234 NumInsts += BB.size();
235 auto &
Info = BlockInfo[&BB];
237 Info.Terminator = BB.getTerminator();
242 InstInfo.reserve(NumInsts);
243 for (
auto &BBInfo : BlockInfo)
245 InstInfo[&
I].Block = &BBInfo.second;
249 for (
auto &BBInfo : BlockInfo)
250 BBInfo.second.TerminatorLiveInfo = &InstInfo[BBInfo.second.Terminator];
267 class DFState :
public StatusMap {
269 std::pair<StatusMap::iterator, bool> insert(
BasicBlock *BB) {
270 return StatusMap::insert(std::make_pair(BB,
true));
274 void completed(
BasicBlock *BB) { (*this)[BB] =
false; }
279 auto Iter =
find(BB);
280 return Iter !=
end() && Iter->second;
284 State.reserve(
F.size());
294 if (State.onStack(Succ)) {
306 for (
const auto &PDTChild : children<DomTreeNode *>(PDT.getRootNode())) {
307 auto *BB = PDTChild->getBlock();
308 auto &
Info = BlockInfo[BB];
310 if (isa<ReturnInst>(
Info.Terminator)) {
311 LLVM_DEBUG(
dbgs() <<
"post-dom root child is a return: " << BB->getName()
318 markLive(BlockInfo[DFNode->getBlock()].Terminator);
322 auto *BB = &
F.getEntryBlock();
323 auto &EntryInfo = BlockInfo[BB];
324 EntryInfo.Live =
true;
325 if (EntryInfo.UnconditionalBranch)
326 markLive(EntryInfo.Terminator);
329 for (
auto &BBInfo : BlockInfo)
330 if (!BBInfo.second.terminatorIsLive())
331 BlocksWithDeadTerminators.insert(BBInfo.second.BB);
334bool AggressiveDeadCodeElimination::isAlwaysLive(
Instruction &
I) {
336 if (
I.isEHPad() ||
I.mayHaveSideEffects()) {
339 if (isInstrumentsConstant(
I))
343 if (!
I.isTerminator())
352bool AggressiveDeadCodeElimination::isInstrumentsConstant(
Instruction &
I) {
354 if (
CallInst *CI = dyn_cast<CallInst>(&
I))
357 if (isa<Constant>(CI->getArgOperand(0)))
362void AggressiveDeadCodeElimination::markLiveInstructions() {
367 while (!Worklist.empty()) {
375 if (
auto *PN = dyn_cast<PHINode>(LiveInst))
381 markLiveBranchesFromControlDependences();
383 }
while (!Worklist.empty());
386void AggressiveDeadCodeElimination::markLive(
Instruction *
I) {
387 auto &
Info = InstInfo[
I];
393 Worklist.push_back(
I);
397 collectLiveScopes(*
DL);
400 auto &BBInfo = *
Info.Block;
401 if (BBInfo.Terminator ==
I) {
402 BlocksWithDeadTerminators.remove(BBInfo.BB);
405 if (!BBInfo.UnconditionalBranch)
412void AggressiveDeadCodeElimination::markLive(BlockInfoType &BBInfo) {
415 LLVM_DEBUG(
dbgs() <<
"mark block live: " << BBInfo.BB->getName() <<
'\n');
417 if (!BBInfo.CFLive) {
418 BBInfo.CFLive =
true;
419 NewLiveBlocks.insert(BBInfo.BB);
424 if (BBInfo.UnconditionalBranch)
425 markLive(BBInfo.Terminator);
428void AggressiveDeadCodeElimination::collectLiveScopes(
const DILocalScope &LS) {
429 if (!AliveScopes.insert(&LS).second)
432 if (isa<DISubprogram>(LS))
436 collectLiveScopes(cast<DILocalScope>(*
LS.getScope()));
439void AggressiveDeadCodeElimination::collectLiveScopes(
const DILocation &
DL) {
442 if (!AliveScopes.insert(&
DL).second)
446 collectLiveScopes(*
DL.getScope());
450 collectLiveScopes(*IA);
453void AggressiveDeadCodeElimination::markPhiLive(
PHINode *PN) {
456 if (
Info.HasLivePhiNodes)
458 Info.HasLivePhiNodes =
true;
464 auto &
Info = BlockInfo[PredBB];
467 NewLiveBlocks.insert(PredBB);
472void AggressiveDeadCodeElimination::markLiveBranchesFromControlDependences() {
473 if (BlocksWithDeadTerminators.empty())
477 dbgs() <<
"new live blocks:\n";
478 for (
auto *BB : NewLiveBlocks)
479 dbgs() <<
"\t" << BB->getName() <<
'\n';
480 dbgs() <<
"dead terminator blocks:\n";
481 for (
auto *BB : BlocksWithDeadTerminators)
482 dbgs() <<
"\t" << BB->getName() <<
'\n';
492 BlocksWithDeadTerminators.
begin(),
493 BlocksWithDeadTerminators.end()
497 IDFs.setDefiningBlocks(NewLiveBlocks);
498 IDFs.setLiveInBlocks(BWDT);
499 IDFs.calculate(IDFBlocks);
500 NewLiveBlocks.clear();
503 for (
auto *BB : IDFBlocks) {
504 LLVM_DEBUG(
dbgs() <<
"live control in: " << BB->getName() <<
'\n');
505 markLive(BB->getTerminator());
514ADCEChanged AggressiveDeadCodeElimination::removeDeadInstructions() {
517 Changed.ChangedControlFlow = updateDeadRegions();
525 if (
auto *DII = dyn_cast<DbgVariableIntrinsic>(&
I)) {
527 if (AliveScopes.count(DII->getDebugLoc()->getScope()))
533 for (
Value *V : DII->location_ops()) {
534 if (Instruction *II = dyn_cast<Instruction>(V)) {
536 dbgs() <<
"Dropping debug info for " << *DII <<
"\n";
554 if (
auto *DII = dyn_cast<DbgInfoIntrinsic>(&
I)) {
557 if (
auto *DAI = dyn_cast<DbgAssignIntrinsic>(DII))
561 if (AliveScopes.count(DII->getDebugLoc()->getScope()))
566 Changed.ChangedNonDebugInstr =
true;
570 Worklist.push_back(&
I);
575 I->dropAllReferences();
579 I->eraseFromParent();
582 Changed.ChangedAnything = Changed.ChangedControlFlow || !Worklist.empty();
588bool AggressiveDeadCodeElimination::updateDeadRegions() {
590 dbgs() <<
"final dead terminator blocks: " <<
'\n';
591 for (
auto *BB : BlocksWithDeadTerminators)
592 dbgs() <<
'\t' << BB->getName()
593 << (BlockInfo[BB].Live ?
" LIVE\n" :
"\n");
597 bool HavePostOrder =
false;
598 bool Changed =
false;
601 for (
auto *BB : BlocksWithDeadTerminators) {
602 auto &
Info = BlockInfo[BB];
603 if (
Info.UnconditionalBranch) {
604 InstInfo[
Info.Terminator].Live =
true;
608 if (!HavePostOrder) {
609 computeReversePostOrder();
610 HavePostOrder =
true;
616 BlockInfoType *PreferredSucc =
nullptr;
618 auto *
Info = &BlockInfo[Succ];
619 if (!PreferredSucc || PreferredSucc->PostOrder <
Info->PostOrder)
620 PreferredSucc =
Info;
622 assert((PreferredSucc && PreferredSucc->PostOrder > 0) &&
623 "Failed to find safe successor for dead branch");
629 if (!First || Succ != PreferredSucc->BB) {
630 Succ->removePredecessor(BB);
631 RemovedSuccessors.
insert(Succ);
635 makeUnconditional(BB, PreferredSucc->BB);
638 for (
auto *Succ : RemovedSuccessors) {
641 if (Succ != PreferredSucc->BB) {
642 LLVM_DEBUG(
dbgs() <<
"ADCE: (Post)DomTree edge enqueued for deletion"
643 << BB->getName() <<
" -> " << Succ->getName()
645 DeletedEdges.
push_back({DominatorTree::Delete, BB, Succ});
649 NumBranchesRemoved += 1;
653 if (!DeletedEdges.
empty())
661void AggressiveDeadCodeElimination::computeReversePostOrder() {
670 unsigned PostOrder = 0;
675 BlockInfo[
Block].PostOrder = PostOrder++;
679void AggressiveDeadCodeElimination::makeUnconditional(
BasicBlock *BB,
684 collectLiveScopes(*
DL);
689 InstInfo[PredTerm].Live =
true;
693 NumBranchesRemoved += 1;
696 InstInfo[NewTerm].Live =
true;
698 NewTerm->setDebugLoc(
DL);
700 InstInfo.erase(PredTerm);
714 ADCEChanged Changed =
715 AggressiveDeadCodeElimination(
F, DT, PDT).performDeadCodeElimination();
716 if (!Changed.ChangedAnything)
720 if (!Changed.ChangedControlFlow) {
722 if (!Changed.ChangedNonDebugInstr) {
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool isUnconditionalBranch(Instruction *Term)
static cl::opt< bool > RemoveLoops("adce-remove-loops", cl::init(false), cl::Hidden)
static cl::opt< bool > RemoveControlFlowFlag("adce-remove-control-flow", cl::init(true), cl::Hidden)
amdgpu Simplify well known AMD library false FunctionCallee Callee
Analysis containing CSE Info
Looks at all the uses of the given value Returns the Liveness deduced from the uses of this value Adds all uses that cause the result to be MaybeLive to MaybeLiveRetUses If the result is Live
static bool isAlwaysLive(Instruction *I)
This file defines the DenseMap class.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
This is the interface for a simple mod/ref and alias analysis over globals.
This file defines the little GraphTraits<X> template class that should be specialized by classes that...
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
This file implements a map that provides insertion order iteration.
This file exposes an interface to building/using memory SSA to walk memory instructions using a use/d...
print must be executed print the must be executed context for all instructions
FunctionAnalysisManager FAM
This header defines various interfaces for pass management in LLVM.
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, ArrayRef< StringLiteral > StandardNames)
Initialize the set of available library functions based on the specified target triple.
This defines the Use class.
A container for analyses that lazily runs them and caches their results.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Represents analyses that only rely on functions' control flow.
This class represents a function call, abstracting a target machine's calling convention.
void applyUpdates(ArrayRef< DominatorTree::UpdateType > Updates)
Submit updates to all available trees.
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
const BasicBlock * getParent() const
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void setSuccessor(unsigned Idx, BasicBlock *BB)
Update the specified successor to point at the provided block.
This class implements a map that also provides access to all stored values in a deterministic order.
An analysis that produces MemorySSA for a function.
Analysis pass which computes a PostDominatorTree.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserveSet()
Mark an analysis set as preserved.
void preserve()
Mark an analysis as preserved.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Target - Wrapper for Target specific information.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
void dump() const
Support for debugging, callable in GDB: V->dump()
AssignmentInstRange getAssignmentInsts(DIAssignID *ID)
Return a range of instructions (typically just one) that have ID as an attachment.
initializer< Ty > init(const Ty &Val)
const_iterator end(StringRef path)
Get end iterator over path.
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< df_ext_iterator< T, SetTy > > depth_first_ext(const T &G, SetTy &S)
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
bool succ_empty(const Instruction *I)
iterator_range< ipo_ext_iterator< T, SetType > > inverse_post_order_ext(const T &G, SetType &S)
void salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI)
Assuming the instruction MI is going to be deleted, attempt to salvage debug users of MI by writing t...
auto successors(const MachineBasicBlock *BB)
auto reverse(ContainerTy &&C)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto predecessors(const MachineBasicBlock *BB)
StringRef getInstrProfValueProfFuncName()
Return the name profile runtime entry point to do value profiling for a given site.
iterator_range< df_iterator< T > > depth_first(const T &G)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &)