1.3.3.2.2.2. GetElementPtrInst
LlvmIR有个有趣的地方:GlobalValue代表全局变量或函数的地址,而且它们是内存对象,总是通过地址来援引它们。正因为如此,一个全局对象的类型总是指向其内容的一个指针。在使用GetElementPtrInst指令时,记住这点很重要,因为这个指针必须首先被解除引用。例如,如果你有一个为24个int数组的GlobalVariable(GlobalValue的派生类),类型为[24×i32],那么该GlobalVariable是指向该数组的指针。虽然该数组第一个元素的地址与这个GlobalVariable的值相同,但它们具有不同的类型。这个GlobalVariable的类型是[24×i32],第一个元素的类型是i32。因为这样,访问一个全局值要求你首先使用GetElementPtrInst解除引用这个指针的引用,然后才可以访问其元素。
GraphBuilder::visitGetElementPtrInst方法为GetElementPtrInst指令(缩写为GEP)产生DSNode。在这个指令中,第一个参数是指向作为这个计算的基址的对象指针。
685 void GraphBuilder::visitGetElementPtrInst(User&GEP) {
686 //
687 // Ensure that theindexed pointer has a DSNode.
688 //
689 DSNodeHandle NodeH = getValueDest(GEP.getOperand(0));
690 if (NodeH.isNull())
691 NodeH = createNode();
692
693 //
694 // There are a fewquick and easy cases to handle. If theDSNode of the
695 // indexed pointeris already folded, then we know that the result of the
696 // GEP will havethe same offset into the same DSNode
697 // as the indexedpointer.
698 //
699
700 if (!NodeH.isNull() &&
701 NodeH.getNode()->isNodeCompletelyFolded()) {
702 setDestTo(GEP,NodeH);
703 return;
704 }
注意,691行的createNode方法只返回DSNode对象的指针,因此这里会调用一次如下的DSNodeHandle的构造函数,绑定DSNode与DSNodeHandle。
63 DSNodeHandle(DSNode *n, unsigned offs = 0) :N(0), Offset(0) {
64 setTo(n,offs);
65 }
然后再调用DSNodeHandle的“=”操作符。
71 DSNodeHandle &operator=(const DSNodeHandle &H) {
71 if (&H == this) return *this; // Don't set offset to 0 if self assigning.
71 DSNode *NN = H.getNode(); // Call getNode()before .Offset
71 setTo(NN,H.Offset);
71 return*this;
71 }
这样,700行的isNull测试必定返回false。如果这个对象已经被缩合(700~701行条件,类似于C中的类型void*),那么就不需要进一步的处理,只需在下面把代表该对象与这个GEP对象的DSNode简并起来。
353 void GraphBuilder::setDestTo(Value &V, const DSNodeHandle &NH) {
354 G.getNodeForValue(&V).mergeWith(NH);
355 }
如果该对象的DSNode没有被缩合,那么GEP指令的后续参数将指定目标域的索引,比如,上面提到的[24×i32]的数组,如果要获取其第3个元素,使用的GEP将是(假定数组变量是A,目标变量是B):
%B= getelementPtr [24×i32]* %A, i32 0, i32 2
其中,第一个索引总是针对对象的解除引用,以上例来说,索引0表示与A地址相同的[24×i32]的数组对象,索引1表示与A+1地址(即A的地址+sizeof(A))相同的[24×i32]的数组对象;而第二个索引则是数组元素的序号(对于struct,则是域的序号);如果结果的类型还是一个struct,则可以有第三个索引来标记目的对象的序号,以此类推。
GraphBuilder::visitGetElementPtrInst(续)
711 int Offset = 0;
712
713 // FIXME: I am notsure if the code below is completely correct (especially
714 // if we start doing fancy analysis onnon-constant array indices).
715 // What if the array is indexed using alarger index than its declared
716 // size? Does the LLVM verifier catch such issues?
717 //
718
719 //
720 // Determine theoffset (in bytes) between the result of the GEP and the
721 // GEP's pointer operand.
722 //
723 // Note: All ofthese subscripts are indexing INTO the elements we have...
724 //
725 // FIXME: We can dobetter for array indexing. First, if thearray index is
726 // constant, we can determine how muchfarther we're moving the
727 // pointer. Second, we can try to use the results ofother analysis
728 // passes (e.g., ScalarEvolution) to findmin/max values to do less
729 // conservative type-folding.
730 //
731 for(gep_type_iterator I = gep_type_begin(GEP), E = gep_type_end(GEP);
732 I != E; ++I)
731行的for循环开始遍历GEP余下的参数,并计算偏移。gep_type_begin与gep_type_end分别返回头尾的迭代器。94行的getScalarType,对非vector类型不做任何操作,返回this。
92 inlinegep_type_iterator gep_type_begin(const User &GEP) {
93 returngep_type_iterator::begin
94 (GEP.getOperand(0)->getType()->getScalarType(), GEP.op_begin()+1);
95 }
96 inlinegep_type_iterator gep_type_end(const User &GEP) {
97 returngep_type_iterator::end(GEP.op_end());
98 }
迭代器gep_type_iterator则是generic_gep_type_iterator对User::const_op_iterator(即constUser*)的具现(这是使用缺省模板参数的具现)。
83 typedefgeneric_gep_type_iterator<> gep_type_iterator;
generic_gep_type_iterator继承关系如下,它的基类是std::iterator,是一个前向迭代器。
22 template<typename ItTy = User::const_op_iterator>
23 classgeneric_gep_type_iterator
24 : publicstd::iterator<std::forward_iterator_tag, Type *, ptrdiff_t>
在下面36及42行,I.OpIt中OpIt的类型是模板参数ItTy,即迭代器的类型,而35及41行的I.CurTy中CurTy的类型则是Type*,显然begin方法设置CurTy指向GEP援引的对象,OpIt指向跟在对象后的索引。
33 staticgeneric_gep_type_iterator begin(Type *Ty,ItTy It) {
34 generic_gep_type_iterator I;
35 I.CurTy = Ty;
36 I.OpIt = It;
37 return I;
38 }
39 staticgeneric_gep_type_iterator end(ItTy It) {
40 generic_gep_type_iterator I;
41 I.CurTy = 0;
42 I.OpIt = It;
43 return I;
44 }
在for循环中的递增操作涉及以下的操作符。其中CompositeType是StructType的基类(llvm使用StructType表示struct/union/class),同时还是PointerType的基类。
68 generic_gep_type_iterator& operator++() { // Preincrement
69 if (CompositeType *CT =dyn_cast<CompositeType>(CurTy)) {
70 CurTy = CT->getTypeAtIndex(getOperand());
71 } else {
72 CurTy = 0;
73 }
74 ++OpIt;
75 return*this;
76 }
78 generic_gep_type_iterator operator++(int) {// Postincrement
79 generic_gep_type_iterator tmp = *this;++*this; return tmp;
80 }
GEP余下的参数必须是整数。如果当前(子)对象是一个复合类型,把CurTy更新为当前索引参数所指定的子对象。70行的getOperand()直接返回迭代器指向的对象(即*OpIt),它是当前类型(CurTy指向)成员(域)的索引(通常是ConstantInt)。getTypeAtIndex返回指定索引位置的子对象类型。
631 Type *CompositeType::getTypeAtIndex(const Value *V) {
632 if (StructType *STy = dyn_cast<StructType>(this)){
633 unsigned Idx =
634 (unsigned)cast<Constant>(V)->getUniqueInteger().getZExtValue();
635 assert(indexValid(Idx)&& "Invalid structure index!");
636 returnSTy->getElementType(Idx);
637 }
对于ConstantInt,634行的getUniqueInteger仅仅是返回其值,getUniqueInteger主要是处理常量整数向量,636行则是返回在索引位置上成员的类型。注意,这个类型在上面70行设置给了CurTy,即当前处理的类型被更新为指定成员的类型,并且在74行递增迭代器。注意,这里的迭代器实际上是const User*,++使该指针指向下一个对象。这是因为在GEP中操作数存放在一个数组中(User的方法getOperand,op_end与op_begin都使用这个数组。这使得遍历能正确结束)。因此,这个++操作符的作用是按照索引的指示把迭代器的CurTy设置为指定的成员的类型(如果不是复合类型,则设置为0,因为大小已知),并把OpIt设置为GEP中的下一个索引参数。
GraphBuilder::visitGetElementPtrInst(续)
733 if (StructType *STy =dyn_cast<StructType>(*I)) {
734 // indexinginto a structure
735 // next indexmust be a constant
736 const ConstantInt* CUI =cast<ConstantInt>(I.getOperand());
737 int FieldNo = CUI->getSExtValue();
738 // incrementthe offset by the actual byte offset being accessed
739
740 unsigned requiredSize =TD.getTypeAllocSize(STy) + NodeH.getOffset() + Offset;
741
742 //
743 // Grow theDSNode size as needed.
744 //
745 if (!NodeH.getNode()->isArrayNode() ||NodeH.getNode()->getSize() <= 0){
746 if (requiredSize >NodeH.getNode()->getSize())
747 NodeH.getNode()->growSize(requiredSize);
748 }
749
750 Offset +=(unsigned)TD.getStructLayout(STy)->getElementOffset(FieldNo);
751 if (TypeInferenceOptimize) {
752 if (ArrayType* AT =dyn_cast<ArrayType>(STy->getTypeAtIndex(FieldNo))) {
753 NodeH.getNode()->mergeTypeInfo(AT, NodeH.getOffset() +Offset);
754 if ((++I) == E) {
755 break;
756 }
757
758 // Check ifwe are still indexing into an array.
759 // We onlyrecord the topmost array type of any nested array.
760 // Keepskipping indexes till we reach a non-array type.
761 // J is thetype of the next index.
762 //Uncomment the line below to get all the nested types.
763 gep_type_iterator J = I;
764 while(isa<ArrayType>(*(++J))) {
765 // NodeH.getNode()->mergeTypeInfo(AT1,NodeH.getOffset() + Offset);
766 if((++I) == E) {
767 break;
768 }
769 J = I;
770 }
771 if ((I) == E) {
772 break;
773 }
774 }
775 }
在733行,迭代器generic_gep_type_iterator把操作符“*”的定义重载为:
53 Type *operator*()const {
54 returnCurTy;
55 }
因此,这行检查当前处理的类型是否是struct/union/class。如果是,跟在后面的整数参数则是其中成员的索引,这个索引被提取到737行的FieldNo。而740行的NodeH是GEP对象的DSNodeHandle(在689行获得),其方法getOffset返回它在所援引的DSNode中的偏移(DSNodeHandle相当于指针,指向相关DSNode的指定偏移)。那么要容纳这个域,740行计算的requiredSize就是对象的最小尺寸。
745行的条件,对于数组而言,只有其大小小于0时才进行调整,在其它情况下,其DSNode中的Size就是其元素的大小。这样,requiredSize大于Size也是合理的。750行调整偏移,因为我们进入FieldNo所指定的子对象。
751行的TypeInferenceOptimize可以通过选项enable-type-inference-opts来激活类型推理优化(typeinference optimization)。在激活这个优化时,对这个StructType直接包含的数组调用下面的方法。
432 void DSNode::mergeTypeInfo(Type *NewTy, unsignedOffset) {
433 if (!NewTy || NewTy->isVoidTy()) return;
434 if (isCollapsedNode()) return;
435
436 growSizeForType(NewTy,Offset);
437
438 // Clang generatesloads and stores of struct types.
439 // %tmp12 = load%struct.demand* %retval, align 1
440
441 // In such cases,merge type information for each struct field
442 // individually(atthe appropriate offset), instead of the
443 // struct type.
444 if(NewTy->isStructTy()) {
445 constDataLayout &TD = getParentGraph()->getDataLayout();
446 StructType *STy =cast<StructType>(NewTy);
447 constStructLayout *SL = TD.getStructLayout(cast<StructType>(STy));
448 unsigned count = 0;
449 for(Type::subtype_iteratorii = STy->element_begin(), ee = STy->element_end(); ii!= ee; ++ii,++count) {
450 unsigned FieldOffset =SL->getElementOffset(count);
451 mergeTypeInfo(*ii, Offset + FieldOffset);
452 }
453 } else {
454 TyMap[Offset] = getParentGraph()->getTypeSS().getOrCreate(TyMap[Offset],NewTy);
455 }
456
457 assert(TyMap[Offset]);
458 }
436行的growSizeForType根据在偏移Offset处出现的类型NewTy来调整这个DSNode的尺寸。对于数组节点,其DSNode中的Size是其元素的大小,因此,Offset要对这个Size取模,更新为相对于某个元素的偏移。
410 void DSNode::growSizeForType(Type *NewTy, unsignedOffset) {
411
412 if (!NewTy || NewTy->isVoidTy()) return;
413
414 if (isCollapsedNode()) return;
415 if (isArrayNode() && getSize() >0) {
416 Offset %= getSize();
417 }
418 constDataLayout &TD = getParentGraph()->getDataLayout();
419 if (Offset + TD.getTypeAllocSize(NewTy) >=getSize())
420 growSize(Offset +TD.getTypeAllocSize(NewTy));
421
422 }
在上面的DSNode::mergeTypeInfo函数中,449行的循环遍历指定的StructType所包含的类型,并对该类型递归调用这个DSNode::mergeTypeInfo函数(注意新的偏移)。递归的最终结果是在454行,当前DSNode节点的TyMap在指定偏移位置记录这个类型。
回到GraphBuilder::visitGetElementPtrInst对StructType处理。对于连续嵌套的、更深的ArrayType,目前的代码(764行的while循环)只是跳过,不做处理(也就避开了下面对它们的处理)。
GraphBuilder::visitGetElementPtrInst(续)
776 } else if (ArrayType *ATy =dyn_cast<ArrayType>(*I)) {
777 // indexinginto an array.
778 NodeH.getNode()->setArrayMarker();
779 Type *CurTy = ATy->getElementType();
780
781 //
782 // Ensure thatthe DSNode's size is large enough to contain one
783 // element ofthe type to which the pointer points.
784 //
785 if (!isa<ArrayType>(CurTy)&& NodeH.getNode()->getSize() <= 0) {
786 NodeH.getNode()->growSize(TD.getTypeAllocSize(CurTy));
787 } else if(isa<ArrayType>(CurTy)&& NodeH.getNode()->getSize() <= 0){
788 Type *ETy =(cast<ArrayType>(CurTy))->getElementType();
789 while(isa<ArrayType>(ETy)){
790 ETy = (cast<ArrayType>(ETy))->getElementType();
791 }
792 NodeH.getNode()->growSize(TD.getTypeAllocSize(ETy));
793 }
794
795 // Find if theDSNode belongs to the array
796 // If not fold.
797 if((NodeH.getOffset() || Offset != 0)
798 || (!isa<ArrayType>(CurTy)
799 &&(NodeH.getNode()->getSize() != TD.getTypeAllocSize(CurTy)))) {
800 NodeH.getNode()->foldNodeCompletely();
801 NodeH.getNode();
802 Offset = 0;
803 break;
804 }
如果成员的类型是数组,把包含该成员的DSNode标记为数组节点,并获取其元素的类型。如果元素的类型还是数组,那么继续寻找其元素,直到元素不是数组,因为数组类型的DSNode的Size是其非数组类型元素的类型大小。797行则是测试是否需要缩合该对象的DSNode节点。如果该数组不是在GetElementPtrInst作用的内存对象的偏移0处(797行第1个条件),或者该内存对象在另一个内存对象的非0偏移处(797行第2个条件),或者对于一维数组,该内存对象的DSNode还代表另一个大小不同的对象(因为786及796行只有在DSNode的大小不大于0时才执行),都要缩合。既然已经缩为一个大小为1的节点,就无需继续处理,从803行处结束731行的for循环。
GraphBuilder::visitGetElementPtrInst(续)
805 } else if (constPointerType *PtrTy = dyn_cast<PointerType>(*I)) {
806 // Get the typepointed to by the pointer
807 Type *CurTy = PtrTy->getElementType();
808
809 //
810 // Some LLVMtransforms lower structure indexing into byte-level
811 //indexing. Try to recognize forms of thathere.
812 //
813 Type * Int8Type = Type::getInt8Ty(CurTy->getContext());
814 ConstantInt * IS =dyn_cast<ConstantInt>(I.getOperand());
815 if (IS &&
816 (NodeH.getOffset() == 0) &&
817 (!(NodeH.getNode()->isArrayNode())) &&
818 (CurTy == Int8Type)) {
819 // Calculatethe offset of the field
820 Offset += IS->getSExtValue() *TD.getTypeAllocSize (Int8Type);
821
822 //
823 // Grow theDSNode size as needed.
824 //
825 unsigned requiredSize = Offset +TD.getTypeAllocSize (Int8Type);
826 if (NodeH.getNode()->getSize() <=requiredSize){
827 NodeH.getNode()->growSize(requiredSize);
828 }
829
830 // Add in theoffset calculated...
831 NodeH.setOffset(NodeH.getOffset()+Offset);
832
833 // Check theoffset
834 DSNode *N = NodeH.getNode();
835 if (N) N->checkOffsetFoldIfNeeded(NodeH.getOffset());
836
837 // NodeH isnow the pointer we want to GEP to be...
838 setDestTo(GEP,NodeH);
839 return;
840 }
对于指针类型的成员,首先检查它是否为字节指针加常量索引的形式。807行获取指针指向对象的类型,814行的getOperand得到在该指针指向对象内的常量偏移值。这其实就是char*/unsigned char*,810~811行注释说到,某些llvm转换会把struct索引变形为字节索引,这段代码就是处理这种情形,825~831行相应地调整偏移及DSNode的大小。
我们知道DSNodeHandle相当于指针,它是DSNode+Offset的形式,上面我们计算出了Offset,但这个Offset可能会超出对应DSNode的大小,这时需要缩合这个DSNode节点,因为我们无法处理这些访问。
727 void DSNode::checkOffsetFoldIfNeeded(intOffset) {
728 if (!isNodeCompletelyFolded() &&
729 (Size != 0 || Offset != 0) &&
730 !isForwarding()) {
731 if ((Offset >= (int)Size) || Offset <0) {
732 // Accessingoffsets out of node size range
733 // This is seenin the "magic" struct in named (from bind), where the
734 // fourth fieldis an array of length 0, presumably used to create struct
735 // instances ofdifferent sizes
736 // Moregenerally this happens whenever code indexes past the end
737 // of a structtype. We don't model this, so fold!
738
739 // Collapse thenode since its size is now variable
740 foldNodeCompletely();
741
742 ++NumFoldsOOBOffset;
743 }
744 }
745 }
如果不是字节指针加索引的形式,继续往下。如果子对象指针的索引不是常量或不是0(850~851行条件),就把对应的内存对象(DSNode)处理做数组(但不是数组类型!),比如*ptr+5这样。
GraphBuilder::visitGetElementPtrInst(续)
842 //
843 // Unless we'readvancing the pointer by zero bytes via array indexing,
844 // fold thenode (i.e., mark it type-unknown) and indicate that we're
845 // indexingzero bytes into the object (because all fields are aliased).
846 //
847 // Note that we break out of the loop if we fold thenode. Once
848 // something isfolded, all values within it are considered to alias.
849 //
850 if (!isa<Constant>(I.getOperand())||
851 !cast<Constant>(I.getOperand())->isNullValue()) {
852
853 //
854 // Treat thememory object (DSNode) as an array.
855 //
856 NodeH.getNode()->setArrayMarker();
857
858 //
859 // Ensurethat the DSNode's size is large enough to contain one
860 // element ofthe type to which the pointer points.
861 //
862 if (!isa<ArrayType>(CurTy)&& NodeH.getNode()->getSize() <= 0){
863 NodeH.getNode()->growSize(TD.getTypeAllocSize(CurTy));
864 } else if (isa<ArrayType>(CurTy)&& NodeH.getNode()->getSize() <= 0){
865 Type *ETy =(cast<ArrayType>(CurTy))->getElementType();
866 while(isa<ArrayType>(ETy)) {
867 ETy =(cast<ArrayType>(ETy))->getElementType();
868 }
869 NodeH.getNode()->growSize(TD.getTypeAllocSize(ETy));
870 }
871
872 //
873 // Fold theDSNode if we're indexing into it in a type-incompatible
874 //manner. That can occur if:
875 // 1) The DSNode represents a pointer into theobject at a non-zero
876 // offset.
877 // 2) The offset of the pointer is alreadynon-zero.
878 // 3) The size of the array element does notmatch the size into which
879 // the pointer indexing is indexing.
880 //
881 if (NodeH.getOffset() || Offset != 0 ||
882 (!isa<ArrayType>(CurTy)&&
883 (NodeH.getNode()->getSize() !=TD.getTypeAllocSize(CurTy)))) {
884 NodeH.getNode()->foldNodeCompletely();
885 NodeH.getNode();
886 Offset = 0;
887 break;
888 }
889 }
890 }
这里的处理与前面看到的与数组的处理类似。注意,如果节点最后缩合了,那么856行设置的数组标记将被清除。
GraphBuilder::visitGetElementPtrInst(续)
892 // Add in theoffset calculated...
893 NodeH.setOffset(NodeH.getOffset()+Offset);
894
895 // Check the offset
896 DSNode *N = NodeH.getNode();
897 if (N) N->checkOffsetFoldIfNeeded(NodeH.getOffset());
898
899 // NodeH is now thepointer we want to GEP to be...
900 setDestTo(GEP,NodeH);
901 }
在处理完所有的域后(可能发生了缩合),更新偏移的数据,因为我们已经到达目标元素了。同样需要检查这个偏移是否已经超出节点的大小。最后,注意900行的setDestTo。它把GEP所带的DSNodeHandle与NodeH进行简并,因为这条GEP指令可能在多处使用,简并使得这些引用被汇集起来。同时,如果出现不兼容的情形,会自动进行安全的缩合。
1.3.3.2.2.3. 其他
UndefValue对应于llvm IR中的undef,这又类似于C++标准中的undefinedbehavor。UndefValue可以用于任何适用常量的地方,表示该值可能没是指定的比特形式。它向编译器表示不管它使用了哪个值,这个程序是定义良好的。这使得编译器有更大的优化自由度。因此,在这里我们无需考虑它。
GraphBuilder::getValueDest(续)
293 } else if (isa<UndefValue>(C)) {
294 G.eraseNodeForValue(V);
295 return 0;
296 } else if (isa<GlobalAlias>(C)) {
297 // XXX: Needmore investigation
298 // According toAndrew, DSA is broken on global aliasing, since it does
299 // not handlethe aliases of parameters correctly. Here is only a quick
300 // fix for somespecial cases.
301 NH= getValueDest(cast<GlobalAlias>(C)->getAliasee());
302 returnNH;
303 } else if (isa<BlockAddress>(C)) {
304 //
305 // FIXME: Thismay not be quite right; we should probably add a
306 // BlockAddressflag to the DSNode instead of using the unknown flag.
307 //
308 N = createNode();
309 N->setUnknownMarker();
310 } else if (isa<ConstantStruct>(C) ||isa<ConstantArray>(C) ||
311 isa<ConstantDataSequential>(C) || isa<ConstantDataArray>(C)||
312 isa<ConstantDataVector>(C)) {
313 // Treat thesethe same way we treat global initializers
314 N = createNode();
315 NH.mergeWith(N);
316 MergeConstantInitIntoNode(NH,C->getType(), C);
317 } else {
318 errs() << "Unknown constant:" << *C << "\n";
319 assert(0&& "Unknown constant type!");
320 }
321 N = createNode();// just create a shadow node
322 } else {
323 // Otherwise justcreate a shadow node
324 N = createNode();
325 }
326
327 NH.setTo(N,0); //Remember that we are pointing to it...
328 return NH;
329 }
310行的ConstantStruct,ConstantArray,ConstantDataSequential,ConstantDataArray及ConstantDataVector都是llvm IR用来表示常量的构造。在315行,NH.isNull一定是true,否则在前面255行就应该退出这个函数,因此,mergeWith只是把N赋给了NH。最后,还要通过下面的函数把这个常量的信息整合入这些DSNode、DSNodeHandle节点。
1253 void
1254 GraphBuilder::MergeConstantInitIntoNode(DSNodeHandle &NH,
1255 Type*Ty,
1256 Constant *C) {
1257 //
1258 // Ensure atype-record exists...
1259 //
1260 DSNode *NHN = NH.getNode();
1261 //NHN->mergeTypeInfo(Ty,NH.getOffset());
1262
1263 //
1264 // If we've foundsomething of pointer type, create or find its DSNode and
1265 // make a link from the specified DSNode tothe new DSNode describing the
1266 // pointer we'vejust found.
1267 //
1268 if (isa<PointerType>(Ty)) {
1269 NHN->mergeTypeInfo(Ty,NH.getOffset());
1270 NH.addEdgeTo(getValueDest(C));
1271 return;
1272 }
我们在前面314行通过createNode创建这些节点时没有提供类型信息。如果常量C是一个指针类型,在1269行把这个类型信息(Type*)记录到节点中,这需要mergeTypeInfo,因为这个类型信息最终是要保存在GlobalsGraph的TypeSS域中。注意,在1270行C的类型是Constant*(是公共基类),这样它将满足GraphBuilder::getValueDest 273行处的条件,不会陷入无穷递归(llvm自己的类型转换系统允许它们到Constant的转换)。
GraphBuilder::MergeConstantInitIntoNode(续)
1274 //
1275 // If the type ofthe object (array element, structure field, etc.) is an
1276 // integer orfloating point type, then just ignore it. It has no DSNode.
1277 //
1278 if (Ty->isIntOrIntVectorTy() ||Ty->isFPOrFPVectorTy()) return;
1279
1280 //
1281 // Handle aggregateconstants.
1282 //
1283 if (ConstantArray *CA =dyn_cast<ConstantArray>(C)) {
1284 //
1285 // For an array,we don't worry about different elements pointing to
1286 // differentobjects; we essentially pretend that all array elements alias.
1287 //
1288 Type * ElementType =cast<ArrayType>(Ty)->getElementType();
1289 for(unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
1290 Constant * ConstElement = cast<Constant>(CA->getOperand(i));
1291 MergeConstantInitIntoNode(NH,ElementType, ConstElement);
1292 }
1293 } else if (ConstantStruct *CS =dyn_cast<ConstantStruct>(C)) {
1294 //
1295 // For astructure, we need to merge each element of the constant structure
1296 // into thespecified DSNode. However, we must alsohandle structures that
1297 // end with azero-length array ([0 x sbyte]); this is a common C idiom
1298 // that continuesto plague the world.
1299 //
1300 //NHN->mergeTypeInfo(Ty,NH.getOffset());
1301
1302 constStructLayout *SL = TD.getStructLayout(cast<StructType>(Ty));
1303
1304 for(unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
1305 DSNode *NHN = NH.getNode();
1306 if (SL->getElementOffset(i) <SL->getSizeInBytes()) {
1307 //
1308 // Get thetype and constant value of this particular element of the
1309 // constantstructure.
1310 //
1311 Type * ElementType =cast<StructType>(Ty)->getElementType(i);
1312 Constant * ConstElement =cast<Constant>(CS->getOperand(i));
1313
1314 //
1315 // Get theoffset (in bytes) into the memory object that we're
1316 // analyzing.
1317 //
1318 unsigned offset =NH.getOffset()+(unsigned)SL->getElementOffset(i);
1319 NHN->mergeTypeInfo(ElementType,offset);
1320 //
1321 // Create anew DSNodeHandle. This DSNodeHandle willpoint to the same
1322 // DSNode asthe one we're constructing for our caller; however, it
1323 // will pointinto a different offset into that DSNode.
1324 //
1325 DSNodeHandle NewNH (NHN, offset);
1326 assert((NHN->isNodeCompletelyFolded() || (NewNH.getOffset() == offset))
1327 && "Need to resizeDSNode!");
1328
1329 //
1330 //Recursively merge in this element of the constant struture into the
1331 // DSNode.
1332 //
1333 MergeConstantInitIntoNode(NewNH,ElementType, ConstElement);
1334 } else if (SL->getElementOffset(i) ==SL->getSizeInBytes()) {
1335 //
1336 // If this isone of those cute structures that ends with a zero-length
1337 // array, justfold the DSNode now and get it over with.
1338 //
1339 DEBUG(errs() << "Zero sizeelement at end of struct\n" );
1340 NHN->foldNodeCompletely();
1341 } else {
1342 assert(0&& "type was smaller than offsets of struct layoutindicate");
1343 }
1344 }
1345 } else if(isa<ConstantAggregateZero>(C) || isa<UndefValue>(C)) {
1346 //
1347 // Undefinedvalues and NULL pointers have no DSNodes, so they do nothing.
1348 //
1349 } else if(isa<ConstantDataSequential>(C)) {
1350 //
1351 //ConstantDataSequential's are arrays of integers or floats, so they
1352 // have noDSNodes. Nothing to do here.
1353 //
1354 } else {
1355 assert(0&& "Unknown constant type!");
1356 }
1357 }
对于常量数组,因为元素类型都是一样的,我们把所有元素都处理做互为别名。对于常量结构,也是按域逐个处理。注意,常量结构体中不允许以长度为0的数组结尾。