From: Chris Lattner Date: Tue, 27 Jul 2004 06:40:37 +0000 (+0000) Subject: Complete rewrite of this pass to be faster, use less memory, be easier to X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=fe98f27e807b478d85240240cb19b6673aaaafb8;p=oota-llvm.git Complete rewrite of this pass to be faster, use less memory, be easier to understand, and more accurate to boot! This implements GlobalModRef/purecse.ll over the previous impl. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15260 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp index cb1d360a930..162b11f74c9 100644 --- a/lib/Analysis/IPA/GlobalsModRef.cpp +++ b/lib/Analysis/IPA/GlobalsModRef.cpp @@ -8,12 +8,13 @@ //===----------------------------------------------------------------------===// // // This simple pass provides alias and mod/ref information for global values -// that do not have their address taken. For this simple (but very common) -// case, we can provide pretty accurate and useful information. +// that do not have their address taken, and keeps track of whether functions +// read or write memory (are "pure"). For this simple (but very common) case, +// we can provide pretty accurate and useful information. // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "globalsmodref" +#define DEBUG_TYPE "globalsmodref-aa" #include "llvm/Analysis/Passes.h" #include "llvm/Module.h" #include "llvm/Pass.h" @@ -21,6 +22,8 @@ #include "llvm/Constants.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CallGraph.h" +#include "llvm/Support/InstIterator.h" +#include "Support/CommandLine.h" #include "Support/Debug.h" #include "Support/Statistic.h" #include "Support/SCCIterator.h" @@ -34,22 +37,44 @@ namespace { Statistic<> NumNonAddrTakenFunctions("globalsmodref-aa", "Number of functions without address taken"); + Statistic<> + NumNoMemFunctions("globalsmodref-aa", + "Number of functions that do not access memory"); + Statistic<> + NumReadMemFunctions("globalsmodref-aa", + "Number of functions that only read memory"); + + /// FunctionRecord - One instance of this structure is stored for every + /// function in the program. Later, the entries for these functions are + /// removed if the function is found to call an external function (in which + /// case we know nothing about it. + struct FunctionRecord { + /// GlobalInfo - Maintain mod/ref info for all of the globals without + /// addresses taken that are read or written (transitively) by this + /// function. + std::map GlobalInfo; + + unsigned getInfoForGlobal(GlobalValue *GV) const { + std::map::const_iterator I = GlobalInfo.find(GV); + if (I != GlobalInfo.end()) + return I->second; + return 0; + } + + /// FunctionEffect - Capture whether or not this function reads or writes to + /// ANY memory. If not, we can do a lot of aggressive analysis on it. + unsigned FunctionEffect; + }; + /// GlobalsModRef - The actual analysis pass. class GlobalsModRef : public Pass, public AliasAnalysis { - /// ModRefFns - One instance of this record is kept for each global without - /// its address taken. - struct ModRefFns { - /// RefFns/ModFns - Sets of functions that and write globals. - std::set RefFns, ModFns; - }; - - /// NonAddressTakenGlobals - A map of globals that do not have their - /// addresses taken to their record. - std::map NonAddressTakenGlobals; + /// NonAddressTakenGlobals - The globals that do not have their addresses + /// taken. + std::set NonAddressTakenGlobals; /// FunctionInfo - For each function, keep track of what globals are /// modified or read. - std::map, unsigned> FunctionInfo; + std::map FunctionInfo; public: bool run(Module &M) { @@ -73,12 +98,37 @@ namespace { ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size); bool hasNoModRefInfoForCalls() const { return false; } + bool doesNotAccessMemory(Function *F) { + if (FunctionRecord *FR = getFunctionInfo(F)) + if (FR->FunctionEffect == 0) + return true; + return AliasAnalysis::doesNotAccessMemory(F); + } + bool onlyReadsMemory(Function *F) { + if (FunctionRecord *FR = getFunctionInfo(F)) + if ((FR->FunctionEffect & Mod) == 0) + return true; + return AliasAnalysis::onlyReadsMemory(F); + } + + virtual void deleteValue(Value *V); virtual void copyValue(Value *From, Value *To); private: + /// getFunctionInfo - Return the function info for the function, or null if + /// the function calls an external function (in which case we don't have + /// anything useful to say about it). + FunctionRecord *getFunctionInfo(Function *F) { + std::map::iterator I = FunctionInfo.find(F); + if (I != FunctionInfo.end()) + return &I->second; + return 0; + } + void AnalyzeGlobals(Module &M); void AnalyzeCallGraph(CallGraph &CG, Module &M); + void AnalyzeSCC(std::vector &SCC); bool AnalyzeUsesOfGlobal(Value *V, std::vector &Readers, std::vector &Writers); }; @@ -100,25 +150,24 @@ void GlobalsModRef::AnalyzeGlobals(Module &M) { for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (I->hasInternalLinkage()) { if (!AnalyzeUsesOfGlobal(I, Readers, Writers)) { - // Remember that we are tracking this global, and the mod/ref fns - ModRefFns &E = NonAddressTakenGlobals[I]; - E.RefFns.insert(Readers.begin(), Readers.end()); - E.ModFns.insert(Writers.begin(), Writers.end()); + // Remember that we are tracking this global. + NonAddressTakenGlobals.insert(I); ++NumNonAddrTakenFunctions; } Readers.clear(); Writers.clear(); } for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) - // FIXME: it is kinda dumb to track aliasing properties for constant - // globals, it will never be particularly useful anyways, 'cause they can - // never be modified (and the optimizer knows this already)! if (I->hasInternalLinkage()) { if (!AnalyzeUsesOfGlobal(I, Readers, Writers)) { // Remember that we are tracking this global, and the mod/ref fns - ModRefFns &E = NonAddressTakenGlobals[I]; - E.RefFns.insert(Readers.begin(), Readers.end()); - E.ModFns.insert(Writers.begin(), Writers.end()); + NonAddressTakenGlobals.insert(I); + for (unsigned i = 0, e = Readers.size(); i != e; ++i) + FunctionInfo[Readers[i]].GlobalInfo[I] |= Ref; + + if (!I->isConstant()) // No need to keep track of writers to constants + for (unsigned i = 0, e = Writers.size(); i != e; ++i) + FunctionInfo[Writers[i]].GlobalInfo[I] |= Mod; ++NumNonAddrTakenGlobalVars; } Readers.clear(); Writers.clear(); @@ -132,7 +181,7 @@ void GlobalsModRef::AnalyzeGlobals(Module &M) { bool GlobalsModRef::AnalyzeUsesOfGlobal(Value *V, std::vector &Readers, std::vector &Writers) { - //if (!isa(V->getType())) return true; + if (!isa(V->getType())) return true; for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI) if (LoadInst *LI = dyn_cast(*UI)) { @@ -175,67 +224,82 @@ bool GlobalsModRef::AnalyzeUsesOfGlobal(Value *V, /// AnalyzeCallGraph - At this point, we know the functions where globals are /// immediately stored to and read from. Propagate this information up the call -/// graph to all callers. +/// graph to all callers and compute the mod/ref info for all memory for each +/// function. void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) { - if (NonAddressTakenGlobals.empty()) return; // Don't bother, nothing to do. - - // Invert the NonAddressTakenGlobals map into the FunctionInfo map. - for (std::map::iterator I = - NonAddressTakenGlobals.begin(), E = NonAddressTakenGlobals.end(); - I != E; ++I) { - GlobalValue *GV = I->first; - ModRefFns &MRInfo = I->second; - for (std::set::iterator I = MRInfo.RefFns.begin(), - E = MRInfo.RefFns.begin(); I != E; ++I) - FunctionInfo[std::make_pair(*I, GV)] |= Ref; - MRInfo.RefFns.clear(); - for (std::set::iterator I = MRInfo.ModFns.begin(), - E = MRInfo.ModFns.begin(); I != E; ++I) - FunctionInfo[std::make_pair(*I, GV)] |= Mod; - MRInfo.ModFns.clear(); - } + DEBUG(std::cerr << "GlobalsModRef: Analyze Call Graph\n"); // We do a bottom-up SCC traversal of the call graph. In other words, we // visit all callees before callers (leaf-first). - for (scc_iterator I = scc_begin(&CG), E = scc_end(&CG); - I != E; ++I) { - std::map ModRefProperties; - const std::vector &SCC = *I; + for (scc_iterator I = scc_begin(&CG), E = scc_end(&CG); I!=E; ++I) + // Do not call AnalyzeSCC on the external function node. + if ((*I).size() != 1 || (*I)[0]->getFunction()) + AnalyzeSCC(*I); +} + +void GlobalsModRef::AnalyzeSCC(std::vector &SCC) { + assert(!SCC.empty() && "SCC with no functions?"); + FunctionRecord &FR = FunctionInfo[SCC[0]->getFunction()]; + + bool CallsExternal = false; + unsigned FunctionEffect = 0; + + // Collect the mod/ref properties due to called functions. We only compute + // one mod-ref set + for (unsigned i = 0, e = SCC.size(); i != e && !CallsExternal; ++i) + for (CallGraphNode::iterator CI = SCC[i]->begin(), E = SCC[i]->end(); + CI != E; ++CI) + if (Function *Callee = (*CI)->getFunction()) { + if (FunctionRecord *CalleeFR = getFunctionInfo(Callee)) { + // Propagate function effect up. + FunctionEffect |= CalleeFR->FunctionEffect; + + // Incorporate callee's effects on globals into our info. + for (std::map::iterator GI = + CalleeFR->GlobalInfo.begin(), E = CalleeFR->GlobalInfo.end(); + GI != E; ++GI) + FR.GlobalInfo[GI->first] |= GI->second; - // Collect the mod/ref properties due to called functions. - for (unsigned i = 0, e = SCC.size(); i != e; ++i) - for (CallGraphNode::iterator CI = SCC[i]->begin(), E = SCC[i]->end(); - CI != E; ++CI) { - if (Function *Callee = (*CI)->getFunction()) { - // Otherwise, combine the callee properties into our accumulated set. - std::map, unsigned>::iterator - CI = FunctionInfo.lower_bound(std::make_pair(Callee, - (GlobalValue*)0)); - for (;CI != FunctionInfo.end() && CI->first.first == Callee; ++CI) - ModRefProperties[CI->first.second] |= CI->second; } else { - // For now assume that external functions could mod/ref anything, - // since they could call into an escaping function that mod/refs an - // internal. FIXME: We need better tracking! - for (std::map::iterator GI = - NonAddressTakenGlobals.begin(), - E = NonAddressTakenGlobals.end(); GI != E; ++GI) - ModRefProperties[GI->first] = ModRef; - goto Out; + CallsExternal = true; + break; } + } else { + CallsExternal = true; + break; } - Out: - // Set all functions in the CFG to have these properties. FIXME: it would - // be better to use union find to only store these properties once, - // PARTICULARLY if it's the universal set. + + // If this SCC calls an external function, we can't say anything about it, so + // remove all SCC functions from the FunctionInfo map. + if (CallsExternal) { for (unsigned i = 0, e = SCC.size(); i != e; ++i) - if (Function *F = SCC[i]->getFunction()) { - for (std::map::iterator I = - ModRefProperties.begin(), E = ModRefProperties.end(); - I != E; ++I) - FunctionInfo[std::make_pair(F, I->first)] = I->second; - } + FunctionInfo.erase(SCC[i]->getFunction()); + return; } + + // Otherwise, unless we already know that this function mod/refs memory, scan + // the function bodies to see if there are any explicit loads or stores. + if (FunctionEffect != ModRef) { + for (unsigned i = 0, e = SCC.size(); i != e && FunctionEffect != ModRef;++i) + for (inst_iterator II = inst_begin(SCC[i]->getFunction()), + E = inst_end(SCC[i]->getFunction()); + II != E && FunctionEffect != ModRef; ++II) + if (isa(*II)) + FunctionEffect |= Ref; + else if (isa(*II)) + FunctionEffect |= Mod; + } + + if ((FunctionEffect & Mod) == 0) + ++NumReadMemFunctions; + if (FunctionEffect == 0) + ++NumNoMemFunctions; + FR.FunctionEffect = FunctionEffect; + + // Finally, now that we know the full effect on this SCC, clone the + // information to each function in the SCC. + for (unsigned i = 1, e = SCC.size(); i != e; ++i) + FunctionInfo[SCC[i]->getFunction()] = FR; } @@ -244,7 +308,7 @@ void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) { /// the specified value points to. If the value points to, or is derived from, /// a global object, return it. static const GlobalValue *getUnderlyingObject(const Value *V) { - //if (!isa(V->getType())) return 0; + if (!isa(V->getType())) return 0; // If we are at some type of object... return it. if (const GlobalValue *GV = dyn_cast(V)) return GV; @@ -286,15 +350,13 @@ GlobalsModRef::getModRefInfo(CallSite CS, Value *P, unsigned Size) { unsigned Known = ModRef; // If we are asking for mod/ref info of a direct call with a pointer to a - // global, return information if we have it. + // global we are tracking, return information if we have it. if (GlobalValue *GV = const_cast(getUnderlyingObject(P))) if (GV->hasInternalLinkage()) - if (Function *F = CS.getCalledFunction()) { - std::map, unsigned>::iterator - it = FunctionInfo.find(std::make_pair(F, GV)); - if (it != FunctionInfo.end()) - Known = it->second; - } + if (Function *F = CS.getCalledFunction()) + if (NonAddressTakenGlobals.count(GV)) + if (FunctionRecord *FR = getFunctionInfo(F)) + Known = FR->getInfoForGlobal(GV); if (Known == NoModRef) return NoModRef; // No need to query other mod/ref analyses @@ -306,20 +368,9 @@ GlobalsModRef::getModRefInfo(CallSite CS, Value *P, unsigned Size) { // Methods to update the analysis as a result of the client transformation. // void GlobalsModRef::deleteValue(Value *V) { - if (GlobalValue *GV = dyn_cast(V)) { - std::map::iterator I = - NonAddressTakenGlobals.find(GV); - if (I != NonAddressTakenGlobals.end()) - NonAddressTakenGlobals.erase(I); - } + if (GlobalValue *GV = dyn_cast(V)) + NonAddressTakenGlobals.erase(GV); } void GlobalsModRef::copyValue(Value *From, Value *To) { - if (GlobalValue *FromGV = dyn_cast(From)) - if (GlobalValue *ToGV = dyn_cast(To)) { - std::map::iterator I = - NonAddressTakenGlobals.find(FromGV); - if (I != NonAddressTakenGlobals.end()) - NonAddressTakenGlobals[ToGV] = I->second; - } }