X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTransforms%2FIPO%2FGlobalDCE.cpp;h=9b276ed28e2e0e14604c97a78f5608747b4e492d;hb=ebe537a930b58a5d32fc41ac133309139c92f7bd;hp=5ce79625b84b72b9a3ec384ed4e59f55c4b0da88;hpb=c9d3e5721b4e7c566a5e3fa4d312ebc6ba935f95;p=oota-llvm.git diff --git a/lib/Transforms/IPO/GlobalDCE.cpp b/lib/Transforms/IPO/GlobalDCE.cpp index 5ce79625b84..9b276ed28e2 100644 --- a/lib/Transforms/IPO/GlobalDCE.cpp +++ b/lib/Transforms/IPO/GlobalDCE.cpp @@ -1,260 +1,256 @@ //===-- GlobalDCE.cpp - DCE unreachable internal functions ----------------===// // -// This transform is designed to eliminate unreachable internal globals -// FIXME: GlobalDCE should update the callgraph, not destroy it! +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This transform is designed to eliminate unreachable internal globals from the +// program. It uses an aggressive algorithm, searching out globals that are +// known to be alive. After it finds all of the globals which are needed, it +// deletes whatever is left over. This allows it to delete recursive chunks of +// the program which are unreachable. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO.h" -#include "llvm/Module.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Analysis/CallGraph.h" -#include "Support/DepthFirstIterator.h" -#include "Support/Statistic.h" -#include +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Transforms/Utils/CtorUtils.h" +#include "llvm/Transforms/Utils/GlobalStatus.h" +#include "llvm/Pass.h" +#include +using namespace llvm; + +#define DEBUG_TYPE "globaldce" + +STATISTIC(NumAliases , "Number of global aliases removed"); +STATISTIC(NumFunctions, "Number of functions removed"); +STATISTIC(NumVariables, "Number of global variables removed"); namespace { - Statistic<> NumFunctions("globaldce","Number of functions removed"); - Statistic<> NumVariables("globaldce","Number of global variables removed"); - Statistic<> NumCPRs("globaldce", "Number of const pointer refs removed"); - Statistic<> NumConsts("globaldce", "Number of init constants removed"); - - bool RemoveUnreachableFunctions(Module &M, CallGraph &CallGraph) { - // Calculate which functions are reachable from the external functions in - // the call graph. - // - std::set ReachableNodes(df_begin(&CallGraph), - df_end(&CallGraph)); - - // Loop over the functions in the module twice. The first time is used to - // drop references that functions have to each other before they are - // deleted. The second pass removes the functions that need to be removed. - // - std::vector FunctionsToDelete; // Track unused functions - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { - CallGraphNode *N = CallGraph[I]; - - if (!ReachableNodes.count(N)) { // Not reachable?? - I->dropAllReferences(); - N->removeAllCalledFunctions(); - FunctionsToDelete.push_back(N); - ++NumFunctions; - } + struct GlobalDCE : public ModulePass { + static char ID; // Pass identification, replacement for typeid + GlobalDCE() : ModulePass(ID) { + initializeGlobalDCEPass(*PassRegistry::getPassRegistry()); } - - // Nothing to do if no unreachable functions have been found... - if (FunctionsToDelete.empty()) return false; - - // Unreachable functions have been found and should have no references to - // them, delete them now. - // - for (std::vector::iterator I = FunctionsToDelete.begin(), - E = FunctionsToDelete.end(); I != E; ++I) - delete CallGraph.removeFunctionFromModule(*I); - - // Walk the function list, removing prototypes for functions which are not - // used. - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->use_size() == 0 && I->isExternal()) { - CallGraph[I]->removeAllCalledFunctions(); - delete CallGraph.removeFunctionFromModule(I); - } - return true; - } - - struct GlobalDCE : public Pass { // run - Do the GlobalDCE pass on the specified module, optionally updating // the specified callgraph to reflect the changes. // - bool run(Module &M) { - return RemoveUnreachableFunctions(M, getAnalysis()) | - RemoveUnreachableGlobalVariables(M); - } - - // getAnalysisUsage - This function works on the call graph of a module. - // It is capable of updating the call graph to reflect the new state of the - // module. - // - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - } + bool runOnModule(Module &M) override; private: - std::vector WorkList; + SmallPtrSet AliveGlobals; + SmallPtrSet SeenConstants; + std::unordered_multimap ComdatMembers; - inline bool RemoveIfDead(GlobalValue *GV); - void DestroyInitializer(Constant *C); + /// GlobalIsNeeded - mark the specific global value as needed, and + /// recursively mark anything that it uses as also needed. + void GlobalIsNeeded(GlobalValue *GV); + void MarkUsedGlobalsAsNeeded(Constant *C); - bool RemoveUnreachableGlobalVariables(Module &M); - bool RemoveUnusedConstantPointerRef(GlobalValue &GV); - bool SafeToDestroyConstant(Constant *C); + bool RemoveUnusedGlobalValue(GlobalValue &GV); }; - RegisterOpt X("globaldce", "Dead Global Elimination"); } -Pass *createGlobalDCEPass() { return new GlobalDCE(); } +/// Returns true if F contains only a single "ret" instruction. +static bool isEmptyFunction(Function *F) { + BasicBlock &Entry = F->getEntryBlock(); + if (Entry.size() != 1 || !isa(Entry.front())) + return false; + ReturnInst &RI = cast(Entry.front()); + return RI.getReturnValue() == nullptr; +} +char GlobalDCE::ID = 0; +INITIALIZE_PASS(GlobalDCE, "globaldce", + "Dead Global Elimination", false, false) -// RemoveIfDead - If this global value is dead, remove it from the current -// module and return true. -// -bool GlobalDCE::RemoveIfDead(GlobalValue *GV) { - // If there is only one use of the global value, it might be a - // ConstantPointerRef... which means that this global might actually be - // dead. - if (GV->use_size() == 1) - RemoveUnusedConstantPointerRef(*GV); - - if (!GV->use_empty()) return false; - - if (GlobalVariable *GVar = dyn_cast(GV)) { - // Eliminate all global variables that are unused, and that are internal, or - // do not have an initializer. - // - if (GVar->hasInternalLinkage() || GVar->isExternal()) { - Constant *Init = GVar->hasInitializer() ? GVar->getInitializer() : 0; - GV->getParent()->getGlobalList().erase(GVar); - ++NumVariables; - - // If there was an initializer for the global variable, try to destroy it - // now. - if (Init) DestroyInitializer(Init); - - // If the global variable is still on the worklist, remove it now. - std::vector::iterator I = std::find(WorkList.begin(), - WorkList.end(), GV); - while (I != WorkList.end()) { - I = WorkList.erase(I); - I = std::find(I, WorkList.end(), GV); - } +ModulePass *llvm::createGlobalDCEPass() { return new GlobalDCE(); } - return true; - } - } else { - Function *F = cast(GV); - // FIXME: TODO +bool GlobalDCE::runOnModule(Module &M) { + bool Changed = false; + // Remove empty functions from the global ctors list. + Changed |= optimizeGlobalCtorsList(M, isEmptyFunction); + + // Collect the set of members for each comdat. + for (Function &F : M) + if (Comdat *C = F.getComdat()) + ComdatMembers.insert(std::make_pair(C, &F)); + for (GlobalVariable &GV : M.globals()) + if (Comdat *C = GV.getComdat()) + ComdatMembers.insert(std::make_pair(C, &GV)); + for (GlobalAlias &GA : M.aliases()) + if (Comdat *C = GA.getComdat()) + ComdatMembers.insert(std::make_pair(C, &GA)); + + // Loop over the module, adding globals which are obviously necessary. + for (Function &F : M) { + Changed |= RemoveUnusedGlobalValue(F); + // Functions with external linkage are needed if they have a body + if (!F.isDeclaration() && !F.hasAvailableExternallyLinkage()) + if (!F.isDiscardableIfUnused()) + GlobalIsNeeded(&F); } - return false; -} -// DestroyInitializer - A global variable was just destroyed and C is its -// initializer. If we can, destroy C and all of the constants it refers to. -// -void GlobalDCE::DestroyInitializer(Constant *C) { - // Cannot destroy constants still being used, and cannot destroy primitive - // types. - if (!C->use_empty() || C->getType()->isPrimitiveType()) return; + for (GlobalVariable &GV : M.globals()) { + Changed |= RemoveUnusedGlobalValue(GV); + // Externally visible & appending globals are needed, if they have an + // initializer. + if (!GV.isDeclaration() && !GV.hasAvailableExternallyLinkage()) + if (!GV.isDiscardableIfUnused()) + GlobalIsNeeded(&GV); + } + + for (GlobalAlias &GA : M.aliases()) { + Changed |= RemoveUnusedGlobalValue(GA); + // Externally visible aliases are needed. + if (!GA.isDiscardableIfUnused()) + GlobalIsNeeded(&GA); + } - // If this is a CPR, the global value referred to may be dead now! Add it to - // the worklist. + // Now that all globals which are needed are in the AliveGlobals set, we loop + // through the program, deleting those which are not alive. // - if (ConstantPointerRef *CPR = dyn_cast(C)) { - WorkList.push_back(CPR->getValue()); - C->destroyConstant(); - ++NumCPRs; - } else { - bool DestroyContents = true; - // As an optimization to the GlobalDCE algorithm, do attempt to destroy the - // contents of an array of primitive types, because we know that this will - // never succeed, and there could be a lot of them. - // - if (ConstantArray *CA = dyn_cast(C)) - if (CA->getType()->getElementType()->isPrimitiveType()) - DestroyContents = false; // Nothing we can do with the subcontents + // The first pass is to drop initializers of global variables which are dead. + std::vector DeadGlobalVars; // Keep track of dead globals + for (GlobalVariable &GV : M.globals()) + if (!AliveGlobals.count(&GV)) { + DeadGlobalVars.push_back(&GV); // Keep track of dead globals + if (GV.hasInitializer()) { + Constant *Init = GV.getInitializer(); + GV.setInitializer(nullptr); + if (isSafeToDestroyConstant(Init)) + Init->destroyConstant(); + } + } - // All other constants refer to other constants. Destroy them if possible - // as well. - // - std::vector SubConstants; - if (DestroyContents) SubConstants.insert(SubConstants.end(), - C->op_begin(), C->op_end()); - - // Destroy the actual constant... - C->destroyConstant(); - ++NumConsts; - - if (DestroyContents) { - // Remove duplicates from SubConstants, so that we do not call - // DestroyInitializer on the same constant twice (the first call might - // delete it, so this would be bad) - // - std::sort(SubConstants.begin(), SubConstants.end()); - SubConstants.erase(std::unique(SubConstants.begin(), SubConstants.end()), - SubConstants.end()); - - // Loop over the subconstants, destroying them as well. - for (unsigned i = 0, e = SubConstants.size(); i != e; ++i) - DestroyInitializer(cast(SubConstants[i])); + // The second pass drops the bodies of functions which are dead... + std::vector DeadFunctions; + for (Function &F : M) + if (!AliveGlobals.count(&F)) { + DeadFunctions.push_back(&F); // Keep track of dead globals + if (!F.isDeclaration()) + F.deleteBody(); } - } -} -bool GlobalDCE::RemoveUnreachableGlobalVariables(Module &M) { - bool Changed = false; - WorkList.reserve(M.gsize()); + // The third pass drops targets of aliases which are dead... + std::vector DeadAliases; + for (GlobalAlias &GA : M.aliases()) + if (!AliveGlobals.count(&GA)) { + DeadAliases.push_back(&GA); + GA.setAliasee(nullptr); + } - // Insert all of the globals into the WorkList, making sure to run - // RemoveUnusedConstantPointerRef at least once on all globals... - // - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { - Changed |= RemoveUnusedConstantPointerRef(*I); - WorkList.push_back(I); - } - for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { - Changed |= RemoveUnusedConstantPointerRef(*I); - WorkList.push_back(I); + if (!DeadFunctions.empty()) { + // Now that all interferences have been dropped, delete the actual objects + // themselves. + for (Function *F : DeadFunctions) { + RemoveUnusedGlobalValue(*F); + M.getFunctionList().erase(F); + } + NumFunctions += DeadFunctions.size(); + Changed = true; } - // Loop over the worklist, deleting global objects that we can. Whenever we - // delete something that might make something else dead, it gets added to the - // worklist. - // - while (!WorkList.empty()) { - GlobalValue *GV = WorkList.back(); - WorkList.pop_back(); + if (!DeadGlobalVars.empty()) { + for (GlobalVariable *GV : DeadGlobalVars) { + RemoveUnusedGlobalValue(*GV); + M.getGlobalList().erase(GV); + } + NumVariables += DeadGlobalVars.size(); + Changed = true; + } - Changed |= RemoveIfDead(GV); + // Now delete any dead aliases. + if (!DeadAliases.empty()) { + for (GlobalAlias *GA : DeadAliases) { + RemoveUnusedGlobalValue(*GA); + M.getAliasList().erase(GA); + } + NumAliases += DeadAliases.size(); + Changed = true; } - // Make sure that all memory is free'd from the worklist... - std::vector().swap(WorkList); + // Make sure that all memory is released + AliveGlobals.clear(); + SeenConstants.clear(); + ComdatMembers.clear(); + return Changed; } +/// GlobalIsNeeded - the specific global value as needed, and +/// recursively mark anything that it uses as also needed. +void GlobalDCE::GlobalIsNeeded(GlobalValue *G) { + // If the global is already in the set, no need to reprocess it. + if (!AliveGlobals.insert(G).second) + return; + + if (Comdat *C = G->getComdat()) { + for (auto &&CM : make_range(ComdatMembers.equal_range(C))) + GlobalIsNeeded(CM.second); + } + + if (GlobalVariable *GV = dyn_cast(G)) { + // If this is a global variable, we must make sure to add any global values + // referenced by the initializer to the alive set. + if (GV->hasInitializer()) + MarkUsedGlobalsAsNeeded(GV->getInitializer()); + } else if (GlobalAlias *GA = dyn_cast(G)) { + // The target of a global alias is needed. + MarkUsedGlobalsAsNeeded(GA->getAliasee()); + } else { + // Otherwise this must be a function object. We have to scan the body of + // the function looking for constants and global values which are used as + // operands. Any operands of these types must be processed to ensure that + // any globals used will be marked as needed. + Function *F = cast(G); + + for (Use &U : F->operands()) + MarkUsedGlobalsAsNeeded(cast(U.get())); + + for (BasicBlock &BB : *F) + for (Instruction &I : BB) + for (Use &U : I.operands()) + if (GlobalValue *GV = dyn_cast(U)) + GlobalIsNeeded(GV); + else if (Constant *C = dyn_cast(U)) + MarkUsedGlobalsAsNeeded(C); + } +} + +void GlobalDCE::MarkUsedGlobalsAsNeeded(Constant *C) { + if (GlobalValue *GV = dyn_cast(C)) + return GlobalIsNeeded(GV); + + // Loop over all of the operands of the constant, adding any globals they + // use to the list of needed globals. + for (Use &U : C->operands()) { + // If we've already processed this constant there's no need to do it again. + Constant *Op = dyn_cast(U); + if (Op && SeenConstants.insert(Op).second) + MarkUsedGlobalsAsNeeded(Op); + } +} -// RemoveUnusedConstantPointerRef - Loop over all of the uses of the specified +// RemoveUnusedGlobalValue - Loop over all of the uses of the specified // GlobalValue, looking for the constant pointer ref that may be pointing to it. // If found, check to see if the constant pointer ref is safe to destroy, and if // so, nuke it. This will reduce the reference count on the global value, which // might make it deader. // -bool GlobalDCE::RemoveUnusedConstantPointerRef(GlobalValue &GV) { - for (Value::use_iterator I = GV.use_begin(), E = GV.use_end(); I != E; ++I) - if (ConstantPointerRef *CPR = dyn_cast(*I)) - if (SafeToDestroyConstant(CPR)) { // Only if unreferenced... - CPR->destroyConstant(); - ++NumCPRs; - return true; - } - - return false; -} - -// SafeToDestroyConstant - It is safe to destroy a constant iff it is only used -// by constants itself. Note that constants cannot be cyclic, so this test is -// pretty easy to implement recursively. -// -bool GlobalDCE::SafeToDestroyConstant(Constant *C) { - for (Value::use_iterator I = C->use_begin(), E = C->use_end(); I != E; ++I) - if (Constant *User = dyn_cast(*I)) { - if (!SafeToDestroyConstant(User)) return false; - } else { - return false; - } - - return true; +bool GlobalDCE::RemoveUnusedGlobalValue(GlobalValue &GV) { + if (GV.use_empty()) + return false; + GV.removeDeadConstantUsers(); + return GV.use_empty(); }