EquivBUDataStructures是CompleteBUDataStructures的更进一步,它会为每个函数同类集产生一个简并的函数图,并以这个简并图作为同类集中每个函数的图。然后在此基础上,在前面CompleteDataStructure遍产生的调用链SCC上进行函数图内联。由此,函数图的个数,进而DSNode节点的个数将进一步减少。注意,这里的同类集不是调用链同类集,而是内存对象同类集(即由同一个DSNode代表)。
42 bool EquivBUDataStructures::runOnModule(Module&M) {
43 init(&getAnalysis<CompleteBUDataStructures>(),true, true, false, true);
44
45 //make a list ofall the DSGraphs
46 std::set<DSGraph *>graphList;
47 for(Module::iteratorF = M.begin(); F != M.end(); ++F)
48 {
49 if(!(F->isDeclaration()))
50 graphList.insert(getOrCreateGraph(F));
51 }
52
53 //update the EQclass from indirect calls
54 buildIndirectFunctionSets();
55 formGlobalECs();
56 mergeGraphsByGlobalECs();
EquivBUDataStructures前面的几步与CompleteBUDataStructures的前几步是一样的。不过这些操作是在CompleteBUDataStructures处理的结果上进行的。上面55行对最新的处理结果更新了同类集关系,56行的mergeGraphsByGlobalECs将函数同类集的图进行简并。
GlobalECs是一个同类集的容器,下面140及141行分别返回这个集合的首尾迭代器。142行的循环遍历这个集合,146行筛选掉不是Leader的成员。154行的member_iterator用于遍历某一个Leader所在的同类集(Leader总是这个同类集的首元素),155行就是遍历这个集合。这里的同类集由同一块内存所代表的对象组成,156行筛选出Function(函数)类型的对象。这里只处理函数的同类集。
对于某个同类集,176行的BaseGraph在一开始为0(147行处赋值),177、178行获取对应的DSGraph及指向返回值、可变参数、指针参数的DSNodeHandle节点。如果函数已经处理过,满足179行条件,我们需要简并这两次(甚至可能更多次)给出的参数,因为这两(几)次给出的参数的数目不一定相同,需要形如202~207行的处理。如果BaseGraph不是空,而指定函数尚未处理(214行条件),BaseGraph中的是同类集中的其他函数,那么218行通过cloneInto把函数图拷贝、简并入BaseGraph,接着简并参数。
131 void
132 EquivBUDataStructures::mergeGraphsByGlobalECs() {
133 //
134 // Merge thegraphs for each equivalence class. Wefirst scan all elements
135 // in theequivalence classes and look for those elements which are leaders.
136 // For eachleader, we scan through all of its members and merge the DSGraphs
137 // for memberswhich are functions.
138 //
139
140 EquivalenceClasses<const GlobalValue*>::iterator EQSI = GlobalECs.begin();
141 EquivalenceClasses<const GlobalValue*>::iterator EQSE = GlobalECs.end();
142 for (;EQSI !=EQSE; ++EQSI) {
143 //
144 // If thiselement is not a leader, then skip it.
145 //
146 if (!EQSI->isLeader()) continue;
147 DSGraph* BaseGraph = 0;
148 std::vector<DSNodeHandle> Args;
149
150 //
151 // Iteratethrough all members of this equivalence class, looking for
152 // functions.
153 //
154 EquivalenceClasses<const GlobalValue*>::member_iterator MI;
155 for (MI =GlobalECs.member_begin(EQSI); MI != GlobalECs.member_end(); ++MI){
156 if (constFunction* F = dyn_cast<Function>(*MI)) {
157 //
158 // If thefunction has no body, then it has no DSGraph.
159 //
160 // FIXME: Idon't believe this is correct; the stdlib pass can assign
161 // DSGraphs to C standard libraryfunctions.
162 //
163 if (F->isDeclaration())
164 continue;
165
166 //
167 // We haveone of three possibilities:
168 // 1) This is the first function we'veseen. If so, grab its DSGraph
169 // and the DSNodes for its arguments.
170 //
171 // 2) We have already seen this functionbefore. Do nothing.
172 //
173 // 3) We haven't seen this function before, andit's not the first one
174 // we've seen. Merge its DSGraph into the DSGraph we'recreating.
175 //
176 if (!BaseGraph) {
177 BaseGraph = getOrCreateGraph(F);
178 BaseGraph->getFunctionArgumentsForCall(F,Args);
179 } else if(BaseGraph->containsFunction(F)) {
180 //
181 // TheDSGraph for this function has already been merged into the
182 // graphthat we are creating. However, that doesnot mean that
183 //function arguments of this function have been merged with the
184 // functionarguments of the other functions in the equivalence graph
185 // (oreven with functions belonging to the same SCC in the call
186 //graph). Furthermore, it doesn'tnecessarily imply that the
187 //contained function's DSGraph is the same as the one we're
188 //building; it is possible (I think) for only the function's DSNodes
189 // andother information to have been merged in.
190 //
191 // Forthese reasons, we will merge the function argument DSNodes and
192 // setthis function's DSGraph to be the same graph used for all
193 // otherfunction's in this equivalence class.
194 //
195
196 //
197 // Mergethe arguments together.
198 //
199 std::vector<DSNodeHandle>NextArgs;
200 BaseGraph->getFunctionArgumentsForCall(F,NextArgs);
201 unsigned i = 0, e = Args.size();
202 for(; i != e; ++i) {
203 if (i == NextArgs.size()) break;
204 Args[i].mergeWith(NextArgs[i]);
205 }
206 for(e = NextArgs.size(); i != e; ++i)
207 Args.push_back(NextArgs[i]);
208
209 //
210 // Makethis function use the DSGraph that we're creating for all of
211 // thefunctions in this equivalence class.
212 //
213 setDSGraph(*F, BaseGraph);
214 } else {
215 //
216 // Mergein the DSGraph.
217 //
218 BaseGraph->cloneInto(getOrCreateGraph(F));
219
220 //
221 // Merge thearguments together.
222 //
223 std::vector<DSNodeHandle>NextArgs;
224 BaseGraph->getFunctionArgumentsForCall(F,NextArgs);
225 unsigned i = 0, e = Args.size();
226 for(; i != e; ++i) {
227 if (i == NextArgs.size()) break;
228 Args[i].mergeWith(NextArgs[i]);
229 }
230 for(e = NextArgs.size(); i != e; ++i)
231 Args.push_back(NextArgs[i]);
232
233 //
234 // Makethis function use the DSGraph that we're creating for all of
235 // thefunctions in this equivalence class.
236 //
237 setDSGraph(*F, BaseGraph);
238 }
239 }
240 }
241
242 //
243 // Update theglobals graph with any information that has changed due to
244 // graphmerging.
245 //
246 if (BaseGraph)
247 cloneIntoGlobals(BaseGraph,DSGraph::DontCloneCallNodes |
248 DSGraph::DontCloneAuxCallNodes |
249 DSGraph::StripAllocaBit);
250 }
251 }
对于简并同类集最后得到的BaseGraph,在247行把其中的信息拷贝回全局图。因为在上面213及237行处把同类集中所有的函数的图都设置为BaseGraph,接下来59~63行把BaseGraph从graphList先行除去(因为BaseGraph可以与graphList中的图相同,参考177行,这对应同类集只包含一个函数的情况。否则BaseGraph是新建的,graphList中没有记录),然后在65~76行,把其余图删除。
EquivBUDataStructures::runOnModule(续)
58 //remove all theDSGraph, that still have references
59 for(Module::iteratorF = M.begin(); F != M.end(); ++F)
60 {
61 if(!(F->isDeclaration()))
62 graphList.erase(getOrCreateGraph(F));
63 }
64 // free memoryfor the DSGraphs, no longer in use.
65 for(std::set<DSGraph*>::iteratori = graphList.begin(),e = graphList.end();
66 i!=e;i++) {
67 delete(*i);
68 }
69 DEBUG(verifyMerging());
70
71 formGlobalECs();
72
73 for(Module::iterator F = M.begin(); F != M.end(); ++F) {
74 if (!(F->isDeclaration())) {
75 if (DSGraph * Graph =getOrCreateGraph(F)) {
76 cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes|
77 DSGraph::DontCloneAuxCallNodes);
78 }
79 }
80 }
81
82 bool result = runOnModuleInternal(M);
83
84 // CBU containsthe correct call graph.
85 // Restore it, sothat subsequent passes and clients can get it.
86 restoreCorrectCallGraph();
87 returnresult;
88 }
71~82行的处理与BUDataStructure相同,但它是在CompleteDataStructure结果的基础上进行的。在86行,通过下面的函数把callgraph恢复为CompleteDataStructure给出的样子。这是因为callgraph反映的是实际函数的调用情况,尽管调用链SCC里的函数调用由其Leader来代表,EquivBUDataStructures实际上不应该改变callgraph,它只是简并同类集函数的图,减少节点数。但以目前的实现,EquivBUDataStructures有可能改变callgraph。
1512 void DataStructures::restoreCorrectCallGraph(){
1513 callgraph = GraphSource->callgraph;
1514 }
其中的GraphSource是在init时设置的,指向CompleteDataStructure的实例。