Example #1
0
void GraphBuilder::visitLoadInst(LoadInst &LI) {
  //
  // Create a DSNode for the pointer dereferenced by the load.  If the DSNode
  // is NULL, do nothing more (this can occur if the load is loading from a
  // NULL pointer constant (bugpoint can generate such code).
  //
  DSNodeHandle Ptr = getValueDest(LI.getPointerOperand());
  if (Ptr.isNull()) return; // Load from null

  // Make that the node is read from...
  Ptr.getNode()->setReadMarker();

  // Ensure a typerecord exists...
  Ptr.getNode()->growSizeForType(LI.getType(), Ptr.getOffset());

  if (isa<PointerType>(LI.getType()))
    setDestTo(LI, getLink(Ptr));

  // check that it is the inserted value
  if(TypeInferenceOptimize)
    if(LI.hasOneUse())
      if(StoreInst *SI = dyn_cast<StoreInst>(*(LI.use_begin())))
        if(SI->getOperand(0) == &LI) {
        ++NumIgnoredInst;
        return;
      }
  Ptr.getNode()->mergeTypeInfo(LI.getType(), Ptr.getOffset());
}
Example #2
0
void GraphBuilder::visitInsertValueInst(InsertValueInst& I) {
  setDestTo(I, createNode()->setAllocaMarker());

  Type *StoredTy = I.getInsertedValueOperand()->getType();
  DSNodeHandle Dest = getValueDest(&I);
  Dest.mergeWith(getValueDest(I.getAggregateOperand()));

  // Mark that the node is written to...
  Dest.getNode()->setModifiedMarker();
  unsigned Offset = 0;
  Type* STy = I.getAggregateOperand()->getType();
  llvm::InsertValueInst::idx_iterator i = I.idx_begin(), e = I.idx_end(); 
  for (; i != e; i++) {
    const StructLayout *SL = TD.getStructLayout(cast<StructType>(STy));
    Offset += SL->getElementOffset(*i);
    STy = (cast<StructType>(STy))->getTypeAtIndex(*i);
  }

  // Ensure a type-record exists...
  Dest.getNode()->mergeTypeInfo(StoredTy, Offset); 

  // Avoid adding edges from null, or processing non-"pointer" stores
  if (isa<PointerType>(StoredTy))
    Dest.addEdgeTo(getValueDest(I.getInsertedValueOperand()));
}
Example #3
0
void GraphBuilder::mergeInGlobalInitializer(GlobalVariable *GV) {
  // Ensure that the global variable is not external
  assert(!GV->isDeclaration() && "Cannot merge in external global!");

  //
  // Get a node handle to the global node and merge the initializer into it.
  //
  DSNodeHandle NH = getValueDest(GV);

  //
  // Ensure that the DSNode is large enough to hold the new constant that we'll
  // be adding to it.
  //
  Type * ElementType = GV->getType()->getElementType();
  while(ArrayType *ATy = dyn_cast<ArrayType>(ElementType)) {
    ElementType = ATy->getElementType();
  }
  if(!NH.getNode()->isNodeCompletelyFolded()) {
    unsigned requiredSize = TD.getTypeAllocSize(ElementType) + NH.getOffset();
    if (NH.getNode()->getSize() < requiredSize){
      NH.getNode()->growSize (requiredSize);
    }
  }

  //
  // Do the actual merging in of the constant initializer.
  //
  MergeConstantInitIntoNode(NH, GV->getType()->getElementType(), GV->getInitializer());

}
Example #4
0
bool DSGraphStats::isNodeForValueUntyped(Value *V, unsigned Offset, const Function *F) {
  DSNodeHandle NH = getNodeHandleForValue(V);
  if(!NH.getNode()){
    return true;
  }
  else {
    DSNode *N = NH.getNode();
    if (N->isNodeCompletelyFolded()){
      ++NumFoldedAccess;
      return true;
    }
    if ( N->isExternalNode()){
      ++NumExternalAccesses;
      return true;
    }
    if ( N->isIncompleteNode()){
      ++NumIncompleteAccesses;
      return true;
    }
    if (N->isUnknownNode()){
      ++NumUnknownAccesses;
      return true;
    }
    if (N->isIntToPtrNode()){
      ++NumI2PAccesses;
      return true;
    }
    // it is a complete node, now check how many types are present
    int count = 0;
    unsigned offset = NH.getOffset() + Offset;
    if (N->type_begin() != N->type_end())
      for (DSNode::TyMapTy::const_iterator ii = N->type_begin(),
           ee = N->type_end(); ii != ee; ++ii) {
        if(ii->first != offset)
          continue;
        count += ii->second->size();
      }

    if (count ==0)
      ++NumTypeCount0Accesses;
    else if(count == 1)
      ++NumTypeCount1Accesses;
    else if(count == 2)
      ++NumTypeCount2Accesses;
    else if(count == 3)
      ++NumTypeCount3Accesses;
    else
      ++NumTypeCount4Accesses;
    DEBUG(assert(TS->isTypeSafe(V,F)));
  }
  return false;
}
Example #5
0
void GraphBuilder::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
  if (isa<PointerType>(I.getType())) {
    visitInstruction (I);
    return;
  }

  //
  // Create a DSNode for the dereferenced pointer .  If the DSNode is NULL, do
  // nothing more (this can occur if the pointer is a NULL constant; bugpoint
  // can generate such code).
  //
  DSNodeHandle Ptr = getValueDest(I.getPointerOperand());
  if (Ptr.isNull()) return;

  //
  // Make that the memory object is read and written.
  //
  Ptr.getNode()->setReadMarker();
  Ptr.getNode()->setModifiedMarker();

  //
  // If the result of the compare-and-swap is a pointer, then we need to do
  // a few things:
  //  o Merge the compare and swap values (which are pointers) with the result
  //  o Merge the DSNode of the pointer *within* the memory object with the
  //    DSNode of the compare, swap, and result DSNode.
  //
  if (isa<PointerType>(I.getType())) {
    //
    // Get the DSNodeHandle of the memory object returned from the load.  Make
    // it the DSNodeHandle of the instruction's result.
    //
    DSNodeHandle FieldPtr = getLink (Ptr);
    setDestTo(I, getLink(Ptr));

    //
    // Merge the result, compare, and swap values of the instruction.
    //
    FieldPtr.mergeWith (getValueDest (I.getCompareOperand()));
    FieldPtr.mergeWith (getValueDest (I.getNewValOperand()));
  }

  //
  // Modify the DSNode so that it has the loaded/written type at the
  // appropriate offset.
  //
  Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset());
  Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset());
  return;
}
Example #6
0
void DSMonitor::witness(DSNodeHandle N, std::vector<Value*> VS, std::string M) {
  if (N.isNull() || N.getNode()->isCollapsedNode())
    return;

  watch(N,VS,M);
  check();
}
Example #7
0
void GraphBuilder::visitVAArgInst(VAArgInst &I) {
  Module *M = FB->getParent();
  Triple TargetTriple(M->getTargetTriple());
  Triple::ArchType Arch = TargetTriple.getArch();
  switch(Arch) {
  case Triple::x86_64: {
    // On x86_64, we have va_list as a struct {i32, i32, i8*, i8* }
    // The first i8* is where arguments generally go, but the second i8* can
    // be used also to pass arguments by register.
    // We model this by having both the i8*'s point to an array of pointers
    // to the arguments.
    DSNodeHandle Ptr = G.getVANodeFor(*FB);
    DSNodeHandle Dest = getValueDest(&I);
    if (Ptr.isNull()) return;

    // Make that the node is read and written
    Ptr.getNode()->setReadMarker()->setModifiedMarker();

    // Not updating type info, as it is already a collapsed node

    if (isa<PointerType>(I.getType()))
      Dest.mergeWith(Ptr);
    return; 
  }

  default: {
    assert(0 && "What frontend generates this?");
    DSNodeHandle Ptr = getValueDest(I.getOperand(0));

    //FIXME: also updates the argument
    if (Ptr.isNull()) return;

    // Make that the node is read and written
    Ptr.getNode()->setReadMarker()->setModifiedMarker();

    // Ensure a type record exists.
    DSNode *PtrN = Ptr.getNode();
    PtrN->mergeTypeInfo(I.getType(), Ptr.getOffset());

    if (isa<PointerType>(I.getType()))
      setDestTo(I, getLink(Ptr));
  }
  }
}
Example #8
0
void GraphBuilder::visitVAStartInst(CallSite CS) {
  // Build out DSNodes for the va_list depending on the target arch
  // And assosiate the right node with the VANode for this function
  // so it can be merged with the right arguments from callsites

  DSNodeHandle RetNH = getValueDest(*CS.arg_begin());

  if (DSNode *N = RetNH.getNode())
    visitVAStartNode(N);
}
Example #9
0
// visitInstruction - For all other instruction types, if we have any arguments
// that are of pointer type, make them have unknown composition bits, and merge
// the nodes together.
void GraphBuilder::visitInstruction(Instruction &Inst) {
  DSNodeHandle CurNode;
  if (isa<PointerType>(Inst.getType()))
    CurNode = getValueDest(&Inst);
  for (User::op_iterator I = Inst.op_begin(), E = Inst.op_end(); I != E; ++I)
    if (isa<PointerType>((*I)->getType()))
      CurNode.mergeWith(getValueDest(*I));

  if (DSNode *N = CurNode.getNode())
    N->setUnknownMarker();
}
Example #10
0
void GraphBuilder::visitExtractValueInst(ExtractValueInst& I) {
  DSNodeHandle Ptr = getValueDest(I.getOperand(0));

  // Make that the node is read from...
  Ptr.getNode()->setReadMarker();
  unsigned Offset = 0;
  Type* STy = I.getAggregateOperand()->getType();
  llvm::ExtractValueInst::idx_iterator i = I.idx_begin(), e = I.idx_end();
  for (; i != e; i++) {
    const StructLayout *SL = TD.getStructLayout(cast<StructType>(STy));
    Offset += SL->getElementOffset(*i);
    STy = (cast<StructType>(STy))->getTypeAtIndex(*i);
  }

  // Ensure a typerecord exists...
  Ptr.getNode()->mergeTypeInfo(I.getType(), Offset);

  if (isa<PointerType>(I.getType()))
    setDestTo(I, getLink(Ptr));
}
void
PoolRegisterElimination::removeTypeSafeRegistrations (const char * name) {
  //
  // Scan through all uses of the registration function and see if it can be
  // safely removed.  If so, schedule it for removal.
  //
  std::vector<CallInst*> toBeRemoved;
  Function * F = intrinsic->getIntrinsic(name).F;

  //
  // Look for and record all registrations that can be deleted.
  //
  for (Value::use_iterator UI=F->use_begin(), UE=F->use_end();
       UI != UE;
       ++UI) {
    //
    // Get the pointer to the registered object.
    //
    CallInst * CI = cast<CallInst>(*UI);
    Value * Ptr = intrinsic->getValuePointer(CI);
    // Lookup the DSNode for the value in the function's DSGraph.
    //
    DSGraph * TDG = dsaPass->getDSGraph(*(CI->getParent()->getParent()));
    DSNodeHandle DSH = TDG->getNodeForValue(Ptr);
    assert ((!(DSH.isNull())) && "No DSNode for Value!\n");

    //
    // If the DSNode is type-safe and is never used as an array, then there
    // will never be a need to look it up in a splay tree, so remove its
    // registration.
    //
    DSNode * N = DSH.getNode();
    if(!N->isArrayNode() && 
       TS->isTypeSafe(Ptr, F)){
      toBeRemoved.push_back(CI);
    }
  }

  //
  // Update the statistics.
  //
  if (toBeRemoved.size()) {
    RemovedRegistration += toBeRemoved.size();
    TypeSafeRegistrations += toBeRemoved.size();
  }

  //
  // Remove the unnecesary registrations.
  //
  std::vector<CallInst*>::iterator it, end;
  for (it = toBeRemoved.begin(), end = toBeRemoved.end(); it != end; ++it) {
    (*it)->eraseFromParent();
  }
}
Example #12
0
void DSMonitor::watch(DSNodeHandle N, std::vector<Value*> VS, std::string M) {
  if (N.isNull() || N.getNode()->isCollapsedNode()) {
    unwatch();
    return;
  }

  this->N = N;
  this->VS = VS;
  this->message = M;
  DSGraph *G = N.getNode()->getParentGraph();
  caption = getCaption(N.getNode(), G);

  if (!VS.empty()) {
    Instruction *I = getInstruction(VS[0]);
    if (I && I->getMetadata("dbg")) {
      const DebugLoc DL = I->getDebugLoc();
      auto *scope = cast<DIScope>(DL.getScope());
      location = scope->getFilename().str() + ":"
        + std::to_string(DL.getLine()) + ":"
        + std::to_string(DL.getCol());
    }
  }
}
Example #13
0
void GraphBuilder::visitStoreInst(StoreInst &SI) {
  Type *StoredTy = SI.getOperand(0)->getType();
  DSNodeHandle Dest = getValueDest(SI.getOperand(1));
  if (Dest.isNull()) return;

  // Mark that the node is written to...
  Dest.getNode()->setModifiedMarker();

  // Ensure a type-record exists...
  Dest.getNode()->growSizeForType(StoredTy, Dest.getOffset());

  // Avoid adding edges from null, or processing non-"pointer" stores
  if (isa<PointerType>(StoredTy))
    Dest.addEdgeTo(getValueDest(SI.getOperand(0)));

  if(TypeInferenceOptimize)
    if(SI.getOperand(0)->hasOneUse())
      if(isa<LoadInst>(SI.getOperand(0))){
        ++NumIgnoredInst;
        return;
      }
  Dest.getNode()->mergeTypeInfo(StoredTy, Dest.getOffset());
}
Example #14
0
void GraphBuilder::visitAtomicRMWInst(AtomicRMWInst &I) {
  //
  // Create a DSNode for the dereferenced pointer .  If the DSNode is NULL, do
  // nothing more (this can occur if the pointer is a NULL constant; bugpoint
  // can generate such code).
  //
  DSNodeHandle Ptr = getValueDest(I.getPointerOperand());
  if (Ptr.isNull()) return;

  //
  // Make that the memory object is read and written.
  //
  Ptr.getNode()->setReadMarker();
  Ptr.getNode()->setModifiedMarker();

  //
  // Modify the DSNode so that it has the loaded/written type at the
  // appropriate offset.
  //
  Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset());
  Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset());
  return;
}
Example #15
0
//
// TODO
//
template<class dsa> bool
TypeSafety<dsa>::isFieldDisjoint (const GlobalValue * V, unsigned offset) {
  //
  // Get the DSNode for the specified value.
  //
  DSNodeHandle DH = getDSNodeHandle (V);
  DSNode *node = DH.getNode();
  //unsigned offset = DH.getOffset();
  DEBUG(errs() << " check fields overlap at: " << offset << "\n");

  //
  // If there is no DSNode, claim that it is not type safe.
  //
  if (DH.isNull()) {
    return false;
  }
  //
  // If the DSNode is completely folded, then we know for sure that it is not
  // type-safe.
  //
  if (node->isNodeCompletelyFolded())
    return false;

  //
  // If the memory object represented by this DSNode can be manipulated by
  // external code or DSA has otherwise not finished analyzing all operations
  // on it, declare it type-unsafe.
  //
  if (node->isExternalNode() || node->isIncompleteNode())
    return false;

  //
  // If the pointer to the memory object came from some source not understood
  // by DSA or somehow came from/escapes to the realm of integers, declare it
  // type-unsafe.
  //
  if (node->isUnknownNode() || node->isIntToPtrNode() || node->isPtrToIntNode()) {
    return false;
  }

  return !((NodeInfo[node])[offset]); 
}
Example #16
0
template<class dsa> bool
TypeSafety<dsa>::isTypeSafe(const GlobalValue *V) {
  //
  // Get the DSNode for the specified value.
  //
  DSNodeHandle DH = getDSNodeHandle(V);

  //
  // If there is no DSNode, claim that it is not typesafe.
  //
  if (DH.isNull())
    return false;

  //
  // See if the DSNode is one that we think is type-safe.
  //
  if (TypeSafeNodes.count (DH.getNode()))
    return true;

  return false;
}
Example #17
0
/// ResolveFunctionCall - Resolve the actual arguments of a call to function F
/// with the specified call site descriptor.  This function links the arguments
/// and the return value for the call site context-insensitively.
///
void
SteensgaardDataStructures::ResolveFunctionCall(const Function *F, 
                                                const DSCallSite &Call,
                                                DSNodeHandle &RetVal) {

  assert(ResultGraph != 0 && "Result graph not allocated!");
  DSGraph::ScalarMapTy &ValMap = ResultGraph->getScalarMap();

  // Handle the return value of the function...
  if (Call.getRetVal().getNode() && RetVal.getNode())
    RetVal.mergeWith(Call.getRetVal());

  // Loop over all pointer arguments, resolving them to their provided pointers
  unsigned PtrArgIdx = 0;
  for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
       AI != AE && PtrArgIdx < Call.getNumPtrArgs(); ++AI) {
    DSGraph::ScalarMapTy::iterator I = ValMap.find(AI);
    if (I != ValMap.end())    // If its a pointer argument...
      I->second.mergeWith(Call.getPtrArg(PtrArgIdx++));
  }
}
void
PoolRegisterElimination::removeSingletonRegistrations (const char * name) {
  //
  // Scan through all uses of the registration function and see if it can be
  // safely removed.  If so, schedule it for removal.
  //
  std::vector<CallInst*> toBeRemoved;
  Function * F = intrinsic->getIntrinsic(name).F;

  //
  // Look for and record all registrations that can be deleted.
  //
  for (Value::use_iterator UI=F->use_begin(), UE=F->use_end();
       UI != UE;
       ++UI) {
    //
    // Get the pointer to the registered object.
    //
    CallInst * CI = cast<CallInst>(*UI);
    Value * Ptr = intrinsic->getValuePointer(CI);

    //
    // Lookup the DSNode for the value in the function's DSGraph.
    //
    DSGraph * TDG = dsaPass->getDSGraph(*(CI->getParent()->getParent()));
    DSNodeHandle DSH = TDG->getNodeForValue(Ptr);
    assert ((!(DSH.isNull())) && "No DSNode for Value!\n");

    //
    // If the object being registered is the same size as that found in the
    // DSNode, then we know it's a singleton object.  The run-time doesn't need
    // such objects registered in the splay trees, so we can remove the
    // registration function.
    //
    DSNode * N = DSH.getNode();
    Value * Size = intrinsic->getObjectSize (Ptr->stripPointerCasts());
    if (Size) {
      if (ConstantInt * C = dyn_cast<ConstantInt>(Size)) {
        unsigned long size = C->getZExtValue();
        if (size == N->getSize()) {
          toBeRemoved.push_back(CI);
          continue;
        }
      }
    }
  }

  //
  // Update the statistics.
  //
  if (toBeRemoved.size()) {
    RemovedRegistration += toBeRemoved.size();
    SingletonRegistrations += toBeRemoved.size();
  }

  //
  // Remove the unnecesary registrations.
  //
  std::vector<CallInst*>::iterator it, end;
  for (it = toBeRemoved.begin(), end = toBeRemoved.end(); it != end; ++it) {
    (*it)->eraseFromParent();
  }
}
Example #19
0
 /// Helper to fetch the node from the nodehandle
 DSNode * getNode() {
   assert(NH.getNode() && "NULL node?");
   return NH.getNode();
 }
Example #20
0
 /// Constructor (from string)
 NodeValue(std::string & raw, const Module * M, const DataStructures *DS)
   : F(NULL), V(NULL), serialized(raw) {
     initialize(M,DS);
     assert(V && NH.getNode() && "Parse failed!");
 }
Example #21
0
///
/// Method: visitIntrinsic()
///
/// Description:
///   Generate correct DSNodes for calls to LLVM intrinsic functions.
///
/// Inputs:
///   CS - The CallSite representing the call or invoke to the intrinsic.
///   F  - A pointer to the function called by the call site.
///
/// Return value:
///   true  - This intrinsic is properly handled by this method.
///   false - This intrinsic is not recognized by DSA.
///
bool GraphBuilder::visitIntrinsic(CallSite CS, Function *F) {
  ++NumIntrinsicCall;

  //
  // If this is a debug intrinsic, then don't do any special processing.
  //
  if (isa<DbgInfoIntrinsic>(CS.getInstruction()))
    return true;

  switch (F->getIntrinsicID()) {
  case Intrinsic::vastart: {
    visitVAStartInst(CS);
    return true;
  }
  case Intrinsic::vacopy: {
    // Simply merge the two arguments to va_copy.
    // This results in loss of precision on the temporaries used to manipulate
    // the va_list, and so isn't a big deal.  In theory we would build a
    // separate graph for this (like the one created in visitVAStartNode)
    // and only merge the node containing the variable arguments themselves.
    DSNodeHandle destNH = getValueDest(CS.getArgument(0));
    DSNodeHandle srcNH = getValueDest(CS.getArgument(1));
    destNH.mergeWith(srcNH);
    return true;
  }
  case Intrinsic::stacksave: {
    DSNode * Node = createNode();
    Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
    Node->foldNodeCompletely();
    setDestTo (*(CS.getInstruction()), Node);
    return true;
  }
  case Intrinsic::stackrestore:
    getValueDest(CS.getInstruction()).getNode()->setAllocaMarker()
      ->setIncompleteMarker()
      ->setUnknownMarker()
      ->foldNodeCompletely();
    return true;
  case Intrinsic::vaend:
  case Intrinsic::memcpy: 
  case Intrinsic::memmove: {
    // Merge the first & second arguments, and mark the memory read and
    // modified.
    DSNodeHandle RetNH = getValueDest(*CS.arg_begin());
    RetNH.mergeWith(getValueDest(*(CS.arg_begin()+1)));
    if (DSNode *N = RetNH.getNode())
      N->setModifiedMarker()->setReadMarker();
    return true;
  }
  case Intrinsic::memset:
    // Mark the memory modified.
    if (DSNode *N = getValueDest(*CS.arg_begin()).getNode())
      N->setModifiedMarker();
    return true;

  case Intrinsic::eh_exception: {
    DSNode * Node = createNode();
    Node->setIncompleteMarker();
    Node->foldNodeCompletely();
    setDestTo (*(CS.getInstruction()), Node);
    return true;
  }

  case Intrinsic::eh_selector: {
    for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
         I != E; ++I) {
      if (isa<PointerType>((*I)->getType())) {
        DSNodeHandle Ptr = getValueDest(*I);
        if(Ptr.getNode()) {
          Ptr.getNode()->setReadMarker();
          Ptr.getNode()->setIncompleteMarker();
        }
      }
    }
    return true;
  }
  case Intrinsic::eh_typeid_for: {
    DSNodeHandle Ptr = getValueDest(*CS.arg_begin());
    Ptr.getNode()->setReadMarker();
    Ptr.getNode()->setIncompleteMarker();
    return true;
  }

  case Intrinsic::prefetch:
    return true;

  case Intrinsic::objectsize:
    return true;

    //
    // The return address/frame address aliases with the stack, 
    // is type-unknown, and should
    // have the unknown flag set since we don't know where it goes.
    //
  case Intrinsic::returnaddress:
  case Intrinsic::frameaddress: {
    DSNode * Node = createNode();
    Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
    Node->foldNodeCompletely();
    setDestTo (*(CS.getInstruction()), Node);
    return true;
  }

  // Process lifetime intrinsics
  case Intrinsic::lifetime_start:
  case Intrinsic::lifetime_end:
  case Intrinsic::invariant_start:
  case Intrinsic::invariant_end:
    return true;

  default: {
    //ignore pointer free intrinsics
    if (!isa<PointerType>(F->getReturnType())) {
      bool hasPtr = false;
      for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
           I != E && !hasPtr; ++I)
        if (isa<PointerType>(I->getType()))
          hasPtr = true;
      if (!hasPtr)
        return true;
    }

    DEBUG(errs() << "[dsa:local] Unhandled intrinsic: " << F->getName() << "\n");
    assert(0 && "Unhandled intrinsic");
    return false;
  }
  }
}
Example #22
0
void GraphBuilder::visitGetElementPtrInst(User &GEP) {
  //
  // Ensure that the indexed pointer has a DSNode.
  //
  DSNodeHandle Value = getValueDest(GEP.getOperand(0));
  if (Value.isNull())
    Value = createNode();

  //
  // There are a few quick and easy cases to handle.  If  the DSNode of the 
  // indexed pointer is already folded, then we know that the result of the 
  // GEP will have the same offset into the same DSNode 
  // as the indexed pointer.
  //

  if (!Value.isNull() &&
      Value.getNode()->isNodeCompletelyFolded()) {
    setDestTo(GEP, Value);
    return;
  }

  //
  // Okay, no easy way out.  Calculate the offset into the object being
  // indexed.
  //

  int Offset = 0;

  // FIXME: I am not sure if the code below is completely correct (especially
  //        if we start doing fancy analysis on non-constant array indices).
  //        What if the array is indexed using a larger index than its declared
  //        size?  Does the LLVM verifier catch such issues?
  //

  //
  // Determine the offset (in bytes) between the result of the GEP and the
  // GEP's pointer operand.
  //
  // Note: All of these subscripts are indexing INTO the elements we have...
  //
  // FIXME: We can do better for array indexing.  First, if the array index is
  //        constant, we can determine how much farther we're moving the
  //        pointer.  Second, we can try to use the results of other analysis
  //        passes (e.g., ScalarEvolution) to find min/max values to do less
  //        conservative type-folding.
  //
  for (gep_type_iterator I = gep_type_begin(GEP), E = gep_type_end(GEP);
       I != E; ++I)
    if (StructType *STy = dyn_cast<StructType>(*I)) {
      // indexing into a structure
      // next index must be a constant
      const ConstantInt* CUI = cast<ConstantInt>(I.getOperand());
      int FieldNo = CUI->getSExtValue();
      // increment the offset by the actual byte offset being accessed

      unsigned requiredSize = TD.getTypeAllocSize(STy) + Value.getOffset() + Offset;
      if(!Value.getNode()->isArrayNode() || Value.getNode()->getSize() <= 0){
        if (requiredSize > Value.getNode()->getSize())
          Value.getNode()->growSize(requiredSize);
      }
      Offset += (unsigned)TD.getStructLayout(STy)->getElementOffset(FieldNo);
      if(TypeInferenceOptimize) {
        if(ArrayType* AT = dyn_cast<ArrayType>(STy->getTypeAtIndex(FieldNo))) {
          Value.getNode()->mergeTypeInfo(AT, Value.getOffset() + Offset);
          if((++I) == E) {
            break;
          }
          // Check if we are still indexing into an array.
          // We only record the topmost array type of any nested array.
          // Keep skipping indexes till we reach a non-array type.
          // J is the type of the next index.
          // Uncomment the line below to get all the nested types.
          gep_type_iterator J = I;
          while(isa<ArrayType>(*(++J))) {
            //      Value.getNode()->mergeTypeInfo(AT1, Value.getOffset() + Offset);
            if((++I) == E) {
              break;
            }
            J = I;
          }
          if((I) == E) {
            break;
          }
        }
      }
    } else if(ArrayType *ATy = dyn_cast<ArrayType>(*I)) {
      // indexing into an array.
      Value.getNode()->setArrayMarker();
      Type *CurTy = ATy->getElementType();

      if(!isa<ArrayType>(CurTy) &&
         Value.getNode()->getSize() <= 0) {
        Value.getNode()->growSize(TD.getTypeAllocSize(CurTy));
      } else if(isa<ArrayType>(CurTy) && Value.getNode()->getSize() <= 0){
        Type *ETy = (cast<ArrayType>(CurTy))->getElementType();
        while(isa<ArrayType>(ETy)) {
          ETy = (cast<ArrayType>(ETy))->getElementType();
        }
        Value.getNode()->growSize(TD.getTypeAllocSize(ETy));
      }

      // Find if the DSNode belongs to the array
      // If not fold.
      if((Value.getOffset() || Offset != 0)
         || (!isa<ArrayType>(CurTy)
             && (Value.getNode()->getSize() != TD.getTypeAllocSize(CurTy)))) {
        Value.getNode()->foldNodeCompletely();
        Value.getNode();
        Offset = 0;
        break;
      }
    } else if (const PointerType *PtrTy = dyn_cast<PointerType>(*I)) {
      Type *CurTy = PtrTy->getElementType();

      //
      // Unless we're advancing the pointer by zero bytes via array indexing,
      // fold the node (i.e., mark it type-unknown) and indicate that we're
      // indexing zero bytes into the object.
      //
      // Note that we break out of the loop if we fold the node.  Once
      // something is folded, all values within it are considered to alias.
      //

      if (!isa<Constant>(I.getOperand()) ||
          !cast<Constant>(I.getOperand())->isNullValue()) {
        Value.getNode()->setArrayMarker();


        if(!isa<ArrayType>(CurTy) && Value.getNode()->getSize() <= 0){
          Value.getNode()->growSize(TD.getTypeAllocSize(CurTy));
        } else if(isa<ArrayType>(CurTy) && Value.getNode()->getSize() <= 0){
          Type *ETy = (cast<ArrayType>(CurTy))->getElementType();
          while(isa<ArrayType>(ETy)) {
            ETy = (cast<ArrayType>(ETy))->getElementType();
          }
          Value.getNode()->growSize(TD.getTypeAllocSize(ETy));
        }
        if(Value.getOffset() || Offset != 0
           || (!isa<ArrayType>(CurTy)
               && (Value.getNode()->getSize() != TD.getTypeAllocSize(CurTy)))) {
          Value.getNode()->foldNodeCompletely();
          Value.getNode();
          Offset = 0;
          break;
        }
      }
    }

  // Add in the offset calculated...
  Value.setOffset(Value.getOffset()+Offset);

  // Check the offset
  DSNode *N = Value.getNode();
  if (N) N->checkOffsetFoldIfNeeded(Value.getOffset());

  // Value is now the pointer we want to GEP to be...
  setDestTo(GEP, Value);
}
Example #23
0
// XXX duplicated from DSA/Printer.cpp XXX
static std::string getCaption(const DSNode *N, const DSGraph *G) {
  std::string empty;
  raw_string_ostream OS(empty);
  const Module *M = 0;

  if (!G) G = N->getParentGraph();

  // Get the module from ONE of the functions in the graph it is available.
  if (G && G->retnodes_begin() != G->retnodes_end())
    M = G->retnodes_begin()->first->getParent();
  if (M == 0 && G) {
    // If there is a global in the graph, we can use it to find the module.
    const DSScalarMap &SM = G->getScalarMap();
    if (SM.global_begin() != SM.global_end())
      M = (*SM.global_begin())->getParent();
  }

  if (N->isNodeCompletelyFolded())
    OS << "COLLAPSED";
  else {
    if (N->type_begin() != N->type_end())
      for (DSNode::TyMapTy::const_iterator ii = N->type_begin(),
           ee = N->type_end(); ii != ee; ++ii) {
        OS << ii->first << ": ";
        if (ii->second)
          for (svset<Type*>::const_iterator ni = ii->second->begin(),
               ne = ii->second->end(); ni != ne; ++ni) {
            Type * t = *ni;
            t->print (OS);
            OS << ", ";
          }
        else
          OS << "VOID";
        OS << " ";
      }
    else
      OS << "VOID";
    if (N->isArrayNode())
      OS << " array";
  }
  if (unsigned NodeType = N->getNodeFlags()) {
    OS << ": ";
    if (NodeType & DSNode::AllocaNode       ) OS << "S";
    if (NodeType & DSNode::HeapNode         ) OS << "H";
    if (NodeType & DSNode::GlobalNode       ) OS << "G";
    if (NodeType & DSNode::UnknownNode      ) OS << "U";
    if (NodeType & DSNode::IncompleteNode   ) OS << "I";
    if (NodeType & DSNode::ModifiedNode     ) OS << "M";
    if (NodeType & DSNode::ReadNode         ) OS << "R";
    if (NodeType & DSNode::ExternalNode     ) OS << "E";
    if (NodeType & DSNode::ExternFuncNode   ) OS << "X";
    if (NodeType & DSNode::IntToPtrNode     ) OS << "P";
    if (NodeType & DSNode::PtrToIntNode     ) OS << "2";
    if (NodeType & DSNode::VAStartNode      ) OS << "V";

#ifndef NDEBUG
    if (NodeType & DSNode::DeadNode       ) OS << "<dead>";
#endif
    OS << "\n";
  }

  //Indicate if this is a VANode for some function
  for (DSGraph::vanodes_iterator I = G->vanodes_begin(), E = G->vanodes_end();
      I != E; ++I) {
    DSNodeHandle VANode = I->second;
    if (N == VANode.getNode()) {
      OS << "(VANode for " << I->first->getName().str() << ")\n";
    }
  }

  EquivalenceClasses<const GlobalValue*> *GlobalECs = 0;
  if (G) GlobalECs = &G->getGlobalECs();

  for (DSNode::globals_iterator i = N->globals_begin(), e = N->globals_end();
       i != e; ++i) {
    (*i)->printAsOperand(OS,false,M);

    // Figure out how many globals are equivalent to this one.
    if (GlobalECs) {
      EquivalenceClasses<const GlobalValue*>::iterator I =
        GlobalECs->findValue(*i);
      if (I != GlobalECs->end()) {
        unsigned NumMembers =
          std::distance(GlobalECs->member_begin(I), GlobalECs->member_end());
        if (NumMembers != 1) OS << " + " << (NumMembers-1) << " EC";
      }
    }
    OS << "\n";
  }

  return OS.str();
}
Example #24
0
void GraphBuilder::visitCallSite(CallSite CS) {
  //
  // Get the called value.  Strip off any casts which are lossless.
  //
  Value *Callee = CS.getCalledValue()->stripPointerCasts();

  // Special case handling of certain libc allocation functions here.
  if (Function *F = dyn_cast<Function>(Callee))
    if (F->isIntrinsic() && visitIntrinsic(CS, F))
      return;

  //Can't do much about inline asm (yet!)
  if (isa<InlineAsm> (Callee)) {
    ++NumAsmCall;
    DSNodeHandle RetVal;
    Instruction *I = CS.getInstruction();
    if (isa<PointerType > (I->getType()))
      RetVal = getValueDest(I);

    // Calculate the arguments vector...
    for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I)
      if (isa<PointerType > ((*I)->getType()))
        RetVal.mergeWith(getValueDest(*I));
    if (!RetVal.isNull())
      RetVal.getNode()->foldNodeCompletely();
    return;
  }

  // Set up the return value...
  DSNodeHandle RetVal;
  Instruction *I = CS.getInstruction();
  if (isa<PointerType>(I->getType()))
    RetVal = getValueDest(I);

  DSNode *CalleeNode = 0;
  if (!isa<Function>(Callee)) {
    CalleeNode = getValueDest(Callee).getNode();
    if (CalleeNode == 0) {
      DEBUG(errs() << "WARNING: Program is calling through a null pointer?\n" << *I);
      return;  // Calling a null pointer?
    }
  }

  // NOTE: This code is identical to 'DSGraph::getDSCallSiteForCallSite',
  // the reason it's duplicated is because this calls getValueDest instead
  // of getNodeForValue to get the DSNodes for the arguments.  Since we're in
  // local it's possible that we need to create a DSNode for the argument, as
  // opposed to getNodeForValue which simply retrieves the existing node.


  //Get the FunctionType for the called function
  const FunctionType *CalleeFuncType = DSCallSite::FunctionTypeOfCallSite(CS);
  int NumFixedArgs = CalleeFuncType->getNumParams();

  // Sanity check--this really, really shouldn't happen
  if (!CalleeFuncType->isVarArg())
    assert(CS.arg_size() == static_cast<unsigned>(NumFixedArgs) &&
           "Too many arguments/incorrect function signature!");

  std::vector<DSNodeHandle> Args;
  Args.reserve(CS.arg_end()-CS.arg_begin());
  DSNodeHandle VarArgNH;

  // Calculate the arguments vector...
  // Add all fixed pointer arguments, then merge the rest together
  for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
       I != E; ++I)
    if (isa<PointerType>((*I)->getType())) {
      DSNodeHandle ArgNode = getValueDest(*I);
      if (I - CS.arg_begin() < NumFixedArgs) {
        Args.push_back(ArgNode);
      } else {
        VarArgNH.mergeWith(ArgNode);
      }
    }

  // Add a new function call entry...
  if (CalleeNode) {
    ++NumIndirectCall;
    G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH, CalleeNode,
                                              Args));
  } else {
    ++NumDirectCall;
    G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH,
                                              cast<Function>(Callee),
                                              Args));
  }


}
Example #25
0
//
// Function: MergeConstantInitIntoNode()
//
// Description:
//  Merge the specified constant into the specified DSNode.
//
void
GraphBuilder::MergeConstantInitIntoNode(DSNodeHandle &NH,
                                        Type* Ty,
                                        Constant *C) {
  //
  // Ensure a type-record exists...
  //
  DSNode *NHN = NH.getNode();
  //NHN->mergeTypeInfo(Ty, NH.getOffset());

  //
  // If we've found something of pointer type, create or find its DSNode and
  // make a link from the specified DSNode to the new DSNode describing the
  // pointer we've just found.
  //
  if (isa<PointerType>(Ty)) {
    NHN->mergeTypeInfo(Ty, NH.getOffset());
    NH.addEdgeTo(getValueDest(C));
    return;
  }

  //
  // If the type of the object (array element, structure field, etc.) is an
  // integer or floating point type, then just ignore it.  It has no DSNode.
  //
  if (Ty->isIntOrIntVectorTy() || Ty->isFPOrFPVectorTy()) return;

  //
  // Handle aggregate constants.
  //
  if (ConstantArray *CA = dyn_cast<ConstantArray>(C)) {
    //
    // For an array, we don't worry about different elements pointing to
    // different objects; we essentially pretend that all array elements alias.
    //
    Type * ElementType = cast<ArrayType>(Ty)->getElementType();
    for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
      Constant * ConstElement = cast<Constant>(CA->getOperand(i));
      MergeConstantInitIntoNode(NH, ElementType, ConstElement);
    }
  } else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) {
    //
    // For a structure, we need to merge each element of the constant structure
    // into the specified DSNode.  However, we must also handle structures that
    // end with a zero-length array ([0 x sbyte]); this is a common C idiom
    // that continues to plague the world.
    //
    //NHN->mergeTypeInfo(Ty, NH.getOffset());

    const StructLayout *SL = TD.getStructLayout(cast<StructType>(Ty));

    for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
      DSNode *NHN = NH.getNode();
      if (SL->getElementOffset(i) < SL->getSizeInBytes()) {
        //
        // Get the type and constant value of this particular element of the
        // constant structure.
        //
        Type * ElementType = cast<StructType>(Ty)->getElementType(i);
        Constant * ConstElement = cast<Constant>(CS->getOperand(i));

        //
        // Get the offset (in bytes) into the memory object that we're
        // analyzing.
        //
        unsigned offset = NH.getOffset()+(unsigned)SL->getElementOffset(i);
        NHN->mergeTypeInfo(ElementType, offset);
        //
        // Create a new DSNodeHandle.  This DSNodeHandle will point to the same
        // DSNode as the one we're constructing for our caller; however, it
        // will point into a different offset into that DSNode.
        //
        DSNodeHandle NewNH (NHN, offset);
        assert ((NHN->isNodeCompletelyFolded() || (NewNH.getOffset() == offset))
                && "Need to resize DSNode!");

        //
        // Recursively merge in this element of the constant struture into the
        // DSNode.
        //
        MergeConstantInitIntoNode(NewNH, ElementType, ConstElement);
      } else if (SL->getElementOffset(i) == SL->getSizeInBytes()) {
        //
        // If this is one of those cute structures that ends with a zero-length
        // array, just fold the DSNode now and get it over with.
        //
        DEBUG(errs() << "Zero size element at end of struct\n" );
        NHN->foldNodeCompletely();
      } else {
        assert(0 && "type was smaller than offsets of struct layout indicate");
      }
    }
  } else if (isa<ConstantAggregateZero>(C) || isa<UndefValue>(C)) {
    //
    // Undefined values and NULL pointers have no DSNodes, so they do nothing.
    //
  } else {
    assert(0 && "Unknown constant type!");
  }
}