dsa算法(23)

1.3.8.2.1.2. 内联DSGraph

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信息十分重要。  

1.3.8.2.2.内联main及其他函数

毫无疑问,在全局构造函数之后要处理的是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的任务完成了——以贪婪的方式把程序中的调用者与被调用者的函数图内联了起来。

你可能感兴趣的:(算法,DSA,compiler,编译器,llvm)