dsa算法(27完)

1.3.11. TDDataStructures与EQTDDataStructures遍

自顶向下阶段非常类似于自底向上阶段。BU阶段已经识别了调用图,因此TD阶段可以使用Tarjan的算法直接遍历调用图的SCC。它不需要像BU阶段那样“重新访问”SCC。注意到在BU阶段可能仅部分访问某些SCC,因此TD阶段负责简并这些图。

总体来说,TD阶段仅在4方面与BU阶段不同:首先,TD阶段不会把一个SCC标记为未访问:它使用由BU阶段发现并记录的调用边。其次,TD阶段以逆后序,而不是后序,访问由BU遍历得到的调用图的SCC。第三,TD遍把每个函数图内联入其调用的函数(而不是相反),并且它是直接把一个调用者的图内联入其所有的潜在的被调用者(不需要“延迟”这个内联操作,因为每个调用点的潜在被调用者是已知的)。最后的差别是,如果一个函数的所有调用者已经被分析识别出来,就把形参节点标记为完整。比如,任何外部函数不能访问的函数。类似的,全局变量可能被标记为完整,除非它们可以被外部函数访问。一个函数或全局对象是外部可见的,如果它没有内部链接性(比如,没有标记为static的C对象),或者在main的图中,该全局对象存在一个没有标记为完整的节点。

1.3.11.1. 确定外部可访问的函数

TDDataStructures作为独立的遍运行时,77行的useEQBU被设置为false,这时它只依赖于BUDataStructures的结果。但当运行EQTDDataStructures遍时,useEQBU被设置为true,则TDDataStructures依赖于EquivBUDataStructures的结果。注意在对init的调用中,倒数第2个参数是true(copyGlobalAuxCalls),在拷贝DSGraph时,还将拷贝AuxFunctionCalls的内容(它现在保存了还未解析的函数调用)。

 

75      bool TDDataStructures::runOnModule(Module&M) {

76     

77        init(useEQBU? &getAnalysis<EquivBUDataStructures>()

78             : &getAnalysis<BUDataStructures>(),

79             true, true, true, false);

80        // Figure outwhich functions must not mark their arguments complete because

81        // they areaccessible outside this compilation unit. Currently, these

82        // arguments arefunctions which are reachable by incomplete or external

83        // nodes in theglobals graph.

84        constDSScalarMap &GGSM = GlobalsGraph->getScalarMap();

85        DenseSet<DSNode*> Visited;

86        for(DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end();

87             I != E; ++I) {

88          DSNode *N =GGSM.find(*I)->second.getNode();

89          if (N->isIncompleteNode() ||N->isExternalNode())

90            markReachableFunctionsExternallyAccessible(N,Visited);

91        }

92     

93        // Loop overunresolved call nodes.  Any functionspassed into (but not

94        // returned!) fromunresolvable call nodes may be invoked outside of the

95        // currentmodule.

96        for(DSGraph::afc_iterator I = GlobalsGraph->afc_begin(),

97               E = GlobalsGraph->afc_end(); I !=E; ++I)

98          for(unsigned arg = 0, e = I->getNumPtrArgs(); arg != e; ++arg)

99            markReachableFunctionsExternallyAccessible(I->getPtrArg(arg).getNode(),

100                                                    Visited);

101      Visited.clear();

 

DSGraph中的ScalarMap保存了该函数所援引的对象,而其中的GlobalSet只保存全局对象,而ValMap则保存所有对象(实际上是Value与DSNodeHandle的对)。上面86行的循环就是遍历全局图的GlobalSet,88行的find则返回DSNodeHandle指向的ValMap中的DSNode——对象在函数图里的节点。如果这个节点是不完整或是外部的,则调用下面的函数。而96行的循环则是遍历AuxFunctionCalls,并对每个指针参数调用同样的函数。

 

51      void TDDataStructures::markReachableFunctionsExternallyAccessible(DSNode*N,

52                                                        DenseSet<DSNode*> &Visited) {

53        if (!N || Visited.count(N)) return;

54        Visited.insert(N);

55     

56        // Handle thisnode

57        {

58         N->addFullFunctionSet(ExternallyCallable);

59        }

60     

61        for(DSNode::edge_iterator ii = N->edge_begin(),

62                ee = N->edge_end(); ii != ee;++ii)

63          if (!ii->second.isNull()) {

64            DSNodeHandle &NH = ii->second;

65            DSNode * NN = NH.getNode();

66            NN->addFullFunctionSet(ExternallyCallable);

67            markReachableFunctionsExternallyAccessible(NN,Visited);

68          }

69      }

 

这里ExternallyCallable记录的是外部可调用函数。在DSA的设计中,从不完整或外部节点可访问的函数都被视为外部可访问的。另外,作为参数传递给未解析的函数的函数也可能是外部可访问的。除此之外,定义在当前编译单元中的函数,如果不是定义为内部或私有,也是外部可访问的。

 

TDDataStructures::runOnModule(续)

 

103      // Clear Aux ofGlobals Graph to be refilled in later by post-TD unresolved

104      // functions

105     GlobalsGraph->getAuxFunctionCalls().clear();

106   

107      // Functionswithout internal linkage are definitely externally callable!

108      for(Module::iterator I = M.begin(), E = M.end(); I != E; ++I)

109        if (!I->isDeclaration() &&!I->hasInternalLinkage() && !I->hasPrivateLinkage())

110          ExternallyCallable.insert(I);

111   

112      // Debug code toprint the functions that are externally callable

113    #if 0

114      for (Module::iterator I = M.begin(), E =M.end(); I != E; ++I)

115        if (ExternallyCallable.count(I)) {

116          errs() << "ExternallyCallable:" << I->getNameStr() << "\n";

117        }

118    #endif

1.3.11.2. 确定调用函数的后序遍历序

接下来,ComputePostOrder计算指定函数中函数调用的后序遍历次序,以这个次序在PostOrder中保存函数的DSGraph。

 

TDDataStructures::runOnModule(续)

 

120      // We want totraverse the call graph in reverse post-order. To do this, we

121      // calculate apost-order traversal, then reverse it.

122      DenseSet<DSGraph*> VisitedGraph;

123      std::vector<DSGraph*> PostOrder;

124   

125    {TIME_REGION(XXX, "td:Computepostorder");

126   

127      // Calculatetop-down from main...

128      if (Function *F =M.getFunction("main"))

129        ComputePostOrder(*F,VisitedGraph, PostOrder);

130   

131      // Next calculatethe graphs for each unreachable function...

132      for(Module::iterator I = M.begin(), E = M.end(); I != E; ++I)

133        if (!I->isDeclaration())

134          ComputePostOrder(*I,VisitedGraph, PostOrder);

135   

136      VisitedGraph.clear();   // Releasememory!

137    }

 

ComputePostOrder对函数的处理次序依然是先main,后其他函数。同样对于直接调用函数,直接进行递归。

 

187    void TDDataStructures::ComputePostOrder(const Function &F,

188                                           DenseSet<DSGraph*> &Visited,

189                                           std::vector<DSGraph*> &PostOrder) {

190      if (F.isDeclaration()) return;

191      DSGraph* G = getOrCreateGraph(&F);

192      if (!Visited.insert(G).second) return;

193   

194      // Recursivelytraverse all of the callee graphs.

195      svset<constFunction*> Callees;

196   

197      // Go through allof the callsites in this graph and find all callees

198      // Here we'retrying to capture all possible callees so that we can ensure

199      // each functionhas all possible callers inlined into it.

200      for(DSGraph::fc_iterator CI = G->fc_begin(), E = G->fc_end();

201           CI != E; ++CI) {

202        // Direct callsare easy, no reason to look at DSCallGraph

203        // or anythingto do with SCC's

204        if (CI->isDirectCall()) {

205          ComputePostOrder(*CI->getCalleeFunc(),Visited, PostOrder);

206        }

207        else {

208          // Otherwise,ask the DSCallGraph for the full set of possible

209          // calleesfor this callsite.

210          // Thisincludes all members of the SCC's of those callees,

211          // and wellas others in F's SCC, since we must assume

212          // anyindirect call might be intra-SCC.

213          callgraph.addFullFunctionSet(CI->getCallSite(),Callees);

214        }

215      }

216   

217      for(svset<const Function*>::iterator I =Callees.begin(),

218           E = Callees.end(); I != E; ++I)

219        ComputePostOrder(**I, Visited, PostOrder);

220   

221      PostOrder.push_back(G);

222    }

 

对于间接调用的函数,通过addFullFunctionSet收集候选函数。下面265行遍历callgraph的ActualCallees容器中与指定CallSite关联的函数(Function)。对于某一特定的函数,如果它属于某个调用链SCC,把这个SCC的所有成员加入Set(如果它不属于某个SCC,267行的scc_begin会返回与scc_end相同的迭代器)。对于该CallSite所在的函数(270行的F1),同样向Set加入其所在SCC的成员,如果存在这样的SCC。因为我们假定间接调用都可能是SCC的任何部分。

 

261    void DSCallGraph::addFullFunctionSet(llvm::CallSiteCS,

262                        svset<const llvm::Function*> &Set) const {

263      DSCallGraph::callee_iterator csi =callee_begin(CS),

264                                   cse = callee_end(CS);

265      while(csi !=cse) {

266        constFunction *F = *csi;

267        Set.insert(scc_begin(F), scc_end(F));

268        ++csi;

269      }

270      constFunction *F1 = CS.getInstruction()->getParent()->getParent();

271      F1 = sccLeader(&*F1);

272      Set.insert(scc_begin(F1), scc_end(F1));

273    }

 

接着在TDDataStructures::ComputePostOrder的217行对这些收集到的间接被调用函数进行递归。221行就是后序遍历的标志。

1.3.11.3. 向被调用者内联调用者

现在在PostOrder中,调用链最底层的被调用函数出现在容器头部,最顶层的则出现在容器的底部,因此143行对InlineCallersIntoGraph的调用从最顶层的(被)调用函数开始。这样对调用图的访问就是逆后序的。

 

TDDataStructures::runOnModule(续)

 

139    {TIME_REGION(XXX,"td:Inline stuff");

140   

141      // Visit each ofthe graphs in reverse post-order now!

142      while(!PostOrder.empty()) {

143        InlineCallersIntoGraph(PostOrder.back());

144        PostOrder.pop_back();

145      }

146    }

 

这个函数用到一个新的数据类型:CallerCallEdge。336~338行的注释已经解释了这个结构的作用。

 

335      struct CallerCallEdge {

336        DSGraph *CallerGraph;        // Thegraph of the caller function.

337        constDSCallSite *CS;        // The actual call site.

338        constFunction *CalledFunction;    // The actual function being called.

339   

340        CallerCallEdge(DSGraph *G, const DSCallSite *cs, constFunction *CF)

341          : CallerGraph(G), CS(cs),CalledFunction(CF) {}

342   

343        bool operator<(const CallerCallEdge &RHS) const {

344          returnCallerGraph < RHS.CallerGraph ||

345                (CallerGraph == RHS.CallerGraph&& CS < RHS.CS);

346        }

347      };

 

下面231行的CallerEdges的定义是std::map<DSGraph*, std::vector<CallerCallEdge> >,它是TDDataStructures的成员。DSG如果在CallerEdges中有记录,这个记录是它的调用者添加的(参考函数的后半段),230~235行取出这个记录。使用CallerCallEdge定义的比较操作符,238行的sort以调用者图的地址排序相关的CallerCallEdge项(这样同一个调用函数用产生的CallerCallEdge项会集合在一起,便于循环处理)。

 

226    void TDDataStructures::InlineCallersIntoGraph(DSGraph*DSG) {

227      // Inline callergraphs into this graph.  First step, getthe list of call

228      // sites thatcall into this graph.

229      std::vector<CallerCallEdge>EdgesFromCaller;

230      std::map<DSGraph*,std::vector<CallerCallEdge> >::iterator

231        CEI = CallerEdges.find(DSG);

232      if (CEI != CallerEdges.end()) {

233        std::swap(CEI->second, EdgesFromCaller);

234        CallerEdges.erase(CEI);

235      }

236   

237      // Sort thecaller sites to provide a by-caller-graph ordering.

238      std::sort(EdgesFromCaller.begin(),EdgesFromCaller.end());

239   

240   

241      // Mergeinformation from the globals graph into this graph.  FIXME: This is

242      // stupid.  Instead of us cloning information from the GGinto this graph,

243      // then havingRemoveDeadNodes clone it back, we should do all of this as a

244      // post-pass overall of the graphs.  We need to takecloning out of

245      //removeDeadNodes and gut removeDeadNodes at the same time first though. :(

246      cloneGlobalsInto(DSG,DSGraph::DontCloneCallNodes |

247                           DSGraph::DontCloneAuxCallNodes);

248   

249      DEBUG(errs() << "[TD] Inliningcallers into '"

250            << DSG->getFunctionNames()<< "'\n");

251   

252      DSG->maskIncompleteMarkers();

253      // Iterativelyinline caller graphs into this graph.

254      while(!EdgesFromCaller.empty()) {

255        DSGraph* CallerGraph =EdgesFromCaller.back().CallerGraph;

256   

257        // Iteratethrough all of the call sites of this graph, cloning and merging

258        // any nodesrequired by the call.

259        ReachabilityCloner RC(DSG, CallerGraph,

260                             DSGraph::DontCloneCallNodes |

261                             DSGraph::DontCloneAuxCallNodes);

262   

263        // Inline all callsites from this caller graph.

264        do {

265          constDSCallSite &CS = *EdgesFromCaller.back().CS;

266          constFunction &CF = *EdgesFromCaller.back().CalledFunction;

267          DEBUG(errs() << "   [TD] Inlining graph into Fn '"

268                << CF.getName().str() << "'from ");

269          if(CallerGraph->getReturnNodes().empty()) {

270            DEBUG(errs() << "SYNTHESIZEDINDIRECT GRAPH");

271          } else {

272            DEBUG(errs() << "Fn '"<< CS.getCallSite().getInstruction()->

273                  getParent()->getParent()->getName().str()<< "'");

274          }

275          DEBUG(errs() << ": "<< CF.getFunctionType()->getNumParams()

276                << " args\n");

277   

278          // Get theformal argument and return nodes for the called function and

279          // merge themwith the cloned subgraph.

280          DSCallSite T1 =DSG->getCallSiteForArguments(CF);

281          RC.mergeCallSite(T1, CS);

282          ++NumTDInlines;

283   

284          EdgesFromCaller.pop_back();

285        } while(!EdgesFromCaller.empty() &&

286                 EdgesFromCaller.back().CallerGraph== CallerGraph);

287      }

 

252行清除所有节点的不完整标记。顶层调用函数不会进入230~235及254~287行。其他函数则根据CallerEdges的记录,把其调用者中调用点信息简并入自己的图。接着,297行的DSG是InlineCallersIntoGraph要处理的DSGraph,retnodes_begin返回ReturnNodes的首迭代器(ReturnNodes的类型是std::map<constFunction*, DSNodeHandle>,它记录函数的返回值。在BU遍中,在向调用者内联被调用者时,被调用者的返回值将被加入调用者的这个容器)。如果这个DSGraph所代表的函数(经过了内联,所代表的函数可以是多个)之一是外部可调用的,在300行isExternallyCallable被置为true。

 

TDDataStructures::InlineCallersIntoGraph(续)

         

291      // Next, now thatthis graph is finalized, we need to recompute the

292      // incompletenessmarkers for this graph and remove unreachable nodes.

293   

294      // If any of thefunctions is externally callable, treat everything in its

295      // SCC asexternally callable.

296      bool isExternallyCallable = false;

297      for(DSGraph::retnodes_iterator I = DSG->retnodes_begin(),

298             E = DSG->retnodes_end(); I != E;++I)

299        if (ExternallyCallable.count(I->first)){

300          isExternallyCallable = true;

301          break;

302        }

303   

304      // Recompute theIncomplete markers.  Depends on whetherargs are complete

305      unsigned IncFlags =DSGraph::IgnoreFormalArgs;

306      IncFlags |= DSGraph::IgnoreGlobals |DSGraph::MarkVAStart;

307      DSG->markIncompleteNodes(IncFlags);

308   

309      // If this graphcontains functions that are externally callable, now is the time to mark

310      // theirarguments and return values as external. At this point TD is inlining all caller information,

311      // and that meansExternal callers too.

312      unsigned ExtFlags = isExternallyCallable ?

313                          DSGraph::MarkFormalsExternal: DSGraph::DontMarkFormalsExternal;

314      DSG->computeExternalFlags(ExtFlags);

315      DSG->computeIntPtrFlags();

316   

317      cloneIntoGlobals(DSG,DSGraph::DontCloneCallNodes |

318                           DSGraph::DontCloneAuxCallNodes);

319      //

320      // Delete deadnodes.  Treat globals that areunreachable as dead also.

321      //

322      // FIXME:

323      //  Do not delete unreachable globals as thecomment describes.  For its

324      //  alignment checks on the results of loadinstructions, SAFECode must be

325      //  able to find the DSNode of both the result ofthe load as well as the

326      //  pointer dereferenced by the load.  If we remove unreachable globals, then

327      //  if the dereferenced pointer is a global, itsDSNode will not reachable

328      //  from the local graph's scalar map, and chaosensues.

329      //

330      //  So, for now, just remove dead nodes but leavethe globals alone.

331      //

332      DSG->removeDeadNodes(0);

 

因为在前面252行已经把所有节点的未完成标记去掉了,在307行重现计算这些节点的未完成标记。根据IncFlags内容,markIncompleteNodes只把AuxFunctionCalls容器内的节点、可变参数节点标记为不完整。而314行的computeExternalFlags,则根据函数是否外部可访问,把函数的指针参数、返回值、可变参数标记为外部。317行将函数图中的全局对象节点克隆、简并入全局图(此时全局图中的全局对象节点是标记为完成的)。332行的removeDeadNodes在前一版是有参数DSGraph::RemoveUnreachableGlobals的,当前版本把这个参数去掉,原因322行的注释解释了。

 

TDDataStructures::InlineCallersIntoGraph(续)

 

334      // We are donewith computing the current TD Graph! Finally, before we can

335      // finishprocessing this function, we figure out which functions it calls and

336      // records thesecall graph edges, so that we have them when we process the

337      // callee graphs.

338      if (DSG->fc_begin() == DSG->fc_end()) return;

339   

340      // Loop over allthe call sites and all the callees at each call site, and add

341      // edges to theCallerEdges structure for each callee.

342      for(DSGraph::fc_iterator CI = DSG->fc_begin(), E = DSG->fc_end();

343           CI != E; ++CI) {

344   

345        // Handle directcalls efficiently.

346        if (CI->isDirectCall()) {

347          if(!CI->getCalleeFunc()->isDeclaration() &&

348             !DSG->getReturnNodes().count(CI->getCalleeFunc()))

349           CallerEdges[getOrCreateGraph(CI->getCalleeFunc())]

350              .push_back(CallerCallEdge(DSG,&*CI, CI->getCalleeFunc()));

351          continue;

352        }

353   

354        svset<constFunction*> AllCallees;

355        std::vector<constFunction*> Callees;

356   

357        // Get the listof callees

358        callgraph.addFullFunctionSet(CI->getCallSite(),AllCallees);

359   

360        // Filter allnon-declarations, and calls within this DSGraph

361        for(svset<const Function*>::iterator I =AllCallees.begin(),

362            E = AllCallees.end(); I != E; ++I) {

363          constFunction *F = *I;

364          if (!F->isDeclaration() &&getDSGraph(**I) != DSG)

365            Callees.push_back(F);

366        }

367        AllCallees.clear();

368   

369        // If there isexactly one callee from this call site, remember the edge in

370        // CallerEdges.

371        if (Callees.size() == 1) {

372          constFunction * Callee = Callees[0];

373          CallerEdges[getOrCreateGraph(Callee)]

374              .push_back(CallerCallEdge(DSG,&*CI, Callee));

375        }

376        if (Callees.size() <= 1) continue;

377   

378        // Otherwise,there are multiple callees from this call site, so it must be

379        // an indirectcall.  Chances are that there will beother call sites with

380        // this set oftargets.  If so, we don't want to do M*Ninlining operations,

381        // so we buildup a new, private, graph that represents the calls of all

382        // calls tothis set of functions.

383   

384        std::map<std::vector<const Function*>, DSGraph*>::iteratorIndCallRecI =

385          IndCallMap.lower_bound(Callees);

386   

387        // If wealready have this graph, recycle it.

388        if (IndCallRecI != IndCallMap.end()&& IndCallRecI->first == Callees) {

389          DEBUG(errs() << "  [TD] *** Reuse of indcall graph for "<< Callees.size()

390                << " callees!\n");

391          DSGraph * IndCallGraph =IndCallRecI->second;

392          assert(IndCallGraph->getFunctionCalls().size()== 1);

393   

394          // Merge thecall into the CS already in the IndCallGraph

395          ReachabilityCloner RC(IndCallGraph, DSG,0);

396          RC.mergeCallSite(IndCallGraph->getFunctionCalls().front(),*CI);

 

DSGraph的fc_begin及fc_end返回容器FunctionCalls的首尾迭代器,FunctionCalls记录了在该函数中进行的函数调用。上面这段代码的目的是找出当前函数调用的函数,并使CallerEdges记录之。对于直接调用(346行条件),如果被调用的函数有定义,且不在当前函数图中,把它记录在CallerEdges里。对于间接调用,在358行首先获取所有可能的被调用函数,在364行过滤掉没有定义或者在当前函数图中调用的函数。如果被调用函数的个数只是1(371行),那么直接把它记录在CallerEdges里。而如果被调用函数的个数多于1个,而且如果这些被调用函数已经处理过了(比如,另一个调用这些函数的调用点,这样它们会被记录在IndCallMap中),那么已经存在一个内联后的图,在396行把这些函数调用简并入这个图(这样避免在InlineCallersIntoGraph开头的更耗时的内联操作)。注意392行断言检查IndCallMap的完整性是否被破坏。

 

1036  void ReachabilityCloner::mergeCallSite(DSCallSite&DestCS,

1037                                         const DSCallSite &SrcCS) {

1038    merge(DestCS.getRetVal(),SrcCS.getRetVal());

1039    merge(DestCS.getVAVal(),SrcCS.getVAVal());

1040    unsigned MinArgs = DestCS.getNumPtrArgs();

1041    if (SrcCS.getNumPtrArgs() < MinArgs)MinArgs = SrcCS.getNumPtrArgs();

1042 

1043    for (unsigneda = 0; a != MinArgs; ++a)

1044      merge(DestCS.getPtrArg(a),SrcCS.getPtrArg(a));

1045 

1046    for (unsigneda = MinArgs, e = SrcCS.getNumPtrArgs(); a != e; ++a) {

1047      // If a callsite passes more params, ignore the extra params.

1048      // If thecalled function is varargs, merge the extra params, with

1049      // the varargsnode.

1050      if(DestCS.getVAVal() != NULL) {

1051        merge(DestCS.getVAVal(),SrcCS.getPtrArg(a));

1052      }

1053    }

1054 

1055    for (unsigneda = MinArgs, e = DestCS.getNumPtrArgs(); a!=e; ++a) {

1056      // If a callsite passes less explicit params, than the function needs

1057      // But passesparams through a varargs node, merge those in.

1058      if(SrcCS.getVAVal() != NULL)  {

1059        merge(DestCS.getPtrArg(a),SrcCS.getVAVal());

1060      }

1061    }

1062  }

 

对于调用点来说,可以看到就是返回值、各种参数,因此简并意味着处理返回值、指针参数以及可变参数。

接下来处理个数多于1个且尚未处理的被调用函数。这种情况下,399行首先创建一个新的DSGraph实例,注意在这个实例中FunctionCalls是空的,而且不包含任何DSNode节点(因为它的目的就是携带CallSite对象)。407行向这个DSGraph加入唯一的一个DSCallSite对象,并在410行加入IndCallMap(这是前面392行断言的依据)。最后,针对每个被调用函数,在CallerEdges中记录下IndCallGraph(携带CallSite信息的图,即代表调用函数),对应的DSCallSite(似乎不需要),被调用函数(以被调用函数图为键值)。

 

TDDataStructures::InlineCallersIntoGraph(续)

 

397        } else {

398          // Otherwise,create a new DSGraph to represent this.

399          DSGraph* IndCallGraph = new DSGraph(DSG->getGlobalECs(),

400                                             DSG->getDataLayout(), *TypeSS);

401   

402          // Clone overthe call into the new DSGraph

403          ReachabilityCloner RC(IndCallGraph, DSG,0);

404          DSCallSite ClonedCS = RC.cloneCallSite(*CI);

405   

406          // Add thecloned CS to the graph, as if it were an original call.

407         IndCallGraph->getFunctionCalls().push_back(ClonedCS);

408   

409          // Save thisgraph for use later, should we need it.

410          IndCallRecI =IndCallMap.insert(IndCallRecI,

411                                         std::make_pair(Callees, IndCallGraph));

412   

413          //Additionally, make sure that each of the callees inlines this graph

414          // exactlyonce.

415          DSCallSite *NCS =&IndCallGraph->getFunctionCalls().front();

416          for(unsigned i = 0, e = Callees.size(); i != e; ++i) {

417            DSGraph* CalleeGraph = getDSGraph(*Callees[i]);

418            if (CalleeGraph != DSG)

419             CallerEdges[CalleeGraph].push_back(CallerCallEdge(IndCallGraph, NCS,

420                                                               Callees[i]));

421          }

422        }

423      }

424    }

 

在处理了所有的函数调用后,IndCallMap,ExternallyCallable的内容不再需要,回收其中的资源。接下来重现计算全局图的各种标记,注意这里不再重现计算完整性标记,因为全局图节点的完整性计算在BUDataStructure及CompleteDataStructure遍中就完成了。同样,函数图的完整性计算在InlineCallersIntoGraph中已经完成。最后,恢复调用图。

 

TDDataStructures::runOnModule(续)

 

148      // Free theIndCallMap.

149     while(!IndCallMap.empty()) {

150        deleteIndCallMap.begin()->second;

151        IndCallMap.erase(IndCallMap.begin());

152      }

153

154      formGlobalECs();

155   

156      ExternallyCallable.clear();

157      GlobalsGraph->removeTriviallyDeadNodes();

158      GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal);

159      GlobalsGraph->computeIntPtrFlags();

160   

161      // Make sure eachgraph has updated external information about globals

162      // in the globalsgraph.

163      VisitedGraph.clear();

164      for(Module::iterator F = M.begin(); F != M.end(); ++F) {

165        if (!(F->isDeclaration())){

166          DSGraph *Graph  = getOrCreateGraph(F);

167          if (!VisitedGraph.insert(Graph).second) continue;

168   

169          cloneGlobalsInto(Graph,DSGraph::DontCloneCallNodes |

170                           DSGraph::DontCloneAuxCallNodes);

171   

172          Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal);

173          Graph->computeIntPtrFlags();

174          // Clean upuninteresting nodes

175          Graph->removeDeadNodes(0);

176   

177        }

178      }

179   

180      // CBU containsthe correct call graph.

181      // Restore it, sothat subsequent passes and clients can get it.

182      restoreCorrectCallGraph();

183      return false;

184    }

 

至此,TDDataStructures及EQTDDataStructures遍的处理全部完成。从DSA分析的结果出发,Chris在论文中提到了其在别名分析及自动池分配(automatic pool allocation)的应用。Poolalloc对此也做了延伸及扩展。Poolalloc目前被应用到SafeCode项目中,它是这个项目的基础。

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