/// visitGraph - Visit the functions in the specified graph, updating the /// specified lattice values for all of their uses. /// void StructureFieldVisitorBase:: visitGraph(DSGraph &DSG, std::multimap<DSNode*, LatticeValue*> &NodeLVs) { assert(!NodeLVs.empty() && "No lattice values to compute!"); // To visit a graph, first step, we visit the instruction making up each // function in the graph, but ignore calls when processing them. We handle // call nodes explicitly by looking at call nodes in the graph if needed. We // handle instructions before calls to avoid interprocedural analysis if we // can drive lattice values to bottom early. // SFVInstVisitor IV(DSG, Callbacks, NodeLVs); for (DSGraph::retnodes_iterator FI = DSG.retnodes_begin(), E = DSG.retnodes_end(); FI != E; ++FI) for (Function::iterator BB = FI->first->begin(), E = FI->first->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) if (IV.visit(*I) && NodeLVs.empty()) return; // Nothing left to analyze. // Keep track of which actual direct callees are handled. std::set<Function*> CalleesHandled; // Once we have visited all of the instructions in the function bodies, if // there are lattice values that have not been driven to bottom, see if any of // the nodes involved are passed into function calls. If so, we potentially // have to recursively traverse the call graph. for (DSGraph::fc_iterator CS = DSG.fc_begin(), E = DSG.fc_end(); CS != E; ++CS) { // Figure out the mapping from a node in the caller (potentially several) // nodes in the callee. DSGraph::NodeMapTy CallNodeMap; Instruction *TheCall = CS->getCallSite().getInstruction(); // If this is an indirect function call, assume nothing gets passed through // it. FIXME: THIS IS BROKEN! Just get the ECG for the fn ptr if it's not // direct. if (CS->isIndirectCall()) continue; // If this is an external function call, it cannot be involved with this // node, because otherwise the node would be marked incomplete! if (CS->getCalleeFunc()->isExternal()) continue; // If we can handle this function call, remove it from the set of direct // calls found by the visitor. CalleesHandled.insert(CS->getCalleeFunc()); std::vector<DSNodeHandle> Args; DSGraph *CG = &ECG.getDSGraph(*CS->getCalleeFunc()); CG->getFunctionArgumentsForCall(CS->getCalleeFunc(), Args); if (!CS->getRetVal().isNull()) DSGraph::computeNodeMapping(Args[0], CS->getRetVal(), CallNodeMap); for (unsigned i = 0, e = CS->getNumPtrArgs(); i != e; ++i) { if (i == Args.size()-1) break; DSGraph::computeNodeMapping(Args[i+1], CS->getPtrArg(i), CallNodeMap); } Args.clear(); // The mapping we just computed maps from nodes in the callee to nodes in // the caller, so we can't query it efficiently. Instead of going through // the trouble of inverting the map to do this (linear time with the size of // the mapping), we just do a linear search to see if any affected nodes are // passed into this call. bool CallCanModifyDataFlow = false; for (DSGraph::NodeMapTy::iterator MI = CallNodeMap.begin(), E = CallNodeMap.end(); MI != E; ++MI) if (NodeLVs.count(MI->second.getNode())) // Okay, the node is passed in, check to see if the call might do // something interesting to it (i.e. if analyzing the call can produce // anything other than "top"). if ((CallCanModifyDataFlow = NodeCanPossiblyBeInteresting(MI->first, Callbacks))) break; // If this function call cannot impact the analysis (either because the // nodes we are tracking are not passed into the call, or the DSGraph for // the callee tells us that analysis of the callee can't provide interesting // information), ignore it. if (!CallCanModifyDataFlow) continue; // Okay, either compute analysis results for the callee function, or reuse // results previously computed. std::multimap<DSNode*, LatticeValue*> &CalleeFacts = getCalleeFacts(*CG); // Merge all of the facts for the callee into the facts for the caller. If // this reduces anything in the caller to 'bottom', remove them. for (DSGraph::NodeMapTy::iterator MI = CallNodeMap.begin(), E = CallNodeMap.end(); MI != E; ++MI) { // If we have Lattice facts in the caller for this node in the callee, // merge any information from the callee into the caller. // If the node is not accessed in the callee at all, don't update. if (MI->first->getType() == Type::VoidTy) continue; // If there are no data-flow facts live in the caller for this node, don't // both processing it. std::multimap<DSNode*, LatticeValue*>::iterator NLVI = NodeLVs.find(MI->second.getNode()); if (NLVI == NodeLVs.end()) continue; // Iterate over all of the lattice values that have corresponding fields // in the callee, merging in information as we go. Be careful about the // fact that the callee may get passed the address of a substructure and // other funny games. //if (CalleeFacts.count(const_cast<DSNode*>(MI->first)) == 0) { DSNode *CalleeNode = const_cast<DSNode*>(MI->first); unsigned CalleeNodeOffset = MI->second.getOffset(); while (NLVI->first == MI->second.getNode()) { // Figure out what offset in the callee this field would land. unsigned FieldOff = NLVI->second->getFieldOffset()+CalleeNodeOffset; // If the field is not within the callee node, ignore it. if (FieldOff >= CalleeNode->getSize()) { ++NLVI; continue; } // Okay, check to see if we have a lattice value for the field at offset // FieldOff in the callee node. const LatticeValue *CalleeLV = 0; std::multimap<DSNode*, LatticeValue*>::iterator CFI = CalleeFacts.lower_bound(CalleeNode); for (; CFI != CalleeFacts.end() && CFI->first == CalleeNode; ++CFI) if (CFI->second->getFieldOffset() == FieldOff) { CalleeLV = CFI->second; // Found it! break; } // If we don't, the lattice value hit bottom and we should remove the // lattice value in the caller. if (!CalleeLV) { delete NLVI->second; // The lattice value hit bottom. NodeLVs.erase(NLVI++); continue; } // Finally, if we did find a corresponding entry, merge the information // into the caller's lattice value and keep going. if (NLVI->second->mergeInValue(CalleeLV)) { // Okay, merging these two caused the caller value to hit bottom. // Remove it. delete NLVI->second; // The lattice value hit bottom. NodeLVs.erase(NLVI++); } ++NLVI; // We successfully merged in some information! } // If we ran out of facts to prove, just exit. if (NodeLVs.empty()) return; } } // The local analysis pass inconveniently discards many local function calls // from the graph if they are to known functions. Loop over direct function // calls not handled above and visit them as appropriate. while (!IV.DirectCallSites.empty()) { Instruction *Call = *IV.DirectCallSites.begin(); IV.DirectCallSites.erase(IV.DirectCallSites.begin()); // Is this one actually handled by DSA? if (CalleesHandled.count(cast<Function>(Call->getOperand(0)))) continue; // Collect the pointers involved in this call. std::vector<Value*> Pointers; if (isa<PointerType>(Call->getType())) Pointers.push_back(Call); for (unsigned i = 1, e = Call->getNumOperands(); i != e; ++i) if (isa<PointerType>(Call->getOperand(i)->getType())) Pointers.push_back(Call->getOperand(i)); // If this is an intrinsic function call, figure out which one. unsigned IID = cast<Function>(Call->getOperand(0))->getIntrinsicID(); for (unsigned i = 0, e = Pointers.size(); i != e; ++i) { // If any of our lattice values are passed into this call, which is // specially handled by the local analyzer, inform the lattice function. DSNode *N = DSG.getNodeForValue(Pointers[i]).getNode(); for (std::multimap<DSNode*, LatticeValue*>::iterator LVI = NodeLVs.lower_bound(N); LVI != NodeLVs.end() && LVI->first == N;) { bool AtBottom = false; switch (IID) { default: AtBottom = LVI->second->visitRecognizedCall(*Call); break; case Intrinsic::memset: if (Callbacks & Visit::Stores) AtBottom = LVI->second->visitMemSet(*cast<CallInst>(Call)); break; } if (AtBottom) { delete LVI->second; NodeLVs.erase(LVI++); } else { ++LVI; } } } } }
/// 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; } } } }