diff --git a/lib/Analysis/DataStructure/BottomUpClosure.cpp b/lib/Analysis/DataStructure/BottomUpClosure.cpp new file mode 100644 index 00000000000..c8e9fc3e33e --- /dev/null +++ b/lib/Analysis/DataStructure/BottomUpClosure.cpp @@ -0,0 +1,188 @@ +//===- BottomUpClosure.cpp - Compute the bottom up interprocedure closure -===// +// +// This file implements the BUDataStructures class, which represents the +// Bottom-Up Interprocedural closure of the data structure graph over the +// program. This is useful for applications like pool allocation, but **not** +// applications like pointer analysis. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/DataStructure.h" +#include "llvm/Module.h" +#include "llvm/DerivedTypes.h" +#include "Support/StatisticReporter.h" +using std::map; + +AnalysisID BUDataStructures::ID(AnalysisID::create()); + +// releaseMemory - If the pass pipeline is done with this pass, we can release +// our memory... here... +// +void BUDataStructures::releaseMemory() { + for (map::iterator I = DSInfo.begin(), + E = DSInfo.end(); I != E; ++I) + delete I->second; + + // Empty map so next time memory is released, data structures are not + // re-deleted. + DSInfo.clear(); +} + +// run - Calculate the bottom up data structure graphs for each function in the +// program. +// +bool BUDataStructures::run(Module &M) { + // Simply calculate the graphs for each function... + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) + if (!I->isExternal()) + calculateGraph(*I); + return false; +} + + +// ResolveArguments - Resolve the formal and actual arguments for a function +// call. +// +static void ResolveArguments(std::vector &Call, Function &F, + map &ValueMap) { + // Resolve all of the function arguments... + Function::aiterator AI = F.abegin(); + for (unsigned i = 2, e = Call.size(); i != e; ++i) { + // Advance the argument iterator to the first pointer argument... + while (!isa(AI->getType())) ++AI; + + // Add the link from the argument scalar to the provided value + DSNode *NN = ValueMap[AI]; + NN->addEdgeTo(Call[i]); + ++AI; + } +} + +// MergeGlobalNodes - Merge global value nodes in the inlined graph with the +// global value nodes in the current graph if there are duplicates. +// +static void MergeGlobalNodes(map &ValMap, + map &OldValMap) { + // Loop over all of the nodes inlined, if any of them are global variable + // nodes, we must make sure they get properly added or merged with the ValMap. + // + for (map::iterator I = OldValMap.begin(), + E = OldValMap.end(); I != E; ++I) + if (isa(I->first)) { + DSNodeHandle &NH = ValMap[I->first]; // Look up global in ValMap. + if (NH == 0) { // No entry for the global yet? + NH = I->second; // Add the one just inlined... + } else { + NH->mergeWith(I->second); // Merge the two globals together. + } + } + +} + +DSGraph &BUDataStructures::calculateGraph(Function &F) { + // Make sure this graph has not already been calculated, or that we don't get + // into an infinite loop with mutually recursive functions. + // + DSGraph *&Graph = DSInfo[&F]; + if (Graph) return *Graph; + + // Copy the local version into DSInfo... + Graph = new DSGraph(getAnalysis().getDSGraph(F)); + + // Start resolving calls... + std::vector > &FCs = Graph->getFunctionCalls(); + + DEBUG(cerr << "Inlining: " << F.getName() << "\n"); + + bool Inlined; + do { + Inlined = false; + for (unsigned i = 0; i != FCs.size(); ++i) { + // Copy the call, because inlining graphs may invalidate the FCs vector. + std::vector Call = FCs[i]; + + // If the function list is not incomplete... + if ((Call[1]->NodeType & DSNode::Incomplete) == 0) { + // Start inlining all of the functions we can... some may not be + // inlinable if they are external... + // + std::vector Globals(Call[1]->getGlobals()); + + // Loop over the functions, inlining whatever we can... + for (unsigned g = 0; g != Globals.size(); ++g) { + // Must be a function type, so this cast MUST succeed. + Function &FI = cast(*Globals[g]); + if (&FI == &F) { + // Self recursion... simply link up the formal arguments with the + // actual arguments... + + DEBUG(cerr << "Self Inlining: " << F.getName() << "\n"); + + if (Call[0]) // Handle the return value if present... + Graph->RetNode->mergeWith(Call[0]); + + // Resolve the arguments in the call to the actual values... + ResolveArguments(Call, F, Graph->getValueMap()); + + // Erase the entry in the globals vector + Globals.erase(Globals.begin()+g--); + } else if (!FI.isExternal()) { + DEBUG(std::cerr << "In " << F.getName() << " inlining: " + << FI.getName() << "\n"); + + // Get the data structure graph for the called function, closing it + // if possible (which is only impossible in the case of mutual + // recursion... + // + DSGraph &GI = calculateGraph(FI); // Graph to inline + + DEBUG(cerr << "Got graph for " << FI.getName() << " in: " + << F.getName() << "\n"); + + + + // Clone the called function's graph into the current graph, keeping + // track of where scalars in the old graph _used_ to point... + map OldValMap; + + // The clone call may invalidate any of the vectors in the data + // structure graph. + DSNode *RetVal = Graph->cloneInto(GI, OldValMap); + + ResolveArguments(Call, FI, OldValMap); + + // Merge global value nodes in the inlined graph with the global + // value nodes in the current graph if there are duplicates. + // + MergeGlobalNodes(Graph->getValueMap(), OldValMap); + + // Erase the entry in the globals vector + Globals.erase(Globals.begin()+g--); + } + } + + if (Globals.empty()) { // Inlined all of the function calls? + // Erase the call if it is resolvable... + FCs.erase(FCs.begin()+i--); // Don't skip a the next call... + Inlined = true; + } else if (Globals.size() != Call[1]->getGlobals().size()) { + // Was able to inline SOME, but not all of the functions. Construct a + // new global node here. + // + assert(0 && "Unimpl!"); + Inlined = true; + } + } + } + + // Recompute the Incomplete markers. If there are any function calls left + // now that are complete, we must loop! + if (Inlined) { + Graph->maskIncompleteMarkers(); + Graph->markIncompleteNodes(); + Graph->removeDeadNodes(); + } + } while (Inlined && !FCs.empty()); + + return *Graph; +} diff --git a/lib/Analysis/DataStructure/DataStructure.cpp b/lib/Analysis/DataStructure/DataStructure.cpp index dd0b52a4383..800c82ad982 100644 --- a/lib/Analysis/DataStructure/DataStructure.cpp +++ b/lib/Analysis/DataStructure/DataStructure.cpp @@ -4,11 +4,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Analysis/DataStructure.h" #include "llvm/Module.h" #include "llvm/DerivedTypes.h" -#include #include "Support/STLExtras.h" +#include "Support/StatisticReporter.h" +#include +#include "llvm/Analysis/DataStructure.h" AnalysisID LocalDataStructures::ID(AnalysisID::create()); @@ -28,6 +29,11 @@ DSNode::DSNode(enum NodeTy NT, const Type *T) : Ty(T), NodeType(NT) { } } +// DSNode copy constructor... do not copy over the referrers list! +DSNode::DSNode(const DSNode &N) + : Ty(N.Ty), Links(N.Links), Globals(N.Globals), NodeType(N.NodeType) { +} + void DSNode::removeReferrer(DSNodeHandle *H) { // Search backwards, because we depopulate the list from the back for // efficiency (because it's a vector). @@ -41,9 +47,15 @@ void DSNode::removeReferrer(DSNodeHandle *H) { // marks the node with the 'G' flag if it does not already have it. // void DSNode::addGlobal(GlobalValue *GV) { - assert(GV->getType()->getElementType() == Ty); - Globals.push_back(GV); - NodeType |= GlobalNode; + // Keep the list sorted. + std::vector::iterator I = + std::lower_bound(Globals.begin(), Globals.end(), GV); + + if (I == Globals.end() || *I != GV) { + assert(GV->getType()->getElementType() == Ty); + Globals.insert(I, GV); + NodeType |= GlobalNode; + } } @@ -89,14 +101,33 @@ void DSNode::mergeWith(DSNode *N) { N->NodeType = 0; // N is now a dead node. // Merge the globals list... - Globals.insert(Globals.end(), N->Globals.begin(), N->Globals.end()); - N->Globals.clear(); + if (!N->Globals.empty()) { + // Save the current globals off to the side... + std::vector OldGlobals(Globals); + + // Resize the globals vector to be big enough to hold both of them... + Globals.resize(Globals.size()+N->Globals.size()); + + // Merge the two sorted globals lists together... + std::merge(OldGlobals.begin(), OldGlobals.end(), + N->Globals.begin(), N->Globals.end(), Globals.begin()); + + // Erase duplicate entries from the globals list... + Globals.erase(std::unique(Globals.begin(), Globals.end()), Globals.end()); + + // Delete the globals from the old node... + N->Globals.clear(); + } } //===----------------------------------------------------------------------===// // DSGraph Implementation //===----------------------------------------------------------------------===// +DSGraph::DSGraph(const DSGraph &G) : Func(G.Func) { + RetNode = cloneInto(G, ValueMap, false); +} + DSGraph::~DSGraph() { FunctionCalls.clear(); ValueMap.clear(); @@ -112,6 +143,182 @@ DSGraph::~DSGraph() { std::for_each(Nodes.begin(), Nodes.end(), deleter); } +// dump - Allow inspection of graph in a debugger. +void DSGraph::dump() const { print(std::cerr); } + +// cloneInto - Clone the specified DSGraph into the current graph, returning the +// Return node of the graph. The translated ValueMap for the old function is +// filled into the OldValMap member. If StripLocals is set to true, Scalar and +// Alloca markers are removed from the graph, as the graph is being cloned into +// a calling function's graph. +// +DSNode *DSGraph::cloneInto(const DSGraph &G, + std::map &OldValMap, + bool StripLocals) { + std::map NodeMap; + NodeMap[0] = 0; // Null pointer maps to null + + unsigned FN = Nodes.size(); // FirstNode... + + // Duplicate all of the nodes, populating the node map... + Nodes.reserve(FN+G.Nodes.size()); + for (unsigned i = 0, e = G.Nodes.size(); i != e; ++i) { + DSNode *Old = G.Nodes[i], *New = new DSNode(*Old); + Nodes.push_back(New); + NodeMap[Old] = New; + } + + // Rewrite the links in the nodes to point into the current graph now. + for (unsigned i = FN, e = Nodes.size(); i != e; ++i) + for (unsigned j = 0, e = Nodes[i]->getNumLinks(); j != e; ++j) + Nodes[i]->setLink(j, NodeMap[Nodes[i]->getLink(j)]); + + // If we are inlining this graph into the called function graph, remove local + // markers. + if (StripLocals) + for (unsigned i = FN, e = Nodes.size(); i != e; ++i) + Nodes[i]->NodeType &= ~(DSNode::AllocaNode | DSNode::ScalarNode); + + // Copy the value map... + for (std::map::const_iterator I = G.ValueMap.begin(), + E = G.ValueMap.end(); I != E; ++I) + OldValMap[I->first] = NodeMap[I->second]; + + // Copy the function calls list... + unsigned FC = FunctionCalls.size(); // FirstCall + FunctionCalls.reserve(FC+G.FunctionCalls.size()); + for (unsigned i = 0, e = G.FunctionCalls.size(); i != e; ++i) { + FunctionCalls.push_back(std::vector()); + FunctionCalls[FC+i].reserve(G.FunctionCalls[i].size()); + for (unsigned j = 0, e = G.FunctionCalls[i].size(); j != e; ++j) + FunctionCalls[FC+i].push_back(NodeMap[G.FunctionCalls[i][j]]); + } + + // Return the returned node pointer... + return NodeMap[G.RetNode]; +} + + +// markIncompleteNodes - Mark the specified node as having contents that are not +// known with the current analysis we have performed. Because a node makes all +// of the nodes it can reach imcomplete if the node itself is incomplete, we +// must recursively traverse the data structure graph, marking all reachable +// nodes as incomplete. +// +static void markIncompleteNode(DSNode *N) { + // Stop recursion if no node, or if node already marked... + if (N == 0 || (N->NodeType & DSNode::Incomplete)) return; + + // Actually mark the node + N->NodeType |= DSNode::Incomplete; + + // Recusively process children... + for (unsigned i = 0, e = N->getNumLinks(); i != e; ++i) + markIncompleteNode(N->getLink(i)); +} + + +// markIncompleteNodes - Traverse the graph, identifying nodes that may be +// modified by other functions that have not been resolved yet. This marks +// nodes that are reachable through three sources of "unknownness": +// +// Global Variables, Function Calls, and Incoming Arguments +// +// For any node that may have unknown components (because something outside the +// scope of current analysis may have modified it), the 'Incomplete' flag is +// added to the NodeType. +// +void DSGraph::markIncompleteNodes() { + // Mark any incoming arguments as incomplete... + for (Function::aiterator I = Func.abegin(), E = Func.aend(); I != E; ++I) + if (isa(I->getType())) + markIncompleteNode(ValueMap[I]->getLink(0)); + + // Mark stuff passed into functions calls as being incomplete... + for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) { + std::vector &Args = FunctionCalls[i]; + if (Args[0]) // If the call returns a pointer... + // Then the return value is certainly incomplete! + markIncompleteNode(Args[0]); + + // The call does not make the function argument incomplete... + + // All arguments to the function call are incomplete though! + for (unsigned i = 2, e = Args.size(); i != e; ++i) + markIncompleteNode(Args[i]); + } + + // Mark all of the nodes pointed to by global nodes as incomplete... + for (unsigned i = 0, e = Nodes.size(); i != e; ++i) + if (Nodes[i]->NodeType & DSNode::GlobalNode) { + DSNode *N = Nodes[i]; + for (unsigned i = 0, e = N->getNumLinks(); i != e; ++i) + markIncompleteNode(N->getLink(i)); + } +} + +// isNodeDead - This method checks to see if a node is dead, and if it isn't, it +// checks to see if there are simple transformations that it can do to make it +// dead. +// +bool DSGraph::isNodeDead(DSNode *N) { + // Is it a trivially dead shadow node... + if (N->getReferrers().empty() && N->NodeType == 0) + return true; + + // Is it a function node or some other trivially unused global? + if ((N->NodeType & ~DSNode::GlobalNode) == 0 && + N->getNumLinks() == 0 && + N->getReferrers().size() == N->getGlobals().size()) { + + // Remove the globals from the valuemap, so that the referrer count will go + // down to zero. + while (!N->getGlobals().empty()) { + GlobalValue *GV = N->getGlobals().back(); + N->getGlobals().pop_back(); + ValueMap.erase(GV); + } + assert(N->getReferrers().empty() && "Referrers should all be gone now!"); + return true; + } + + return false; +} + + +// removeDeadNodes - After the graph has been constructed, this method removes +// all unreachable nodes that are created because they got merged with other +// nodes in the graph. These nodes will all be trivially unreachable, so we +// don't have to perform any non-trivial analysis here. +// +void DSGraph::removeDeadNodes() { + for (unsigned i = 0; i != Nodes.size(); ++i) + if (isNodeDead(Nodes[i])) { // This node is dead! + delete Nodes[i]; // Free memory... + Nodes.erase(Nodes.begin()+i--); // Remove from node list... + } + + // Remove identical function calls + unsigned NumFns = FunctionCalls.size(); + std::sort(FunctionCalls.begin(), FunctionCalls.end()); + FunctionCalls.erase(std::unique(FunctionCalls.begin(), FunctionCalls.end()), + FunctionCalls.end()); + + DEBUG(if (NumFns != FunctionCalls.size()) + std::cerr << "Merged " << (NumFns-FunctionCalls.size()) + << " call nodes in " << Func.getName() << "\n";); +} + + +// maskNodeTypes - Apply a mask to all of the node types in the graph. This +// is useful for clearing out markers like Scalar or Incomplete. +// +void DSGraph::maskNodeTypes(unsigned char Mask) { + for (unsigned i = 0, e = Nodes.size(); i != e; ++i) + Nodes[i]->NodeType &= Mask; +} + + //===----------------------------------------------------------------------===// // LocalDataStructures Implementation //===----------------------------------------------------------------------===// @@ -132,11 +339,8 @@ void LocalDataStructures::releaseMemory() { bool LocalDataStructures::run(Module &M) { // Calculate all of the graphs... for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (!I->isExternal()) { - std::map::iterator DI = DSInfo.find(I); - if (DI == DSInfo.end() || DI->second == 0) - DSInfo.insert(std::make_pair(&*I, new DSGraph(*I))); - } + if (!I->isExternal()) + DSInfo.insert(std::make_pair(&*I, new DSGraph(*I))); return false; } diff --git a/lib/Analysis/DataStructure/Local.cpp b/lib/Analysis/DataStructure/Local.cpp index 142133dbefd..f37146e57f0 100644 --- a/lib/Analysis/DataStructure/Local.cpp +++ b/lib/Analysis/DataStructure/Local.cpp @@ -5,15 +5,16 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Analysis/DataStructure.h" #include "llvm/Function.h" #include "llvm/iMemory.h" #include "llvm/iTerminators.h" #include "llvm/iPHINode.h" #include "llvm/iOther.h" #include "llvm/Constants.h" +#include "llvm/GlobalVariable.h" #include "llvm/DerivedTypes.h" #include "llvm/Support/InstVisitor.h" +#include "llvm/Analysis/DataStructure.h" // FIXME: using std::map; using std::vector; @@ -38,8 +39,15 @@ namespace { map &vm, vector > &fc) : G(g), Nodes(nodes), RetNode(retNode), ValueMap(vm), FunctionCalls(fc) { + + // Create scalar nodes for all pointer arguments... + for (Function::aiterator I = G.getFunction().abegin(), + E = G.getFunction().aend(); I != E; ++I) + if (isa(I->getType())) + getValueNode(*I); + visit(G.getFunction()); // Single pass over the function - removeDeadNodes(); + G.removeDeadNodes(); } private: @@ -84,6 +92,11 @@ namespace { // DSNode *getValueNode(Value &V); + // getGlobalNode - Just like getValueNode, except the global node itself is + // returned, not a scalar node pointing to a global. + // + DSNode *getGlobalNode(GlobalValue &V); + // getLink - This method is used to either return the specified link in the // specified node if one exists. If a link does not already exist (it's // null), then we create a new node, link it, then return it. @@ -94,12 +107,6 @@ namespace { // must be factored out of gep, load and store while they are all MAI's. // DSNode *getSubscriptedNode(MemAccessInst &MAI, DSNode *Ptr); - - // removeDeadNodes - After the graph has been constructed, this method - // removes all unreachable nodes that are created because they got merged - // with other nodes in the graph. - // - void removeDeadNodes(); }; } @@ -109,6 +116,7 @@ namespace { DSGraph::DSGraph(Function &F) : Func(F), RetNode(0) { // Use the graph builder to construct the local version of the graph GraphBuilder B(*this, Nodes, RetNode, ValueMap, FunctionCalls); + markIncompleteNodes(); } @@ -127,6 +135,26 @@ DSNode *GraphBuilder::createNode(DSNode::NodeTy NodeType, const Type *Ty) { } +// getGlobalNode - Just like getValueNode, except the global node itself is +// returned, not a scalar node pointing to a global. +// +DSNode *GraphBuilder::getGlobalNode(GlobalValue &V) { + DSNodeHandle &NH = ValueMap[&V]; + if (NH) return NH; // Already have a node? Just return it... + + // Create a new global node for this global variable... + DSNode *G = createNode(DSNode::GlobalNode, V.getType()->getElementType()); + G->addGlobal(&V); + + // If this node has outgoing edges, make sure to recycle the same node for + // each use. For functions and other global variables, this is unneccesary, + // so avoid excessive merging by cloning these nodes on demand. + // + NH = G; + return G; +} + + // getValueNode - Return a DSNode that corresponds the the specified LLVM value. // This either returns the already existing node, or creates a new one and adds // it to the graph, if none exists. @@ -134,27 +162,17 @@ DSNode *GraphBuilder::createNode(DSNode::NodeTy NodeType, const Type *Ty) { DSNode *GraphBuilder::getValueNode(Value &V) { assert(isa(V.getType()) && "Should only use pointer scalars!"); if (!isa(V)) { - DSNodeHandle &N = ValueMap[&V]; - if (N) return N; // Already have a node? Just return it... + DSNodeHandle &NH = ValueMap[&V]; + if (NH) return NH; // Already have a node? Just return it... } // Otherwise we need to create a new scalar node... DSNode *N = createNode(DSNode::ScalarNode, V.getType()); + // If this is a global value, create the global pointed to. if (GlobalValue *GV = dyn_cast(&V)) { - DSNodeHandle &GVH = ValueMap[GV]; - DSNode *G = getLink(N, 0); - - if (GVH == 0) { - // Traverse the global graph, adding nodes for them all, and marking them - // all globals. Be careful to mark functions global as well as the - // potential graph of global variables. - // - G->addGlobal(GV); - GVH = G; - } else { - GVH->mergeWith(G); - } + DSNode *G = getGlobalNode(*GV); + N->addEdgeTo(G); } else { ValueMap[&V] = N; } @@ -162,6 +180,7 @@ DSNode *GraphBuilder::getValueNode(Value &V) { return N; } + // getLink - This method is used to either return the specified link in the // specified node if one exists. If a link does not already exist (it's // null), then we create a new node, link it, then return it. @@ -214,25 +233,6 @@ DSNode *GraphBuilder::getSubscriptedNode(MemAccessInst &MAI, DSNode *Ptr) { return Ptr; } - -// removeDeadNodes - After the graph has been constructed, this method removes -// all unreachable nodes that are created because they got merged with other -// nodes in the graph. These nodes will all be trivially unreachable, so we -// don't have to perform any non-trivial analysis here. -// -void GraphBuilder::removeDeadNodes() { - for (unsigned i = 0; i != Nodes.size(); ) - if (Nodes[i]->NodeType || !Nodes[i]->getReferrers().empty()) - ++i; // This node is alive! - else { // This node is dead! - delete Nodes[i]; // Free memory... - Nodes.erase(Nodes.begin()+i); // Remove from node list... - } -} - - - - //===----------------------------------------------------------------------===// // Specific instruction type handler implementations... // @@ -259,13 +259,13 @@ void GraphBuilder::visitPHINode(PHINode &PN) { } void GraphBuilder::visitGetElementPtrInst(GetElementPtrInst &GEP) { - DSNode *Ptr = getSubscriptedNode(GEP, getValueNode(*GEP.getOperand(0))); + DSNode *Ptr = getSubscriptedNode(GEP, getValueNode(*GEP.getOperand(0))); getValueNode(GEP)->addEdgeTo(Ptr); } void GraphBuilder::visitLoadInst(LoadInst &LI) { if (!isa(LI.getType())) return; // Only pointer PHIs - DSNode *Ptr = getSubscriptedNode(LI, getValueNode(*LI.getOperand(0))); + DSNode *Ptr = getSubscriptedNode(LI, getValueNode(*LI.getOperand(0))); getValueNode(LI)->addEdgeTo(getLink(Ptr, 0)); } @@ -285,17 +285,25 @@ void GraphBuilder::visitReturnInst(ReturnInst &RI) { } void GraphBuilder::visitCallInst(CallInst &CI) { + // Add a new function call entry... FunctionCalls.push_back(vector()); vector &Args = FunctionCalls.back(); // Set up the return value... if (isa(CI.getType())) - Args.push_back(getValueNode(CI)); + Args.push_back(getLink(getValueNode(CI), 0)); else Args.push_back(0); + unsigned Start = 0; + // Special case for direct call, avoid creating spurious scalar node... + if (GlobalValue *GV = dyn_cast(CI.getOperand(0))) { + Args.push_back(getGlobalNode(*GV)); + Start = 1; + } + // Pass the arguments in... - for (unsigned i = 0, e = CI.getNumOperands(); i != e; ++i) + for (unsigned i = Start, e = CI.getNumOperands(); i != e; ++i) if (isa(CI.getOperand(i)->getType())) - Args.push_back(getValueNode(*CI.getOperand(i))); + Args.push_back(getLink(getValueNode(*CI.getOperand(i)), 0)); } diff --git a/lib/Analysis/DataStructure/Printer.cpp b/lib/Analysis/DataStructure/Printer.cpp index 15f8df19ef1..4a58c69afd3 100644 --- a/lib/Analysis/DataStructure/Printer.cpp +++ b/lib/Analysis/DataStructure/Printer.cpp @@ -9,10 +9,11 @@ #include "llvm/Assembly/Writer.h" #include #include +using std::string; void DSNode::dump() const { print(std::cerr, 0); } -std::string DSNode::getCaption(const DSGraph *G) const { +string DSNode::getCaption(const DSGraph *G) const { std::stringstream OS; Module *M = G ? G->getFunction().getParent() : 0; WriteTypeSymbolic(OS, getType(), M); @@ -24,6 +25,7 @@ std::string DSNode::getCaption(const DSGraph *G) const { if (NodeType & GlobalNode) OS << "G"; if (NodeType & SubElement) OS << "E"; if (NodeType & CastNode ) OS << "C"; + if (NodeType & Incomplete) OS << "I"; for (unsigned i = 0, e = Globals.size(); i != e; ++i) { OS << "\n"; @@ -43,7 +45,7 @@ std::string DSNode::getCaption(const DSGraph *G) const { return OS.str(); } -static std::string getValueName(Value *V, Function &F) { +static string getValueName(Value *V, Function &F) { std::stringstream OS; WriteAsOperand(OS, V, true, true, F.getParent()); return OS.str(); @@ -51,7 +53,7 @@ static std::string getValueName(Value *V, Function &F) { -static void replaceIn(std::string &S, char From, const std::string &To) { +static void replaceIn(string &S, char From, const string &To) { for (unsigned i = 0; i < S.size(); ) if (S[i] == From) { S.replace(S.begin()+i, S.begin()+i+1, @@ -144,23 +146,32 @@ void DSGraph::print(std::ostream &O) const { O << "}\n"; } - - - -// print - Print out the analysis results... -void LocalDataStructures::print(std::ostream &O, Module *M) const { +template +static void printCollection(const Collection &C, std::ostream &O, Module *M, + const string &Prefix) { for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) if (!I->isExternal()) { - std::string Filename = "ds." + I->getName() + ".dot"; + string Filename = Prefix + "." + I->getName() + ".dot"; O << "Writing '" << Filename << "'..."; std::ofstream F(Filename.c_str()); - + if (F.good()) { - DSGraph &Graph = getDSGraph(*I); + DSGraph &Graph = C.getDSGraph(*I); Graph.print(F); - O << " [" << Graph.getGraphSize() << "]\n"; + O << " [" << Graph.getGraphSize() << "+" + << Graph.getFunctionCalls().size() << "]\n"; } else { O << " error opening file for writing!\n"; } } } + + +// print - Print out the analysis results... +void LocalDataStructures::print(std::ostream &O, Module *M) const { + printCollection(*this, O, M, "ds"); +} + +void BUDataStructures::print(std::ostream &O, Module *M) const { + printCollection(*this, O, M, "bu"); +}