Add FastDLE, the load-elimination counterpart of FastDSE.
authorOwen Anderson <resistor@mac.com>
Mon, 23 Jul 2007 21:48:08 +0000 (21:48 +0000)
committerOwen Anderson <resistor@mac.com>
Mon, 23 Jul 2007 21:48:08 +0000 (21:48 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40445 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Transforms/Scalar.h
lib/Transforms/Scalar/FastDLE.cpp [new file with mode: 0644]

index 4fea3f73be17efe8912ef5288abfd72d36060b55..59306dceaca387ffee62bb8912948758f3407138 100644 (file)
@@ -330,6 +330,13 @@ FunctionPass *createGVNPREPass();
 //
 FunctionPass *createFastDeadStoreEliminationPass();
 
+//===----------------------------------------------------------------------===//
+//
+// FastDeadStoreElimination - This pass deletes loads that are dominated by
+// must-aliased loads and are not stored to between the loads.
+//
+FunctionPass *createFastDeadLoadEliminationPass();
+
 //===----------------------------------------------------------------------===//
 //
 // CodeGenPrepare - This pass prepares a function for instruction selection.
diff --git a/lib/Transforms/Scalar/FastDLE.cpp b/lib/Transforms/Scalar/FastDLE.cpp
new file mode 100644 (file)
index 0000000..001f834
--- /dev/null
@@ -0,0 +1,128 @@
+//===- 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 "fdle"
+#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 FDLE : public FunctionPass {
+    static char ID; // Pass identification, replacement for typeid
+    FDLE() : 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<MemoryDependenceAnalysis>();
+      AU.addPreserved<MemoryDependenceAnalysis>();
+    }
+  };
+  char FDLE::ID = 0;
+  RegisterPass<FDLE> X("fdle", "Fast Dead Load Elimination");
+}
+
+FunctionPass *llvm::createFastDeadLoadEliminationPass() { return new FDLE(); }
+
+bool FDLE::runOnBasicBlock(BasicBlock &BB) {
+  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
+  
+  // Record the last-seen load from this pointer
+  DenseMap<Value*, LoadInst*> 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<LoadInst>(BBI)) {
+      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<LoadInst>(dep) || isa<StoreInst>(dep))) {
+        // ... that depends on a store ...
+        if (StoreInst* S = dyn_cast<StoreInst>(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;
+}
+
+