/// OptimizeGlobals - This method uses information taken from DSA to optimize /// global variables. /// bool DSOpt::OptimizeGlobals(Module &M) { DSGraph* GG = TD->getGlobalsGraph(); const DSGraph::ScalarMapTy &SM = GG->getScalarMap(); bool Changed = false; for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) if (!I->isDeclaration()) { // Loop over all of the non-external globals... // Look up the node corresponding to this global, if it exists. DSNode *GNode = 0; DSGraph::ScalarMapTy::const_iterator SMI = SM.find(I); if (SMI != SM.end()) GNode = SMI->second.getNode(); if (GNode == 0 && I->hasInternalLinkage()) { // If there is no entry in the scalar map for this global, it was never // referenced in the program. If it has internal linkage, that means we // can delete it. We don't ACTUALLY want to delete the global, just // remove anything that references the global: later passes will take // care of nuking it. if (!I->use_empty()) { I->replaceAllUsesWith(ConstantPointerNull::get(I->getType())); ++NumGlobalsIsolated; } } else if (GNode && GNode->NodeType.isCompleteNode()) { // If the node has not been read or written, and it is not externally // visible, kill any references to it so it can be DCE'd. if (!GNode->NodeType.isModifiedNode() && !GNode->NodeType.isReadNode() &&I->hasInternalLinkage()){ if (!I->use_empty()) { I->replaceAllUsesWith(ConstantPointerNull::get(I->getType())); ++NumGlobalsIsolated; } } // We expect that there will almost always be a node for this global. // If there is, and the node doesn't have the M bit set, we can set the // 'constant' bit on the global. if (!GNode->NodeType.isModifiedNode() && !I->isConstant()) { I->setConstant(true); ++NumGlobalsConstanted; Changed = true; } } } return Changed; }
// // Method: TransformCollapsedAllocas() // // Description: // Transform all stack allocated objects that are type-unknown // (i.e., are completely folded) to heap allocations. // void ConvertUnsafeAllocas::TransformCollapsedAllocas(Module &M) { // // Need to check if the following is incomplete because we are only looking // at scalars. // // It may be complete because every instruction actually is a scalar in // LLVM?! for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { if (!MI->isDeclaration()) { DSGraph *G = budsPass->getDSGraph(*MI); DSGraph::ScalarMapTy &SM = G->getScalarMap(); for (DSGraph::ScalarMapTy::iterator SMI = SM.begin(), SME = SM.end(); SMI != SME; ) { if (AllocaInst *AI = dyn_cast<AllocaInst>((Value *)(SMI->first))) { if (SMI->second.getNode()->isNodeCompletelyFolded()) { Value *AllocSize = ConstantInt::get(Int32Type, TD->getTypeAllocSize(AI->getAllocatedType())); if (AI->isArrayAllocation()) AllocSize = BinaryOperator::Create(Instruction::Mul, AllocSize, AI->getOperand(0), "sizetmp", AI); CallInst *CI = CallInst::Create (kmalloc, AllocSize, "", AI); Value * MI = castTo (CI, AI->getType(), "", AI); InsertFreesAtEnd(CI); AI->replaceAllUsesWith(MI); SMI->second.getNode()->setHeapMarker(); SM.erase(SMI++); AI->getParent()->getInstList().erase(AI); ++ConvAllocas; } else { ++SMI; } } else { ++SMI; } } } } }
// // Method: getFunctionTargets() // // Description: // This method finds all of the potential targets of the specified indirect // function call. // void CompleteChecks::getFunctionTargets (CallSite CS, std::vector<const Function *> & Targets) { EQTDDataStructures & dsaPass = getAnalysis<EQTDDataStructures>(); const DSCallGraph & callgraph = dsaPass.getCallGraph(); DSGraph* G = dsaPass.getGlobalsGraph(); DSGraph::ScalarMapTy& SM = G->getScalarMap(); DSCallGraph::callee_iterator csi = callgraph.callee_begin(CS); DSCallGraph::callee_iterator cse = callgraph.callee_end(CS); for (; csi != cse; ++csi) { const Function *F = *csi; DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F), sccee = callgraph.scc_end(F); for (;sccii != sccee; ++sccii) { DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); if (I != SM.end() && !((*sccii)->isDeclaration())) { Targets.push_back (*sccii); } } } const Function *F1 = CS.getInstruction()->getParent()->getParent(); F1 = callgraph.sccLeader(&*F1); DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F1), sccee = callgraph.scc_end(F1); for(;sccii != sccee; ++sccii) { DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); if (I != SM.end() && !((*sccii)->isDeclaration())) { Targets.push_back (*sccii); } } return; }
// // Method: visitCallSite() // // Description: // This method transforms a call site. A call site may either be a call // instruction or an invoke instruction. // // Inputs: // CS - The call site representing the instruction that should be transformed. // void FuncTransform::visitCallSite(CallSite& CS) { const Function *CF = CS.getCalledFunction(); Instruction *TheCall = CS.getInstruction(); bool thread_creation_point = false; // // Get the value that is called at this call site. Strip away any pointer // casts that do not change the representation of the data (i.e., are // lossless casts). // Value * CalledValue = CS.getCalledValue()->stripPointerCasts(); // // The CallSite::getCalledFunction() method is not guaranteed to strip off // pointer casts. If no called function was found, manually strip pointer // casts off of the called value and see if we get a function. If so, this // is a direct call, and we want to update CF accordingly. // if (!CF) CF = dyn_cast<Function>(CalledValue); // // Do not change any inline assembly code. // if (isa<InlineAsm>(TheCall->getOperand(0))) { errs() << "INLINE ASM: ignoring. Hoping that's safe.\n"; return; } // // Ignore calls to NULL pointers or undefined values. // if ((isa<ConstantPointerNull>(CalledValue)) || (isa<UndefValue>(CalledValue))) { errs() << "WARNING: Ignoring call using NULL/Undef function pointer.\n"; return; } // If this function is one of the memory manipulating functions built into // libc, emulate it with pool calls as appropriate. if (CF && CF->isDeclaration()) { std::string Name = CF->getName(); if (Name == "free" || Name == "cfree") { visitFreeCall(CS); return; } else if (Name == "malloc") { visitMallocCall(CS); return; } else if (Name == "calloc") { visitCallocCall(CS); return; } else if (Name == "realloc") { visitReallocCall(CS); return; } else if (Name == "memalign" || Name == "posix_memalign") { visitMemAlignCall(CS); return; } else if (Name == "strdup") { visitStrdupCall(CS); return; } else if (Name == "valloc") { errs() << "VALLOC USED BUT NOT HANDLED!\n"; abort(); } else if (unsigned PoolArgc = PAInfo.getNumInitialPoolArguments(Name)) { visitRuntimeCheck(CS, PoolArgc); return; } else if (Name == "pthread_create") { thread_creation_point = true; // // Get DSNode representing the DSNode of the function pointer Value of // the pthread_create call // DSNode* thread_callee_node = G->getNodeForValue(CS.getArgument(2)).getNode(); if (!thread_callee_node) { assert(0 && "apparently you need this code"); FuncInfo *CFI = PAInfo.getFuncInfo(*CF); thread_callee_node = G->getNodeForValue(CFI->MapValueToOriginal(CS.getArgument(2))).getNode(); } // Fill in CF with the name of one of the functions in thread_callee_node CF = const_cast<Function*>(dyn_cast<Function>(*thread_callee_node->globals_begin())); } } // // We need to figure out which local pool descriptors correspond to the pool // descriptor arguments passed into the function call. Calculate a mapping // from callee DSNodes to caller DSNodes. We construct a partial isomophism // between the graphs to figure out which pool descriptors need to be passed // in. The roots of this mapping is found from arguments and return values. // DataStructures& Graphs = PAInfo.getGraphs(); DSGraph::NodeMapTy NodeMapping; Instruction *NewCall; Value *NewCallee; std::vector<const DSNode*> ArgNodes; DSGraph *CalleeGraph; // The callee graph // For indirect callees, find any callee since all DS graphs have been // merged. if (CF) { // Direct calls are nice and simple. DEBUG(errs() << " Handling direct call: " << *TheCall << "\n"); // // Do not try to add pool handles to the function if it: // a) Already calls a cloned function; or // b) Calls a function which was never cloned. // // For such a call, just replace any arguments that take original functions // with their cloned function poiner values. // FuncInfo *CFI = PAInfo.getFuncInfo(*CF); if (CFI == 0 || CFI->Clone == 0) { // Nothing to transform... visitInstruction(*TheCall); return; } // // Oh, dear. We must add pool descriptors to this direct call. // NewCallee = CFI->Clone; ArgNodes = CFI->ArgNodes; assert ((Graphs.hasDSGraph (*CF)) && "Function has no ECGraph!\n"); CalleeGraph = Graphs.getDSGraph(*CF); } else { DEBUG(errs() << " Handling indirect call: " << *TheCall << "\n"); DSGraph *G = Graphs.getGlobalsGraph(); DSGraph::ScalarMapTy& SM = G->getScalarMap(); // Here we fill in CF with one of the possible called functions. Because we // merged together all of the arguments to all of the functions in the // equivalence set, it doesn't really matter which one we pick. // (If the function was cloned, we have to map the cloned call instruction // in CS back to the original call instruction.) Instruction *OrigInst = cast<Instruction>(getOldValueIfAvailable(CS.getInstruction())); // // Attempt to get one of the function targets of this indirect call site by // looking at the call graph constructed by the points-to analysis. Be // sure to use the original call site from the original function; the // points-to analysis has no information on the clones we've created. // // Also, look for the target that has the greatest number of arguments that // have associated DSNodes. This ensures that we pass the maximum number // of pools possible and prevents us from eliding a pool because we're // examining a target that doesn't need it. // const DSCallGraph & callGraph = Graphs.getCallGraph(); DSCallGraph::callee_iterator I = callGraph.callee_begin(OrigInst); for (; I != callGraph.callee_end(OrigInst); ++I) { for(DSCallGraph::scc_iterator sccii = callGraph.scc_begin(*I), sccee = callGraph.scc_end(*I); sccii != sccee; ++sccii){ if(SM.find(SM.getLeaderForGlobal(*sccii)) == SM.end()) continue; // // Get the information for this function. Since this is coming from // DSA, it should be an original function. // // This call site calls a function, that is not defined in this module if (!(Graphs.hasDSGraph(**sccii))) return; // For all other cases Func Info must exist. PAInfo.getFuncInfo(**sccii); // // If this target takes more DSNodes than the last one we found, then // make *this* target our canonical target. // CF = *sccii; break; } } if(!CF){ const Function *F1 = OrigInst->getParent()->getParent(); F1 = callGraph.sccLeader(&*F1); for(DSCallGraph::scc_iterator sccii = callGraph.scc_begin(F1), sccee = callGraph.scc_end(F1); sccii != sccee; ++sccii){ if(SM.find(SM.getLeaderForGlobal(*sccii)) == SM.end()) continue; // // Get the information for this function. Since this is coming from DSA, // it should be an original function. // // This call site calls a function, that is not defined in this module if (!(Graphs.hasDSGraph(**sccii))) return; // For all other cases Func Info must exist. PAInfo.getFuncInfo(**sccii); // // If this target takes more DSNodes than the last one we found, then // make *this* target our canonical target. // CF = *sccii; } } // Assuming the call graph is always correct. And if the call graph reports, // no callees, we can assume that it is right. // // If we didn't find the callee in the constructed call graph, try // checking in the DSNode itself. // This isn't ideal as it means that this call site didn't have inlining // happen. // // // If we still haven't been able to find a target function of the call site // to transform, do nothing. // // One may be tempted to think that we should always have at least one // target, but this is not true. There are perfectly acceptable (but // strange) programs for which no function targets exist. Function // pointers loaded from undef values, for example, will have no targets. // if (!CF) return; // // It's possible that this program has indirect call targets that are // not defined in this module. Do not transformation for such functions. // if (!(Graphs.hasDSGraph(*CF))) return; // // Get the common graph for the set of functions this call may invoke. // assert ((Graphs.hasDSGraph(*CF)) && "Function has no DSGraph!\n"); CalleeGraph = Graphs.getDSGraph(*CF); #ifndef NDEBUG // Verify that all potential callees at call site have the same DS graph. DSCallGraph::callee_iterator E = Graphs.getCallGraph().callee_end(OrigInst); for (; I != E; ++I) { const Function * F = *I; assert (F); if (!(F)->isDeclaration()) assert(CalleeGraph == Graphs.getDSGraph(**I) && "Callees at call site do not have a common graph!"); } #endif // Find the DS nodes for the arguments that need to be added, if any. FuncInfo *CFI = PAInfo.getFuncInfo(*CF); assert(CFI && "No function info for callee at indirect call?"); ArgNodes = CFI->ArgNodes; if (ArgNodes.empty()) return; // No arguments to add? Transformation is a noop! // Cast the function pointer to an appropriate type! std::vector<Type*> ArgTys(ArgNodes.size(), PoolAllocate::PoolDescPtrTy); for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I) ArgTys.push_back((*I)->getType()); FunctionType *FTy = FunctionType::get(TheCall->getType(), ArgTys, false); PointerType *PFTy = PointerType::getUnqual(FTy); // If there are any pool arguments cast the func ptr to the right type. NewCallee = CastInst::CreatePointerCast(CS.getCalledValue(), PFTy, "tmp", TheCall); } // // FIXME: Why do we disable strict checking when calling the // DSGraph::computeNodeMapping() method? // Function::const_arg_iterator FAI = CF->arg_begin(), E = CF->arg_end(); CallSite::arg_iterator AI = CS.arg_begin() + (thread_creation_point ? 3 : 0); CallSite::arg_iterator AE = CS.arg_end(); for ( ; FAI != E && AI != AE; ++FAI, ++AI) if (!isa<Constant>(*AI)) { DSGraph::computeNodeMapping(CalleeGraph->getNodeForValue(FAI), getDSNodeHFor(*AI), NodeMapping, false); } //assert(AI == AE && "Varargs calls not handled yet!"); // Map the return value as well... if (isa<PointerType>(TheCall->getType())) DSGraph::computeNodeMapping(CalleeGraph->getReturnNodeFor(*CF), getDSNodeHFor(TheCall), NodeMapping, false); // This code seems redundant (and crashes occasionally) // There is no reason to map globals here, since they are not passed as // arguments // // Map the nodes that are pointed to by globals. // DSScalarMap &CalleeSM = CalleeGraph->getScalarMap(); // for (DSScalarMap::global_iterator GI = G.getScalarMap().global_begin(), // E = G.getScalarMap().global_end(); GI != E; ++GI) // if (CalleeSM.count(*GI)) // DSGraph::computeNodeMapping(CalleeGraph->getNodeForValue(*GI), // getDSNodeHFor(*GI), // NodeMapping, false); // // Okay, now that we have established our mapping, we can figure out which // pool descriptors to pass in... // // Note: // There used to be code here that would create a new pool before the // function call and destroy it after the function call. This could would // get triggered if bounds checking was disbled or the DSNode for the // argument was an array value. // // I believe that code was incorrect; an argument may have a NULL pool handle // (i.e., no pool handle) because the pool allocation heuristic used simply // decided not to assign that value a pool. The argument may alias data // that should not be freed after the function call is complete, so calling // pooldestroy() after the call would free data, causing dangling pointer // dereference errors. // std::vector<Value*> Args; for (unsigned i = 0, e = ArgNodes.size(); i != e; ++i) { Value *ArgVal = Constant::getNullValue(PoolAllocate::PoolDescPtrTy); if (NodeMapping.count(ArgNodes[i])) { if (DSNode *LocalNode = NodeMapping[ArgNodes[i]].getNode()) if (FI.PoolDescriptors.count(LocalNode)) ArgVal = FI.PoolDescriptors.find(LocalNode)->second; } Args.push_back(ArgVal); } // Add the rest of the arguments unless we're a thread creation point, in which case we only need the pools if(!thread_creation_point) Args.insert(Args.end(), CS.arg_begin(), CS.arg_end()); // // There are circumstances where a function is casted to another type and // then called (que horible). We need to perform a similar cast if the // type doesn't match the number of arguments. // if (Function * NewFunction = dyn_cast<Function>(NewCallee)) { FunctionType * NewCalleeType = NewFunction->getFunctionType(); if (NewCalleeType->getNumParams() != Args.size()) { std::vector<Type *> Types; Type * FuncTy = FunctionType::get (NewCalleeType->getReturnType(), Types, true); FuncTy = PointerType::getUnqual (FuncTy); NewCallee = new BitCastInst (NewCallee, FuncTy, "", TheCall); } } std::string Name = TheCall->getName(); TheCall->setName(""); if(thread_creation_point) { Module *M = CS.getInstruction()->getParent()->getParent()->getParent(); Value* pthread_replacement = M->getFunction("poolalloc_pthread_create"); std::vector<Value*> thread_args; //Push back original thread arguments through the callee thread_args.push_back(CS.getArgument(0)); thread_args.push_back(CS.getArgument(1)); thread_args.push_back(CS.getArgument(2)); //Push back the integer argument saying how many uses there are thread_args.push_back(Constant::getIntegerValue(llvm::Type::getInt32Ty(M->getContext()),APInt(32,Args.size()))); thread_args.insert(thread_args.end(),Args.begin(),Args.end()); thread_args.push_back(CS.getArgument(3)); //Make the thread creation call NewCall = CallInst::Create(pthread_replacement, thread_args, Name,TheCall); } else if (InvokeInst *II = dyn_cast<InvokeInst>(TheCall)) { NewCall = InvokeInst::Create (NewCallee, II->getNormalDest(), II->getUnwindDest(), Args, Name, TheCall); } else { NewCall = CallInst::Create (NewCallee, Args, Name, TheCall); } // Add all of the uses of the pool descriptor for (unsigned i = 0, e = ArgNodes.size(); i != e; ++i) AddPoolUse(*NewCall, Args[i], PoolUses); TheCall->replaceAllUsesWith(NewCall); DEBUG(errs() << " Result Call: " << *NewCall << "\n"); if (!TheCall->getType()->isVoidTy()) { // If we are modifying the original function, update the DSGraph... DSGraph::ScalarMapTy &SM = G->getScalarMap(); DSGraph::ScalarMapTy::iterator CII = SM.find(TheCall); if (CII != SM.end()) { SM[NewCall] = CII->second; SM.erase(CII); // Destroy the CallInst } else if (!FI.NewToOldValueMap.empty()) { // Otherwise, if this is a clone, update the NewToOldValueMap with the new // CI return value. UpdateNewToOldValueMap(TheCall, NewCall); } } else if (!FI.NewToOldValueMap.empty()) { UpdateNewToOldValueMap(TheCall, NewCall); } // // Copy over the calling convention and attributes of the original call // instruction to the new call instruction. // CallSite(NewCall).setCallingConv(CallSite(TheCall).getCallingConv()); TheCall->eraseFromParent(); visitInstruction(*NewCall); }
AliasAnalysis::AliasResult DSAAA::alias(const AliasAnalysis::Location& l1, const AliasAnalysis::Location& l2) { DSAAA_TOTAL_ANSWER++; if (l1.Size == 0 || l2.Size == 0) return NoAlias; /// ? Zhiyuan: weired, l1 & l2's locations are both instructions, in my opinion, they should be operands const Value* v1 = (l1.Ptr)->stripPointerCasts(); const Value* v2 = (l2.Ptr)->stripPointerCasts(); if (!v1->getType()->isPointerTy() || !v2->getType()->isPointerTy()) return NoAlias; if (v1 == v2) return MustAlias; DSGraph *G1 = getGraphForValue(v1); DSGraph *G2 = getGraphForValue(v2); assert((!G1 || !G2 || G1 == G2) && "Alias query for 2 different functions?"); const Function *func = nullptr; /// Zhiyuan: Debug if (const Instruction *I = dyn_cast<Instruction>(v1)) { func = I->getParent()->getParent(); } else if (const Argument *A = dyn_cast<Argument>(v1)) { func = A->getParent(); } else if (const BasicBlock *BB = dyn_cast<BasicBlock>(v1)) { func = BB->getParent(); } if (func != nullptr) { //errs() << "[DSAAA Debug] We are in function [" << func->getName() << "].\n"; DEBUG_QueryFunctionSet.insert(func->getName().str()); } DSAAA_TOTAL_QUERY_FUNCTIONS = DEBUG_QueryFunctionSet.size(); // Get the graph to use... DSGraph* G = G1 ? G1 : (G2 ? G2 : TD->getGlobalsGraph()); const DSGraph::ScalarMapTy &GSM = G->getScalarMap(); DSGraph::ScalarMapTy::const_iterator I = GSM.find((Value*)v1); if (I == GSM.end()) return NoAlias; DSGraph::ScalarMapTy::const_iterator J = GSM.find((Value*)v2); if (J == GSM.end()) return NoAlias; DSNode *N1 = I->second.getNode(), *N2 = J->second.getNode(); unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset(); if (N1 == nullptr || N2 == nullptr) { // Can't tell whether anything aliases null. errs() << "[DSAAA DEBUG] nullptr for this value. \n"; return AliasAnalysis::alias(l1, l2); } if (!N1->isCompleteNode() && !N2->isCompleteNode()) { // if (llvm::DebugFlag) { // errs() << "We calculate MayAlias here.\n"; // errs() << "v1 = " << *(l1.Ptr) << "; v2 = " << *(l2.Ptr) << "\n"; // errs() << "N1 = " << N1 << "; N2 = " << N2 << "\n"; // errs() << "N1 complete? " << N1->isCompleteNode() << "; N2 complete? " << N2->isCompleteNode() << "\n"; // } if (N1 == N2) { DSAAA_INCOMPLETE_SAME_NODE++; } DSAAA_INCOMPLETE_NODE++; DEBUG_IncompleteNodeSet.insert(N1); DSAAA_INCOMPLETE_NODE_COUNT = DEBUG_IncompleteNodeSet.size(); if ( llvm::DebugFlag && func != nullptr && func->getName().str() == "BZ2_decompress") { errs() << "[DSAAA DEBUG] # of referrers: " << N1->getNumReferrers() << "\n"; // errs() << "[DSAAA DEBUG] # of links: " << N1->getLinkCount() << "\n"; N1->print(errs(), G); const DSScalarMap &SM = G->getScalarMap(); int refCount = 1; for (DSScalarMap::const_iterator i = SM.begin(); i != SM.end(); i++) { if (i->second.getNode() == N1 && refCount < 240) { errs() << refCount++ <<": " << *(i->first) << "\n"; } } //exit(0); } return AliasAnalysis::alias(l1, l2); } // We can only make a judgment if one of the nodes is complete. if (N1->isCompleteNode() || N2->isCompleteNode()) { if (N1 != N2) return NoAlias; // Completely different nodes. // See if they point to different offsets... if so, we may be able to // determine that they do not alias... if (O1 != O2) { uint64_t V1Size = l1.Size; uint64_t V2Size = l2.Size; if (O2 < O1) { // Ensure that O1 <= O2 std::swap(v1, v2); std::swap(O1, O2); std::swap(V1Size, V2Size); } if (O1+V1Size <= O2) return NoAlias; } } /** * Below added by Zhiyuan */ // if (N1 == N2 && N1->isCompleteNode() && N2->isCompleteNode()) return MustAlias; // if (llvm::DebugFlag) { // errs() << "We need to consult other alias analysis for better results.\n"; // errs() << "v1 = " << *(l1.Ptr) << "; v2 = " << *(l2.Ptr) << "\n"; // errs() << "N1 = " << N1 << "; N2 = " << N2 << "\n"; // errs() << "N1 complete? " << N1->isCompleteNode() << "; N2 complete? " << N2->isCompleteNode() << "\n"; // } /** * Above added by Zhiyuan */ DSAAA_CANNOT_ANSWER++; // FIXME: we could improve on this by checking the globals graph for aliased // global queries... return AliasAnalysis::alias(l1, l2); }
void CallTargetFinder<dsa>::findIndTargets(Module &M) { dsa* T = &getAnalysis<dsa>(); const DSCallGraph & callgraph = T->getCallGraph(); DSGraph* G = T->getGlobalsGraph(); DSGraph::ScalarMapTy& SM = G->getScalarMap(); for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration()) for (Function::iterator F = I->begin(), FE = I->end(); F != FE; ++F) for (BasicBlock::iterator B = F->begin(), BE = F->end(); B != BE; ++B) if (isa<CallInst>(B) || isa<InvokeInst>(B)) { CallSite cs(B); AllSites.push_back(cs); Function* CF = cs.getCalledFunction(); if (isa<UndefValue>(cs.getCalledValue())) continue; if (isa<InlineAsm>(cs.getCalledValue())) continue; // // If the called function is casted from one function type to // another, peer into the cast instruction and pull out the actual // function being called. // if (!CF) CF = dyn_cast<Function>(cs.getCalledValue()->stripPointerCasts()); if (!CF) { Value * calledValue = cs.getCalledValue()->stripPointerCasts(); if (isa<ConstantPointerNull>(calledValue)) { ++DirCall; CompleteSites.insert(cs); } else { IndCall++; DSCallGraph::callee_iterator csi = callgraph.callee_begin(cs), cse = callgraph.callee_end(cs); while(csi != cse) { const Function *F = *csi; DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F), sccee = callgraph.scc_end(F); for(;sccii != sccee; ++sccii) { DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); if (I != SM.end()) { IndMap[cs].push_back (*sccii); } } ++csi; } const Function *F1 = (cs).getInstruction()->getParent()->getParent(); F1 = callgraph.sccLeader(&*F1); DSCallGraph::scc_iterator sccii = callgraph.scc_begin(F1), sccee = callgraph.scc_end(F1); for(;sccii != sccee; ++sccii) { DSGraph::ScalarMapTy::const_iterator I = SM.find(SM.getLeaderForGlobal(*sccii)); if (I != SM.end()) { IndMap[cs].push_back (*sccii); } } DSNode* N = T->getDSGraph(*cs.getCaller()) ->getNodeForValue(cs.getCalledValue()).getNode(); assert (N && "CallTarget: findIndTargets: No DSNode!"); if (!N->isIncompleteNode() && !N->isExternalNode() && IndMap[cs].size()) { CompleteSites.insert(cs); ++CompleteInd; } if (!N->isIncompleteNode() && !N->isExternalNode() && !IndMap[cs].size()) { ++CompleteEmpty; DEBUG(errs() << "Call site empty: '" << cs.getInstruction()->getName() << "' In '" << cs.getInstruction()->getParent()->getParent()->getName() << "'\n"); } } } else { ++DirCall; IndMap[cs].push_back(CF); CompleteSites.insert(cs); } } //Print the indirect call Map: for(std::map<CallSite, std::vector<const Function*> >::iterator indMapIt = IndMap.begin(); indMapIt != IndMap.end(); ++indMapIt ) { CallSite CS = indMapIt->first; Instruction* Inst = CS.getInstruction(); Inst->dump(); } }
/// 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; } } } }
// Precondition: Enforce that the alloca nodes haven't been already converted void ConvertUnsafeAllocas::TransformAllocasToMallocs(std::list<DSNode *> & unsafeAllocaNodes) { std::list<DSNode *>::const_iterator iCurrent = unsafeAllocaNodes.begin(), iEnd = unsafeAllocaNodes.end(); for (; iCurrent != iEnd; ++iCurrent) { DSNode *DSN = *iCurrent; // Now change the alloca instruction corresponding to the node // to malloc DSGraph *DSG = DSN->getParentGraph(); DSGraph::ScalarMapTy &SM = DSG->getScalarMap(); #ifndef LLVA_KERNEL Instruction *MI = 0; #else Value *MI = 0; #endif for (DSGraph::ScalarMapTy::iterator SMI = SM.begin(), SME = SM.end(); SMI != SME; ) { bool stackAllocate = true; // If this is already a heap node, then you cannot allocate this on the // stack if (DSN->isHeapNode()) { stackAllocate = false; } if (SMI->second.getNode() == DSN) { if (AllocaInst *AI = dyn_cast<AllocaInst>((Value *)(SMI->first))) { // // Create a new heap allocation instruction. // if (AI->getParent() != 0) { // // Create an LLVM value representing the size of the allocation. // If it's an array allocation, we'll need to insert a // multiplication instruction to get the size times the number of // elements. // unsigned long size = TD->getTypeAllocSize(AI->getAllocatedType()); Value *AllocSize = ConstantInt::get(Int32Type, size); if (AI->isArrayAllocation()) AllocSize = BinaryOperator::Create(Instruction::Mul, AllocSize, AI->getOperand(0), "sizetmp", AI); std::vector<Value *> args(1, AllocSize); CallInst *CI = CallInst::Create (kmalloc, args.begin(), args.end(), "", AI); MI = castTo (CI, AI->getType(), "", AI); DSN->setHeapMarker(); AI->replaceAllUsesWith(MI); SM.erase(SMI++); AI->getParent()->getInstList().erase(AI); ++ConvAllocas; InsertFreesAtEnd(MI); #ifndef LLVA_KERNEL if (stackAllocate) { ArrayMallocs.insert(MI); } #endif } else { ++SMI; } } else { ++SMI; } } else { ++SMI; } } } }