BUDataStructures遍只能处理可解析的函数调用,因此它不能处理递归的间接函数调用(比如函数指针调用)。CompleteBUDataStructures则是完整的BU处理遍,能够处理递归的间接函数调用。当然,CompleteBUDataStructures处理的数据是基于BUDataStructures处理的结果,即可解析函数调用已经被内联,函数调用的SCC也已经发现并记录。
45行的init将拷贝前面BUDataStructures遍所更新的全局图,并获取该遍生成的调用图(callgraph),及全局函数列表(GlobalFunctionList,由LocalDataStructures产生)。55行则拷贝每个函数图(因为init中的clone参数是true)。
43 bool
44 CompleteBUDataStructures::runOnModule (Module &M) {
45 init(&getAnalysis<BUDataStructures>(), true, true,false, true);
46
47
48 //
49 // Make sure wehave a DSGraph for all declared functions in the Module.
50 // formGlobalECsassumes that DSInfo is populated with a list of
51 // DSgraphs forall the functions.
52
53 for(Module::iterator F = M.begin(); F != M.end(); ++F) {
54 if (!(F->isDeclaration())){
55 getOrCreateGraph(F);
56 }
57 }
58
59 buildIndirectFunctionSets();
59行的buildIndirectFunctionSets确保对于每个间接调用点,所有目标函数都关联到同一个DSNode。Callgraph中的ActualCallees记录了调用点与被调用函数一对多的映射关系,它本身是一个容器,下面109行的循环迭代保存在这个容器中的调用点(CallSite,每个记录的首项)。112~149行是调试用代码,它确保每个被间接调用的函数都能通过全局图访问。
在这里有一个前提条件,即直接调用的函数不会出现在全局图的ScalarMap中。这是基于下列事实:首先,在当前程序中定义是函数在一开始是要加入全局图的ScalarMap(参考LocalDataStructure的runOnModule)。但在BU遍中,这些函数中在当前程序被调用到的,都内联到了全局构造函数或main中,这些函数都会从全局图的ScalarMap中删除;另一方面,如果部分函数没有在当前程序中调用,对于当前函数,它们是不可到达的,不会有调用记录。而对于外部函数定义,当前程序的全局图的ScalarMap里是不会有它们的记录。而在处理CallSite对象时,间接调用函数需要为被调用函数在ScalarMap中创建一个记录,直接调用函数不需要(参考GraphBuilder::visitCallSite)。
98 void
99 CompleteBUDataStructures::buildIndirectFunctionSets (void) {
100 //
101 // Loop over allof the indirect calls in the program. Ifa call site can
102 // call multipledifferent functions, we need to unify all of the callees into
103 // the sameequivalence class.
104 //
105 DSGraph* G = getGlobalsGraph();
106 DSGraph::ScalarMapTy& SM =G->getScalarMap();
107
108 // Merge nodes inthe global graph for these functions
109 for(DSCallGraph::callee_key_iterator ii = callgraph.key_begin(),
110 ee = callgraph.key_end(); ii != ee;++ii) {
111
112 #ifndef NDEBUG
113 // --Verifythat for every callee of an indirect function call
114 // we have an entry in the GlobalsGraph
115
116 // If anyfunction in an SCC is a callee of an indirect function
117 // call, theDScallgraph contains the leader of the SCC as the
118 // callee ofthe indirect call.
119 // The leasderof the SCC may not have an entry in the Globals
120 // Graph, butat least one of the functions in the SCC
121 // should havean entry in the GlobalsGraph
122
123 Value *CalledValue =(*ii).getCalledValue()->stripPointerCasts();
124
125 bool isIndirect =(!isa<Function>(CalledValue));
126 if (isIndirect) {
127 DSCallGraph::callee_iterator csii =callgraph.callee_begin(*ii),
128 csee =callgraph.callee_end(*ii);
129
130 for (;csii != csee; ++csii) {
131 //
132 //Declarations don't have to have entries. Functions may be
133 // equivalence classed already, so we have to check theirequivalence
134 // classleader instead of the global itself.
135 //
136 constFunction * F = *csii;
137 if (!(F->isDeclaration())){
138 DSCallGraph::scc_iterator sccii =callgraph.scc_begin(F),
139 sccee =callgraph.scc_end(F);
140 bool flag = false;
141 for(;sccii != sccee; ++sccii) {
142 flag |=SM.count(SM.getLeaderForGlobal(*sccii));
143 }
144 assert(flag &&
145 "Indirect functioncallee not in globals?");
146 }
147 }
148 }
149 #endif
150
151 //
152 // Note: Thecode above and below is dealing with the fact that the targets
153 // of *direct*function calls do not show up in the Scalar Map of the
154 // globalsgraph. The above assertion simplyverifies that all targets of
155 // indirectfunction calls show up in the Scalar Map of the globals graph,
156 // and then thecode below can just check the scalar map to see if the
157 // call needsto be processed because it is an indirect function call.
158 //
159 // I suspectthat this code is designed this way more for historical
160 // reasons thanfor simplicity. We should simplify thecode is possible at
161 // a futuredate.
162 //
163 // FIXME: Giventhe above is a valid assertion, we could probably replace
164 // this codewith something that *assumes* we have entries in the Scalar
165 // Map. However, because
166 // I'm notconvinced that we can just *skip* direct calls in this function
167 // this code iscareful to handle callees not existing in the globals graph
168 // In otherwords what we have here should be correct, but might be overkill
169 // that we cantrim down later as needed.
170
171 DSNodeHandle calleesNH;
172
173 // When webuild SCCs we remove any calls that are to functions in the
174 // same SCC.Hence, for every indirect call site we must assume that it
175 // might callfunctions in its function's SCC that are address taken.
176 constFunction *F1 = (*ii).getInstruction()->getParent()->getParent();
177 F1 = callgraph.sccLeader(&*F1);
178
179 DSCallGraph::scc_iterator sccii =callgraph.scc_begin(F1),
180 sccee =callgraph.scc_end(F1);
181 for(;sccii!= sccee; ++sccii) {
182 DSGraph::ScalarMapTy::const_iterator I =SM.find(SM.getLeaderForGlobal(*sccii));
183 if (I != SM.end()) {
184 calleesNH.mergeWith(I->second);
185 }
186 }
187
188 DSCallGraph::callee_iterator csi =callgraph.callee_begin(*ii),
189 cse = callgraph.callee_end(*ii);
190
191
192 // We get allthe callees, and then for all functions in that SCC, find the
193 // ones thathave entries in the GlobalsGraph.
194
195 // We merge allthe functions in the SCC that have entries, and then move
196 // on to thenext callee and repeat.
197
198 // If an SCChas functions that have entries in the GlobalsGraph, and are
199 // targets ofan indirect function call site, they will be merged.
200
201 // However, ifan SCC has functions, that have entries in the GlobalsGraph,
202 // bur are notthe targets of an indirect function call site, they will not
203 // be merged byCBU.
204
205 // This NHstarts off empty, but ends up merging them all together
206
207 while(csi!= cse) {
208 constFunction *F = *csi;
209 DSCallGraph::scc_iterator sccii =callgraph.scc_begin(F),
210 sccee =callgraph.scc_end(F);
211 for(;sccii!= sccee; ++sccii) {
212 DSGraph::ScalarMapTy::const_iterator I= SM.find(SM.getLeaderForGlobal(*sccii));
213 if (I != SM.end()) {
214 calleesNH.mergeWith(I->second);
215 }
216 }
217 ++csi;
218 }
219 }
220 }
在前面的处理中,callgraph中处于同一个调用SCC中的函数被构建为一个同类集,对于这个指定的调用点,176行返回该调用点所在的函数,而177行则返回在callgraph同类集中代表它的Leader。181行遍历这个同类集,而182行的getLeaderForGlobal则返回这些对象在另一个同类集中的Leader(这个同类集是DSNode节点简并的结果,及由同一个DSNode所代表的全局对象,或者更确切地说,访问相同内存的全局对象)。因为这个Leader是由ScalarMap返回的,如果存在,它是被间接调用的函数。那么181行循环的作用就是简并调用链SCC中被间接调用的函数,而这些函数本身可能又间接调用了别的函数。
188行的callee_begin与key_begin相类,但返回被调用函数集合(ActualCallees元素的第二项)的首迭代器。207行遍历这个被调用函数集合。对每个被调用函数,在211行遍历其在callgraph中的同类集成员(构成调用链SCC),同样212行的getLeaderForGlobal返回代表其内存地址的这些间接调用函数的Leader。因此,在214行,如果调用它的函数是被间接调用的,那么这些间接调用的函数也会与调用它们的被间接调用的函数简并在一起。
CompleteBUDataStructures::runOnModule(续)
60 formGlobalECs();
61 for(Module::iterator F = M.begin(); F != M.end(); ++F) {
62 if (!(F->isDeclaration())) {
63 if (DSGraph * Graph =getOrCreateGraph(F)) {
64 cloneIntoGlobals(Graph,DSGraph::DontCloneCallNodes |
65 DSGraph::DontCloneAuxCallNodes |
66 DSGraph::StripAllocaBit);
67 }
68 }
69 }
70
71 for(Module::iterator F = M.begin(); F != M.end(); ++F) {
72 if (!(F->isDeclaration())) {
73 if(DSGraph * Graph = getOrCreateGraph(F)) {
74 cloneGlobalsInto(Graph,DSGraph::DontCloneCallNodes |
75 DSGraph::DontCloneAuxCallNodes);
76 }
77 }
78 }
79
80 //
81 // Do bottom-uppropagation.
82 //
83 bool modified = runOnModuleInternal(M);
84
85 callgraph.buildSCCs();
86 callgraph.buildRoots();
87
88 returnmodified;
89 }
CompleteBUDataStructures::runOnModule之后的操作与BUDataStrutcures基本一样。在简并了未解析的间接函数调用的基础上,重现查找调用函数SCC,内联新发现的可解析的调用函数。