diff options
Diffstat (limited to 'lib/Analysis/DataStructure/DataStructure.cpp')
-rw-r--r-- | lib/Analysis/DataStructure/DataStructure.cpp | 861 |
1 files changed, 407 insertions, 454 deletions
diff --git a/lib/Analysis/DataStructure/DataStructure.cpp b/lib/Analysis/DataStructure/DataStructure.cpp index 81e6db3d75..2a0dc998a0 100644 --- a/lib/Analysis/DataStructure/DataStructure.cpp +++ b/lib/Analysis/DataStructure/DataStructure.cpp @@ -17,6 +17,7 @@ #include "llvm/DerivedTypes.h" #include "llvm/Target/TargetData.h" #include "llvm/Assembly/Writer.h" +#include "Support/CommandLine.h" #include "Support/Debug.h" #include "Support/STLExtras.h" #include "Support/Statistic.h" @@ -27,6 +28,11 @@ using namespace llvm; namespace { Statistic<> NumFolds ("dsnode", "Number of nodes completely folded"); Statistic<> NumCallNodesMerged("dsnode", "Number of call nodes merged"); + Statistic<> NumNodeAllocated ("dsnode", "Number of nodes allocated"); + + cl::opt<bool> + EnableDSNodeGlobalRootsHack("enable-dsa-globalrootshack", cl::Hidden, + cl::desc("Make DSA less aggressive when cloning graphs")); }; #if 0 @@ -68,13 +74,19 @@ DSNode::DSNode(const Type *T, DSGraph *G) // Add the type entry if it is specified... if (T) mergeTypeInfo(T, 0); G->getNodes().push_back(this); + ++NumNodeAllocated; } // DSNode copy constructor... do not copy over the referrers list! -DSNode::DSNode(const DSNode &N, DSGraph *G) +DSNode::DSNode(const DSNode &N, DSGraph *G, bool NullLinks) : NumReferrers(0), Size(N.Size), ParentGraph(G), - Ty(N.Ty), Links(N.Links), Globals(N.Globals), NodeType(N.NodeType) { + Ty(N.Ty), Globals(N.Globals), NodeType(N.NodeType) { + if (!NullLinks) + Links = N.Links; + else + Links.resize(N.Links.size()); // Create the appropriate number of null links G->getNodes().push_back(this); + ++NumNodeAllocated; } /// getTargetData - Get the target data object used to construct this node. @@ -138,26 +150,40 @@ void DSNode::foldNodeCompletely() { ++NumFolds; - // Create the node we are going to forward to... - DSNode *DestNode = new DSNode(0, ParentGraph); - DestNode->NodeType = NodeType|DSNode::Array; - DestNode->Ty = Type::VoidTy; - DestNode->Size = 1; - DestNode->Globals.swap(Globals); - - // Start forwarding to the destination node... - forwardNode(DestNode, 0); - - if (Links.size()) { - DestNode->Links.push_back(Links[0]); - DSNodeHandle NH(DestNode); - - // If we have links, merge all of our outgoing links together... - for (unsigned i = Links.size()-1; i != 0; --i) - NH.getNode()->Links[0].mergeWith(Links[i]); - Links.clear(); + // If this node has a size that is <= 1, we don't need to create a forwarding + // node. + if (getSize() <= 1) { + NodeType |= DSNode::Array; + Ty = Type::VoidTy; + Size = 1; + assert(Links.size() <= 1 && "Size is 1, but has more links?"); + Links.resize(1); } else { - DestNode->Links.resize(1); + // Create the node we are going to forward to. This is required because + // some referrers may have an offset that is > 0. By forcing them to + // forward, the forwarder has the opportunity to correct the offset. + DSNode *DestNode = new DSNode(0, ParentGraph); + DestNode->NodeType = NodeType|DSNode::Array; + DestNode->Ty = Type::VoidTy; + DestNode->Size = 1; + DestNode->Globals.swap(Globals); + + // Start forwarding to the destination node... + forwardNode(DestNode, 0); + + if (!Links.empty()) { + DestNode->Links.reserve(1); + + DSNodeHandle NH(DestNode); + DestNode->Links.push_back(Links[0]); + + // If we have links, merge all of our outgoing links together... + for (unsigned i = Links.size()-1; i != 0; --i) + NH.getNode()->Links[0].mergeWith(Links[i]); + Links.clear(); + } else { + DestNode->Links.resize(1); + } } } @@ -432,6 +458,10 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset, // If we found our type exactly, early exit if (SubType == NewTy) return false; + // Differing function types don't require us to merge. They are not values anyway. + if (isa<FunctionType>(SubType) && + isa<FunctionType>(NewTy)) return false; + unsigned SubTypeSize = SubType->isSized() ? TD.getTypeSize(SubType) : 0; // Ok, we are getting desperate now. Check for physical subtyping, where we @@ -523,10 +553,10 @@ bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset, // can cause merging of nodes in the graph. // void DSNode::addEdgeTo(unsigned Offset, const DSNodeHandle &NH) { - if (NH.getNode() == 0) return; // Nothing to do + if (NH.isNull()) return; // Nothing to do DSNodeHandle &ExistingEdge = getLink(Offset); - if (ExistingEdge.getNode()) { + if (!ExistingEdge.isNull()) { // Merge the two nodes... ExistingEdge.mergeWith(NH); } else { // No merging to perform... @@ -578,8 +608,11 @@ static void MergeSortedVectors(std::vector<GlobalValue*> &Dest, } } +void DSNode::mergeGlobals(const std::vector<GlobalValue*> &RHS) { + MergeSortedVectors(Globals, RHS); +} -// MergeNodes() - Helper function for DSNode::mergeWith(). +// MergeNodes - Helper function for DSNode::mergeWith(). // This function does the hard work of merging two nodes, CurNodeH // and NH after filtering out trivial cases and making sure that // CurNodeH.offset >= NH.offset. @@ -642,7 +675,7 @@ void DSNode::MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH) { if (CurNodeH.getNode() == N || N == 0) return; assert(!CurNodeH.getNode()->isDeadNode()); - // Merge the NodeType information... + // Merge the NodeType information. CurNodeH.getNode()->NodeType |= N->NodeType; // Start forwarding to the new node! @@ -673,7 +706,7 @@ void DSNode::MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH) { // Merge the globals list... if (!N->Globals.empty()) { - MergeSortedVectors(CurNodeH.getNode()->Globals, N->Globals); + CurNodeH.getNode()->mergeGlobals(N->Globals); // Delete the globals from the old node... std::vector<GlobalValue*>().swap(N->Globals); @@ -731,6 +764,213 @@ void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) { DSNode::MergeNodes(CurNodeH, NHCopy); } + +//===----------------------------------------------------------------------===// +// ReachabilityCloner Implementation +//===----------------------------------------------------------------------===// + +DSNodeHandle ReachabilityCloner::getClonedNH(const DSNodeHandle &SrcNH) { + if (SrcNH.isNull()) return DSNodeHandle(); + const DSNode *SN = SrcNH.getNode(); + + DSNodeHandle &NH = NodeMap[SN]; + if (!NH.isNull()) // Node already mapped? + return DSNodeHandle(NH.getNode(), NH.getOffset()+SrcNH.getOffset()); + + DSNode *DN = new DSNode(*SN, &Dest, true /* Null out all links */); + DN->maskNodeTypes(BitsToKeep); + NH.setNode(DN); + NH.setOffset(SrcNH.getOffset()); + + // Next, recursively clone all outgoing links as necessary. Note that + // adding these links can cause the node to collapse itself at any time, and + // the current node may be merged with arbitrary other nodes. For this + // reason, we must always go through NH. + DN = 0; + for (unsigned i = 0, e = SN->getNumLinks(); i != e; ++i) { + const DSNodeHandle &SrcEdge = SN->getLink(i << DS::PointerShift); + if (!SrcEdge.isNull()) { + const DSNodeHandle &DestEdge = getClonedNH(SrcEdge); + // Compute the offset into the current node at which to + // merge this link. In the common case, this is a linear + // relation to the offset in the original node (with + // wrapping), but if the current node gets collapsed due to + // recursive merging, we must make sure to merge in all remaining + // links at offset zero. + unsigned MergeOffset = 0; + DSNode *CN = NH.getNode(); + if (CN->getSize() != 1) + MergeOffset = ((i << DS::PointerShift)+NH.getOffset() + - SrcNH.getOffset()) %CN->getSize(); + CN->addEdgeTo(MergeOffset, DestEdge); + } + } + + // If this node contains any globals, make sure they end up in the scalar + // map with the correct offset. + for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end(); + I != E; ++I) { + GlobalValue *GV = *I; + const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV); + DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; + assert(DestGNH.getNode() == NH.getNode() &&"Global mapping inconsistent"); + Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), + DestGNH.getOffset()+NH.getOffset())); + + if (CloneFlags & DSGraph::UpdateInlinedGlobals) + Dest.getInlinedGlobals().insert(GV); + } + + return DSNodeHandle(NH.getNode(), NH.getOffset()+SrcNH.getOffset()); +} + +void ReachabilityCloner::merge(const DSNodeHandle &NH, + const DSNodeHandle &SrcNH) { + if (SrcNH.isNull()) return; // Noop + if (NH.isNull()) { + // If there is no destination node, just clone the source and assign the + // destination node to be it. + NH.mergeWith(getClonedNH(SrcNH)); + return; + } + + // Okay, at this point, we know that we have both a destination and a source + // node that need to be merged. Check to see if the source node has already + // been cloned. + const DSNode *SN = SrcNH.getNode(); + DSNodeHandle &SCNH = NodeMap[SN]; // SourceClonedNodeHandle + if (SCNH.getNode()) { // Node already cloned? + NH.mergeWith(DSNodeHandle(SCNH.getNode(), + SCNH.getOffset()+SrcNH.getOffset())); + + return; // Nothing to do! + } + + // Okay, so the source node has not already been cloned. Instead of creating + // a new DSNode, only to merge it into the one we already have, try to perform + // the merge in-place. The only case we cannot handle here is when the offset + // into the existing node is less than the offset into the virtual node we are + // merging in. In this case, we have to extend the existing node, which + // requires an allocation anyway. + DSNode *DN = NH.getNode(); // Make sure the Offset is up-to-date + if (NH.getOffset() >= SrcNH.getOffset()) { + + if (!DN->isNodeCompletelyFolded()) { + // Make sure the destination node is folded if the source node is folded. + if (SN->isNodeCompletelyFolded()) { + DN->foldNodeCompletely(); + DN = NH.getNode(); + } else if (SN->getSize() != DN->getSize()) { + // If the two nodes are of different size, and the smaller node has the + // array bit set, collapse! + if (SN->getSize() < DN->getSize()) { + if (SN->isArray()) { + DN->foldNodeCompletely(); + DN = NH.getNode(); + } + } else if (DN->isArray()) { + DN->foldNodeCompletely(); + DN = NH.getNode(); + } + } + + // Merge the type entries of the two nodes together... + if (SN->getType() != Type::VoidTy && !DN->isNodeCompletelyFolded()) { + DN->mergeTypeInfo(SN->getType(), NH.getOffset()-SrcNH.getOffset()); + DN = NH.getNode(); + } + } + + assert(!DN->isDeadNode()); + + // Merge the NodeType information. + DN->mergeNodeFlags(SN->getNodeFlags() & BitsToKeep); + + // Before we start merging outgoing links and updating the scalar map, make + // sure it is known that this is the representative node for the src node. + SCNH = DSNodeHandle(DN, NH.getOffset()-SrcNH.getOffset()); + + // If the source node contains any globals, make sure they end up in the + // scalar map with the correct offset. + if (SN->global_begin() != SN->global_end()) { + // Update the globals in the destination node itself. + DN->mergeGlobals(SN->getGlobals()); + + // Update the scalar map for the graph we are merging the source node + // into. + for (DSNode::global_iterator I = SN->global_begin(), E = SN->global_end(); + I != E; ++I) { + GlobalValue *GV = *I; + const DSNodeHandle &SrcGNH = Src.getNodeForValue(GV); + DSNodeHandle &DestGNH = NodeMap[SrcGNH.getNode()]; + assert(DestGNH.getNode()==NH.getNode() &&"Global mapping inconsistent"); + Dest.getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(), + DestGNH.getOffset()+NH.getOffset())); + + if (CloneFlags & DSGraph::UpdateInlinedGlobals) + Dest.getInlinedGlobals().insert(GV); + } + } + } else { + // We cannot handle this case without allocating a temporary node. Fall + // back on being simple. + + DSNode *NewDN = new DSNode(*SN, &Dest, true /* Null out all links */); + NewDN->maskNodeTypes(BitsToKeep); + + unsigned NHOffset = NH.getOffset(); + NH.mergeWith(DSNodeHandle(NewDN, SrcNH.getOffset())); + assert(NH.getNode() && + (NH.getOffset() > NHOffset || + (NH.getOffset() == 0 && NH.getNode()->isNodeCompletelyFolded())) && + "Merging did not adjust the offset!"); + + // Before we start merging outgoing links and updating the scalar map, make + // sure it is known that this is the representative node for the src node. + SCNH = DSNodeHandle(NH.getNode(), NH.getOffset()-SrcNH.getOffset()); + } + + + // Next, recursively merge all outgoing links as necessary. Note that + // adding these links can cause the destination node to collapse itself at + // any time, and the current node may be merged with arbitrary other nodes. + // For this reason, we must always go through NH. + DN = 0; + for (unsigned i = 0, e = SN->getNumLinks(); i != e; ++i) { + const DSNodeHandle &SrcEdge = SN->getLink(i << DS::PointerShift); + if (!SrcEdge.isNull()) { + // Compute the offset into the current node at which to + // merge this link. In the common case, this is a linear + // relation to the offset in the original node (with + // wrapping), but if the current node gets collapsed due to + // recursive merging, we must make sure to merge in all remaining + // links at offset zero. + unsigned MergeOffset = 0; + DSNode *CN = SCNH.getNode(); + if (CN->getSize() != 1) + MergeOffset = ((i << DS::PointerShift)+SCNH.getOffset()) %CN->getSize(); + + // Perform the recursive merging. Make sure to create a temporary NH, + // because the Link can disappear in the process of recursive merging. + DSNodeHandle Tmp = CN->getLink(MergeOffset); + merge(Tmp, SrcEdge); + } + } +} + +/// mergeCallSite - Merge the nodes reachable from the specified src call +/// site into the nodes reachable from DestCS. +void ReachabilityCloner::mergeCallSite(const DSCallSite &DestCS, + const DSCallSite &SrcCS) { + merge(DestCS.getRetVal(), SrcCS.getRetVal()); + unsigned MinArgs = DestCS.getNumPtrArgs(); + if (SrcCS.getNumPtrArgs() < MinArgs) MinArgs = SrcCS.getNumPtrArgs(); + + for (unsigned a = 0; a != MinArgs; ++a) + merge(DestCS.getPtrArg(a), SrcCS.getPtrArg(a)); +} + + //===----------------------------------------------------------------------===// // DSCallSite Implementation //===----------------------------------------------------------------------===// @@ -740,6 +980,10 @@ Function &DSCallSite::getCaller() const { return *Site.getInstruction()->getParent()->getParent(); } +void DSCallSite::InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, + ReachabilityCloner &RC) { + NH = RC.getClonedNH(Src); +} //===----------------------------------------------------------------------===// // DSGraph Implementation @@ -807,108 +1051,29 @@ void DSNode::remapLinks(DSGraph::NodeMapTy &OldNodeMap) { } } - -/// cloneReachableNodes - Clone all reachable nodes from *Node into the current -/// graph. This is a recursive function. The map OldNodeMap is a map from the -/// original nodes to their clones. This populates the Globals set with all of -/// the global values that are cloned in. -/// -void DSGraph::cloneReachableNodes(const DSNode *Node, unsigned BitsToClear, - NodeMapTy &OldNodeMap, GlobalSetTy &Globals) { - DSNodeHandle &NH = OldNodeMap[Node]; - if (NH.getNode()) return; // Already cloned this node? - - // FIXME: eliminate eventually! - Globals.insert(Node->getGlobals().begin(), Node->getGlobals().end()); - - // else Node has not yet been cloned: clone it and clear the specified bits - DSNode *New = new DSNode(*Node, this); - New->maskNodeTypes(~BitsToClear); - NH = New; // enters in OldNodeMap - - // now recursively clone nodes pointed to by this node - for (unsigned i = 0, e = Node->getNumLinks(); i != e; ++i) - if (const DSNode *N = Node->getLink(i << DS::PointerShift).getNode()) - cloneReachableNodes(N, BitsToClear, OldNodeMap, Globals); -} - -void DSGraph::cloneReachableSubgraph(const DSGraph &G, - hash_set<const DSNode*> &RootNodes, - NodeMapTy &OldNodeMap, - unsigned CloneFlags) { - RootNodes.erase(0); // Null is not a root node - if (RootNodes.empty()) return; - TIME_REGION(X, "cloneReachableSubgraph"); - - assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!"); - assert(&G != this && "Cannot clone graph into itself!"); - assert((*RootNodes.begin())->getParentGraph() == &G && - "Root nodes do not belong to this graph!"); - - // Remove alloca or mod/ref bits as specified... - unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0) - | ((CloneFlags & StripModRefBits)? (DSNode::Modified | DSNode::Read) : 0) - | ((CloneFlags & StripIncompleteBit)? DSNode::Incomplete : 0); - BitsToClear |= DSNode::DEAD; // Clear dead flag... - - GlobalSetTy Globals; - - // Clone all nodes reachable from each root node, using a recursive helper. - for (hash_set<const DSNode*>::const_iterator I = RootNodes.begin(), - E = RootNodes.end(); I != E; ++I) - cloneReachableNodes(*I, BitsToClear, OldNodeMap, Globals); - - // Rewrite the links in the newly created nodes (the nodes in OldNodeMap) - // to point into the current graph. - for (NodeMapTy::iterator I=OldNodeMap.begin(), E=OldNodeMap.end(); I!= E; ++I) - I->second.getNode()->remapLinks(OldNodeMap); - - if (CloneFlags & DSGraph::UpdateInlinedGlobals) - InlinedGlobals.insert(Globals.begin(), Globals.end()); - - // Make sure to set up the scalar map entries for all of the globals. - // - // FIXME: when cloneReachableNodes is improved to not require 'remapLinks', - // this should not be needed! - for (GlobalSetTy::iterator I = Globals.begin(), E = Globals.end(); I!=E; ++I){ - const DSNodeHandle &GOrig = G.getNodeForValue(*I); - DSNodeHandle &GClone = OldNodeMap[GOrig.getNode()]; - GClone.setOffset(GClone.getOffset()+GOrig.getOffset()); - ScalarMap[*I].mergeWith(GClone); - } -} - - /// updateFromGlobalGraph - This function rematerializes global nodes and /// nodes reachable from them from the globals graph into the current graph. -/// It invokes cloneReachableSubgraph, using the globals in the current graph -/// as the roots. It also uses the vector InlinedGlobals to avoid cloning and -/// merging globals that are already up-to-date in the current graph. In -/// practice, in the TD pass, this is likely to be a large fraction of the -/// live global nodes in each function (since most live nodes are likely to -/// have been brought up-to-date in at _some_ caller or callee). +/// It uses the vector InlinedGlobals to avoid cloning and merging globals that +/// are already up-to-date in the current graph. In practice, in the TD pass, +/// this is likely to be a large fraction of the live global nodes in each +/// function (since most live nodes are likely to have been brought up-to-date +/// in at _some_ caller or callee). /// void DSGraph::updateFromGlobalGraph() { - // Put the live, non-up-to-date global nodes into a set and the up-to-date - // ones in the map above, mapping node in GlobalsGraph to the up-to-date node. - hash_set<const DSNode*> GlobalNodeSet; - for (ScalarMapTy::const_iterator I = getScalarMap().begin(), - E = getScalarMap().end(); I != E; ++I) - if (GlobalValue* GV = dyn_cast<GlobalValue>(I->first)) { - DSNode* GNode = I->second.getNode(); - assert(GNode && "No node for live global in current Graph?"); - if (const DSNode* GGNode = GlobalsGraph->ScalarMap[GV].getNode()) - if (InlinedGlobals.count(GV) == 0) // GNode is not up-to-date - GlobalNodeSet.insert(GGNode); - } + TIME_REGION(X, "updateFromGlobalGraph"); - // Clone the subgraph reachable from the vector of nodes in GlobalNodes - // and merge the cloned global nodes with the corresponding ones, if any. - { - NodeMapTy OldNodeMap; // Scope ensures these is deleted promptly - cloneReachableSubgraph(*GlobalsGraph, GlobalNodeSet, OldNodeMap); - } + ReachabilityCloner RC(*this, *GlobalsGraph, 0); + // Clone the non-up-to-date global nodes into this graph. + for (ScalarMapTy::const_iterator I = getScalarMap().begin(), + E = getScalarMap().end(); I != E; ++I) + if (GlobalValue* GV = dyn_cast<GlobalValue>(I->first)) + if (InlinedGlobals.count(GV) == 0) { // GNode is not up-to-date + ScalarMapTy::iterator It = GlobalsGraph->ScalarMap.find(GV); + if (It != GlobalsGraph->ScalarMap.end()) + RC.getClonedNH(It->second); + } + // Merging global nodes leaves behind unused nodes: get rid of them now. removeTriviallyDeadNodes(); } @@ -950,8 +1115,6 @@ void DSGraph::cloneInto(const DSGraph &G, ScalarMapTy &OldValMap, for (unsigned i = FN, e = Nodes.size(); i != e; ++i) Nodes[i]->remapLinks(OldNodeMap); - { TIME_REGION(X, "cloneInto:scalars"); - // Copy the scalar map... merging all of the global nodes... for (ScalarMapTy::const_iterator I = G.ScalarMap.begin(), E = G.ScalarMap.end(); I != E; ++I) { @@ -967,7 +1130,6 @@ void DSGraph::cloneInto(const DSGraph &G, ScalarMapTy &OldValMap, InlinedGlobals.insert(GV); } } - } if (!(CloneFlags & DontCloneCallNodes)) { // Copy the function calls list... @@ -996,174 +1158,6 @@ void DSGraph::cloneInto(const DSGraph &G, ScalarMapTy &OldValMap, } } -/// clonePartiallyInto - Clone the reachable subset of the specified DSGraph -/// into the current graph, for the specified function. -/// -/// This differs from cloneInto in that it only clones nodes reachable from -/// globals, call nodes, the scalars specified in ValBindings, and the return -/// value of the specified function. This method merges the the cloned -/// version of the scalars and return value with the specified DSNodeHandles. -/// -/// On return, OldNodeMap contains a mapping from the original nodes to the -/// newly cloned nodes, for the subset of nodes that were actually cloned. -/// -/// The CloneFlags member controls various aspects of the cloning process. -/// -void DSGraph::clonePartiallyInto(const DSGraph &G, Function &F, - const DSNodeHandle &RetVal, - const ScalarMapTy &ValBindings, - NodeMapTy &OldNodeMap, - unsigned CloneFlags) { - - TIME_REGION(X, "clonePartiallyInto"); - assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!"); - assert(&G != this && "Cannot clone graph into itself!"); - -#if 0 // ENABLE THIS to get the cloneReachableSubGraph code path - hash_set<const DSNode*> RootNodes; - -#if 0 - // THIS IS A HACK that sanity checks the cloner. This is inefficient, and - // causes all nodes to be cloned. - - // Add the nodes that we need to clone to the RootNodes set. - for (unsigned i = 0, e = G.Nodes.size(); i != e; ++i) - RootNodes.insert(G.Nodes[i]); - -#else - // We need the return value nodes... - if (RetVal.getNode()) - RootNodes.insert(G.getReturnNodeFor(F).getNode()); - - // We need the nodes whose bindings are specified by the ValBindings map. - for (ScalarMapTy::const_iterator I = ValBindings.begin(), - E = ValBindings.end(); I != E; ++I) - RootNodes.insert(G.getNodeForValue(I->first).getNode()); - - // If requested, we need the nodes from the calls list... - if (!(CloneFlags & DontCloneCallNodes)) { - for (unsigned i = 0, e = G.FunctionCalls.size(); i != e; ++i) { - const DSCallSite &CS = G.FunctionCalls[i]; - RootNodes.insert(CS.getRetVal().getNode()); - if (CS.isIndirectCall()) - RootNodes.insert(CS.getCalleeNode()); - for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a) - RootNodes.insert(CS.getPtrArg(a).getNode()); - } - } - - // If requested, we need the nodes from the aux calls list... - if (!(CloneFlags & DontCloneAuxCallNodes)) { - for (unsigned i = 0, e = G.AuxFunctionCalls.size(); i != e; ++i) { - const DSCallSite &CS = G.AuxFunctionCalls[i]; - RootNodes.insert(CS.getRetVal().getNode()); - if (CS.isIndirectCall()) - RootNodes.insert(CS.getCalleeNode()); - for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a) - RootNodes.insert(CS.getPtrArg(a).getNode()); - } - } - - - /// FIXME: This is another hack, which adds all global nodes to the roots, - /// this is necessary for correctness for some reason??? - - // Add the nodes that we need to clone to the RootNodes set. - for (unsigned i = 0, e = G.Nodes.size(); i != e; ++i) - if (!G.Nodes[i]->getGlobals().empty()) - RootNodes.insert(G.Nodes[i]); - - -#endif - - // Finally, clone the subgraph reachable from these roots. - cloneReachableSubgraph(G, RootNodes, OldNodeMap, CloneFlags); -#else - unsigned FN = Nodes.size(); // First new node... - - /// FIXME: This currently clones the whole graph over, instead of doing it - /// incrementally. This could be sped up quite a bit further! - - // Duplicate all of the nodes, populating the node map... - Nodes.reserve(FN+G.Nodes.size()); - - // Remove alloca or mod/ref bits as specified... - unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0) - | ((CloneFlags & StripModRefBits)? (DSNode::Modified | DSNode::Read) : 0) - | ((CloneFlags & StripIncompleteBit)? DSNode::Incomplete : 0); - BitsToClear |= DSNode::DEAD; // Clear dead flag... - - GlobalSetTy ClonedGlobals; - for (unsigned i = 0, e = G.Nodes.size(); i != e; ++i) { - DSNode *Old = G.Nodes[i]; - DSNode *New = new DSNode(*Old, this); - New->maskNodeTypes(~BitsToClear); - OldNodeMap[Old] = New; - - ClonedGlobals.insert(New->getGlobals().begin(), New->getGlobals().end()); - } - - // Rewrite the links in the new nodes to point into the current graph now. - for (unsigned i = FN, e = Nodes.size(); i != e; ++i) - Nodes[i]->remapLinks(OldNodeMap); - - // Ensure that all global nodes end up in the scalar map, as appropriate. - for (GlobalSetTy::iterator CI = ClonedGlobals.begin(), - E = ClonedGlobals.end(); CI != E; ++CI) { - const DSNodeHandle &NGH = G.getNodeForValue(*CI); - - DSNodeHandle &MappedNode = OldNodeMap[NGH.getNode()]; - DSNodeHandle H(MappedNode.getNode(),NGH.getOffset()+MappedNode.getOffset()); - ScalarMap[*CI].mergeWith(H); - - if (CloneFlags & DSGraph::UpdateInlinedGlobals) - InlinedGlobals.insert(*CI); - } -#endif - -#ifndef NDEBUG - Timer::addPeakMemoryMeasurement(); -#endif - - // Merge the requested portion of the scalar map with the values specified. - for (ScalarMapTy::const_iterator I = ValBindings.begin(), - E = ValBindings.end(); I != E; ++I) { - const DSNodeHandle &SNH = G.getNodeForValue(I->first); - - DSNodeHandle &MappedNode = OldNodeMap[SNH.getNode()]; - DSNodeHandle H(MappedNode.getNode(),SNH.getOffset()+MappedNode.getOffset()); - H.mergeWith(I->second); - } - - // Map the return node pointer over. - if (RetVal.getNode()) { - const DSNodeHandle &Ret = G.getReturnNodeFor(F); - DSNodeHandle &MappedRet = OldNodeMap[Ret.getNode()]; - DSNodeHandle H(MappedRet.getNode(), - MappedRet.getOffset()+Ret.getOffset()); - H.mergeWith(RetVal); - } - - // If requested, copy the calls or aux-calls lists. - if (!(CloneFlags & DontCloneCallNodes)) { - // Copy the function calls list... - unsigned FC = FunctionCalls.size(); // FirstCall - FunctionCalls.reserve(FC+G.FunctionCalls.size()); - for (unsigned i = 0, ei = G.FunctionCalls.size(); i != ei; ++i) - FunctionCalls.push_back(DSCallSite(G.FunctionCalls[i], OldNodeMap)); - } - - if (!(CloneFlags & DontCloneAuxCallNodes)) { - // Copy the auxiliary function calls list... - unsigned FC = AuxFunctionCalls.size(); // FirstCall - AuxFunctionCalls.reserve(FC+G.AuxFunctionCalls.size()); - for (unsigned i = 0, ei = G.AuxFunctionCalls.size(); i != ei; ++i) - AuxFunctionCalls.push_back(DSCallSite(G.AuxFunctionCalls[i], OldNodeMap)); - } -} - - - /// mergeInGraph - The method is used for merging graphs together. If the /// argument graph is not *this, it makes a clone of the specified graph, then @@ -1172,13 +1166,15 @@ void DSGraph::clonePartiallyInto(const DSGraph &G, Function &F, /// void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F, const DSGraph &Graph, unsigned CloneFlags) { + TIME_REGION(X, "mergeInGraph"); + // If this is not a recursive call, clone the graph into this graph... if (&Graph != this) { - // Clone the callee's graph into the current graph, keeping - // track of where scalars in the old graph _used_ to point, - // and of the new nodes matching nodes of the old graph. - ScalarMapTy ValueBindings; - + // Clone the callee's graph into the current graph, keeping track of where + // scalars in the old graph _used_ to point, and of the new nodes matching + // nodes of the old graph. + ReachabilityCloner RC(*this, Graph, CloneFlags); + // Set up argument bindings Function::aiterator AI = F.abegin(); for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i, ++AI) { @@ -1193,16 +1189,38 @@ void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F, if (AI == F.aend()) break; // Add the link from the argument scalar to the provided value. - ValueBindings[AI] = CS.getPtrArg(i); + RC.merge(CS.getPtrArg(i), Graph.getNodeForValue(AI)); } - NodeMapTy OldNodeMap; - clonePartiallyInto(Graph, F, CS.getRetVal(), ValueBindings, OldNodeMap, - CloneFlags | DSGraph::UpdateInlinedGlobals); - + // Map the return node pointer over. + if (CS.getRetVal().getNode()) + RC.merge(CS.getRetVal(), Graph.getReturnNodeFor(F)); + + // If requested, copy the calls or aux-calls lists. + if (!(CloneFlags & DontCloneCallNodes)) { + // Copy the function calls list... + FunctionCalls.reserve(FunctionCalls.size()+Graph.FunctionCalls.size()); + for (unsigned i = 0, ei = Graph.FunctionCalls.size(); i != ei; ++i) + FunctionCalls.push_back(DSCallSite(Graph.FunctionCalls[i], RC)); + } + + if (!(CloneFlags & DontCloneAuxCallNodes)) { + // Copy the auxiliary function calls list... + AuxFunctionCalls.reserve(AuxFunctionCalls.size()+ + Graph.AuxFunctionCalls.size()); + for (unsigned i = 0, ei = Graph.AuxFunctionCalls.size(); i != ei; ++i) + AuxFunctionCalls.push_back(DSCallSite(Graph.AuxFunctionCalls[i], RC)); + } + + // If the user requested it, add the nodes that we need to clone to the + // RootNodes set. + if (!EnableDSNodeGlobalRootsHack) + for (unsigned i = 0, e = Graph.Nodes.size(); i != e; ++i) + if (!Graph.Nodes[i]->getGlobals().empty()) + RC.getClonedNH(Graph.Nodes[i]); + } else { DSNodeHandle RetVal = getReturnNodeFor(F); - ScalarMapTy &ScalarMap = getScalarMap(); // Merge the return value with the return value of the context... RetVal.mergeWith(CS.getRetVal()); @@ -1222,8 +1240,7 @@ void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F, if (AI == F.aend()) break; // Add the link from the argument scalar to the provided value - assert(ScalarMap.count(AI) && "Argument not in scalar map?"); - DSNodeHandle &NH = ScalarMap[AI]; + DSNodeHandle &NH = getNodeForValue(AI); assert(NH.getNode() && "Pointer argument without scalarmap entry?"); NH.mergeWith(CS.getPtrArg(i)); } @@ -1238,7 +1255,7 @@ DSCallSite DSGraph::getCallSiteForArguments(Function &F) const { for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I) if (isPointerType(I->getType())) - Args.push_back(getScalarMap().find(I)->second); + Args.push_back(getNodeForValue(I)); return DSCallSite(CallSite(), getReturnNodeFor(F), &F, Args); } @@ -1291,9 +1308,8 @@ void DSGraph::markIncompleteNodes(unsigned Flags) { Function &F = *FI->first; if (F.getName() != "main") for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I) - if (isPointerType(I->getType()) && - ScalarMap.find(I) != ScalarMap.end()) - markIncompleteNode(ScalarMap[I].getNode()); + if (isPointerType(I->getType())) + markIncompleteNode(getNodeForValue(I).getNode()); } // Mark stuff passed into functions calls as being incomplete... @@ -1330,11 +1346,11 @@ static inline bool nodeContainsExternalFunction(const DSNode *N) { } static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) { - // Remove trivially identical function calls unsigned NumFns = Calls.size(); std::sort(Calls.begin(), Calls.end()); // Sort by callee as primary key! +#if 1 // Scan the call list cleaning it up as necessary... DSNode *LastCalleeNode = 0; Function *LastCalleeFunc = 0; @@ -1375,12 +1391,21 @@ static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) { else LastCalleeContainsExternalFunction = LastCalleeFunc->isExternal(); } - + + // It is not clear why, but enabling this code makes DSA really + // sensitive to node forwarding. Basically, with this enabled, DSA + // performs different number of inlinings based on which nodes are + // forwarding or not. This is clearly a problem, so this code is + // disabled until this can be resolved. #if 1 - if (LastCalleeContainsExternalFunction || + if (LastCalleeContainsExternalFunction +#if 0 + || // This should be more than enough context sensitivity! // FIXME: Evaluate how many times this is tripped! - NumDuplicateCalls > 20) { + NumDuplicateCalls > 20 +#endif + ) { DSCallSite &OCS = Calls[i-1]; OCS.mergeWith(CS); @@ -1403,7 +1428,7 @@ static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) { } } } - +#endif Calls.erase(std::unique(Calls.begin(), Calls.end()), Calls.end()); // Track the number of call nodes merged away... @@ -1421,7 +1446,6 @@ static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) { // void DSGraph::removeTriviallyDeadNodes() { TIME_REGION(X, "removeTriviallyDeadNodes"); - removeIdenticalCalls(FunctionCalls); removeIdenticalCalls(AuxFunctionCalls); @@ -1434,26 +1458,21 @@ void DSGraph::removeTriviallyDeadNodes() { N->getLink(l*N->getPointerSize()).getNode(); } + // NOTE: This code is disabled. Though it should, in theory, allow us to + // remove more nodes down below, the scan of the scalar map is incredibly + // expensive for certain programs (with large SCCs). In the future, if we can + // make the scalar map scan more efficient, then we can reenable this. +#if 0 + { TIME_REGION(X, "removeTriviallyDeadNodes:scalarmap"); + // Likewise, forward any edges from the scalar nodes. While we are at it, // clean house a bit. for (ScalarMapTy::iterator I = ScalarMap.begin(),E = ScalarMap.end();I != E;){ - // Check to see if this is a worthless node generated for non-pointer - // values, such as integers. Consider an addition of long types: A+B. - // Assuming we can track all uses of the value in this context, and it is - // NOT used as a pointer, we can delete the node. We will be able to detect - // this situation if the node pointed to ONLY has Unknown bit set in the - // node. In this case, the node is not incomplete, does not point to any - // other nodes (no mod/ref bits set), and is therefore uninteresting for - // data structure analysis. If we run across one of these, prune the scalar - // pointing to it. - // - DSNode *N = I->second.getNode(); - if (N->getNodeFlags() == DSNode::UnknownNode && !isa<Argument>(I->first)) - ScalarMap.erase(I++); - else - ++I; + I->second.getNode(); + ++I; } - + } +#endif bool isGlobalsGraph = !GlobalsGraph; for (unsigned i = 0; i != Nodes.size(); ++i) { @@ -1474,46 +1493,15 @@ void DSGraph::removeTriviallyDeadNodes() { if (Node->getNumReferrers() == Node->getGlobals().size()) { const std::vector<GlobalValue*> &Globals = Node->getGlobals(); - // Loop through and make sure all of the globals are referring directly - // to the node... - for ( |