Ejemplo n.º 1
0
void DSGraphStats::countCallees(const Function& F) {
  const DSCallGraph callgraph = DS->getCallGraph();
  unsigned numIndirectCalls = 0, totalNumCallees = 0;

  for (DSGraph::fc_iterator I = TDGraph->fc_begin(), E = TDGraph->fc_end();
       I != E; ++I)
    if (isIndirectCallee(I->getCallSite().getCalledValue())) {
      // This is an indirect function call
      std::vector<const Function*> Callees;
      callgraph.addFullFunctionList(I->getCallSite(), Callees);

      if (Callees.size() > 0) {
        totalNumCallees  += Callees.size();
        ++numIndirectCalls;
      } else {
        DEBUG(errs() << "WARNING: No callee in Function '" 
              << F.getName().str() << " at call: \n"
              << *I->getCallSite().getInstruction());
      }
    }

  TotalNumCallees  += totalNumCallees;
  NumIndirectCalls += numIndirectCalls;

  if (numIndirectCalls) {
    DEBUG(errs() << "  In function " << F.getName() << ":  "
          << (totalNumCallees / (double) numIndirectCalls)
          << " average callees per indirect call\n");
  }
}
Ejemplo n.º 2
0
void TDDataStructures::ComputePostOrder(const Function* F,
                                        hash_set<DSGraph*> &Visited,
                                        std::vector<DSGraph*> &PostOrder) {
  if (F->isDeclaration()) return;
  DSGraph* G = getOrFetchDSGraph(F);
  if (Visited.count(G)) return;
  Visited.insert(G);

  // Recursively traverse all of the callee graphs.
  for (DSGraph::fc_iterator CI = G->fc_begin(), CE = G->fc_end(); CI != CE; ++CI){
    Instruction *CallI = CI->getCallSite().getInstruction();
    for (calleeTy::iterator I = callee.begin(CallI),
           E = callee.end(CallI); I != E; ++I)
      ComputePostOrder(*I, Visited, PostOrder);
  }

  PostOrder.push_back(G);
}
Ejemplo n.º 3
0
void TDDataStructures::ComputePostOrder(const Function &F,
                                        DenseSet<DSGraph*> &Visited,
                                        std::vector<DSGraph*> &PostOrder) {
  if (F.isDeclaration()) return;
  DSGraph* G = getOrCreateGraph(&F);
  if (!Visited.insert(G).second) return;

  // Recursively traverse all of the callee graphs.
  svset<const Function*> Callees;

  // Go through all of the callsites in this graph and find all callees
  // Here we're trying to capture all possible callees so that we can ensure
  // each function has all possible callers inlined into it.
  for (DSGraph::fc_iterator CI = G->fc_begin(), E = G->fc_end();
       CI != E; ++CI) {
    // Direct calls are easy, no reason to look at DSCallGraph
    // or anything to do with SCC's
    if (CI->isDirectCall()) {
      ComputePostOrder(*CI->getCalleeFunc(), Visited, PostOrder);
    }
    else {
      // Otherwise, ask the DSCallGraph for the full set of possible
      // callees for this callsite.
      // This includes all members of the SCC's of those callees,
      // and well as others in F's SCC, since we must assume
      // any indirect call might be intra-SCC.
      callgraph.addFullFunctionSet(CI->getCallSite(), Callees);
    }
  }

  for (svset<const Function*>::iterator I = Callees.begin(),
       E = Callees.end(); I != E; ++I)
    ComputePostOrder(**I, Visited, PostOrder);

  PostOrder.push_back(G);
}
Ejemplo n.º 4
0
/// InlineCallersIntoGraph - Inline all of the callers of the specified DS graph
/// into it, then recompute completeness of nodes in the resultant graph.
void TDDataStructures::InlineCallersIntoGraph(DSGraph* DSG) {
  // Inline caller graphs into this graph.  First step, get the list of call
  // sites that call into this graph.
  std::vector<CallerCallEdge> EdgesFromCaller;
  std::map<DSGraph*, std::vector<CallerCallEdge> >::iterator
    CEI = CallerEdges.find(DSG);
  if (CEI != CallerEdges.end()) {
    std::swap(CEI->second, EdgesFromCaller);
    CallerEdges.erase(CEI);
  }

  // Sort the caller sites to provide a by-caller-graph ordering.
  std::sort(EdgesFromCaller.begin(), EdgesFromCaller.end());


  // Merge information from the globals graph into this graph.  FIXME: This is
  // stupid.  Instead of us cloning information from the GG into this graph,
  // then having RemoveDeadNodes clone it back, we should do all of this as a
  // post-pass over all of the graphs.  We need to take cloning out of
  // removeDeadNodes and gut removeDeadNodes at the same time first though. :(
  cloneGlobalsInto(DSG, DSGraph::DontCloneCallNodes |
                        DSGraph::DontCloneAuxCallNodes);

  DEBUG(errs() << "[TD] Inlining callers into '"
        << DSG->getFunctionNames() << "'\n");

  DSG->maskIncompleteMarkers();
  // Iteratively inline caller graphs into this graph.
  while (!EdgesFromCaller.empty()) {
    DSGraph* CallerGraph = EdgesFromCaller.back().CallerGraph;

    // Iterate through all of the call sites of this graph, cloning and merging
    // any nodes required by the call.
    ReachabilityCloner RC(DSG, CallerGraph,
                          DSGraph::DontCloneCallNodes |
                          DSGraph::DontCloneAuxCallNodes);

    // Inline all call sites from this caller graph.
    do {
      const DSCallSite &CS = *EdgesFromCaller.back().CS;
      const Function &CF = *EdgesFromCaller.back().CalledFunction;
      DEBUG(errs() << "   [TD] Inlining graph into Fn '"
            << CF.getName().str() << "' from ");
      if (CallerGraph->getReturnNodes().empty()) {
        DEBUG(errs() << "SYNTHESIZED INDIRECT GRAPH");
      } else {
        DEBUG(errs() << "Fn '" << CS.getCallSite().getInstruction()->
              getParent()->getParent()->getName().str() << "'");
      }
      DEBUG(errs() << ": " << CF.getFunctionType()->getNumParams()
            << " args\n");

      // Get the formal argument and return nodes for the called function and
      // merge them with the cloned subgraph.
      DSCallSite T1 = DSG->getCallSiteForArguments(CF);
      RC.mergeCallSite(T1, CS);
      ++NumTDInlines;

      EdgesFromCaller.pop_back();
    } while (!EdgesFromCaller.empty() &&
             EdgesFromCaller.back().CallerGraph == CallerGraph);
  }



  // Next, now that this graph is finalized, we need to recompute the
  // incompleteness markers for this graph and remove unreachable nodes.

  // If any of the functions is externally callable, treat everything in its
  // SCC as externally callable.
  bool isExternallyCallable = false;
  for (DSGraph::retnodes_iterator I = DSG->retnodes_begin(),
         E = DSG->retnodes_end(); I != E; ++I)
    if (ExternallyCallable.count(I->first)) {
      isExternallyCallable = true;
      break;
    }

  // Recompute the Incomplete markers.  Depends on whether args are complete
  unsigned IncFlags = DSGraph::IgnoreFormalArgs;
  IncFlags |= DSGraph::IgnoreGlobals | DSGraph::MarkVAStart;
  DSG->markIncompleteNodes(IncFlags);

  // If this graph contains functions that are externally callable, now is the time to mark
  // their arguments and return values as external.  At this point TD is inlining all caller information,
  // and that means External callers too.
  unsigned ExtFlags
    = isExternallyCallable ? DSGraph::MarkFormalsExternal : DSGraph::DontMarkFormalsExternal;
  DSG->computeExternalFlags(ExtFlags);
  DSG->computeIntPtrFlags();

  cloneIntoGlobals(DSG, DSGraph::DontCloneCallNodes |
                        DSGraph::DontCloneAuxCallNodes);
  //
  // Delete dead nodes.  Treat globals that are unreachable as dead also.
  //
  // FIXME:
  //  Do not delete unreachable globals as the comment describes.  For its
  //  alignment checks on the results of load instructions, SAFECode must be
  //  able to find the DSNode of both the result of the load as well as the
  //  pointer dereferenced by the load.  If we remove unreachable globals, then
  //  if the dereferenced pointer is a global, its DSNode will not reachable
  //  from the local graph's scalar map, and chaos ensues.
  //
  //  So, for now, just remove dead nodes but leave the globals alone.
  //
  DSG->removeDeadNodes(0);

  // We are done with computing the current TD Graph!  Finally, before we can
  // finish processing this function, we figure out which functions it calls and
  // records these call graph edges, so that we have them when we process the
  // callee graphs.
  if (DSG->fc_begin() == DSG->fc_end()) return;

  // Loop over all the call sites and all the callees at each call site, and add
  // edges to the CallerEdges structure for each callee.
  for (DSGraph::fc_iterator CI = DSG->fc_begin(), E = DSG->fc_end();
       CI != E; ++CI) {

    // Handle direct calls efficiently.
    if (CI->isDirectCall()) {
      if (!CI->getCalleeFunc()->isDeclaration() &&
          !DSG->getReturnNodes().count(CI->getCalleeFunc()))
        CallerEdges[getOrCreateGraph(CI->getCalleeFunc())]
          .push_back(CallerCallEdge(DSG, &*CI, CI->getCalleeFunc()));
      continue;
    }

    svset<const Function*> AllCallees;
    std::vector<const Function*> Callees;

    // Get the list of callees
    callgraph.addFullFunctionSet(CI->getCallSite(), AllCallees);

    // Filter all non-declarations, and calls within this DSGraph
    for (svset<const Function*>::iterator I = AllCallees.begin(),
        E = AllCallees.end(); I != E; ++I) {
      const Function *F = *I;
      if (!F->isDeclaration() && getDSGraph(**I) != DSG)
        Callees.push_back(F);
    }
    AllCallees.clear();

    // If there is exactly one callee from this call site, remember the edge in
    // CallerEdges.
    if (Callees.size() == 1) {
      const Function * Callee = Callees[0];
      CallerEdges[getOrCreateGraph(Callee)]
          .push_back(CallerCallEdge(DSG, &*CI, Callee));
    }
    if (Callees.size() <= 1) continue;

    // Otherwise, there are multiple callees from this call site, so it must be
    // an indirect call.  Chances are that there will be other call sites with
    // this set of targets.  If so, we don't want to do M*N inlining operations,
    // so we build up a new, private, graph that represents the calls of all
    // calls to this set of functions.

    std::map<std::vector<const Function*>, DSGraph*>::iterator IndCallRecI =
      IndCallMap.lower_bound(Callees);

    // If we already have this graph, recycle it.
    if (IndCallRecI != IndCallMap.end() && IndCallRecI->first == Callees) {
      DEBUG(errs() << "  [TD] *** Reuse of indcall graph for " << Callees.size()
            << " callees!\n");
      DSGraph * IndCallGraph = IndCallRecI->second;
      assert(IndCallGraph->getFunctionCalls().size() == 1);

      // Merge the call into the CS already in the IndCallGraph
      ReachabilityCloner RC(IndCallGraph, DSG, 0);
      RC.mergeCallSite(IndCallGraph->getFunctionCalls().front(), *CI);
    } else {
      // Otherwise, create a new DSGraph to represent this.
      DSGraph* IndCallGraph = new DSGraph(DSG->getGlobalECs(),
                                          DSG->getDataLayout(), *TypeSS);

      // Clone over the call into the new DSGraph
      ReachabilityCloner RC(IndCallGraph, DSG, 0);
      DSCallSite ClonedCS = RC.cloneCallSite(*CI);

      // Add the cloned CS to the graph, as if it were an original call.
      IndCallGraph->getFunctionCalls().push_back(ClonedCS);

      // Save this graph for use later, should we need it.
      IndCallRecI = IndCallMap.insert(IndCallRecI,
                                      std::make_pair(Callees, IndCallGraph));

      // Additionally, make sure that each of the callees inlines this graph
      // exactly once.
      DSCallSite *NCS = &IndCallGraph->getFunctionCalls().front();
      for (unsigned i = 0, e = Callees.size(); i != e; ++i) {
        DSGraph* CalleeGraph = getDSGraph(*Callees[i]);
        if (CalleeGraph != DSG)
          CallerEdges[CalleeGraph].push_back(CallerCallEdge(IndCallGraph, NCS,
                                                            Callees[i]));
      }
    }
  }
}
Ejemplo n.º 5
0
/// InlineCallersIntoGraph - Inline all of the callers of the specified DS graph
/// into it, then recompute completeness of nodes in the resultant graph.
void TDDataStructures::InlineCallersIntoGraph(DSGraph* DSG) {
  // Inline caller graphs into this graph.  First step, get the list of call
  // sites that call into this graph.
  std::vector<CallerCallEdge> EdgesFromCaller;
  std::map<DSGraph*, std::vector<CallerCallEdge> >::iterator
    CEI = CallerEdges.find(DSG);
  if (CEI != CallerEdges.end()) {
    std::swap(CEI->second, EdgesFromCaller);
    CallerEdges.erase(CEI);
  }

  // Sort the caller sites to provide a by-caller-graph ordering.
  std::sort(EdgesFromCaller.begin(), EdgesFromCaller.end());


  // Merge information from the globals graph into this graph.  FIXME: This is
  // stupid.  Instead of us cloning information from the GG into this graph,
  // then having RemoveDeadNodes clone it back, we should do all of this as a
  // post-pass over all of the graphs.  We need to take cloning out of
  // removeDeadNodes and gut removeDeadNodes at the same time first though. :(
  {
    DSGraph* GG = DSG->getGlobalsGraph();
    ReachabilityCloner RC(DSG, GG,
                          DSGraph::DontCloneCallNodes |
                          DSGraph::DontCloneAuxCallNodes);
    for (DSScalarMap::global_iterator
           GI = DSG->getScalarMap().global_begin(),
           E = DSG->getScalarMap().global_end(); GI != E; ++GI)
      RC.getClonedNH(GG->getNodeForValue(*GI));
  }

  DEBUG(errs() << "[TD] Inlining callers into '" 
	<< DSG->getFunctionNames() << "'\n");

  // Iteratively inline caller graphs into this graph.
  while (!EdgesFromCaller.empty()) {
    DSGraph* CallerGraph = EdgesFromCaller.back().CallerGraph;

    // Iterate through all of the call sites of this graph, cloning and merging
    // any nodes required by the call.
    ReachabilityCloner RC(DSG, CallerGraph,
                          DSGraph::DontCloneCallNodes |
                          DSGraph::DontCloneAuxCallNodes);

    // Inline all call sites from this caller graph.
    do {
      const DSCallSite &CS = *EdgesFromCaller.back().CS;
      const Function &CF = *EdgesFromCaller.back().CalledFunction;
      DEBUG(errs() << "   [TD] Inlining graph into Fn '" 
	    << CF.getNameStr() << "' from ");
      if (CallerGraph->getReturnNodes().empty()) {
        DEBUG(errs() << "SYNTHESIZED INDIRECT GRAPH");
      } else {
        DEBUG(errs() << "Fn '" << CS.getCallSite().getInstruction()->
	      getParent()->getParent()->getNameStr() << "'");
      }
      DEBUG(errs() << ": " << CF.getFunctionType()->getNumParams() 
	    << " args\n");

      // Get the formal argument and return nodes for the called function and
      // merge them with the cloned subgraph.
      DSCallSite T1 = DSG->getCallSiteForArguments(CF);
      RC.mergeCallSite(T1, CS);
      ++NumTDInlines;

      EdgesFromCaller.pop_back();
    } while (!EdgesFromCaller.empty() &&
             EdgesFromCaller.back().CallerGraph == CallerGraph);
  }


  {
    DSGraph* GG = DSG->getGlobalsGraph();
    ReachabilityCloner RC(GG, DSG,
                          DSGraph::DontCloneCallNodes |
                          DSGraph::DontCloneAuxCallNodes);
    for (DSScalarMap::global_iterator
           GI = DSG->getScalarMap().global_begin(),
           E = DSG->getScalarMap().global_end(); GI != E; ++GI)
      RC.getClonedNH(DSG->getNodeForValue(*GI));
  }

  // Next, now that this graph is finalized, we need to recompute the
  // incompleteness markers for this graph and remove unreachable nodes.
  DSG->maskIncompleteMarkers();

  // If any of the functions has incomplete incoming arguments, don't mark any
  // of them as complete.
  bool HasIncompleteArgs = false;
  for (DSGraph::retnodes_iterator I = DSG->retnodes_begin(),
         E = DSG->retnodes_end(); I != E; ++I)
    if (ArgsRemainIncomplete.count(I->first)) {
      HasIncompleteArgs = true;
      break;
    }

  // Recompute the Incomplete markers.  Depends on whether args are complete
  unsigned Flags
    = HasIncompleteArgs ? DSGraph::MarkFormalArgs : DSGraph::IgnoreFormalArgs;
  Flags |= DSGraph::IgnoreGlobals | DSGraph::MarkVAStart;
  DSG->markIncompleteNodes(Flags);

  // Delete dead nodes.  Treat globals that are unreachable as dead also.
  DSG->removeDeadNodes(DSGraph::RemoveUnreachableGlobals);

  // We are done with computing the current TD Graph!  Finally, before we can
  // finish processing this function, we figure out which functions it calls and
  // records these call graph edges, so that we have them when we process the
  // callee graphs.
  if (DSG->fc_begin() == DSG->fc_end()) return;

  // Loop over all the call sites and all the callees at each call site, and add
  // edges to the CallerEdges structure for each callee.
  for (DSGraph::fc_iterator CI = DSG->fc_begin(), E = DSG->fc_end();
       CI != E; ++CI) {

    // Handle direct calls efficiently.
    if (CI->isDirectCall()) {
      if (!CI->getCalleeFunc()->isDeclaration() &&
          !DSG->getReturnNodes().count(CI->getCalleeFunc()))
        CallerEdges[getOrFetchDSGraph(CI->getCalleeFunc())]
          .push_back(CallerCallEdge(DSG, &*CI, CI->getCalleeFunc()));
      continue;
    }

    Instruction *CallI = CI->getCallSite().getInstruction();
    // For each function in the invoked function list at this call site...
    calleeTy::iterator IPI =
      callee.begin(CallI), IPE = callee.end(CallI);

    // Skip over all calls to this graph (SCC calls).
    while (IPI != IPE && getDSGraph(*IPI) == DSG)
      ++IPI;

    // All SCC calls?
    if (IPI == IPE) continue;

    const Function *FirstCallee = *IPI;
    ++IPI;

    // Skip over more SCC calls.
    while (IPI != IPE && getDSGraph(*IPI) == DSG)
      ++IPI;

    // If there is exactly one callee from this call site, remember the edge in
    // CallerEdges.
    if (IPI == IPE) {
      if (!FirstCallee->isDeclaration())
        CallerEdges[getOrFetchDSGraph(FirstCallee)]
          .push_back(CallerCallEdge(DSG, &*CI, FirstCallee));
      continue;
    }

    // Otherwise, there are multiple callees from this call site, so it must be
    // an indirect call.  Chances are that there will be other call sites with
    // this set of targets.  If so, we don't want to do M*N inlining operations,
    // so we build up a new, private, graph that represents the calls of all
    // calls to this set of functions.
    std::vector<const Function*> Callees;
    for (calleeTy::iterator I = callee.begin(CallI), E = callee.end(CallI);
         I != E; ++I)
      if (!(*I)->isDeclaration())
        Callees.push_back(*I);
    std::sort(Callees.begin(), Callees.end());

    std::map<std::vector<const Function*>, DSGraph*>::iterator IndCallRecI =
      IndCallMap.lower_bound(Callees);

    DSGraph *IndCallGraph;

    // If we already have this graph, recycle it.
    if (IndCallRecI != IndCallMap.end() && IndCallRecI->first == Callees) {
      DEBUG(errs() << "  [TD] *** Reuse of indcall graph for " << Callees.size()
	    << " callees!\n");
      IndCallGraph = IndCallRecI->second;
    } else {
      // Otherwise, create a new DSGraph to represent this.
      IndCallGraph = new DSGraph(DSG->getGlobalECs(), DSG->getTargetData(), GlobalsGraph);
      // Make a nullary dummy call site, which will eventually get some content
      // merged into it.  The actual callee function doesn't matter here, so we
      // just pass it something to keep the ctor happy.
      std::vector<DSNodeHandle> ArgDummyVec;
      DSCallSite DummyCS(CI->getCallSite(), DSNodeHandle(), Callees[0]/*dummy*/,
                         ArgDummyVec);
      IndCallGraph->getFunctionCalls().push_back(DummyCS);

      IndCallRecI = IndCallMap.insert(IndCallRecI,
                                      std::make_pair(Callees, IndCallGraph));

      // Additionally, make sure that each of the callees inlines this graph
      // exactly once.
      DSCallSite *NCS = &IndCallGraph->getFunctionCalls().front();
      for (unsigned i = 0, e = Callees.size(); i != e; ++i) {
        DSGraph* CalleeGraph = getDSGraph(Callees[i]);
        if (CalleeGraph != DSG)
          CallerEdges[CalleeGraph].push_back(CallerCallEdge(IndCallGraph, NCS,
                                                            Callees[i]));
      }
    }

    // Now that we know which graph to use for this, merge the caller
    // information into the graph, based on information from the call site.
    ReachabilityCloner RC(IndCallGraph, DSG, 0);
    RC.mergeCallSite(IndCallGraph->getFunctionCalls().front(), *CI);
  }
}
Ejemplo n.º 6
0
/// 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;
        }
      }
    }
  }
}