Beispiel #1
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;
        }
      }
    }
  }
}
Beispiel #2
0
/// 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;
      }
    }
  }
}