1.3.8.2.1.2.1. 非递归或直接递归情形
首先考虑只有一个节点的SCC。注意,这意味着没有出现函数递归(这时,在调用链中的函数按从底至上的次序得到处理),或者出现直接函数递归(自己调用自己)。
BUDataStructures::calculateGraphs(续)
432 //
433 // If this is anew SCC, process it now.
434 //
435 if (Stack.back() == F) { //Special case the single "SCC" case here.
436 DEBUG(errs() << "Visiting singlenode SCC #: " << MyID << " fn: "
437 << F->getName()<< "\n");
438 Stack.pop_back();
439 DEBUG(errs() << " [BU] Calculating graph for: " <<F->getName()<< "\n");
440 DSGraph* G = getOrCreateGraph(F);
441 calculateGraph(G);
442 DEBUG(errs() << " [BU] Done inlining: " <<F->getName() << " ["
443 <<G->getGraphSize() << "+" <<G->getAuxFunctionCalls().size()
444 << "]\n");
445
446 if (MaxSCC < 1) MaxSCC = 1;
447
448 //
449 // Should werevisit the graph? Only do it if thereare now new resolvable
450 // callees.
451 FuncSet NewCallees;
452 getAllAuxCallees(G,NewCallees);
453 if (!NewCallees.empty()) {
454 if (hasNewCallees(NewCallees,CalleeFunctions)) {
455 DEBUG(errs() <<"Recalculating " << F->getName() << " due to newknowledge\n");
456 ValMap.erase(F);
457 ++NumRecalculations;
458 return calculateGraphs(F, Stack, NextID,ValMap);
459 }
460 ++NumRecalculationsSkipped;
461 }
462 ValMap[F] = ~0U;
463 returnMyID;
calculateGraph内联callgraph(DataStructures的成员,程序的调用图)所使用的图,删除处理后的调用点。627行的GlobalFunctionList在buildCallGraph中完全没有用到,相反buildCallGraph从Graph中查找可解析的函数调用,并记录在callgraph中。
625 void BUDataStructures::calculateGraph(DSGraph*Graph) {
626 DEBUG(Graph->AssertGraphOK();Graph->getGlobalsGraph()->AssertGraphOK());
627 Graph->buildCallGraph(callgraph,GlobalFunctionList, filterCallees);
628
629 // Move our callsite list into TempFCs so that inline call sites go into the
630 // new call sitelist and doesn't invalidate our iterators!
631 DSGraph::FunctionListTy TempFCs;
632 DSGraph::FunctionListTy &AuxCallsList =Graph->getAuxFunctionCalls();
633 TempFCs.swap(AuxCallsList);
634
635 for(DSGraph::FunctionListTy::iteratorI = TempFCs.begin(), E = TempFCs.end();
636 I != E; ++I) {
637 DEBUG(Graph->AssertGraphOK();Graph->getGlobalsGraph()->AssertGraphOK());
638
639 DSCallSite &CS = *I;
640
641 // Fast pathfor noop calls. Note that we don't careabout merging globals
642 // in thecallee with nodes in the caller here.
643 if (!CS.isIndirectCall() &&CS.getRetVal().isNull()
644 && CS.getNumPtrArgs() == 0&& !CS.isVarArg()) {
645 continue;
646 }
647
648 // If thiscallsite is unresolvable, get rid of it now.
649 if (CS.isUnresolvable()){
650 continue;
651 }
652
653 // Find allcallees for this callsite, according to the DSGraph!
654 // Do *not* usethe callgraph, because we're updating that as we go!
655 FuncSet CalledFuncs;
656 getAllCallees(CS,CalledFuncs);
657
658 if (CalledFuncs.empty()) {
659 ++NumEmptyCalls;
660 if (CS.isIndirectCall())
661 ++NumIndUnresolved;
662 // Rememberthat we could not resolve this yet!
663 DSGraph::FunctionListTy::iterator S =I++;
664 AuxCallsList.splice(AuxCallsList.end(),TempFCs, S);
665 continue;
666 }
667 // If we get tothis point, we know the callees, and can inline.
668 // This means,that either it is a direct call site. Or if it is
669 // an indirectcall site, its calleeNode is complete, and we can
670 // resolve thisparticular call site.
671 assert((CS.isDirectCall()|| CS.getCalleeNode()->isCompleteNode())
672 && "Resolving an indirectincomplete call site");
673
674 if (CS.isIndirectCall()) {
675 ++NumIndResolved;
676 }
677
678 DSGraph *GI;
679
680 for (FuncSet::iteratorI = CalledFuncs.begin(), E = CalledFuncs.end();
681 I != E; ++I) {
682 constFunction *Callee = *I;
683 // Get thedata structure graph for the called function.
684
685 GI = getDSGraph(*Callee); // Graph to inline
686 DEBUG(GI->AssertGraphOK();GI->getGlobalsGraph()->AssertGraphOK());
687 DEBUG(errs() << " Inlining graph for " <<Callee->getName()
688 << "["<< GI->getGraphSize() << "+"
689 <<GI->getAuxFunctionCalls().size() << "] into '"
690 <<Graph->getFunctionNames() << "' [" <<Graph->getGraphSize() <<"+"
691 <<Graph->getAuxFunctionCalls().size() << "]\n");
692
693 //
694 // Merge inthe DSGraph of the called function.
695 //
696 // TODO:
697 // Why are thestrip alloca bit and don't clone call nodes bit set?
698 //
699 // I believe the answer is on page 6 of the PLDIpaper on DSA. The
700 // idea is that stack objects are invalid ifthey escape.
701 //
702 Graph->mergeInGraph(CS,*Callee, *GI,
703 DSGraph::StripAllocaBit|DSGraph::DontCloneCallNodes);
704 ++NumInlines;
705 DEBUG(Graph->AssertGraphOK(););
706 }
707 }
708 TempFCs.clear();
635行开始遍历该函数所调用的函数, 649行的isUnresolvable再次检查调用的函数是否可解析(实际上在buildCallGraph中已经检查过)。
1138 bool DSCallSite::isUnresolvable() const {
1139 // Direct callsare forever unresolvable if they are calls to declarations.
1140 if (isDirectCall())
1141 returngetCalleeFunc()->isDeclaration();
1142 // Indirect callsare forever unresolvable if the call node is marked
1143 // external.
1144 // (Nodes can'tbecome non-external through additional information)
1145 returngetCalleeNode()->isExternFuncNode();
1146 }
如果调用点是合格的,在656行获取所调用函数所调用的函数。如果这个列表是空,把这个函数加回AuxCallsList(664行),表示暂时还无法处理它。注意AuxCallsList在633行被清空了。否则的话,对这些被调用的函数,通过下面的函数把它的函数图与调用它的函数的图进行合并。
516 void DSGraph::mergeInGraph(constDSCallSite &CS, const Function &F,
517 const DSGraph &Graph, unsigned CloneFlags) {
518 // Set upargument bindings.
519 std::vector<DSNodeHandle> Args;
520 Graph.getFunctionArgumentsForCall(&F,Args);
521
522 mergeInGraph(CS,Args, Graph, CloneFlags);
523 }
DSGraph::getFunctionArgumentsForCall拷贝出被调用函数的返回值,可变参数值及指针类型参数。在局部分析遍中,因为在GraphBuilder构造函数的172行,为每个函数都调用了getOrCreateReturnNodeFor,如果函数没有返回值,下面将返回缺省的DSNodeHandle对象。类似的,在同一函数的176行,也为每个函数调用了getOrCreateVANodeFor,如果函数没有可变参数,下面将返回缺省的DSNodeHandle对象。
295 void DSGraph::getFunctionArgumentsForCall(const Function *F,
296 std::vector<DSNodeHandle> &Args) const{
297 Args.push_back(getReturnNodeFor(*F));
298 Args.push_back(getVANodeFor(*F));
299 for(Function::const_arg_iterator AI = F->arg_begin(), E = F->arg_end();
300 AI != E; ++AI)
301 if(isa<PointerType>(AI->getType())) {
302 Args.push_back(getNodeForValue(AI));
303 assert(!Args.back().isNull()&& "Pointer argument w/o scalarmap entry!?");
304 }
305 }
在前面调用mergeInGraph的地方(调用mergeInGraph的是调用者函数的图),传给参数Graph的值是被调用函数的图。因为DSGraph与函数是一一对应,或一多对应(在这里合并了调用者与被调用者后)的,因此如果428行条件满足,表明这是递归调用,那么只需要把代表返回值、可变参数及指针参数的DSNode简并来即可。
421 void DSGraph::mergeInGraph(constDSCallSite &CS,
422 std::vector<DSNodeHandle>&Args,
423 const DSGraph &Graph, unsigned CloneFlags) {
424 assert((CloneFlags& DontCloneCallNodes) &&
425 "Doesn't support copying of callnodes!");
426
427 // If this is nota recursive call, clone the graph into this graph...
428 if (&Graph == this) {
429 // Merge thereturn value with the return value of the context.
430 Args[0].mergeWith(CS.getRetVal());
431
432 // Mergevar-arg node
433 Args[1].mergeWith(CS.getVAVal());
434
435 // Resolve allof the function arguments.
436 for(unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) {
437 if (i == Args.size()-2)
438 break;
439
440 // Add thelink from the argument scalar to the provided value.
441 Args[i+2].mergeWith(CS.getPtrArg(i));
442 }
443 return;
444 }
445
446 // Clone thecallee's graph into the current graph, keeping track of where
447 // scalars in theold graph _used_ to point, and of the new nodes matching
448 // nodes of theold graph.
449 ReachabilityCloner RC(this, &Graph,CloneFlags);
450
451 // Map the returnnode pointer over.
452 if (!CS.getRetVal().isNull())
453 RC.merge(CS.getRetVal(),Args[0]);
454
455 // Map thevariable arguments
456 if (!CS.getVAVal().isNull())
457 RC.merge(CS.getVAVal(),Args[1]);
458
459 // Map over allof the arguments.
460 for (unsignedi = 0, e = CS.getNumPtrArgs(); i != e; ++i) {
461 if (i == Args.size()-2)
462 break;
463
464 // Add the linkfrom the argument scalar to the provided value.
465 RC.merge(CS.getPtrArg(i),Args[i+2]);
466 }
467
468 // We generallydon't want to copy global nodes or aux calls from the callee
469 // graph to thecaller graph. However, we have to copythem if there is a
470 // path from thenode to a node we have already copied which does not go
471 // throughanother global. Compute the set of nodethat can reach globals and
472 // aux call nodesto copy over, then do it.
473 std::vector<constDSCallSite*> AuxCallToCopy;
474 std::vector<constGlobalValue*> GlobalsToCopy;
475
476 //NodesReachCopiedNodes - Memoize results for efficiency. Contains a
477 // true/falsevalue for every visited node that reaches a copied node without
478 // going througha global.
479 HackedGraphSCCFinder SCCFinder(RC);
480
481 if (!(CloneFlags &DontCloneAuxCallNodes))
482 for(afc_const_iterator I = Graph.afc_begin(), E = Graph.afc_end(); I!=E; ++I)
483 if (!I->isUnresolvable() && SCCFinder.PathExistsToClonedNode(*I))
484 AuxCallToCopy.push_back(&*I);
485
486 // Copy aux callsthat are needed.
487 // Copy thesebefore calculating the globals to be copied, as there might be
488 // globals thatreach the nodes cloned due to aux calls.
489 for (unsignedi = 0, e = AuxCallToCopy.size(); i != e; ++i)
490 AuxFunctionCalls.push_back(DSCallSite(*AuxCallToCopy[i], RC));
491
492 const DSScalarMap&GSM = Graph.getScalarMap();
493 for(DSScalarMap::global_iterator GI = GSM.global_begin(),
494 E = GSM.global_end(); GI != E; ++GI) {
495 DSNode *GlobalNode = Graph.getNodeForValue(*GI).getNode();
496 for(DSNode::edge_iterator EI = GlobalNode->edge_begin(),
497 EE = GlobalNode->edge_end(); EI!= EE; ++EI)
498 if (SCCFinder.PathExistsToClonedNode(EI->second.getNode())){
499 GlobalsToCopy.push_back(*GI);
500 break;
501 }
502 }
503
504 // Copy globalsthat are needed.
505 for (unsignedi = 0, e = GlobalsToCopy.size(); i != e; ++i)
506 RC.getClonedNH(Graph.getNodeForValue(GlobalsToCopy[i]));
507 }
反之,则需要ReachabilityCloner帮助把被调用者代表返回值、可变参数及指针参数的DSNode节点克隆到调用者图并进行简并。另外,被调用者函数图中的全局节点与调用点也是要考虑的对象。考虑的准则是:如果存在一条路径从考察节点到达一个已经拷贝的节点,且该路径不通过另一个全局对象(因为如果在到达另一个全局对象前遇不到拷贝的节点,这个全局对象与调用者图其实是无关的),那么我们需要拷贝这个节点。否则,这个考察节点与当前的调用者图是不相关的,无需拷贝。是否存在这条路径通过下面的函数进行判断。
327 bool PathExistsToClonedNode(const DSNode *N) {
328 return VisitForSCCs(N).second;
329 }
HackedGraphSCCFinder的成员NodeInfo具有类型std::map<constDSNode*, std::pair< unsigned, bool> >,在HackedGraphSCCFinder的构造函数中它被初始化成NodeInfo[0]= std::make_pair(0, false)。在VisitForSCCs定义349行的lower_bound返回指向该容器中第一个不小于N的迭代器,如果这个元素就是N本身,那么我们已经找到一个SCC,并且N就是SCC的头节点。
否则,递增353行的CurNodeId(它在构造函数中初始化为1),并把N及std::pair<MyId, false>(注意这个false)保存在lower_bound返回的迭代器指向的位置。在发现SCC之前,首先要判断这个节点是否已经克隆,如果是,那么我们已经找到这条路径了;而如果这个节点代表一个全局对象,那么这条路径不是我们想要的。如果两者都不是,那么使用与前面寻找SCC类似的算法沿着DSNode的边进行深度优先探索。
346 std::pair<unsigned, bool>&HackedGraphSCCFinder::
347 VisitForSCCs(const DSNode *N) {
348 std::map<constDSNode*, std::pair<unsigned, bool> >::iterator
349 NodeInfoIt = NodeInfo.lower_bound(N);
350 if (NodeInfoIt != NodeInfo.end() &&NodeInfoIt->first == N)
351 returnNodeInfoIt->second;
352
353 unsigned Min = CurNodeId++;
354 unsigned MyId = Min;
355 std::pair<unsigned, bool>&ThisNodeInfo =
356 NodeInfo.insert(NodeInfoIt,
357 std::make_pair(N,std::make_pair(MyId, false)))->second;
358
359
360 // Base case: ifthis does reach the cloned graph portion... it does. :)
361 if (RC.hasClonedNode(N)) {
362 ThisNodeInfo.second = true;
363 returnThisNodeInfo;
364 }
365 // Base case: ifwe find a global, this doesn't reach the cloned graph
366 // portion.
367 if (N->isGlobalNode()) {
368 ThisNodeInfo.second = false;
369 returnThisNodeInfo;
370 }
371
372 SCCStack.push_back(N);
373
374 // Otherwise,check all successors.
375 bool AnyDirectSuccessorsReachClonedNodes =false;
376 for(DSNode::const_edge_iterator EI = N->edge_begin(), EE = N->edge_end();
377 EI != EE; ++EI)
378 if (DSNode * Succ =EI->second.getNode()) {
379 std::pair<unsigned, bool>&SuccInfo = VisitForSCCs(Succ);
380 if (SuccInfo.first < Min) Min =SuccInfo.first;
381 AnyDirectSuccessorsReachClonedNodes |=SuccInfo.second;
382 }
383
384 if (Min != MyId)
385 returnThisNodeInfo; //Part of a large SCC. Leave self onstack.
386
387 if (SCCStack.back() == N) { // Special casesingle node SCC.
388 SCCStack.pop_back();
389 ThisNodeInfo.second =AnyDirectSuccessorsReachClonedNodes;
390 returnThisNodeInfo;
391 }
392
393 // Find out ifany direct successors of any node reach cloned nodes.
394 if (!AnyDirectSuccessorsReachClonedNodes)
395 for(unsigned i = SCCStack.size() - 1; SCCStack[i] != N; --i)
396 for(DSNode::const_edge_iterator EI = N->edge_begin(), EE = N->edge_end();
397 EI != EE; ++EI)
398 if (DSNode * N =EI->second.getNode())
399 if (NodeInfo[N].second) {
400 AnyDirectSuccessorsReachClonedNodes= true;
401 gotoOutOfLoop;
402 }
403 OutOfLoop:
404 // If anysuccessor reaches a cloned node, mark all nodes in this SCC as
405 // reaching thecloned node.
406 if (AnyDirectSuccessorsReachClonedNodes)
407 while(SCCStack.back() != N) {
408 NodeInfo[SCCStack.back()].second = true;
409 SCCStack.pop_back();
410 }
411 SCCStack.pop_back();
412 ThisNodeInfo.second =AnyDirectSuccessorsReachClonedNodes;
413 returnThisNodeInfo;
414 }
在找到SCC并返回到SCC的首节点时,我们回到顶层VisitForSCCs调用的387行。对于多个节点组成的SCC,如果组成节点都不是克隆节点(394行条件),那么检查这些节点的直接后继者是否是克隆节点(因为是深度优先算法,在回到SCC首节点时,SCC组成节点的后继者(不仅只是直接后继者,但是否到达的信息已经汇总到直接后继者)必定已经处理了,NodeInfo中一定有记录),如果有的话,整个SCC的节点都要克隆。
需要克隆的全局对象都会保存在GlobalsToCopy中(mergeInGraph的499行),并通过RC进行克隆、简并(mergeInGraph的506行)。
BUDataStructures::calculateGraph(续)
710 // Recompute theIncomplete markers
711 Graph->maskIncompleteMarkers();
712 Graph->markIncompleteNodes(DSGraph::MarkFormalArgs);
713 Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal);
714 Graph->computeIntPtrFlags();
715
716 //
717 // Update thecallgraph with the new information that we have gleaned.
718 // NOTE : Thismust be called before removeDeadNodes, so that no
719 // information islost due to deletion of DSCallNodes.
720 Graph->buildCallGraph(callgraph,GlobalFunctionList, filterCallees);
721
722 // Delete deadnodes. Treat globals that areunreachable but that can
723 // reach livenodes as live.
724 Graph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
725
726 cloneIntoGlobals(Graph,DSGraph::DontCloneCallNodes |
727 DSGraph::DontCloneAuxCallNodes|
728 DSGraph::StripAllocaBit);
729 //Graph->writeGraphToFile(cerr,"bu_" + F.getName());
730 }
接下来,在711行,把函数图所有节点的未完成标记去掉,然后仅把函数的指针参数、返回值、可变参数及未解析的调用函数标记为未完成。然后计算外部标记以及整数与指针转换标记。并在720行再次计算调用图(因为内联了被调用函数图),接着删除死节点,最后把全局节点信息克隆回全局图。
1.3.8.2.1.2.2. 间接递归情形
回到BUDataStructures::calculateGraphs,多个节点的SCC由下面的代码来处理。这意味着出现了间接递归的函数调用。
BUDataStructures::calculateGraphs(续)
464 } else {
465 unsigned SCCSize = 1;
466 constFunction *NF = Stack.back();
467 if(NF!= F)
468 ValMap[NF] = ~0U;
469 DSGraph* SCCGraph = getDSGraph(*NF);
470
471 //
472 // First thingfirst: collapse all of the DSGraphs into a single graph for
473 // the entireSCC. Splice all of the graphs into oneand discard all of
474 // the oldgraphs.
475 //
476 while (NF!= F) {
477 Stack.pop_back();
478 NF = Stack.back();
479 if(NF != F)
480 ValMap[NF] = ~0U;
481
482 DSGraph* NFG = getDSGraph(*NF);
483
484 if (NFG != SCCGraph) {
485 // Updatethe Function -> DSG map.
486 for(DSGraph::retnodes_iterator I = NFG->retnodes_begin(),
487 E = NFG->retnodes_end(); I !=E; ++I)
488 setDSGraph(*I->first, SCCGraph);
489
490 SCCGraph->spliceFrom(NFG);
491 deleteNFG;
492 ++SCCSize;
493 }
494 }
495 Stack.pop_back();
对于这些DSNode节点,用SCC首节点的DSGraph来替换它们的DSGraph,与此同时通过下面的DSGraph::spliceFrom方法将这些DSGraph的内容合并入首节点的DSGraph。
267 void DSGraph::spliceFrom(DSGraph* RHS) {
268 assert(this!= RHS && "Splicing self");
269 // Change all ofthe nodes in RHS to think we are their parent.
270 for(NodeListTy::iterator I = RHS->Nodes.begin(), E = RHS->Nodes.end();
271 I != E; ++I)
272 I->setParentGraph(this);
273 // Take all of thenodes.
274 splice(Nodes, RHS->Nodes);
275
276 // Take all of thecalls.
277 splice(FunctionCalls, RHS->FunctionCalls);
278 splice(AuxFunctionCalls,RHS->AuxFunctionCalls);
279
280 // Take all of thereturn nodes.
281 splice(ReturnNodes, RHS->ReturnNodes);
282
283 // Same for the VAnodes
284 splice(VANodes, RHS->VANodes);
285
286 // Merge the scalarmap in.
287 ScalarMap. spliceFrom(RHS->ScalarMap);
288 }
其中的splice方法,比如splice(Nodes, RHS->Nodes),是将RHS->Nodes的内容追加入Nodes中。287行的DSScalarMap::spliceFrom则有如下定义:
114 void DSScalarMap::spliceFrom(DSScalarMap &RHS){
115 // Special case ifthis is empty.
116 if (ValueMap.empty()) {
117 ValueMap.swap(RHS.ValueMap);
118 GlobalSet.swap(RHS.GlobalSet);
119 } else {
120 GlobalSet.insert(RHS.GlobalSet.begin(),RHS.GlobalSet.end());
121 for(ValueMapTy::iterator I = RHS.ValueMap.begin(), E = RHS.ValueMap.end();
122 I != E; ++I)
123 ValueMap[I->first].mergeWith(I->second);
124 RHS.ValueMap.clear();
125 }
126 }
在123行调用ValueMap的[]操作符是非常量版本的,因此会插入新的元素,mergeWith对新元素会维持原来DSNode与DSNodeHandle的绑定,对两边都存在的元素则进行DSNode的简并。这样,多个节点的SCC最终会产生一张大的,涵盖了这些节点的DSGraph。下面的SCCGraph就是这个DSGraph。
BUDataStructures::calculateGraphs(续)
497 DEBUG(errs() << "Calculatinggraph for SCC #: " << MyID << " of size: "
498 << SCCSize <<"\n");
499
500 // Compute theMax SCC Size.
501 if (MaxSCC < SCCSize)
502 MaxSCC = SCCSize;
503
504 // Clean up thegraph before we start inlining a bunch again...
505 SCCGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
506
507 // Now that wehave one big happy family, resolve all of the call sites in
508 // the graph...
509 calculateGraph(SCCGraph);
510 DEBUG(errs() << " [BU] Done inlining SCC [" << SCCGraph->getGraphSize()
511 << "+"<< SCCGraph->getAuxFunctionCalls().size() << "]\n"
512 << "DONE withSCC #: " << MyID << "\n");
513 FuncSet NewCallees;
514 getAllAuxCallees(SCCGraph,NewCallees);
515 if (!NewCallees.empty()) {
516 if (hasNewCallees(NewCallees,CalleeFunctions)) {
517 DEBUG(errs() <<"Recalculating SCC Graph " << F->getName() << "due to new knowledge\n");
518 ValMap.erase(F);
519 ++NumRecalculations;
520 return calculateGraphs(F, Stack, NextID,ValMap);
521 }
522 ++NumRecalculationsSkipped;
523 }
524 ValMap[F] = ~0U;
525 returnMyID;
526 }
527 }
505行删除死节点,但保留不可到达的全局节点。然后对这张大图所调用的函数进行内联。内联后继续查找是否引入新的调用函数,如果是就继续递归调用calcuateGraphs,这个过程直到没有引入新的调用函数为止。
BUDataStructures::postOrderInline(续)
264 GlobalsGraph->removeTriviallyDeadNodes();
265 GlobalsGraph->maskIncompleteMarkers();
266
267 // Markexternal globals incomplete.
268 GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals);
269 GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal);
270 GlobalsGraph->computeIntPtrFlags();
271
272 //
273 // Createequivalence classes for aliasing globals so that we only need to
274 // record oneglobal per DSNode.
275 //
276 formGlobalECs();
277 // propogteinformation calculated
278 // from theglobals graph to the other graphs.
279 for(Module::iterator F = M.begin(); F != M.end(); ++F) {
280 if (!(F->isDeclaration())){
281 DSGraph *Graph = getDSGraph(*F);
282 cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes|
283 DSGraph::DontCloneAuxCallNodes);
284 Graph->buildCallGraph(callgraph,GlobalFunctionList, filterCallees);
285 Graph->maskIncompleteMarkers();
286 Graph->markIncompleteNodes(DSGraph::MarkFormalArgs|
287 DSGraph::IgnoreGlobals);
288 Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal);
289 Graph->computeIntPtrFlags();
290 }
291 }
292 }
293 }
在完成了全局构造函数与其调用函数的DSGraph内联后,首先是对全局对象未完成标记的计算。在265行把全局图中节点的未完成标记去掉,而在268行不对全局对象节点进行未完成标记,这样全局对象节点就是完整的。接着重新计算全局对象同类集。然后把全局对象信息导入函数图,并在callgraph中收集它们调用的函数等等。最后,在285行将该函数图的节点的未完成标记去掉,接着把该函数的指针参数、返回值、可变参数标记为未完成,但忽略全局对象。这样的处理对在简并节点时得到正确的NodeType信息十分重要。
毫无疑问,在全局构造函数之后要处理的是main函数。
BUDataStructures::postOrderInline(续)
295 //
296 // Start the postorder traversal with the main() function. If there is no
297 // main()function, don't worry; we'll have a separate traversal for inlining
298 // graphs forfunctions not reachable from main().
299 //
300 Function *MainFunc = M.getFunction("main");
301 if (MainFunc &&!MainFunc->isDeclaration()) {
302 calculateGraphs(MainFunc,Stack, NextID, ValMap);
303 CloneAuxIntoGlobal(getDSGraph(*MainFunc));
304 }
因为我们已经进行了调用者与被调用者的内联,原来的调用点(DSCallSite,仍然保存在AuxFunctionCalls中)成为孤立的节点,由removeIdenticalCalls从AuxFunctionCalls中删除(由removeTriviallyDeadNodes以及removeDeadNodes调用)。因此,如果指定函数图中的AuxFunctionCalls不是空的话,说明这些调用点没能完全内联。那么需要把这些调用点克隆进全局图,因为全局图可能有额外的信息可用。
539 void BUDataStructures::CloneAuxIntoGlobal(DSGraph*G) {
540 //
541 // If thisDSGraph has no unresolved call sites, do nothing. We do enough
542 // work thatwastes time even when the list is empty that this extra check
543 // is probablyworth it.
544 //
545 if (G->afc_begin() == G->afc_end())
546 return;
547
548 DSGraph* GG = G->getGlobalsGraph();
549 ReachabilityCloner RC(GG, G, 0);
550
551 //
552 // Determinewhich called values are both within the local graph DSCallsites
553 // and the globalgraph DSCallsites. Note that we requirethat the global
554 // graph have aDSNode for the called value.
555 //
556 std::map<Value *, DSCallSite *>CommonCallValues;
557 for(DSGraph::afc_iterator ii = G->afc_begin(), ee = G->afc_end();
558 ii != ee;
559 ++ii) {
560 //
561 // If theglobals graph has a DSNode for the LLVM value used in the local
562 // unresolvedcall site, then it might have a DSCallSite for it, too.
563 // Record thiscall site as a potential call site that will need to be
564 // merged.
565 //
566 // Otherwise,just add the call site to the globals graph.
567 //
568 Value * V =ii->getCallSite().getCalledValue();
569 if (GG->hasNodeForValue(V)) {
570 DSCallSite & DS = *ii;
571 CommonCallValues[V] = &DS;
572 } else {
573 GG->addAuxFunctionCall(RC.cloneCallSite(*ii));
574 }
575 }
576
577 //
578 // Scan throughall the unresolved call sites in the globals graph and see if
579 // the localgraph has a call using the same LLVM value. If so, merge the
580 // call sites.
581 //
582 DSGraph::afc_iterator GGii =GG->afc_begin();
583 for (; GGii!= GG->afc_end(); ++GGii) {
584 //
585 // Determine ifthis unresolved call site is also in the local graph.
586 // If so, thenmerge it.
587 //
588 Value * CalledValue =GGii->getCallSite().getCalledValue();
589 std::map<Value *, DSCallSite*>::iterator v;
590 v = CommonCallValues.find (CalledValue);
591 if (v != CommonCallValues.end()) {
592 //
593 // Merge theunresolved call site into the globals graph.
594 //
595 RC.cloneCallSite(*(v->second)).mergeWith(*GGii);
596
597 //
598 // Mark thatthis call site was merged by removing the called LLVM value
599 // from theset of values common to both the local and global DSGraphs.
600 //
601 CommonCallValues.erase (v);
602 }
603 }
604
605 //
606 // We've nowmerged all DSCallSites that were known both to the local graph
607 // and theglobals graph. Now, there are still somelocal call sites that
608 // need to be*added* to the globals graph; they are in DSCallSites remaining
609 // inCommonCallValues.
610 //
611 std::map<Value *, DSCallSite*>::iterator v = CommonCallValues.begin ();
612 for (; v !=CommonCallValues.end(); ++v) {
613 GG->addAuxFunctionCall(RC.cloneCallSite(*(v->second)));
614 }
615
616 return;
617 }
569行的hasNodeForValue只是检查指定的Value是否在全局图的ScalarMap中出现,如果是的话把Value及相关的DSCallSite记录在CommonCallValues。在583行遍历全局图的调用点,如果某一调用点也出现在CommonCallValues中,通过下面的函数克隆这个调用点。
1064 DSCallSite ReachabilityCloner::cloneCallSite(const DSCallSite& SrcCS) {
1065 std::vector<DSNodeHandle> Args;
1066 for(unsignedx = 0; x < SrcCS.getNumPtrArgs(); ++x)
1067 Args.push_back(getClonedNH(SrcCS.getPtrArg(x)));
1068 if (SrcCS.isDirectCall())
1069 returnDSCallSite(SrcCS.getCallSite(),
1070 getClonedNH(SrcCS.getRetVal()),
1071 getClonedNH(SrcCS.getVAVal()),
1072 SrcCS.getCalleeFunc(),
1073 Args);
1074 else {
1075 DSNodeHandle Ret = getClonedNH(SrcCS.getRetVal()),
1076 VA =getClonedNH(SrcCS.getVAVal()),
1077 Callee =getClonedNH(SrcCS.getCalleeNode());
1078 // Resolveforwarding now as much as possible.
1079 Ret.getNode(); VA.getNode();
1080 // Mostimportantly, ensure the node passed to DSCallSite
1081 // is not aforwarding node:
1082 DSNode * CalleeN = Callee.getNode();
1083 returnDSCallSite(SrcCS.getCallSite(), Ret, VA, CalleeN, Args);
1084 }
1085 }
然后克隆后的DSCallSite与全局图的DSCallSite进行简并。在611行CommonCallValues如果不是空,这些都是全局图没有的调用点,加入全局图。
在main函数之后就是普通的函数,注意这些函数是从main函数不可到达的!它们与main函数有基本相同的处理步骤,除了需要在321~330行标记该图已经被处理(不过,就像注释中提到的,calculateGraphs应该做了这个工作,这里只是抓漏网之鱼)。
BUDataStructures::postOrderInline(续)
306 //
307 // Calculate thegraphs for any functions that are unreachable from main...
308 //
309 for(Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
310 if (!I->isDeclaration() &&!ValMap.count(I)) {
311 if (MainFunc)
312 DEBUG(errs() << debugname<< ": Function unreachable from main: "
313 << I->getName() <<"\n");
314 calculateGraphs(I, Stack, NextID,ValMap); //Calculate all graphs.
315 CloneAuxIntoGlobal(getDSGraph(*I));
316
317 // Mark thisgraph as processed. Do this by findingall functions
318 // in thegraph that map to it, and mark them visited.
319 // Note thatthis really should be handled neatly by calculateGraphs
320 // itself,not here. However this catches the worstoffenders.
321 DSGraph *G = getDSGraph(*I);
322 for(DSGraph::retnodes_iteratorRI = G->retnodes_begin(),
323 RE = G->retnodes_end(); RI != RE;++RI) {
324 if (getDSGraph(*RI->first) == G) {
325 if (!ValMap.count(RI->first))
326 ValMap[RI->first] = ~0U;
327 else
328 assert(ValMap[RI->first]== ~0U);
329 }
330 }
331 }
332 return;
333 }
至此,postOrderInline的任务完成了——以贪婪的方式把程序中的调用者与被调用者的函数图内联了起来。