Add FastDSE, a new algorithm for doing dead store elimination. This algorithm is...
authorOwen Anderson <resistor@mac.com>
Wed, 11 Jul 2007 00:46:18 +0000 (00:46 +0000)
committerOwen Anderson <resistor@mac.com>
Wed, 11 Jul 2007 00:46:18 +0000 (00:46 +0000)
as the current DSE, but it only a linear scan over each block, rather than quadratic.  Eventually
(once it has been improved somewhat), this will replace the current DSE.

NOTE: This has not yet been extensively tested.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@38517 91177308-0d34-0410-b5e6-96231b3b80d8

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

index be98f074b76d37163342bf55415f640d2c9b38c6..b445ba05be8c88480c557ba32136179976d7d13a 100644 (file)
@@ -61,6 +61,7 @@ namespace {
       (void) llvm::createDeadStoreEliminationPass();
       (void) llvm::createDeadTypeEliminationPass();
       (void) llvm::createEdgeProfilerPass();
+      (void) llvm::createFastDeadStoreEliminationPass();
       (void) llvm::createFunctionInliningPass();
       (void) llvm::createFunctionProfilerPass();
       (void) llvm::createGCSEPass();
index 948d6b5aaed5d543a8627db20e876a72a990d2d3..ff12dc9ab7b2f53451b47fcfb8457c697a31d1e2 100644 (file)
@@ -323,6 +323,13 @@ FunctionPass *createPredicateSimplifierPass();
 //
 FunctionPass *createGVNPREPass();
 
+//===----------------------------------------------------------------------===//
+//
+// FastDeadStoreElimination - This pass deletes stores that are post-dominated by
+// must-aliased stores and are not loaded used between the stores.
+//
+FunctionPass *createFastDeadStoreEliminationPass();
+
 //===----------------------------------------------------------------------===//
 //
 // CodeGenPrepare - This pass prepares a function for instruction selection.
diff --git a/lib/Transforms/Scalar/FastDSE.cpp b/lib/Transforms/Scalar/FastDSE.cpp
new file mode 100644 (file)
index 0000000..10873cd
--- /dev/null
@@ -0,0 +1,130 @@
+//===- DeadStoreElimination.cpp - Dead Store Elimination ------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group 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<Instruction*> &DeadInsts);
+
+    // 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 FDSE::ID = 0;
+  RegisterPass<FDSE> X("fdse", "Fast Dead Store Elimination");
+}
+
+FunctionPass *llvm::createFastDeadStoreEliminationPass() { return new FDSE(); }
+
+bool FDSE::runOnBasicBlock(BasicBlock &BB) {
+  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
+  
+  DenseMap<Value*, StoreInst*> lastStore;
+  SetVector<Instruction*> 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...
+    if (StoreInst* S = dyn_cast<StoreInst>(BBI)) {
+      
+      // ... to a pointer that has been stored to before...
+      if (lastStore.count(S->getPointerOperand())) {
+        StoreInst* last = lastStore[S->getPointerOperand()];
+        
+        // ... and no other memory dependencies are between them....
+        if (MD.getDependency(S) == last) {
+          // Remove it!
+          MD.removeInstruction(last);
+          
+          // DCE instructions only used to calculate that store
+          if (Instruction* D = dyn_cast<Instruction>(last->getOperand(0)))
+            possiblyDead.insert(D);
+          
+          last->eraseFromParent();
+          NumFastStores++;
+          MadeChange = true;
+        }
+      }
+      
+      // Update our most-recent-store map
+      lastStore.insert(std::make_pair(S->getPointerOperand(), S));
+    }
+  }
+  
+  // 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<Instruction*> &DeadInsts) {
+  // Instruction must be dead.
+  if (!I->use_empty() || !isInstructionTriviallyDead(I)) return;
+
+  // Let the memory dependence know
+  getAnalysis<MemoryDependenceAnalysis>().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 (Instruction *Op = dyn_cast<Instruction>(I->getOperand(i)))
+      DeadInsts.insert(Op);      // Attempt to nuke it later.
+    I->setOperand(i, 0);         // Drop from the operand list.
+  }
+
+  I->eraseFromParent();
+  ++NumFastOther;
+}