dsa算法(5)

1.3. EQTDDataStructures遍

EQTDDataStructures是poolalloc包里另一个实现DSA算法的遍。这个遍完整实现了ChrisLatter在其论文中提到的算法,因此不像BasicDataStructure,这是一个有实际意义的处理。这个类从TDDataStructures派生而来。

 

394    class EQTDDataStructures: public TDDataStructures {

395    public:

396      static charID;

397      EQTDDataStructures()

398        :TDDataStructures(ID, "eqtd.",true)

399      {}

400      ~EQTDDataStructures();

401    };

 

而TDDataStructures派生自DataStructures。EQTDDataStructures与TDDataStructures在代码中都进行了注册,因此可以通过getAnalysis来援引它们的实例。

 

31        RegisterPass<TDDataStructures>   // Register thepass

32        Y("dsa-td", "Top-down DataStructure Analysis");

33     

34        RegisterPass<EQTDDataStructures>   // Register thepass

35        Z("dsa-eqtd", "EQ Top-downData Structure Analysis");

 

因此,可以使用选项-dsa-td及-dsa-eqtd指定这两个遍进行分析操作。因为在RegisterPass的过程中,会调用该Pass的构造函数。这个构造函数在上面398行,调用TDDataStructures的构造函数:

 

363      TDDataStructures(char& CID = ID, const char* printname ="td.", bool useEQ = false)

364        : DataStructures(CID, printname),useEQBU(useEQ) {}

1.3.1. EQTDDataStructures依赖的Pass

EQTDDataStructures通过TDDataStructures的构造函数指出依赖的Pass,这体现在下面的TDDataStructures::getAnalysisUsage方法中,这些Pass需要在TDDataStructures之前执行。

 

371      virtual void getAnalysisUsage(AnalysisUsage&AU) const {

372        if (useEQBU) {

373          AU.addRequired<EquivBUDataStructures>();

374        } else {

375          AU.addRequired<BUDataStructures>();

376         AU.addPreserved<BUDataStructures>();

377        }

378       AU.setPreservesAll();

379      }

 

在EQTDDataStructures构造函数中,它把TDDataStructures的useEQBU设置为true,因此基类TDDataStructures仅依赖于EquivBUDataStructures。另外,这个Pass不改变所分析的llvm程序,在378行调用setPreservesAll来表示之。

而EquivBUDataStructures派生自CompleteBUDataStructures,它有这样的依赖关系:

 

319      virtual voidgetAnalysisUsage(AnalysisUsage&AU) const {

320       AU.addRequired<CompleteBUDataStructures>();

321        AU.setPreservesAll();

322      }

 

所依赖的CompleteBUDataStructures则派生自BUDataStructures,而它的依赖关系是:

 

295      virtual voidgetAnalysisUsage(AnalysisUsage&AU) const {

296        AU.addRequired<BUDataStructures>();

297        AU.setPreservesAll();

298      }

 

BUDataStructures的基类是DataStructures,但它依赖于StdLibDataStructures:

 

248      virtual voidgetAnalysisUsage(AnalysisUsage&AU) const {

249       AU.addRequired<StdLibDataStructures>();

250        AU.setPreservesAll();

251      }

 

StdLibDataStructures也派生自DataStructures,它所依赖的Pass有:

 

213      virtual voidgetAnalysisUsage(AnalysisUsage&AU) const {

214       AU.addRequired<LocalDataStructures>();

215        AU.addRequired<AllocIdentify>();

216       AU.setPreservesAll();

217      }

 

LocalDataStructures同样派生自DataStructures,它依赖于:

 

190      virtual voidgetAnalysisUsage(AnalysisUsage&AU) const {

191        AU.addRequired<DataLayout>();

192       AU.addRequired<AddressTakenAnalysis>();

193       AU.setPreservesAll();

194      }

 

AddressTakenAnalysis派生自ModulePass,它不依赖任何其它Pass。而AllocIdentify也派生自ModulePass,它依赖于LoopInfo:

 

191    void AllocIdentify::getAnalysisUsage(AnalysisUsage&AU) const {

192      AU.addRequired<LoopInfo>();

193      AU.setPreservesAll();

194    }

 

LoopInfo则派生自FunctionPass,它依赖于DominatorTree:

 

667    void LoopInfo::getAnalysisUsage(AnalysisUsage&AU) const {

668      AU.setPreservesAll();

669      AU.addRequired<DominatorTree>();

670    }

 

DominatorTree也派生自FunctionPass,它不依赖于其它任何Pass。

我们已经知道,通过AnalysisUsage::addRequired指定的Pass一定会在调用者Pass执行前先得到执行,因此我们现在有这样的依赖关系:

EquivBUDataStructures

  à CompleteBUDataStructures                                               |à DataLayout

         à BUDataStructures              |à LocalDataStructures -+

              à StdLibDataStructures -+                                         |à AddressTakenAnalysis

                                                         |à AllocIdentify à LoopInfo à DominatorTree

因此Pass的执行次序是DataLayout à AddressTakenAnalysis à LocalDataStructures à DominatorTree à LoopInfo à AllocIdentify à StdLibDataStructures à BUDataStructures à CompleteBUDataStructures à EquivBUDataStructures。其中DataLayout没有实际的操作,因此,最先得到执行的是AddressTakenAnalysis。

1.3.2. AddressTakenAnalysis遍

AddressTakenAnalysis完全不修改被分析的程序。它的runOnModule方法遍历指定Module中的Function对象,找出会获取地址的llvm对象。Llvm IR有一个非常重要的特性,就是它必须是SSA形式的。在Chris Lattner以假想的Kaleidoscope语言演示llvm对新语言实现的支持的系列网文里(http://llvm.org/docs/tutorial/index.html),Chris演示了如何让llvm帮我们产生SSA形式的IR(与此同时,产生CFG)。总之,各个Pass所运行的llvm程序必须是SSA形式的,并且生成了对应的CFG及def-use链。

 

70      bool AddressTakenAnalysis::runOnModule(llvm::Module&M) {

71        for(Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI){

72          if(isAddressTaken(FI)) {

73            addressTakenFunctions.insert(FI);

74          }

75        }

76     

77        return false;

78      }

 

71行的begin方法返回的是Module实例中的FunctionList,即该Module中所声明/定义的函数的集合。Llvm中函数由Function类来抽象,它的基类之一是Value(不是直接基类)。Value类在llvm中地位重要。它是程序计算的、可用于操作数或其它值的所有对象的基类。它是其它重要类,比如Instruction及Function,的超类(superclass)。

在llvm中一个特定的Value可能被使用了许多次。比如,函数的传入参数(Argument类的一个实例)为该函数中每条援引该参数的指令所“使用”。为了记录这个关系,Value类维护一个使用它的User列表(User类是llvm中可以援引Value的所有llvm IR节点类型的一个公共基类)。这个列表是llvm在程序中表示def-use信息的方式,并通过use_*方法访问。在下面38行遍历这个“使用列表”。

 

37      static bool isAddressTaken(Value* V) {

38        for(Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) {

39          User *U = *I;

40          if(isa<StoreInst>(U))

41            returntrue;

42          if (!isa<CallInst>(U) &&!isa<InvokeInst>(U)) {

43            if(U->use_empty())

44              continue;

45            if(isa<GlobalAlias>(U)) {

46              if(isAddressTaken(U))

47                returntrue;

48            } else {

49              if (Constant *C =dyn_cast<Constant>(U)) {

50                if (ConstantExpr *CE =dyn_cast<ConstantExpr>(C)) {

51                  if (CE->getOpcode() ==Instruction::BitCast) {

52                    return isAddressTaken(CE);

53                  }

54                }

55              }

56              returntrue;

57            }

58     

59            // FIXME: Canbe more robust here for weak aliases that

60            // are neverused

61          } else {

62            llvm::CallSiteCS(cast<Instruction>(U));

63            if (!CS.isCallee(I))

64              returntrue;

65          }

66        }

67        return false;

68      }

 

上面只要有一个user是获取地址的,就跳出循环。

40行的StoreInst表示向内存储存的指令,其基类是Instruction。Instruction类是使用llvm指令的类的公共基类。Instruction类本身所记录的主要数据是opcode(指令类型)及该指令所嵌入的父BasicBlock(基本块)。

CallInst类表示一个函数调用,它从Instruction派生,抽象了目标机器的调用惯例;InvokeInst表示在基本块末尾的跳转(llvm要求每个基本块的结尾以跳转结束),它从TerminatorInst派生。

Constant类代表llvm中各种常量的类的一个公共基类,ConstantExpr则是其派生类之一,代表以一个使用其它常量表达式初始化的常量值。其方法getOpcode是该表达式根节点的指令操作码(表达式的IR形式为树),其中操作码BitCast代表从一个类型到另一个类型的空操作转换。其它的转换操作码还包括截断(Trunc)、0扩展、符号扩展、指针到整数等,这些都会涉及临时对象。

62行的llvm::CallSite代表一个调用点,63行的isCallee方法表示U所代表的对象是被调用函数的参数。

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