// // Method: findGlobalPoolNodes() // // Description: // This method finds DSNodes that are reachable from globals and that need a // pool. The Automatic Pool Allocation transform will use the returned // information to build global pools for the DSNodes in question. // // Note that this method does not assign DSNodes to pools; it merely decides // which DSNodes are reachable from globals and will need a pool of global // scope. // // Outputs: // Nodes - The DSNodes that are both reachable from globals and which should // have global pools will be *added* to this container. // void AllHeapNodesHeuristic::findGlobalPoolNodes (DSNodeSet_t & Nodes) { // Get the globals graph for the program. DSGraph* GG = Graphs->getGlobalsGraph(); // Get all of the nodes reachable from globals. DenseSet<const DSNode*> GlobalHeapNodes; GetNodesReachableFromGlobals (GG, GlobalHeapNodes); // // Create a global pool for each global DSNode. // for (DenseSet<const DSNode *>::iterator NI = GlobalHeapNodes.begin(); NI != GlobalHeapNodes.end();++NI) { const DSNode * N = *NI; PoolMap[N] = OnePool(N); } // // Now find all DSNodes belonging to function-local DSGraphs which are // mirrored in the globals graph. These DSNodes require a global pool, too. // for (Module::iterator F = M->begin(); F != M->end(); ++F) { if (Graphs->hasDSGraph(*F)) { DSGraph* G = Graphs->getDSGraph(*F); DSGraph::NodeMapTy NodeMap; G->computeGToGGMapping (NodeMap); // // Scan through all DSNodes in the local graph. If a local DSNode has a // corresponding DSNode in the globals graph that is reachable from a // global, then add the local DSNode to the set of DSNodes reachable from // a global. // DSGraph::node_iterator ni = G->node_begin(); for (; ni != G->node_end(); ++ni) { DSNode * N = ni; DSNode * GGN = NodeMap[N].getNode(); //assert (!GGN || GlobalHeapNodes.count (GGN)); if (GGN && GlobalHeapNodes.count (GGN)) PoolMap[GGN].NodesInPool.push_back (N); } } } // // Copy the values into the output container. Note that DenseSet has no // iterator traits (or whatever allows us to treat DenseSet has a generic // container), so we have to use a loop to copy values from the DenseSet into // the output container. // for (DenseSet<const DSNode*>::iterator I = GlobalHeapNodes.begin(), E = GlobalHeapNodes.end(); I != E; ++I) { Nodes.insert (*I); } return; }
// // Method: getLocalPoolNodes() // // Description: // For a given function, determine which DSNodes for that function should have // local pools created for them. // void Heuristic::getLocalPoolNodes (const Function & F, DSNodeList_t & Nodes) { // // Get the DSGraph of the specified function. If the DSGraph has no nodes, // then there is nothing we need to do. // DSGraph* G = Graphs->getDSGraph(F); if (G->node_begin() == G->node_end()) return; // // Calculate which DSNodes are reachable from globals. If a node is reachable // from a global, we will create a global pool for it, so no argument passage // is required. Graphs->getGlobalsGraph(); // Map all node reachable from this global to the corresponding nodes in // the globals graph. DSGraph::NodeMapTy GlobalsGraphNodeMapping; G->computeGToGGMapping(GlobalsGraphNodeMapping); // // Loop over all of the nodes which are non-escaping, adding pool-allocatable // ones to the NodesToPA vector. In other words, scan over the DSGraph and // find nodes for which a new pool must be created within this function. // for (DSGraph::node_iterator I = G->node_begin(), E = G->node_end(); I != E; ++I){ // Get the DSNode and, if applicable, its mirror in the globals graph DSNode * N = I; DSNode * GGN = GlobalsGraphNodeMapping[N].getNode(); // // Only the following nodes are pool allocated: // 1) Local Heap nodes // 2) Nodes which are mirrored in the globals graph and, in the globals // graph, are heap nodes. // if ((N->isHeapNode()) || (GGN && GGN->isHeapNode())) { if (!(GlobalPoolNodes.count (N) || GlobalPoolNodes.count (GGN))) { // Otherwise, if it was not passed in from outside the function, it must // be a local pool! assert((!N->isGlobalNode() || N->isPtrToIntNode()) && "Should be in global mapping!"); if(!N->isPtrToIntNode()) { Nodes.push_back (N); } } } } return; }
// Get all nodes in all function DSGraphs and the global DSGraph that contain // global values. void CSDataRando::findGlobalNodes(Module &M) { DSGraph *GG = DSA->getGlobalsGraph(); for (auto i = GG->node_begin(), e = GG->node_end(); i != e; i++) { GlobalNodes.insert(&*i); } for (Function &F : M) { if ((!F.isDeclaration()) && DSA->hasDSGraph(F)) { DSGraph *G = DSA->getDSGraph(F); FuncInfo &FI = FunctionInfo[&F]; DSGraph::NodeMapTy NodeMap; G->computeGToGGMapping(NodeMap); for (auto i : NodeMap) { GlobalNodes.insert(i.first); FI.ToGlobalNodeMap[i.first] = i.second.getNode(); } } } }
// // Method: findGlobalPoolNodes() // // Description: // This method finds DSNodes that are reachable from globals and that need a // pool. The Automatic Pool Allocation transform will use the returned // information to build global pools for the DSNodes in question. // // For efficiency, this method also determines which DSNodes should be in the // same pool. // // Outputs: // Nodes - The DSNodes that are both reachable from globals and which should // have global pools will be *added* to this container. // void AllNodesHeuristic::findGlobalPoolNodes (DSNodeSet_t & Nodes) { // Get the globals graph for the program. DSGraph* GG = Graphs->getGlobalsGraph(); // // Get all of the nodes reachable from globals. // DenseSet<const DSNode*> GlobalNodes; GetNodesReachableFromGlobals (GG, GlobalNodes); // // Create a global pool for each global DSNode. // for (DenseSet<const DSNode *>::iterator NI = GlobalNodes.begin(); NI != GlobalNodes.end(); ++NI) { const DSNode * N = *NI; PoolMap[N] = OnePool(N); } // // Now find all DSNodes belonging to function-local DSGraphs which are // mirrored in the globals graph. These DSNodes require a global pool, too, // but must use the same pool as the one assigned to the corresponding global // DSNode. // for (Module::iterator F = M->begin(); F != M->end(); ++F) { // // Ignore functions that have no DSGraph. // if (!(Graphs->hasDSGraph(*F))) continue; // // Compute a mapping between local DSNodes and DSNodes in the globals // graph. // DSGraph* G = Graphs->getDSGraph(*F); DSGraph::NodeMapTy NodeMap; G->computeGToGGMapping (NodeMap); // // Scan through all DSNodes in the local graph. If a local DSNode has a // corresponding DSNode in the globals graph that is reachable from a // global, then add the local DSNode to the set of DSNodes reachable from // a global. // DSGraph::node_iterator ni = G->node_begin(); for (; ni != G->node_end(); ++ni) { DSNode * N = ni; DSNode * GGN = NodeMap[N].getNode(); assert (!GGN || GlobalNodes.count (GGN)); if (GGN && GlobalNodes.count (GGN)) PoolMap[GGN].NodesInPool.push_back (N); } } // // Scan through all the local graphs looking for DSNodes which may be // reachable by a global. These nodes may not end up in the globals graph // because of the fact that DSA doesn't actually know what is happening to // them. // // FIXME: I believe this code causes a condition in which a local DSNode is // given a local pool in one function but not in other functions. // Someone needs to investigate whether DSA is being consistent here, // and if not, if that inconsistency is correct. // #if 0 for (Module::iterator F = M->begin(); F != M->end(); ++F) { if (F->isDeclaration()) continue; DSGraph* G = Graphs->getDSGraph(*F); for (DSGraph::node_iterator I = G->node_begin(), E = G->node_end(); I != E; ++I) { DSNode * Node = I; if (Node->isExternalNode() || Node->isUnknownNode()) { GlobalNodes.insert (Node); } } } #endif // // Copy the values into the output container. Note that DenseSet has no // iterator traits (or whatever allows us to treat DenseSet has a generic // container), so we have to use a loop to copy values from the DenseSet into // the output container. // // Note that we do not copy local DSNodes into the output container; we // merely copy those nodes in the globals graph. // for (DenseSet<const DSNode*>::iterator I = GlobalNodes.begin(), E = GlobalNodes.end(); I != E; ++I) { Nodes.insert (*I); } return; }
/// ProcessNodesReachableFromGlobals - If we inferred anything about nodes /// reachable from globals, we have to make sure that we incorporate data for /// all graphs that include those globals due to the nature of the globals /// graph. /// void StructureFieldVisitorBase:: ProcessNodesReachableFromGlobals(DSGraph &DSG, std::multimap<DSNode*,LatticeValue*> &NodeLVs){ // Start by marking all nodes reachable from globals. DSScalarMap &SM = DSG.getScalarMap(); if (SM.global_begin() == SM.global_end()) return; hash_set<const DSNode*> Reachable; for (DSScalarMap::global_iterator GI = SM.global_begin(), E = SM.global_end(); GI != E; ++GI) SM[*GI].getNode()->markReachableNodes(Reachable); if (Reachable.empty()) return; // If any of the nodes with dataflow facts are reachable from the globals // graph, we have to do the GG processing step. bool MustProcessThroughGlobalsGraph = false; for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(), E = NodeLVs.end(); I != E; ++I) if (Reachable.count(I->first)) { MustProcessThroughGlobalsGraph = true; break; } if (!MustProcessThroughGlobalsGraph) return; Reachable.clear(); // Compute the mapping from DSG to the globals graph. DSGraph::NodeMapTy DSGToGGMap; DSG.computeGToGGMapping(DSGToGGMap); // Most of the times when we find facts about things reachable from globals we // we are in the main graph. This means that we have *all* of the globals // graph in this DSG. To be efficient, we compute the minimum set of globals // that can reach any of the NodeLVs facts. // // I'm not aware of any wonderful way of computing the set of globals that // points to the set of nodes in NodeLVs that is not N^2 in either NodeLVs or // the number of globals, except to compute the inverse of DSG. As such, we // compute the inverse graph of DSG, which basically has the edges going from // pointed to nodes to pointing nodes. Because we only care about one // connectedness properties, we ignore field info. In addition, we only // compute inverse of the portion of the graph reachable from the globals. std::set<std::pair<DSNode*,DSNode*> > InverseGraph; for (DSScalarMap::global_iterator GI = SM.global_begin(), E = SM.global_end(); GI != E; ++GI) ComputeInverseGraphFrom(SM[*GI].getNode(), InverseGraph); // Okay, now that we have our bastardized inverse graph, compute the set of // globals nodes reachable from our lattice nodes. for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(), E = NodeLVs.end(); I != E; ++I) ComputeNodesReachableFrom(I->first, InverseGraph, Reachable); // Now that we know which nodes point to the data flow facts, figure out which // globals point to the data flow facts. std::set<GlobalValue*> Globals; for (hash_set<const DSNode*>::iterator I = Reachable.begin(), E = Reachable.end(); I != E; ++I) Globals.insert((*I)->globals_begin(), (*I)->globals_end()); // Finally, loop over all of the DSGraphs for the program, computing // information for the graph if not done already, mapping the result into our // context. for (hash_map<const Function*, DSGraph*>::iterator GI = ECG.DSInfo.begin(), E = ECG.DSInfo.end(); GI != E; ++GI) { DSGraph &FG = *GI->second; // Graphs can contain multiple functions, only process the graph once. if (GI->first != FG.retnodes_begin()->first || // Also, do not bother reprocessing DSG. &FG == &DSG) continue; bool GraphUsesGlobal = false; for (std::set<GlobalValue*>::iterator I = Globals.begin(), E = Globals.end(); I != E; ++I) if (FG.getScalarMap().count(*I)) { GraphUsesGlobal = true; break; } // If this graph does not contain the global at all, there is no reason to // even think about it. if (!GraphUsesGlobal) continue; // Otherwise, compute the full set of dataflow effects of the function. std::multimap<DSNode*, LatticeValue*> &FGF = getCalleeFacts(FG); //std::cerr << "Computed: " << FG.getFunctionNames() << "\n"; #if 0 for (std::multimap<DSNode*, LatticeValue*>::iterator I = FGF.begin(), E = FGF.end(); I != E; ++I) I->second->dump(); #endif // Compute the mapping of nodes in the globals graph to the function's // graph. Note that this function graph may not have nodes (or may have // fragments of full nodes) in the globals graph, and we don't want this to // pessimize the analysis. std::multimap<const DSNode*, std::pair<DSNode*,int> > GraphMap; DSGraph::NodeMapTy GraphToGGMap; FG.computeGToGGMapping(GraphToGGMap); // "Invert" the mapping. We compute the mapping from the start of a global // graph node to a place in the graph's node. Note that not all of the GG // node may be present in the graphs node, so there may be a negative offset // involved. while (!GraphToGGMap.empty()) { DSNode *GN = const_cast<DSNode*>(GraphToGGMap.begin()->first); DSNodeHandle &GGNH = GraphToGGMap.begin()->second; GraphMap.insert(std::make_pair(GGNH.getNode(), std::make_pair(GN, -GGNH.getOffset()))); GraphToGGMap.erase(GraphToGGMap.begin()); } // Loop over all of the dataflow facts that we have computed, mapping them // to the globals graph. for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(), E = NodeLVs.end(); I != E; ) { bool FactHitBottom = false; //I->second->dump(); assert(I->first->getParentGraph() == &DSG); assert(I->second->getNode()->getParentGraph() == &DSG); // Node is in the GG? DSGraph::NodeMapTy::iterator DSGToGGMapI = DSGToGGMap.find(I->first); if (DSGToGGMapI != DSGToGGMap.end()) { DSNodeHandle &GGNH = DSGToGGMapI->second; const DSNode *GGNode = GGNH.getNode(); unsigned DSGToGGOffset = GGNH.getOffset(); // See if there is a node in FG that corresponds to this one. If not, // no information will be computed in this scope, as the memory is not // accessed. std::multimap<const DSNode*, std::pair<DSNode*,int> >::iterator GMI = GraphMap.find(GGNode); // LatticeValOffset - The offset from the start of the GG Node to the // start of the field we are interested in. unsigned LatticeValOffset = I->second->getFieldOffset()+DSGToGGOffset; // Loop over all of the nodes in FG that correspond to this single node // in the GG. for (; GMI != GraphMap.end() && GMI->first == GGNode; ++GMI) { // Compute the offset to the field in the user graph. unsigned FieldOffset = LatticeValOffset - GMI->second.second; // If the field is within the amount of memory accessed by this scope, // then there must be a corresponding lattice value. DSNode *FGNode = GMI->second.first; if (FieldOffset < FGNode->getSize()) { LatticeValue *CorrespondingLV = 0; std::multimap<DSNode*, LatticeValue*>::iterator FGFI = FGF.find(FGNode); for (; FGFI != FGF.end() && FGFI->first == FGNode; ++FGFI) if (FGFI->second->getFieldOffset() == FieldOffset) { CorrespondingLV = FGFI->second; break; } // Finally, if either there was no corresponding fact (because it // hit bottom in this scope), or if merging the two pieces of // information makes it hit bottom, remember this. if (CorrespondingLV == 0 || I->second->mergeInValue(CorrespondingLV)) FactHitBottom = true; } } } if (FactHitBottom) { delete I->second; NodeLVs.erase(I++); if (NodeLVs.empty()) return; } else { ++I; } } } }