diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Transforms/IPO/GlobalOpt.cpp | 55 |
1 files changed, 52 insertions, 3 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index f37be86e1e..3a5a351a3a 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -26,10 +26,12 @@ #include "llvm/Support/Debug.h" #include "llvm/ADT/Statistic.h" #include <set> +#include <algorithm> using namespace llvm; namespace { - Statistic<> NumMarked("constify", "Number of globals marked constant"); + Statistic<> NumMarked ("constify", "Number of globals marked constant"); + Statistic<> NumDeleted("constify", "Number of globals deleted"); struct Constifier : public ModulePass { bool runOnModule(Module &M); @@ -50,6 +52,7 @@ static bool ContainingFunctionIsTriviallyDead(Instruction *I) { 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. /// @@ -68,7 +71,16 @@ static bool isStoredThrough(Value *V, std::set<PHINode*> &PHIUsers) { // have to be careful about infinite recursion. if (PHIUsers.insert(PN).second) // Not already visited. if (isStoredThrough(I, PHIUsers)) return true; - + } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { + // If this store is just storing the initializer into a global + // (i.e. not changing the value), ignore it. For now we just handle + // direct stores, no stores to fields of aggregates. + if (!isa<GlobalVariable>(SI->getOperand(1))) + return true; + Constant *GVInit = + cast<GlobalVariable>(SI->getOperand(1))->getInitializer(); + if (SI->getOperand(0) != GVInit) + return true; } else if (!isa<LoadInst>(I) && !isa<SetCondInst>(I)) { return true; // Any other non-load instruction might store! } @@ -81,18 +93,55 @@ static bool isStoredThrough(Value *V, std::set<PHINode*> &PHIUsers) { return false; } +/// CleanupConstantGlobalUsers - We just marked GV constant. Loop over all +/// users of the global, cleaning up the obvious ones. This is largely just a +/// quick scan over the use list to clean up the easy and obvious cruft. +static void CleanupConstantGlobalUsers(GlobalVariable *GV) { + Constant *Init = GV->getInitializer(); + if (!Init->getType()->isFirstClassType()) + return; // We can't simplify aggregates yet! + + std::vector<User*> Users(GV->use_begin(), GV->use_end()); + + std::sort(Users.begin(), Users.end()); + Users.erase(std::unique(Users.begin(), Users.end()), Users.end()); + for (unsigned i = 0, e = Users.size(); i != e; ++i) { + if (LoadInst *LI = dyn_cast<LoadInst>(Users[i])) { + // Replace the load with the initializer. + LI->replaceAllUsesWith(Init); + LI->getParent()->getInstList().erase(LI); + } else if (StoreInst *SI = dyn_cast<StoreInst>(Users[i])) { + // Store must be unreachable or storing Init into the global. + SI->getParent()->getInstList().erase(SI); + } + } +} + + bool Constifier::runOnModule(Module &M) { bool Changed = false; std::set<PHINode*> PHIUsers; - for (Module::giterator GV = M.gbegin(), E = M.gend(); GV != E; ++GV) + for (Module::giterator GVI = M.gbegin(), E = M.gend(); GVI != E;) { + GlobalVariable *GV = GVI++; if (!GV->isConstant() && GV->hasInternalLinkage() && GV->hasInitializer()) { if (!isStoredThrough(GV, PHIUsers)) { DEBUG(std::cerr << "MARKING CONSTANT: " << *GV << "\n"); GV->setConstant(true); + + // Clean up any obviously simplifiable users now. + CleanupConstantGlobalUsers(GV); + + // If the global is dead now, just nuke it. + if (GV->use_empty()) { + M.getGlobalList().erase(GV); + ++NumDeleted; + } + ++NumMarked; Changed = true; } PHIUsers.clear(); } + } return Changed; } |