FunctionList DSNodeEquivs::getCallees(CallSite &CS) { const Function *CalledFunc = CS.getCalledFunction(); // 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 *CExpr = dyn_cast<ConstantExpr>(CS.getCalledValue())) { if (CExpr->getOpcode() == Instruction::BitCast && isa<Function>(CExpr->getOperand(0))) CalledFunc = cast<Function>(CExpr->getOperand(0)); } FunctionList Callees; // Direct calls are simple. if (CalledFunc) { Callees.push_back(CalledFunc); return Callees; } // Okay, indirect call. // Ask the DSCallGraph what this calls... TDDataStructures &TDDS = getAnalysis<TDDataStructures>(); const DSCallGraph &DSCG = TDDS.getCallGraph(); DSCallGraph::callee_iterator CalleeIt = DSCG.callee_begin(CS); DSCallGraph::callee_iterator CalleeItEnd = DSCG.callee_end(CS); for (; CalleeIt != CalleeItEnd; ++CalleeIt) Callees.push_back(*CalleeIt); // If the callgraph doesn't give us what we want, query the DSGraph // ourselves. if (Callees.empty()) { Instruction *Inst = CS.getInstruction(); Function *Parent = Inst->getParent()->getParent(); Value *CalledValue = CS.getCalledValue(); DSNodeHandle &NH = TDDS.getDSGraph(*Parent)->getNodeForValue(CalledValue); if (!NH.isNull()) { DSNode *Node = NH.getNode(); Node->addFullFunctionList(Callees); } } // For debugging, dump out the callsites we are unable to get callees for. DEBUG( if (Callees.empty()) { errs() << "Failed to get callees for callsite:\n"; CS.getInstruction()->dump(); });
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(); }