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行分别创建了代表全局可见的内部、外部节点。
- dsa算法(2)
- dsa算法(1)
- dsa算法(3)
- dsa算法(4)
- dsa算法(5)
- dsa算法(6)
- dsa算法(7)
- dsa算法(8)
- dsa算法(9)
- dsa算法(10)
- dsa算法(11)
- dsa算法(12)
- dsa算法(13)
- dsa算法(14)
- dsa算法(15)
- dsa算法(16)
- dsa算法(17)
- dsa算法(18)
- 娱乐时间,我们来画一下星星
- 没有login页面
- ActiveMQ参考手册
- CCLayerLoader
- 机会往往留给有准备的人—找工作[1]
- dsa算法(2)
- 将C++转换成VB,C#语言小工具介绍
- 某新生院赛CTF 移动题writeup
- CCLayerGradientLoader
- CCLayerColorLoader
- 大数据领域的顶级开源工具大集合
- VC2010 Tab控件使用
- JAVA多线程学习专题
- Maven 整理