//===- FastDLE.cpp - Fast Dead Load 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 load elimination that only considers // basic-block local redundant load. // // FIXME: This should eventually be extended to be a post-dominator tree // traversal. Doing so would be pretty trivial. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "rle" #include "llvm/Transforms/Scalar.h" #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/Pass.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(NumFastLoads, "Number of loads deleted"); namespace { struct VISIBILITY_HIDDEN RLE : public FunctionPass { static char ID; // Pass identification, replacement for typeid RLE() : 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); // getAnalysisUsage - We require post dominance frontiers (aka Control // Dependence Graph) virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); AU.addRequired(); AU.addPreserved(); } }; char RLE::ID = 0; RegisterPass X("rle", "Redundant Load Elimination"); } FunctionPass *llvm::createRedundantLoadEliminationPass() { return new RLE(); } bool RLE::runOnBasicBlock(BasicBlock &BB) { MemoryDependenceAnalysis& MD = getAnalysis(); // Record the last-seen load from this pointer DenseMap lastLoad; 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 (LoadInst* L = dyn_cast(BBI)) { // We can't delete volatile loads if (L->isVolatile()) { lastLoad[L->getPointerOperand()] = L; continue; } Value* pointer = L->getPointerOperand(); LoadInst*& last = lastLoad[pointer]; // ... to a pointer that has been loaded from before... Instruction* dep = MD.getDependency(BBI); bool deletedLoad = false; while (dep != MemoryDependenceAnalysis::None && dep != MemoryDependenceAnalysis::NonLocal && (isa(dep) || isa(dep))) { // ... that depends on a store ... if (StoreInst* S = dyn_cast(dep)) { if (S->getPointerOperand() == pointer) { // Remove it! MD.removeInstruction(BBI); BBI--; L->replaceAllUsesWith(S->getOperand(0)); L->eraseFromParent(); NumFastLoads++; deletedLoad = true; MadeChange = true; } // Whether we removed it or not, we can't // go any further break; } else if (!last) { // If we don't depend on a store, and we haven't // been loaded before, bail. break; } else if (dep == last) { // Remove it! MD.removeInstruction(BBI); BBI--; L->replaceAllUsesWith(last); L->eraseFromParent(); deletedLoad = true; NumFastLoads++; MadeChange = true; break; } else { dep = MD.getDependency(BBI, dep); } } if (!deletedLoad) last = L; } } return MadeChange; }