Changes For Bug 352
[oota-llvm.git] / lib / Transforms / IPO / GlobalOpt.cpp
index 6f01f25f507478a2851383c202fbb9e93aa246f8..dd9894cd19f30bfdb83b405e3ccd65f8bb53ad76 100644 (file)
@@ -23,8 +23,9 @@
 #include "llvm/Instructions.h"
 #include "llvm/Module.h"
 #include "llvm/Pass.h"
-#include "Support/Debug.h"
-#include "Support/Statistic.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/ADT/Statistic.h"
+#include <set>
 using namespace llvm;
 
 namespace {
@@ -39,19 +40,39 @@ namespace {
 
 Pass *llvm::createGlobalConstifierPass() { return new Constifier(); }
 
+/// A lot of global constants are stored only in trivially dead setter
+/// functions.  Because we don't want to cycle between globaldce and this pass,
+/// just do a simple check to catch the common case.
+static bool ContainingFunctionIsTriviallyDead(Instruction *I) {
+  Function *F = I->getParent()->getParent();
+  if (!F->hasInternalLinkage()) return false;
+  F->removeDeadConstantUsers();
+  return F->use_empty();
+}
+
 /// isStoredThrough - Return false if the specified pointer is provably never
 /// stored through.  If we can't tell, we must conservatively assume it might.
 ///
-static bool isStoredThrough(Value *V) {
+static bool isStoredThrough(Value *V, std::set<PHINode*> &PHIUsers) {
   for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI)
     if (ConstantExpr *CE = dyn_cast<ConstantExpr>(*UI)) {
-      if (isStoredThrough(CE))
+      if (isStoredThrough(CE, PHIUsers))
         return true;
     } else if (Instruction *I = dyn_cast<Instruction>(*UI)) {
-      if (I->getOpcode() == Instruction::GetElementPtr) {
-        if (isStoredThrough(I)) return true;
-      } else if (!isa<LoadInst>(*UI) && !isa<SetCondInst>(*UI))
-        return true;  // Any other non-load instruction might store!
+      if (!ContainingFunctionIsTriviallyDead(I)) {
+        if (I->getOpcode() == Instruction::GetElementPtr ||
+            I->getOpcode() == Instruction::Select) {
+          if (isStoredThrough(I, PHIUsers)) return true;
+        } else if (PHINode *PN = dyn_cast<PHINode>(I)) {
+          // PHI nodes we can check just like select or GEP instructions, but we
+          // have to be careful about infinite recursion.
+          if (PHIUsers.insert(PN).second)  // Not already visited.
+            if (isStoredThrough(I, PHIUsers)) return true;
+
+        } else if (!isa<LoadInst>(I) && !isa<SetCondInst>(I)) {
+          return true;  // Any other non-load instruction might store!
+        }
+      }
     } else {
       // Otherwise must be a global or some other user.
       return true;
@@ -62,14 +83,16 @@ static bool isStoredThrough(Value *V) {
 
 bool Constifier::run(Module &M) {
   bool Changed = false;
+  std::set<PHINode*> PHIUsers;
   for (Module::giterator GV = M.gbegin(), E = M.gend(); GV != E; ++GV)
     if (!GV->isConstant() && GV->hasInternalLinkage() && GV->hasInitializer()) {
-      if (!isStoredThrough(GV)) {
+      if (!isStoredThrough(GV, PHIUsers)) {
         DEBUG(std::cerr << "MARKING CONSTANT: " << *GV << "\n");
         GV->setConstant(true);
         ++NumMarked;
         Changed = true;
       }
+      PHIUsers.clear();
     }
   return Changed;
 }