//===- DeadStoreElimination.cpp - Dead Store Elimination ------------------===// // // The LLVM Compiler Infrastructure // // This file was developed by Owen Anderson and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements a trivial dead store elimination that only considers // basic-block local redundant stores. // // FIXME: This should eventually be extended to be a post-dominator tree // traversal. Doing so would be pretty trivial. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "fdse" #include "llvm/Transforms/Scalar.h" #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/Pass.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/MemoryDependenceAnalysis.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Support/Compiler.h" using namespace llvm; STATISTIC(NumFastStores, "Number of stores deleted"); STATISTIC(NumFastOther , "Number of other instrs removed"); namespace { struct VISIBILITY_HIDDEN FDSE : public FunctionPass { static char ID; // Pass identification, replacement for typeid FDSE() : FunctionPass((intptr_t)&ID) {} virtual bool runOnFunction(Function &F) { bool Changed = false; for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) Changed |= runOnBasicBlock(*I); return Changed; } bool runOnBasicBlock(BasicBlock &BB); void DeleteDeadInstructionChains(Instruction *I, SetVector &DeadInsts); // getAnalysisUsage - We require post dominance frontiers (aka Control // Dependence Graph) virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); AU.addRequired(); AU.addPreserved(); } }; char FDSE::ID = 0; RegisterPass X("fdse", "Fast Dead Store Elimination"); } FunctionPass *llvm::createFastDeadStoreEliminationPass() { return new FDSE(); } bool FDSE::runOnBasicBlock(BasicBlock &BB) { MemoryDependenceAnalysis& MD = getAnalysis(); // Record the last-seen store to this pointer DenseMap lastStore; // Record instructions possibly made dead by deleting a store SetVector possiblyDead; bool MadeChange = false; // Do a top-down walk on the BB for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; ++BBI) { // If we find a store or a free... if (isa(BBI) || isa(BBI)) { Value* pointer = 0; if (StoreInst* S = dyn_cast(BBI)) pointer = S->getPointerOperand(); else if (FreeInst* F = dyn_cast(BBI)) pointer = F->getPointerOperand(); assert(pointer && "Not a free or a store?"); StoreInst*& last = lastStore[pointer]; // ... to a pointer that has been stored to before... if (last) { // ... and no other memory dependencies are between them.... if (MD.getDependency(BBI) == last) { // Remove it! MD.removeInstruction(last); // DCE instructions only used to calculate that store if (Instruction* D = dyn_cast(last->getOperand(0))) possiblyDead.insert(D); last->eraseFromParent(); NumFastStores++; MadeChange = true; } } // Update our most-recent-store map if (StoreInst* S = dyn_cast(BBI)) last = S; else last = 0; } } // If this block ends in a return, unwind, unreachable, and eventually // tailcall, then all allocas are dead at its end. if (BB.getTerminator()->getNumSuccessors() == 0) { // Pointers alloca'd in this function are dead in the end block SmallPtrSet deadPointers; // Find all of the alloca'd pointers in the entry block BasicBlock *Entry = BB.getParent()->begin(); for (BasicBlock::iterator I = Entry->begin(), E = Entry->end(); I != E; ++I) if (AllocaInst *AI = dyn_cast(I)) deadPointers.insert(AI); // Scan the basic block backwards for (BasicBlock::iterator BBI = BB.end(); BBI != BB.begin(); ){ --BBI; if (deadPointers.empty()) break; // If we find a store whose pointer is dead... if (StoreInst* S = dyn_cast(BBI)) { if (deadPointers.count(S->getPointerOperand())){ // Remove it! MD.removeInstruction(S); // DCE instructions only used to calculate that store if (Instruction* D = dyn_cast(S->getOperand(0))) possiblyDead.insert(D); BBI++; S->eraseFromParent(); NumFastStores++; MadeChange = true; } // If we encounter a use of the pointer, it is no longer considered dead } else if (LoadInst* L = dyn_cast(BBI)) { deadPointers.erase(L->getPointerOperand()); } else if (VAArgInst* V = dyn_cast(BBI)) { deadPointers.erase(V->getOperand(0)); } } } // Do a trivial DCE while (!possiblyDead.empty()) { Instruction *I = possiblyDead.back(); possiblyDead.pop_back(); DeleteDeadInstructionChains(I, possiblyDead); } return MadeChange; } void FDSE::DeleteDeadInstructionChains(Instruction *I, SetVector &DeadInsts) { // Instruction must be dead. if (!I->use_empty() || !isInstructionTriviallyDead(I)) return; // Let the memory dependence know getAnalysis().removeInstruction(I); // See if this made any operands dead. We do it this way in case the // instruction uses the same operand twice. We don't want to delete a // value then reference it. for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { if (I->getOperand(i)->hasOneUse()) if (Instruction* Op = dyn_cast(I->getOperand(i))) DeadInsts.insert(Op); // Attempt to nuke it later. I->setOperand(i, 0); // Drop from the operand list. } I->eraseFromParent(); ++NumFastOther; }