diff --git a/include/llvm/Analysis/IPModRef.h b/include/llvm/Analysis/IPModRef.h new file mode 100644 index 00000000000..aa6c308fb2c --- /dev/null +++ b/include/llvm/Analysis/IPModRef.h @@ -0,0 +1,235 @@ +//===- IPModRef.h - Compute IP Mod/Ref information --------------*- C++ -*-===// +// +// class IPModRef: +// +// class IPModRef is an interprocedural analysis pass that computes +// flow-insensitive IP Mod and Ref information for every function +// (the GMOD and GREF problems) and for every call site (MOD and REF). +// +// In practice, this needs to do NO real interprocedural work because +// all that is needed is done by the data structure analysis. +// This uses the top-down DS graph for a function and the bottom-up DS graph +// for each callee (including the Mod/Ref flags in the bottom-up graph) +// to compute the set of nodes that are Mod and Ref for the function and +// for each of its call sites. +// +// +// class FunctionModRefInfo: +// +// The results of IPModRef are encapsulated in the class FunctionModRefInfo. +// The results are stored as bit vectors: bit i represents node i +// in the TD DSGraph for the current function. (This node numbering is +// implemented by class FunctionModRefInfo.) Each FunctionModRefInfo +// includes: +// -- 2 bit vectors for the function (GMOD and GREF), and +// -- 2 bit vectors for each call site (MOD and REF). +// +// +// IPModRef vs. Alias Analysis for Clients: +// +// The IPModRef pass does not provide simpler query interfaces for specific +// LLVM values, instructions, or pointers because those results should be +// obtained through alias analysis (e.g., class DSAliasAnalysis). +// class IPModRef is primarily meant for other analysis passes that need to +// use Mod/Ref information efficiently for more complicated purposes; +// the bit-vector representations make propagation very efficient. +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_ANALYSIS_IPMODREF_H +#define LLVM_ANALYSIS_IPMODREF_H + + +#include "llvm/Analysis/DataStructure.h" +#include "llvm/Analysis/DSGraph.h" +#include "llvm/Pass.h" +#include "Support/BitSetVector.h" +#include "Support/NonCopyable.h" + +class Module; +class Function; +class CallInst; +class DSGraph; +class ModRefInfo; // Result of IP Mod/Ref for one entity +class FunctionModRefInfo; // ModRefInfo for a func and all calls in it +class IPModRef; // Pass that computes IP Mod/Ref info + + +//--------------------------------------------------------------------------- +// class ModRefInfo +// +// Purpose: +// Representation of Mod/Ref information for a single function or callsite. +// This is represented as a pair of bit vectors, one each for Mod and Ref. +// Each bit vector is indexed by the node id of the DS graph node index. +//--------------------------------------------------------------------------- + +class ModRefInfo { + BitSetVector modNodeSet; // set of modified nodes + BitSetVector refNodeSet; // set of referenced nodes + +public: + // + // Methods to construct ModRefInfo objects. + // + ModRefInfo(unsigned int numNodes) + : modNodeSet(numNodes), + refNodeSet(numNodes) { } + + void setNodeIsMod (unsigned nodeId) { modNodeSet[nodeId] = true; } + void setNodeIsRef (unsigned nodeId) { refNodeSet[nodeId] = true; } + + // + // Methods to query the mod/ref info + // + bool nodeIsMod (unsigned nodeId) const { return modNodeSet.test(nodeId); } + bool nodeIsRef (unsigned nodeId) const { return refNodeSet.test(nodeId); } + bool nodeIsKill(unsigned nodeId) const { return false; } + + const BitSetVector& getModSet() const { return modNodeSet; } + BitSetVector& getModSet() { return modNodeSet; } + + const BitSetVector& getRefSet() const { return refNodeSet; } + BitSetVector& getRefSet() { return refNodeSet; } + + // Debugging support methods + void print(std::ostream &O) const; + void dump() const; +}; + + +//---------------------------------------------------------------------------- +// class FunctionModRefInfo +// +// Representation of the results of IP Mod/Ref analysis for a function +// and for each of the call sites within the function. +// Each of these are represented as bit vectors of size = the number of +// nodes in the top-dwon DS graph of the function. Nodes are identified by +// their nodeId, in the range [0 .. funcTDGraph.size()-1]. +//---------------------------------------------------------------------------- + +class FunctionModRefInfo { + const Function& F; // The function + const DSGraph& funcTDGraph; // Top-down DS graph for function + const DSGraph& funcLocalGraph; // Local DS graph for function + ModRefInfo funcModRefInfo; // ModRefInfo for the function body + std::map + callSiteModRefInfo; // ModRefInfo for each callsite + std::map NodeIds; + + friend class IPModRef; + + void computeModRef (const Function &func); + void computeModRef (const CallInst& callInst); + +public: + /* ctor */ FunctionModRefInfo (const Function& func, + const DSGraph& tdg, + const DSGraph& ldg); + /* dtor */ ~FunctionModRefInfo (); + + // Identify the function and its relevant DS graph + // + const Function& getFunction() const { return F; } + const DSGraph& getFuncGraph() const { return funcTDGraph; } + + // Retrieve Mod/Ref results for a single call site and for the function body + // + const ModRefInfo* getModRefInfo (const Function& func) const { + return &funcModRefInfo; + } + const ModRefInfo* getModRefInfo (const CallInst& callInst) const { + std::map::const_iterator I = + callSiteModRefInfo.find(&callInst); + return (I == callSiteModRefInfo.end())? NULL : I->second; + } + + // Get the nodeIds used to index all Mod/Ref information for current function + // + unsigned getNodeId (const DSNode* node) const { + std::map::const_iterator iter = NodeIds.find(node); + assert(iter == NodeIds.end() || iter->second < funcTDGraph.getGraphSize()); + return (iter == NodeIds.end())? funcTDGraph.getGraphSize() : iter->second; + } + unsigned getNodeId (const Value* value) const { + return getNodeId(funcTDGraph.getNodeForValue(const_cast(value)) + .getNode()); + } + + // Debugging support methods + void print(std::ostream &O) const; + void dump() const; +}; + + +//---------------------------------------------------------------------------- +// class IPModRef +// +// Purpose: +// An interprocedural pass that computes IP Mod/Ref info for functions and +// for individual call sites. +// +// Given the DSGraph of a function, this class can be queried for +// a ModRefInfo object describing all the nodes in the DSGraph that are +// (a) modified, and (b) referenced during an execution of the function +// from an arbitrary callsite, or during an execution of a single call-site +// within the function. +//---------------------------------------------------------------------------- + +class IPModRef : public Pass { + std::map funcToModRefInfoMap; + Module* M; + + FunctionModRefInfo& getFuncInfo(const Function& func, + bool computeIfMissing = false) + { + FunctionModRefInfo*& funcInfo = funcToModRefInfoMap[&func]; + assert (funcInfo != NULL || computeIfMissing); + if (funcInfo == NULL && computeIfMissing) + { // Create a new FunctionModRefInfo object + funcInfo = new FunctionModRefInfo(func, // inserts into map + getAnalysis().getDSGraph(func), + getAnalysis().getDSGraph(func)); + funcInfo->computeModRef(func); // computes the mod/ref info + } + return *funcInfo; + } + +public: + IPModRef() : M(NULL) { } + ~IPModRef() { } + + // Driver function to run IP Mod/Ref on a Module. + // This initializes the module reference, and then computes IPModRef + // results immediately if demand-driven analysis was *not* specified. + // + virtual bool run(Module &M); + + // Retrieve the Mod/Ref information for a single function + // + const FunctionModRefInfo& getFunctionModRefInfo(const Function& func) { + return getFuncInfo(func); + } + + // Debugging support methods + // + void print(std::ostream &O) const; + void dump() const; + + // Release memory held by this pass when the pass pipeline is done + // + virtual void releaseMemory(); + + // getAnalysisUsage - This pass requires top-down data structure graphs. + // It modifies nothing. + // + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + AU.addRequired(); + } +}; + +//===----------------------------------------------------------------------===// + +#endif diff --git a/lib/Analysis/DataStructure/IPModRef.cpp b/lib/Analysis/DataStructure/IPModRef.cpp new file mode 100644 index 00000000000..e4d0062f386 --- /dev/null +++ b/lib/Analysis/DataStructure/IPModRef.cpp @@ -0,0 +1,218 @@ +//===- IPModRef.cpp - Compute IP Mod/Ref information ------------*- C++ -*-===// +// +// See high-level comments in include/llvm/Analysis/IPModRef.h +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/DataStructure.h" +#include "llvm/Analysis/DSGraph.h" +#include "llvm/Analysis/IPModRef.h" +#include "llvm/Module.h" +#include "llvm/Function.h" +#include "llvm/iOther.h" +#include "llvm/Pass.h" +#include "Support/Statistic.h" +#include "Support/STLExtras.h" +#include "Support/StringExtras.h" + +#include +#include +#include + + +//---------------------------------------------------------------------------- +// Private constants and data +//---------------------------------------------------------------------------- + +static RegisterAnalysis +Z("ipmodref", "Interprocedural mod/ref analysis"); + + +//---------------------------------------------------------------------------- +// class ModRefInfo +//---------------------------------------------------------------------------- + +void ModRefInfo::print(std::ostream &O) const +{ + O << std::endl << "Modified nodes = " << modNodeSet; + O << "Referenced nodes = " << refNodeSet << std::endl; +} + +void ModRefInfo::dump() const +{ + print(std::cerr); +} + +//---------------------------------------------------------------------------- +// class FunctionModRefInfo +//---------------------------------------------------------------------------- + + +// This constructor computes a node numbering for the TD graph. +// +FunctionModRefInfo::FunctionModRefInfo(const Function& func, + const DSGraph& tdg, + const DSGraph& ldg) + : F(func), + funcTDGraph(tdg), + funcLocalGraph(ldg), + funcModRefInfo(tdg.getGraphSize()) +{ + for (unsigned i=0, N = funcTDGraph.getGraphSize(); i < N; ++i) + NodeIds[funcTDGraph.getNodes()[i]] = i; +} + + +FunctionModRefInfo::~FunctionModRefInfo() +{ + for(std::map::iterator + I=callSiteModRefInfo.begin(), E=callSiteModRefInfo.end(); I != E; ++I) + delete(I->second); + + // Empty map just to make problems easier to track down + callSiteModRefInfo.clear(); +} + + +// Dummy function that will be replaced with one that inlines +// the callee's BU graph into the caller's TD graph. +// +const DSGraph* ResolveGraphForCallSite(const DSGraph& funcTDGraph, + const CallInst& callInst) +{ + return &funcTDGraph; // TEMPORARY +} + + +// Compute Mod/Ref bit vectors for the entire function. +// These are simply copies of the Read/Write flags from the nodes of +// the top-down DS graph. +// +void FunctionModRefInfo::computeModRef(const Function &func) +{ + // Mark all nodes in the graph that are marked MOD as being mod + // and all those marked REF as being ref. + for (unsigned i = 0, N = funcTDGraph.getGraphSize(); i < N; ++i) + { + if (funcTDGraph.getNodes()[i]->isModified()) + funcModRefInfo.setNodeIsMod(i); + if (funcTDGraph.getNodes()[i]->isRead()) + funcModRefInfo.setNodeIsRef(i); + } + + // Compute the Mod/Ref info for all call sites within the function + // Use the Local DSgraph, which includes all the call sites in the + // original program. + const std::vector& callSites = funcLocalGraph.getFunctionCalls(); + for (unsigned i = 0, N = callSites.size(); i < N; ++i) + computeModRef(callSites[i].getCallInst()); +} + + +// Compute Mod/Ref bit vectors for a single call site. +// These are copies of the Read/Write flags from the nodes of +// the graph produced by clearing all flags in teh caller's TD graph +// and then inlining the callee's BU graph into the caller's TD graph. +// +void +FunctionModRefInfo::computeModRef(const CallInst& callInst) +{ + // Allocate the mod/ref info for the call site. Bits automatically cleared. + ModRefInfo* callModRefInfo = new ModRefInfo(funcTDGraph.getGraphSize()); + callSiteModRefInfo[&callInst] = callModRefInfo; + + // Get a copy of the graph for the callee with the callee inlined + const DSGraph* csgp = ResolveGraphForCallSite(funcTDGraph, callInst); + assert(csgp && "Unable to compute callee mod/ref information"); + + // For all nodes in the graph, extract the mod/ref information + const std::vector& csgNodes = csgp->getNodes(); + const std::vector& origNodes = funcTDGraph.getNodes(); + assert(csgNodes.size() == origNodes.size()); + for (unsigned i=0, N = csgNodes.size(); i < N; ++i) + { + if (csgNodes[i]->isModified()) + callModRefInfo->setNodeIsMod(getNodeId(origNodes[i])); + if (csgNodes[i]->isRead()) + callModRefInfo->setNodeIsRef(getNodeId(origNodes[i])); + } +} + + +// Print the results of the pass. +// Currently this just prints bit-vectors and is not very readable. +// +void FunctionModRefInfo::print(std::ostream &O) const +{ + O << "---------- Mod/ref information for function " + << F.getName() << "---------- \n\n"; + + O << "Mod/ref info for function body:\n"; + funcModRefInfo.print(O); + + for (std::map::const_iterator + CI = callSiteModRefInfo.begin(), CE = callSiteModRefInfo.end(); + CI != CE; ++CI) + { + O << "Mod/ref info for call site " << CI->first << ":\n"; + CI->second->print(O); + } + + O << "\n"; +} + +void FunctionModRefInfo::dump() const +{ + print(std::cerr); +} + + +//---------------------------------------------------------------------------- +// class IPModRef: An interprocedural pass that computes IP Mod/Ref info. +//---------------------------------------------------------------------------- + + +// Free the FunctionModRefInfo objects cached in funcToModRefInfoMap. +// +void IPModRef::releaseMemory() +{ + for(std::map::iterator + I=funcToModRefInfoMap.begin(), E=funcToModRefInfoMap.end(); I != E; ++I) + delete(I->second); + + // Clear map so memory is not re-released if we are called again + funcToModRefInfoMap.clear(); +} + + +// Run the "interprocedural" pass on each function. This needs to do +// NO real interprocedural work because all that has been done the +// data structure analysis. +// +bool IPModRef::run(Module &theModule) +{ + M = &theModule; + for (Module::const_iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) + if (! FI->isExternal()) + getFuncInfo(*FI, /*computeIfMissing*/ true); + return true; +} + + +void IPModRef::print(std::ostream &O) const +{ + O << "\n========== Results of Interprocedural Mod/Ref Analysis ==========\n"; + + for (std::map::const_iterator + mapI = funcToModRefInfoMap.begin(), mapE = funcToModRefInfoMap.end(); + mapI != mapE; ++mapI) + mapI->second->print(O); + + O << "\n"; +} + + +void IPModRef::dump() const +{ + print(std::cerr); +} diff --git a/lib/Analysis/IPA/IPModRef.cpp b/lib/Analysis/IPA/IPModRef.cpp new file mode 100644 index 00000000000..e4d0062f386 --- /dev/null +++ b/lib/Analysis/IPA/IPModRef.cpp @@ -0,0 +1,218 @@ +//===- IPModRef.cpp - Compute IP Mod/Ref information ------------*- C++ -*-===// +// +// See high-level comments in include/llvm/Analysis/IPModRef.h +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/DataStructure.h" +#include "llvm/Analysis/DSGraph.h" +#include "llvm/Analysis/IPModRef.h" +#include "llvm/Module.h" +#include "llvm/Function.h" +#include "llvm/iOther.h" +#include "llvm/Pass.h" +#include "Support/Statistic.h" +#include "Support/STLExtras.h" +#include "Support/StringExtras.h" + +#include +#include +#include + + +//---------------------------------------------------------------------------- +// Private constants and data +//---------------------------------------------------------------------------- + +static RegisterAnalysis +Z("ipmodref", "Interprocedural mod/ref analysis"); + + +//---------------------------------------------------------------------------- +// class ModRefInfo +//---------------------------------------------------------------------------- + +void ModRefInfo::print(std::ostream &O) const +{ + O << std::endl << "Modified nodes = " << modNodeSet; + O << "Referenced nodes = " << refNodeSet << std::endl; +} + +void ModRefInfo::dump() const +{ + print(std::cerr); +} + +//---------------------------------------------------------------------------- +// class FunctionModRefInfo +//---------------------------------------------------------------------------- + + +// This constructor computes a node numbering for the TD graph. +// +FunctionModRefInfo::FunctionModRefInfo(const Function& func, + const DSGraph& tdg, + const DSGraph& ldg) + : F(func), + funcTDGraph(tdg), + funcLocalGraph(ldg), + funcModRefInfo(tdg.getGraphSize()) +{ + for (unsigned i=0, N = funcTDGraph.getGraphSize(); i < N; ++i) + NodeIds[funcTDGraph.getNodes()[i]] = i; +} + + +FunctionModRefInfo::~FunctionModRefInfo() +{ + for(std::map::iterator + I=callSiteModRefInfo.begin(), E=callSiteModRefInfo.end(); I != E; ++I) + delete(I->second); + + // Empty map just to make problems easier to track down + callSiteModRefInfo.clear(); +} + + +// Dummy function that will be replaced with one that inlines +// the callee's BU graph into the caller's TD graph. +// +const DSGraph* ResolveGraphForCallSite(const DSGraph& funcTDGraph, + const CallInst& callInst) +{ + return &funcTDGraph; // TEMPORARY +} + + +// Compute Mod/Ref bit vectors for the entire function. +// These are simply copies of the Read/Write flags from the nodes of +// the top-down DS graph. +// +void FunctionModRefInfo::computeModRef(const Function &func) +{ + // Mark all nodes in the graph that are marked MOD as being mod + // and all those marked REF as being ref. + for (unsigned i = 0, N = funcTDGraph.getGraphSize(); i < N; ++i) + { + if (funcTDGraph.getNodes()[i]->isModified()) + funcModRefInfo.setNodeIsMod(i); + if (funcTDGraph.getNodes()[i]->isRead()) + funcModRefInfo.setNodeIsRef(i); + } + + // Compute the Mod/Ref info for all call sites within the function + // Use the Local DSgraph, which includes all the call sites in the + // original program. + const std::vector& callSites = funcLocalGraph.getFunctionCalls(); + for (unsigned i = 0, N = callSites.size(); i < N; ++i) + computeModRef(callSites[i].getCallInst()); +} + + +// Compute Mod/Ref bit vectors for a single call site. +// These are copies of the Read/Write flags from the nodes of +// the graph produced by clearing all flags in teh caller's TD graph +// and then inlining the callee's BU graph into the caller's TD graph. +// +void +FunctionModRefInfo::computeModRef(const CallInst& callInst) +{ + // Allocate the mod/ref info for the call site. Bits automatically cleared. + ModRefInfo* callModRefInfo = new ModRefInfo(funcTDGraph.getGraphSize()); + callSiteModRefInfo[&callInst] = callModRefInfo; + + // Get a copy of the graph for the callee with the callee inlined + const DSGraph* csgp = ResolveGraphForCallSite(funcTDGraph, callInst); + assert(csgp && "Unable to compute callee mod/ref information"); + + // For all nodes in the graph, extract the mod/ref information + const std::vector& csgNodes = csgp->getNodes(); + const std::vector& origNodes = funcTDGraph.getNodes(); + assert(csgNodes.size() == origNodes.size()); + for (unsigned i=0, N = csgNodes.size(); i < N; ++i) + { + if (csgNodes[i]->isModified()) + callModRefInfo->setNodeIsMod(getNodeId(origNodes[i])); + if (csgNodes[i]->isRead()) + callModRefInfo->setNodeIsRef(getNodeId(origNodes[i])); + } +} + + +// Print the results of the pass. +// Currently this just prints bit-vectors and is not very readable. +// +void FunctionModRefInfo::print(std::ostream &O) const +{ + O << "---------- Mod/ref information for function " + << F.getName() << "---------- \n\n"; + + O << "Mod/ref info for function body:\n"; + funcModRefInfo.print(O); + + for (std::map::const_iterator + CI = callSiteModRefInfo.begin(), CE = callSiteModRefInfo.end(); + CI != CE; ++CI) + { + O << "Mod/ref info for call site " << CI->first << ":\n"; + CI->second->print(O); + } + + O << "\n"; +} + +void FunctionModRefInfo::dump() const +{ + print(std::cerr); +} + + +//---------------------------------------------------------------------------- +// class IPModRef: An interprocedural pass that computes IP Mod/Ref info. +//---------------------------------------------------------------------------- + + +// Free the FunctionModRefInfo objects cached in funcToModRefInfoMap. +// +void IPModRef::releaseMemory() +{ + for(std::map::iterator + I=funcToModRefInfoMap.begin(), E=funcToModRefInfoMap.end(); I != E; ++I) + delete(I->second); + + // Clear map so memory is not re-released if we are called again + funcToModRefInfoMap.clear(); +} + + +// Run the "interprocedural" pass on each function. This needs to do +// NO real interprocedural work because all that has been done the +// data structure analysis. +// +bool IPModRef::run(Module &theModule) +{ + M = &theModule; + for (Module::const_iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) + if (! FI->isExternal()) + getFuncInfo(*FI, /*computeIfMissing*/ true); + return true; +} + + +void IPModRef::print(std::ostream &O) const +{ + O << "\n========== Results of Interprocedural Mod/Ref Analysis ==========\n"; + + for (std::map::const_iterator + mapI = funcToModRefInfoMap.begin(), mapE = funcToModRefInfoMap.end(); + mapI != mapE; ++mapI) + mapI->second->print(O); + + O << "\n"; +} + + +void IPModRef::dump() const +{ + print(std::cerr); +}