dsa算法(2)

来源:互联网 发布:linux shell 变量赋值 编辑:程序博客网 时间:2024/05/21 15:47

1.2. BasicDataStructures遍

就BasicDataStructures本身而言,它从DataStructures派生而来:

 

157    classBasicDataStructures: public DataStructures {

158    public:

159      static charID;

160      BasicDataStructures() : DataStructures(ID,"basic.") {}

161      ~BasicDataStructures() { releaseMemory(); }

162   

163      virtual boolrunOnModule(Module &M);

164   

165      ///getAnalysisUsage - This obviously provides a data structure graph.

166      ///

167      virtual voidgetAnalysisUsage(AnalysisUsage &AU)const {

168        AU.addRequired<DataLayout>();

169        AU.setPreservesAll();

170      }

171    };

 

其基类DataStructures则派生自ModulePass,从ModulePass派生意味着该Pass可以把整个程序作为一个单元使用,以无法预测的次序援引函数体,以及(可能)添加或删除函数。派生于ModulePass的类,需要实现的是runOnModule这个方法,DataStructures本身没有实现这个方法,因此它不是满足llvm要求的Pass,但BasicDataStructures是。runOnModule方法实现了这个Pass的功能:

 

35      bool BasicDataStructures::runOnModule(Module&M) {

36        init(&getAnalysis<DataLayout>());

1.2.1. BasicDataStructures的初始化

PassManager的一个主要责任是确保Pass彼此能正确交互。因为PassManager尝试优化Pass的执行,它必须知道pass如何交互,以及在各个pass间存在怎样的依赖性。为了追踪这,每个pass可以声明之前必须执行的pass,及为之失效的pass的集合。

通常,这个功能用于规定在你的pass运行前计算的分析结果。运行任意转换pass会使已计算的分析结果无效,这正是失效集合(invalidation set)指定的。如果一个pass没有实现getAnalysisUsage方法,默认它没有任何先决的pass,并且它使所有其它pass失效。

通过实现getAnalysisUsage方法,可以对你的Pass指定必需以及失效的pass集合。那些必需且不失效的pass由AnalysisUsage对象保存。BasicDataStructures的getAnalysisUsage方法指出DataLayout是其先决pass,并在169行通过setPreservesAll表示它完全不改变当前的llvm程序(即完全不改变其输入)。

runOnModule36行上的getAnalysis定义在最底层的基类Pass中,通过它可以访问已经以getAnalysisUsage方法请求的pass。

 

198    template<typenameAnalysisType>

199    AnalysisType &Pass::getAnalysis()const{

200      assert(Resolver&& "Pass has not been inserted into a PassManager object!");

201      returngetAnalysisID<AnalysisType>(&AnalysisType::ID);

202    }

 

AnalysisID是void*的typedef,显然参数AnalysisType通常是pass的派生类。在201行的getAnalysisID函数通过分析的ID号(对每种分析都是唯一的)来查找分析(也就是派生自Pass的遍)。

 

204    template<typenameAnalysisType>

205    AnalysisType &Pass::getAnalysisID(AnalysisID PI)const {

206      assert(PI&& "getAnalysis for unregistered pass!");

207      assert(Resolver&&"Passhas not been inserted into a PassManager object!");

208      // PI *must* appearin AnalysisImpls.  Because the number ofpasses used

209      // should be asmall number, we just do a linear search over a (dense)

210      // vector.

211      Pass *ResultPass =Resolver->findImplPass(PI);

212      assert(ResultPass &&

213              "getAnalysis*() called on ananalysis that was not "

214              "'required' by pass!");

215   

216      // Because theAnalysisType may not be a subclass of pass (for

217      // AnalysisGroups),we use getAdjustedAnalysisPointer here to potentially

218      // adjust thereturn pointer (because the class may multiply inherit, once

219      // from pass, oncefrom AnalysisType).

220      return*(AnalysisType*)ResultPass->getAdjustedAnalysisPointer(PI);

221    }

 

所有的pass实例保存在一个std::vector容器内,211行的AnalysisResolver::findImplPass从这个集合中查找指定的pass。220行的getAdjustedAnalysisPointer方法是留给AnalysisGroup用的。对于普通pass而言,它只返回this指针。

因此在201行,Pass::getAnalysis方法返回DataLayout实例作为DataStructures::init的参数。DataLayout是一个Pass的派生类,继承自ImmutablePass。ImmutablePass用于不需要运行,不改变状态,且不需要更新成员的Pass。这不是一个普通的转换或分析类型,但可以提供当前编译器配置的信息。这对提供正要为之编译的目标平台的信息,以及影响各种转换(遍)的静态信息是重要的。这里的DataLayout类实际上提供了各种内置类型的布局参数,比如大小,对齐等。

 

1499  void DataStructures::init(DataLayout* T) {

1500    assert (!TD&& "Already init");

1501    GraphSource = 0;

1502    Clone = false;

1503    TD = T;

1504    TypeSS = newSuperSet<Type*>();

1505    GlobalsGraph = newDSGraph(GlobalECs, *T, *TypeSS);

1506  }

 

1504行的Type类用于记录类型信息,其实例一旦创建就不可更改。Llvm所识别的类型(所谓的类型系统)由Type类中的枚举类型TypeID标识:

 

53        enum TypeID {

54          // PrimitiveTypes- make sure LastPrimitiveTyID stays up to date.

55          VoidTyID = 0,    ///<  0: type with no size

56          HalfTyID,        ///<  1: 16-bit floating point type

57          FloatTyID,       ///<  2: 32-bit floating point type

58          DoubleTyID,      ///<  3: 64-bit floating point type

59          X86_FP80TyID,    ///<  4: 80-bit floating point type (X87)

60          FP128TyID,       ///<  5: 128-bit floating point type (112-bitmantissa)

61          PPC_FP128TyID,   ///<  6: 128-bit floating point type (two 64-bits,PowerPC)

62          LabelTyID,       ///<  7: Labels

63          MetadataTyID,    ///<  8: Metadata

64          X86_MMXTyID,     ///<  9: MMX vectors (64 bits, X86 specific)

65     

66          // Derivedtypes... see DerivedTypes.h file.

67          // Make sureFirstDerivedTyID stays up to date!

68          IntegerTyID,     ///< 10:Arbitrary bit width integers

69          FunctionTyID,    ///< 11:Functions

70          StructTyID,      ///< 12:Structures

71          ArrayTyID,       ///< 13:Arrays

72          PointerTyID,     ///< 14:Pointers

73          VectorTyID,      ///< 15:SIMD 'packed' format, or other vector type

74     

75          NumTypeIDs,                        // Must remain as last defined ID

76          LastPrimitiveTyID = X86_MMXTyID,

77          FirstDerivedTyID = IntegerTyID

78        };

 

同一行的SuperSet是一个以集合为元素的Set类型(这就是其名字集合超集的来由)。这里创建一个Type类型的空集合。

1505行的GlobalECs是DataStructures的成员,为EquivalenceClasses<constGlobalValue*>类型。其中,类GlobalValue用于描述全局值,类EquivalenceClasses用于描述同类集,GlobalECs将保存在DSGraph中全局值的所有同类集。

DSGraph是DSA算法的一个重要的数据结构,在ChrisLatter的论文中这样定义它:数据结构分析(DataStructure Analysis)为程序中的每个函数计算一个我们称为数据结构图(DataStructure  Graph, DS Graph)的对象,汇总在该函数内访问的内存对象连同它们的连接模式。每个DS图的节点表示一组(可能无限的)动态内存对象,独立节点表示不相交的对象集,即这个图是内存对象的一个有限的,静态的划分。因为我们使用一个基于简并的做法(unification-basedapproach),所有被单个静态指针变量或域指向的动态对象(在某个上下文中)被表示为图中的单个节点。

 

260      DSGraph(EquivalenceClasses<const GlobalValue*> &ECs,const DataLayout &td,

261              SuperSet<Type*>& tss,

262              DSGraph *GG = 0)

263        :GlobalsGraph(GG), UseAuxCalls(false),

264         ScalarMap(ECs), TD(td), TypeSS(tss)

265      { }

 

在这个构造函数中的263行,GlobalsGraph也是一个DSGraph指针,它将指向表示所有的全局对象的DSGraph。264行的ScalarMap的类型是DSScalarMap,它的构造函数是:

 

52      DSScalarMap(EquivalenceClasses<const GlobalValue*> &ECs) : GlobalECs(ECs) {}

 

它将记录在一个函数中所引用的所有DSNode。它的ValueMap域专门记录引用的所有对象及其关联的DSNodeHandler,GlobalSet则记录了引用的全局对象。

1.2.2. BasicDataStructures的操作

1.2.2.1. DSNode

接下来为DSGraph准备DSNode。Chris的论文详细描述了这个结构:

DS图中的DS节点用于表示该节点内存对象集合的信息。每个节点n带有3部分信息:

Ø  T(n)标志由n表示的内存对象的类型。

Ø  G(n)表示一组(可能是空的)全局对象,换而言之,所有由节点n代表的全局对象。注意,函数也被处理作全局对象。

Ø  Flags(n)是一组与节点n关联的标记。有8种标记(h,s,g,u,m,r,c及o)。

·       内存分配类别标记:H,S,G,U:

H,S,G及U标记用于区分四类内存对象:堆分配,栈分配,全局(包括函数)及未知(unknown)对象。

在单个DS节点中可以出现多个标记,例如,分析发现一个指针可能指向一个堆对象或一个栈对象。当创建它的指令不可识别时,比如转换一个常量值到一个指针值(例如,访问一个内存映射的硬件设备),或找到一个无法分析的地址算术(在可移植程序中这种情形很少发生)时,内存对象被标记为未知。代表由外部未分析函数创建对象的节点不标记为U,而是处理作“缺少信息(missinginformation)”。

·       修改/援引标记:M,R

M及R标记表示在当前分析上下文中一个特定的内存对象是否被修改(Modified)或援引(Read)。修改/援引信息对于各种客户端分析是有用的。

·       完整信息标记:C

实用的算法必须正确处理不完整的程序:没有某些函数代码的程序;或者“程序”实际上是一个库,没有使用者的信息。为了在这样的情形下支持一个进取的分析,每个DS节点记录它是否可能漏掉信息。

为了处理这样的情形,数据结构分析计算在图中哪个节点是“完整的”,把它们打上Complete标记。如果一个节点没有标记为完整,为该DS节点计算的信息是部分信息,必须被保守处理。特别地,该节点在后面可能被赋予额外的边、标记,不同的类型,或甚至可能最终与图中其它不完整的节点简并。不过,在这样的图中其它节点可能是完整的,并且这样的节点不会与其它任何完整节点合并,这允许用户从带有部分信息的图获取有用的信息。

这个能力是我们算法(即DSA)本质上是递增的关键:因为节点记录了哪些信息是最终的,哪些仍然在创建中,由我们的算法构建的图总是保守但正确的,即使是在分析的中间步骤中。

·       类型安全或类型不安全感的域感知标记:O

“完整”标记的一个特别重要的好处是,它允许DS分析有效地为程序类型安全的子集提供域感知(field-sensitive)信息。这是重要的,因为域感知对于类型不安全的结构类型,代价可是非常高昂的,但实际上我们观察到大多数可移植代码是完全(或几乎)类型安全的,即使源语言不这样要求(比如C或C++)。

完整性标记允许DS分析推测性地假定对一个节点的所有访问都是类型安全的,直到对该节点的一次访问被发现与其它访问冲突。因为只要潜在有未处理的访问,一个节点就不会标记为完整,这是安全的。

DS分析通过对每个DS节点n关联一个类型,T(n),并记录该类型的每个指针域个别的外向边,来提供域敏感信息。如果对该节点处所有对象的访问都使用了一致的类型τ,那么T(n) = τ。

如果发现使用不兼容类型的操作,该节点的类型被处理为大小不定的字节数组(T(n) = char[],但实际在DSA算法中,类型不进行更改),并且该节点的域与边“萎缩(cOllapsed)”为至多一条外向边的单个域。

类型信息T(n)确定了在一个节点中域及外向(outgoing)边的数目。对于在T(n)中的每个指针兼容的域,节点可以有一个外出边。一条进入(incoming)边可以指向节点的任意一个域,但不能再指向别处的字节。

 

BasicDataStructures::runOnModule(续)

 

42        DSNode * GVNodeInternal =new DSNode(GlobalsGraph);

43        DSNode * GVNodeExternal =new DSNode(GlobalsGraph);

 

有了前面的描述,下面的构造函数就不难理解了:

 

132    DSNode::DSNode(DSGraph *G)

133      : NumReferrers(0), Size(0), ParentGraph(G),NodeType(0) {

134        // Add the typeentry if it is specified...

135        if (G) G->addNode(this);

136        ++NumNodeAllocated;

137      }

 

133行的NodeType是以下的枚举类型,其中的AllocaNode是上面的S标记,因为llvm总是使用alloca分配栈上的内存。

 

91        enum NodeTy {

92          ShadowNode      = 0,       // Nothing isknown about this node...

93          AllocaNode      = 1 << 0,  // This node wasallocated with alloca

94          HeapNode        = 1 << 1,  // This node wasallocated with malloc

95          GlobalNode      = 1 << 2,  // This node wasallocated by a global var decl

96          ExternFuncNode  = 1 << 3,  // This nodecontains external functions

97          ExternGlobalNode = 1 << 4, // This nodecontains external globals

98          UnknownNode     = 1 << 5,  // This nodepoints to unknown allocated memory

99          IncompleteNode  = 1 << 6,  // This node maynot be complete

100   

101        ModifiedNode    = 1 << 7,  // This node ismodified in this context

102        ReadNode       = 1 << 8,  // This node isread in this context

103   

104        ArrayNode       = 1 << 9,  // This node istreated like an array

105        CollapsedNode   = 1 << 10, // This node iscollapsed

106        ExternalNode    = 1 << 11, // This node comesfrom an external source

107        IntToPtrNode    = 1 << 12, // This node comesfrom an int cast

108                                   // and is used in pointer operations

109                                   // like geps, loads, stores

110        PtrToIntNode    = 1 << 13, // This nodeescapes to an int cast

111                                   // and DSA does not track it further.

112        VAStartNode     = 1 << 14, // This node isfrom a vastart call

113   

114        //#ifndef NDEBUG

115        DeadNode        = 1 << 15,  // This node isdead and should not be pointed to

116        //#endif

117   

118        Composition = AllocaNode | HeapNode |GlobalNode | UnknownNode

119      };

 

在DSGraph中,DSNode被保存在链表Nodes里,135行就是把新创建的DSNode加到这个链表。在BasicDataStructures::runOnModule的42、43行分别创建了代表全局可见的内部、外部节点。

0 0
原创粉丝点击