LocalDataStructures派生自DataStructures。该Pass为程序中的所有函数计算局部数据结构图。Chris Latter论文中给出的局部分析的伪代码算法(具体算法请参考Chris的论文)。不过,DSA的实现实际已经大大突破了论文中的定义。
1442 bool LocalDataStructures::runOnModule(Module&M) {
1443 init(&getAnalysis<DataLayout>());
1444 addrAnalysis =&getAnalysis<AddressTakenAnalysis>();
1445
1446 // First step,build the globals graph.
1447 {
1448 GraphBuilder GGB(*GlobalsGraph);
1449
1450 // Addinitializers for all of the globals to the globals graph.
1451 for(Module::global_iterator I = M.global_begin(), E = M.global_end();
1452 I != E; ++I)
1453 if (!(I->hasSection() &&I->getSection() == "llvm.metadata")) {
1454 if (I->isDeclaration())
1455 GGB.mergeExternalGlobal(I);
1456 else
1457 GGB.mergeInGlobalInitializer(I);
1458 }
1443行调用的是DataStructures::init,它为全局对象(包括函数)构建了一个DSGraph实例(1448行的GlobalsGraph)。1444行获取这个Pass所依赖的AddressTakenAnalysis对象(它是全局唯一的)。1448行的GraphBuilder是数据结构图(datastructure graph)的构造器,它继承自InstVisitor<GraphBuilder>。InstVisitor是各种指令访问者(instructionvistor)的基类。显然,GraphBuilder是一个指令访问者。指令访问者的好处是:使用它,你无需使用大量的转换或者巨大的switch语句块来对不同类型的指令执行不同的操作,但你必须重载必要的的visitXXX方法。
210 explicit GraphBuilder(DSGraph& g)
211 :G(g), FB(0), TD(g.getDataLayout()),VAArray(0)
212 {}
在llvm IR中一个对象是否是声明由下面的方法来判断。这是一个简单实用的方法。
66 bool GlobalValue::isDeclaration() const {
67 // Globals aredefinitions if they have an initializer.
68 if (constGlobalVariable *GV = dyn_cast<GlobalVariable>(this))
69 returnGV->getNumOperands() == 0;
70
71 // Functions aredefinitions if they have a body.
72 if (constFunction *F = dyn_cast<Function>(this))
73 returnF->empty();
74
75 // Aliases arealways definitions.
76 assert(isa<GlobalAlias>(this));
77 return false;
78 }
对于声明,比如全局对象的初始值,我们不掌握其细节,通过下面的方法来处理。
在LocalDataStructures::runOnModule的1453行,getSection方法给出这个全局对象注入的节,在llvm文件中,节“llvm.metadata”用于保存调试信息。放入这个节的都是调试数据。如果不是调试数据,对这些全局对象声明调用下面的方法:
1390 void GraphBuilder::mergeExternalGlobal(GlobalVariable*GV) {
1391 // Get a nodehandle to the global node and merge the initializer into it.
1392 DSNodeHandle NH = getValueDest(GV);
1393 }
方法getValueDest返回图中代表实际值的DSNode(封装在DSNodeHandle中)。我们已经知道,DSNodeHandle相当于指向对应DSNode的指针,它的实例由一个DSNode与一个偏移量组成。DSNode则表示一个指定大小的内存对象,显然DSNodeHandle的实例表示对这个对象的一次援引。
249 DSNodeHandle GraphBuilder::getValueDest(Value* V) {
250 if (isa<Constant>(V) &&cast<Constant>(V)->isNullValue())
251 return0; // Nulldoesn't point to anything, don't add to ScalarMap!
252
253 DSNodeHandle &NH = G.getNodeForValue(V);
254 if (!NH.isNull())
255 returnNH; //Already have a node? Just return it...
256
257 // Otherwise weneed to create a new node to point to.
258 // Check first forconstant expressions that must be traversed to
259 // extract theactual value.
260 DSNode* N;
261 if (Function * F = dyn_cast<Function >(V)) {
262 // Create a newglobal node for this function.
263 N = createNode();
264 N->addFunction(F);
265 if (F->isDeclaration())
266 N->setExternFuncMarker();
267 } else if (GlobalValue * GV =dyn_cast<GlobalValue > (V)) {
268 // Create a newglobal node for this global variable.
269 N = createNode();
270 N->addGobal(GV);
271 if (GV->isDeclaration())
272 N->setExternGlobalMarker();
注意253行的getNodeForValue,如果V还未加入G的ScalarMap,它把V插入,与一个缺省构造的DSNodeHandle关联,并返回这个DSNodeHandle。此时,满足254行条件。如果这个指定的内存对象尚未产生,GraphBuilder的createNode方法就在DSGraph中创建一个DSNode,下面92行的G就是GraphBuilder中保存的DSGraph对象。
90 DSNode *createNode()
91 {
92 DSNode* ret = new DSNode(&G);
93 assert(ret->getParentGraph()&& "No parent?");
94 returnret;
95 }
264行的addFunction主要是调用addGlobal方法。每个函数都有一个对应的DSGraph,每个图分配有一个DSScalarMap实例记录该函数中的全局对象。
208 void DSNode::addGlobal(const GlobalValue *GV) {
209 // First, check tomake sure this is the leader if the global is in an
210 // equivalenceclass.
211 GV = getParentGraph()->getScalarMap().getLeaderForGlobal(GV);
212
213 Globals.insert(GV);
214 setGlobalMarker();
215 }
DSScalarMap中的GlobalECs是保存同类(在离散数学里,同类被定义为满足自反、传递及对称的关系)的集合。一个同类关系被组织为一个链表(ECValue实例),其中一个称为领导者(Leader)的对象作为该同类的代表。因此,getLeaderForGlobal返回同类集的Leader,如果存在的话,否则就是GV本身。
65 constGlobalValue *getLeaderForGlobal(const GlobalValue *GV) const{
66 EquivalenceClasses<const GlobalValue*>::iterator ECI =GlobalECs.findValue(GV);
67 if (ECI == GlobalECs.end()) return GV;
68 return*GlobalECs.findLeader(ECI);
69 }
GraphBuilder::getValueDest余下的部分,除了UndefValue(293~295行),其它的处理对象都是定义。最后,DSNode与DSNodeHandle必须绑定,这由在getValueDest 327行的setTo完成(代码在下面显示)。
全局对象的定义的处理则稍微复杂一些,因为对于变量这涉及确认内存的大小及初始值的优化处理。在LocalDataStructures::runOnModule的1457行,调用下面的函数。
1359 void GraphBuilder::mergeInGlobalInitializer(GlobalVariable*GV) {
1360 // Ensure that theglobal variable is not external
1361 assert(!GV->isDeclaration()&& "Cannot merge in external global!");
1362
1363 //
1364 // Get a nodehandle to the global node and merge the initializer into it.
1365 //
1366 DSNodeHandle NH = getValueDest(GV);
1367
1368 //
1369 // Ensure that theDSNode is large enough to hold the new constant that we'll
1370 // be adding to it.
1371 //
1372 Type * ElementType =GV->getType()->getElementType();
1373 while(ArrayType*ATy = dyn_cast<ArrayType>(ElementType)) {
1374 ElementType = ATy->getElementType();
1375 }
1376 if(!NH.getNode()->isNodeCompletelyFolded()) {
1377 unsigned requiredSize =TD.getTypeAllocSize(ElementType) + NH.getOffset();
1378 if (NH.getNode()->getSize() <requiredSize){
1379 NH.getNode()->growSize (requiredSize);
1380 }
1381 }
1382
1383 //
1384 // Do the actualmerging in of the constant initializer.
1385 //
1386 MergeConstantInitIntoNode(NH,GV->getType()->getElementType(), GV->getInitializer());
1387
1388 }
同样,首先通过GraphBuilder::getValueDest,为这些定义产生对应的DSNode。
为变量及函数定义产生DSNode的过程与声明基本类似,除了定义使用的DSNode不需要记上外部标记。
LlvmIR中的常量类型的公共基类就是Constant,它也是Value的派生类。下面274行的ConstantExpr表示一个使用常量值的表达式,它通常由一个操作符及两个常量组成。275行的isCast方法检测这个表达式是否是一个转换,llvm IR定义了如下的转换(通过源文件instruction.def及系列的宏):截断、0扩展、符号扩展、浮点到无符号整数、浮点到有符号整数、无符号整数到浮点、有符号整数到浮点、浮点截断为整数、浮点控制为整数、指针到整数、整数到指针、无需操作的转换。显然,转换可视为一个一元操作符,如果被转换常量是一个指针类型,使用getVlueDest处理,也同样会通过createNode创建一个新节点,不过没有Unknown标记。
GraphBuilder::getValueDest(续)
273 } else if (Constant *C =dyn_cast<Constant>(V)) {
274 if (ConstantExpr *CE =dyn_cast<ConstantExpr>(C)) {
275 if (CE->isCast()) {
276 if(isa<PointerType>(CE->getOperand(0)->getType()))
277 NH = getValueDest(CE->getOperand(0));
278 else
279 NH = createNode()->setUnknownMarker();
280 } else if (CE->getOpcode() ==Instruction::GetElementPtr) {
281 visitGetElementPtrInst(*CE);
282 assert(G.hasNodeForValue(CE)&& "GEP didn't get processed right?");
283 NH = G.getNodeForValue(CE);
284 } else {
285 // Thisreturns a conservative unknown node for any unhandled ConstExpr
286 NH = createNode()->setUnknownMarker();
287 }
288 if (NH.isNull()) { // (getelementptrnull, X) returns null
289 G.eraseNodeForValue(V);
290 return0;
291 }
292 returnNH;
注意,对ConstantExpr的处理在292行退出getValueDest函数。