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()); }
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())); }
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()); }
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; }
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; }
void DSMonitor::witness(DSNodeHandle N, std::vector<Value*> VS, std::string M) { if (N.isNull() || N.getNode()->isCollapsedNode()) return; watch(N,VS,M); check(); }
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)); } } }
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); }
// 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(); }
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(); } }
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()); } } }
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()); }
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; }
// // 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]); }
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; }
/// 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(); } }
/// Helper to fetch the node from the nodehandle DSNode * getNode() { assert(NH.getNode() && "NULL node?"); return NH.getNode(); }
/// 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!"); }
/// /// 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; } } }
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); }
// 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(); }
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)); } }
// // 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!"); } }