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 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())); }
// 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::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)); } } }
/// 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++)); } }
/// /// 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::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)); } }