dsa算法(25)

1.3.9. CompleteBUDataStructures遍

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,内联新发现的可解析的调用函数。

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