| //===- DCE.cpp - Code to perform dead code elimination --------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements dead inst elimination and dead code elimination. |
| // |
| // Dead Inst Elimination performs a single pass over the function removing |
| // instructions that are obviously dead. Dead Code Elimination is similar, but |
| // it rechecks instructions that were used by removed instructions to see if |
| // they are newly dead. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Transforms/Scalar/DCE.h" |
| #include "llvm/ADT/SetVector.h" |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/Analysis/TargetLibraryInfo.h" |
| #include "llvm/Transforms/Utils/Local.h" |
| #include "llvm/IR/InstIterator.h" |
| #include "llvm/IR/Instruction.h" |
| #include "llvm/Pass.h" |
| #include "llvm/Transforms/Scalar.h" |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "dce" |
| |
| STATISTIC(DIEEliminated, "Number of insts removed by DIE pass"); |
| STATISTIC(DCEEliminated, "Number of insts removed"); |
| |
| namespace { |
| //===--------------------------------------------------------------------===// |
| // DeadInstElimination pass implementation |
| // |
| struct DeadInstElimination : public BasicBlockPass { |
| static char ID; // Pass identification, replacement for typeid |
| DeadInstElimination() : BasicBlockPass(ID) { |
| initializeDeadInstEliminationPass(*PassRegistry::getPassRegistry()); |
| } |
| bool runOnBasicBlock(BasicBlock &BB) override { |
| if (skipBasicBlock(BB)) |
| return false; |
| auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>(); |
| TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI() : nullptr; |
| bool Changed = false; |
| for (BasicBlock::iterator DI = BB.begin(); DI != BB.end(); ) { |
| Instruction *Inst = &*DI++; |
| if (isInstructionTriviallyDead(Inst, TLI)) { |
| salvageDebugInfo(*Inst); |
| Inst->eraseFromParent(); |
| Changed = true; |
| ++DIEEliminated; |
| } |
| } |
| return Changed; |
| } |
| |
| void getAnalysisUsage(AnalysisUsage &AU) const override { |
| AU.setPreservesCFG(); |
| } |
| }; |
| } |
| |
| char DeadInstElimination::ID = 0; |
| INITIALIZE_PASS(DeadInstElimination, "die", |
| "Dead Instruction Elimination", false, false) |
| |
| Pass *llvm::createDeadInstEliminationPass() { |
| return new DeadInstElimination(); |
| } |
| |
| static bool DCEInstruction(Instruction *I, |
| SmallSetVector<Instruction *, 16> &WorkList, |
| const TargetLibraryInfo *TLI) { |
| if (isInstructionTriviallyDead(I, TLI)) { |
| salvageDebugInfo(*I); |
| |
| // Null out all of the instruction's operands to see if any operand becomes |
| // dead as we go. |
| for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { |
| Value *OpV = I->getOperand(i); |
| I->setOperand(i, nullptr); |
| |
| if (!OpV->use_empty() || I == OpV) |
| continue; |
| |
| // If the operand is an instruction that became dead as we nulled out the |
| // operand, and if it is 'trivially' dead, delete it in a future loop |
| // iteration. |
| if (Instruction *OpI = dyn_cast<Instruction>(OpV)) |
| if (isInstructionTriviallyDead(OpI, TLI)) |
| WorkList.insert(OpI); |
| } |
| |
| I->eraseFromParent(); |
| ++DCEEliminated; |
| return true; |
| } |
| return false; |
| } |
| |
| static bool eliminateDeadCode(Function &F, TargetLibraryInfo *TLI) { |
| bool MadeChange = false; |
| SmallSetVector<Instruction *, 16> WorkList; |
| // Iterate over the original function, only adding insts to the worklist |
| // if they actually need to be revisited. This avoids having to pre-init |
| // the worklist with the entire function's worth of instructions. |
| for (inst_iterator FI = inst_begin(F), FE = inst_end(F); FI != FE;) { |
| Instruction *I = &*FI; |
| ++FI; |
| |
| // We're visiting this instruction now, so make sure it's not in the |
| // worklist from an earlier visit. |
| if (!WorkList.count(I)) |
| MadeChange |= DCEInstruction(I, WorkList, TLI); |
| } |
| |
| while (!WorkList.empty()) { |
| Instruction *I = WorkList.pop_back_val(); |
| MadeChange |= DCEInstruction(I, WorkList, TLI); |
| } |
| return MadeChange; |
| } |
| |
| PreservedAnalyses DCEPass::run(Function &F, FunctionAnalysisManager &AM) { |
| if (!eliminateDeadCode(F, AM.getCachedResult<TargetLibraryAnalysis>(F))) |
| return PreservedAnalyses::all(); |
| |
| PreservedAnalyses PA; |
| PA.preserveSet<CFGAnalyses>(); |
| return PA; |
| } |
| |
| namespace { |
| struct DCELegacyPass : public FunctionPass { |
| static char ID; // Pass identification, replacement for typeid |
| DCELegacyPass() : FunctionPass(ID) { |
| initializeDCELegacyPassPass(*PassRegistry::getPassRegistry()); |
| } |
| |
| bool runOnFunction(Function &F) override { |
| if (skipFunction(F)) |
| return false; |
| |
| auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>(); |
| TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI() : nullptr; |
| |
| return eliminateDeadCode(F, TLI); |
| } |
| |
| void getAnalysisUsage(AnalysisUsage &AU) const override { |
| AU.setPreservesCFG(); |
| } |
| }; |
| } |
| |
| char DCELegacyPass::ID = 0; |
| INITIALIZE_PASS(DCELegacyPass, "dce", "Dead Code Elimination", false, false) |
| |
| FunctionPass *llvm::createDeadCodeEliminationPass() { |
| return new DCELegacyPass(); |
| } |