// // Method: getDSNodeHandle() // // Description: // This method looks up the DSNodeHandle for a given LLVM value. The context // of the value is the specified function, although if it is a global value, // the DSNodeHandle may exist within the global DSGraph. // // Return value: // A DSNodeHandle for the value is returned. This DSNodeHandle could either // be in the function's DSGraph or from the GlobalsGraph. Note that the // DSNodeHandle may represent a NULL DSNode. // DSNodeHandle CompleteChecks::getDSNodeHandle (const Value * V, const Function * F) { // // Get access to the points-to results. // EQTDDataStructures & dsaPass = getAnalysis<EQTDDataStructures>(); // // Ensure that the function has a DSGraph // assert (dsaPass.hasDSGraph(*F) && "No DSGraph for function!\n"); // // Lookup the DSNode for the value in the function's DSGraph. // DSGraph * TDG = dsaPass.getDSGraph(*F); DSNodeHandle DSH = TDG->getNodeForValue(V); // // If the value wasn't found in the function's DSGraph, then maybe we can // find the value in the globals graph. // if ((DSH.isNull()) && (isa<GlobalValue>(V))) { // // Try looking up this DSNode value in the globals graph. Note that // globals are put into equivalence classes; we may need to first find the // equivalence class to which our global belongs, find the global that // represents all globals in that equivalence class, and then look up the // DSNode Handle for *that* global. // DSGraph * GlobalsGraph = TDG->getGlobalsGraph (); DSH = GlobalsGraph->getNodeForValue(V); if (DSH.isNull()) { // // DSA does not currently handle global aliases. // if (!isa<GlobalAlias>(V)) { // // We have to dig into the globalEC of the DSGraph to find the DSNode. // const GlobalValue * GV = dyn_cast<GlobalValue>(V); const GlobalValue * Leader; Leader = GlobalsGraph->getGlobalECs().getLeaderValue(GV); DSH = GlobalsGraph->getNodeForValue(Leader); } } } return DSH; }
bool SteensgaardDataStructures::runOnModuleInternal(Module &M) { assert(ResultGraph == 0 && "Result graph already allocated!"); // Get a copy for the globals graph. DSGraph * GG = DS->getGlobalsGraph(); GlobalsGraph = new DSGraph(GG, GG->getGlobalECs(), 0, 0); // Create a new, empty, graph... ResultGraph = new DSGraph(GG->getGlobalECs(), getDataLayout(), GlobalsGraph); // Loop over the rest of the module, merging graphs for non-external functions // into this graph. // for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { if (!I->isDeclaration()) { ResultGraph->spliceFrom(DS->getDSGraph(I)); } } ResultGraph->removeTriviallyDeadNodes(); // FIXME: Must recalculate and use the Incomplete markers!! // Now that we have all of the graphs inlined, we can go about eliminating // call nodes... // // Start with a copy of the original call sites. std::list<DSCallSite> & Calls = ResultGraph->getFunctionCalls(); for (std::list<DSCallSite>::iterator CI = Calls.begin(), E = Calls.end(); CI != E;) { DSCallSite &CurCall = *CI++; // Loop over the called functions, eliminating as many as possible... std::vector<const Function*> CallTargets; if (CurCall.isDirectCall()) CallTargets.push_back(CurCall.getCalleeFunc()); else CurCall.getCalleeNode()->addFullFunctionList(CallTargets); for (unsigned c = 0; c != CallTargets.size(); ) { // If we can eliminate this function call, do so! const Function *F = CallTargets[c]; if (!F->isDeclaration()) { ResolveFunctionCall(F, CurCall, ResultGraph->getReturnNodes()[F]); CallTargets[c] = CallTargets.back(); CallTargets.pop_back(); } else ++c; // Cannot eliminate this call, skip over it... } if (CallTargets.empty()) { // Eliminated all calls? std::list<DSCallSite>::iterator I = CI; Calls.erase(--I); // Remove entry } } // Remove our knowledge of what the return values of the functions are, except // for functions that are externally visible from this module (e.g. main). We // keep these functions so that their arguments are marked incomplete. for (DSGraph::ReturnNodesTy::iterator I = ResultGraph->getReturnNodes().begin(), E = ResultGraph->getReturnNodes().end(); I != E; ) if (I->first->hasInternalLinkage()) ResultGraph->getReturnNodes().erase(I++); else ++I; // Update the "incomplete" markers on the nodes, ignoring unknownness due to // incoming arguments... ResultGraph->maskIncompleteMarkers(); ResultGraph->markIncompleteNodes(DSGraph::MarkFormalArgs | DSGraph::IgnoreGlobals); // Remove any nodes that are dead after all of the merging we have done... ResultGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals); GlobalsGraph->removeTriviallyDeadNodes(true); GlobalsGraph->maskIncompleteMarkers(); // Mark external globals incomplete. GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals); formGlobalECs(); // Clone the global nodes into this graph. ReachabilityCloner RC(ResultGraph, GlobalsGraph, DSGraph::DontCloneCallNodes | DSGraph::DontCloneAuxCallNodes); for (DSScalarMap::global_iterator I = GlobalsGraph->getScalarMap().global_begin(), E = GlobalsGraph->getScalarMap().global_end(); I != E; ++I) if (isa<GlobalVariable>(*I)) RC.getClonedNH(GlobalsGraph->getNodeForValue(*I)); print(DOUT, &M); return false; }
void RTAssociate::replaceCall(CallSite CS, FuncInfo& FI, DataStructures* DS) { const Function *CF = CS.getCalledFunction(); Instruction *TheCall = CS.getInstruction(); // 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 (ConstantExpr *CE = dyn_cast<ConstantExpr>(CS.getCalledValue())) if (CE->getOpcode() == Instruction::BitCast && isa<Function>(CE->getOperand(0))) CF = cast<Function>(CE->getOperand(0)); if (isa<InlineAsm>(TheCall->getOperand(0))) { errs() << "INLINE ASM: ignoring. Hoping that's safe.\n"; return; } // Ignore calls to NULL pointers. if (isa<ConstantPointerNull>(CS.getCalledValue())) { errs() << "WARNING: Ignoring call using NULL function pointer.\n"; return; } // 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. // 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); FuncInfo *CFI = getFuncInfo(CF); if (CFI == 0 || CFI->Clone == 0) // Nothing to transform... return; NewCallee = CFI->Clone; ArgNodes = CFI->ArgNodes; assert ((DS->hasDSGraph (*CF)) && "Function has no ECGraph!\n"); CalleeGraph = DS->getDSGraph(*CF); } else { DEBUG(errs() << " Handling indirect call: " << *TheCall); // 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>(FI.getOldValueIfAvailable(CS.getInstruction())); DSCallGraph::callee_iterator I = DS->getCallGraph().callee_begin(CS); if (I != DS->getCallGraph().callee_end(CS)) CF = *I; // 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 (!CF) { DSGraph* dg = DS->getDSGraph(*OrigInst->getParent()->getParent()); DSNode* d = dg->getNodeForValue(OrigInst->getOperand(0)).getNode(); assert (d && "No DSNode!\n"); std::vector<const Function*> g; d->addFullFunctionList(g); if (g.size()) { EquivalenceClasses< const GlobalValue *> & EC = dg->getGlobalECs(); for(std::vector<const Function*>::const_iterator ii = g.begin(), ee = g.end(); !CF && ii != ee; ++ii) { for (EquivalenceClasses<const GlobalValue *>::member_iterator MI = EC.findLeader(*ii); MI != EC.member_end(); ++MI) // Loop over members in this set. if ((CF = dyn_cast<Function>(*MI))) { break; } } } } // // Do an assert unless we're bugpointing something. // // if ((UsingBugpoint) && (!CF)) return; if (!CF) errs() << "No Graph for CallSite in " << TheCall->getParent()->getParent()->getName().str() << " originally " << OrigInst->getParent()->getParent()->getName().str() << "\n"; assert (CF && "No call graph info"); // Get the common graph for the set of functions this call may invoke. // if (UsingBugpoint && (!(Graphs.hasDSGraph(*CF)))) return; assert ((DS->hasDSGraph(*CF)) && "Function has no DSGraph!\n"); CalleeGraph = DS->getDSGraph(*CF); #ifndef NDEBUG // Verify that all potential callees at call site have the same DS graph. DSCallGraph::callee_iterator E = DS->getCallGraph().callee_end(CS); for (; I != E; ++I) if (!(*I)->isDeclaration()) assert(CalleeGraph == DS->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 = 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(), 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); } Function::const_arg_iterator FAI = CF->arg_begin(), E = CF->arg_end(); CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); for ( ; FAI != E && AI != AE; ++FAI, ++AI) if (!isa<Constant>(*AI)) DSGraph::computeNodeMapping(CalleeGraph->getNodeForValue(FAI), FI.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), FI.getDSNodeHFor(TheCall), NodeMapping, false); // Okay, now that we have established our mapping, we can figure out which // pool descriptors to pass in... std::vector<Value*> Args; for (unsigned i = 0, e = ArgNodes.size(); i != e; ++i) { Value *ArgVal = Constant::getNullValue(PoolDescPtrTy); if (NodeMapping.count(ArgNodes[i])) if (DSNode *LocalNode = NodeMapping[ArgNodes[i]].getNode()) if (FI.PoolDescriptors.count(LocalNode)) ArgVal = FI.PoolDescriptors.find(LocalNode)->second; if (isa<Constant > (ArgVal) && cast<Constant > (ArgVal)->isNullValue()) errs() << "WARNING: NULL POOL ARGUMENTS ARE PASSED IN!\n"; Args.push_back(ArgVal); } // Add the rest of the arguments... 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 (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); } TheCall->replaceAllUsesWith(NewCall); DEBUG(errs() << " Result Call: " << *NewCall); if (TheCall->getType()->getTypeID() != Type::VoidTyID) { // If we are modifying the original function, update the DSGraph... DSGraph::ScalarMapTy &SM = FI.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. FI.UpdateNewToOldValueMap(TheCall, NewCall); } } else if (!FI.NewToOldValueMap.empty()) { FI.UpdateNewToOldValueMap(TheCall, NewCall); } //FIXME: attributes on call? CallSite(NewCall).setCallingConv(CallSite(TheCall).getCallingConv()); TheCall->eraseFromParent(); }