1.3.3.4.1.1.5. 对AtomicCmpXchg指令的处理
AtomicCmpXchg指令是原子性地从内存中载入一个值,与一个给定值比较,如果相等,向该处存入一个新值。同样,访问这个内存的必须是一个指针。在这个指令中,给定值与新值的类型必须
1.3.3.4.1.1.5. 对AtomicCmpXchg指令的处理
AtomicCmpXchg指令是原子性地从内存中载入一个值,与一个给定值比较,如果相等,向该处存入一个新值。同样,访问这个内存的必须是一个指针。在这个指令中,给定值与新值的类型必须相同,是宽度不小于8、不大于平台上限、为2的指数的整数,访问内存的指针必须指向这个类型。不管成功与否,AtomicCmpXchg指令都将返回指针所指向的值,因此AtomicCmpXchg指令的类型是由指针所指向值的类型决定。438~441行比较奇怪,参考visitAtomicRMWInst,似乎应该去掉。
437 voidGraphBuilder::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
438 if (isa<PointerType>(I.getType())) {
439 visitInstruction (I);
440 return;
441 }
442
443 //
444 // Create a DSNodefor the dereferenced pointer . If theDSNode is NULL, do
445 // nothing more(this can occur if the pointer is a NULL constant; bugpoint
446 // can generatesuch code).
447 //
448 DSNodeHandle Ptr = getValueDest(I.getPointerOperand());
449 if (Ptr.isNull()) return;
450
451 //
452 // Make that thememory object is read and written.
453 //
454 Ptr.getNode()->setReadMarker();
455 Ptr.getNode()->setModifiedMarker();
456
457 //
458 // If the result ofthe compare-and-swap is a pointer, then we need to do
459 // a few things:
460 // o Merge the compare and swap values (whichare pointers) with the result
461 // o Merge the DSNode of the pointer *within*the memory object with the
462 // DSNode of the compare, swap, and resultDSNode.
463 //
464 if (isa<PointerType>(I.getType())) {
465 //
466 // Get the DSNodeHandle of the memory objectreturned from the load. Make
467 // it the DSNodeHandle of the instruction'sresult.
468 //
469 DSNodeHandle FieldPtr = getLink (Ptr);
470 setDestTo(I,getLink(Ptr));
471
472 //
473 // Merge the result, compare, and swap valuesof the instruction.
474 //
475 FieldPtr.mergeWith(getValueDest (I.getCompareOperand()));
476 FieldPtr.mergeWith (getValueDest(I.getNewValOperand()));
477 }
478
479 //
480 // Modify theDSNode so that it has the loaded/written type at the
481 // appropriateoffset.
482 //
483 Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset());
484 Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset());
485 return;
486 }
如果指针所指向的值本身也是一个指针类型,该值与给定值及新值构成别名,因此需要把它们指向的对象的DSNode节点进行简并(475~476行)。
1.3.3.4.1.1.6. 对AtomicRMW指令的处理
AtomicRMW指令是原子性地从内存中载入一个值,修改,然后回写。指令返回内存的初值。修改操作由指令的参数指定。
488 void GraphBuilder::visitAtomicRMWInst(AtomicRMWInst&I) {
489 //
490 // Create a DSNodefor the dereferenced pointer . If theDSNode is NULL, do
491 // nothing more(this can occur if the pointer is a NULL constant; bugpoint
492 // can generatesuch code).
493 //
494 DSNodeHandle Ptr = getValueDest(I.getPointerOperand());
495 if (Ptr.isNull()) return;
496
497 //
498 // Make that thememory object is read and written.
499 //
500 Ptr.getNode()->setReadMarker();
501 Ptr.getNode()->setModifiedMarker();
502
503 //
504 // Modify theDSNode so that it has the loaded/written type at the
505 // appropriateoffset.
506 //
507 Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset());
508 Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset());
509 return;
510 }
同样,必须通过一个指针访问这个内存。指针指向对象的类型与指令本身的类型是一致的,但这个内存有可能是结构体的一部分,508行让这个结构体知道这个情况。
1.3.3.4.1.1.7. 对Return指令的处理
这是函数返回值的抽象。514行的FB是这个GraphBuilder所对应的Function实例,如果返回值是一个指针类型,把返回值节点与函数中代表返回语句的节点进行简并。
512 void GraphBuilder::visitReturnInst(ReturnInst&RI) {
513 if (RI.getNumOperands() &&isa<PointerType>(RI.getOperand(0)->getType()))
514 G.getOrCreateReturnNodeFor(*FB).mergeWith(getValueDest(RI.getOperand(0)));
515 }
DSGraph中的成员ReturnNodes(类型std::map<constFunction*, DSNodeHandle>)专门用于保存函数的返回值,上面的getOrCreateReturnNodeFor就是为该函数在ReturnNodes中返回对应的DSNodeHandle,如果不存在就新创建(不过,函数的GraphBuilder在构造函数中已经创建了ReturnNodes)。
显然,如果函数没有返回值(void),ReturnNodes将是空的。
1.3.3.4.1.1.8. 对变长参数的处理
CallSite在llvm中代表调用点。这里是对va_start的调用(va_start是llvm的内置函数,而不是定义为宏,参考clang,va_start被定义为__builtin_va_start)。va_start的一般调用形式为:va_start (ap, param)。
912 void GraphBuilder::visitVAStart(CallSite CS) {
913 // Build outDSNodes for the va_list depending on the target arch
914 // And assosiatethe right node with the VANode for this function
915 // so it can bemerged with the right arguments from callsites
916
917 DSNodeHandle RetNH = getValueDest(CS.getArgument(0));
918
919 if (DSNode *N = RetNH.getNode())
920 visitVAStartNode(N);
921 }
Va_start的第一个参数具有va_list*类型,va_start使得这个参数指向实参列表。上面为ap的实参创建在DSGraph中的代表——DSNode及DSNodeHandle。
在DSGraph中VANodes域专门为每个函数提供变长参数的绑定。VANodes的类型是std::map<const Function*, DSNodeHandle>,getVANodeFor返回在其中与指定Function*关联的DSNodeHandle。
VAArray则是GraphBuilder的成员,初始化为0。每个函数都有自己的GraphBuilder,因此VAArray实例是与函数对应的。它代表可变实参列表。在941行,va_start的ap实参指向了实参列表(VANH是DSNodeHandle,VAArray是DSNode,在DSA算法中DSNodeHandle视为指向DSNode的指针)。
922 void GraphBuilder::visitVAStartNode(DSNode*N) {
923 assert(N&& "Null node as argument");
924 assert(FB&& "No function for this graph?");
925 Module *M = FB->getParent();
926 assert(M&& "No module for function");
927 Triple TargetTriple(M->getTargetTriple());
928 Triple::ArchType Arch =TargetTriple.getArch();
929
930 // Fetch theVANode associated with the func containing the call to va_start
931 DSNodeHandle & VANH =G.getVANodeFor(*FB);
932 // Make sure thisNodeHandle has a node to go with it
933 if (VANH.isNull()) VANH.mergeWith(createNode());
934
935 // Create adsnode for an array of pointers to the VAInfo for this func
936 // We create onesuch array for each function analyzed, as all
937 // calls tova_start will populate their argument with the same data.
938 if (!VAArray) VAArray = createNode();
939 VAArray->setArrayMarker();
940 VAArray->foldNodeCompletely();
941 VAArray->setLink(0,VANH);
942
943 //VAStartmodifies its argument
944 N->setModifiedMarker();
945
946 // For thearchitectures we support, build dsnodes that match
947 // how we knowva_list is used.
948 switch (Arch){
949 caseTriple::x86:
950 // On x86, wehave:
951 // va_list as apointer to an array of pointers to the variable arguments
952 if (N->getSize() < 1)
953 N->growSize(1);
954 N->setLink(0, VAArray);
955 break;
956 caseTriple::x86_64:
957 // On x86_64,we have va_list as a struct {i32, i32, i8*, i8* }
958 // The firsti8* is where arguments generally go, but the second i8* can
959 // be used alsoto pass arguments by register.
960 // We modelthis by having both the i8*'s point to an array of pointers
961 // to thearguments.
962 if (N->getSize() < 24)
963 N->growSize(24); //sizeof the va_list struct mentioned above
964 N->setLink(8,VAArray); //first i8*
965 N->setLink(16,VAArray); //second i8*
966
967 break;
968 default:
969 // FIXME: Fornow we abort if we don't know how to handle this arch
970 // Either addsupport for other architectures, or at least mark the
971 // nodesunknown/incomplete or whichever results in the correct
972 // conservativebehavior in the general case
973 assert(0&& "VAstart not supported on this architecture!");
974 //XXX: Thismight be good enough in those cases that we don't know
975 //what the archdoes
976 N->setIncompleteMarker()->setUnknownMarker()->foldNodeCompletely();
977 }
978
979 // XXX: We usedto set the alloca marker for the DSNode passed to va_start.
980 // Seems to methat you could allocate the va_list on the heap, so ignoring
981 // for now.
982 N->setModifiedMarker()->setVAStartMarker();
983 }
接下来,让ap的实参指向这个实参列表,在这一块DSA目前只支持x86系列机器。对于32位的x86机器,va_list类型是指向变长实参指针数组的指针,而对于64位x86机器,va_list的类型则是{i32, i32, i8*, i8*}。这里的N代表ap的实参,因此952~955,962~965行都是在DSGraph中表示ap实参指向实参列表。
在使用va_start将ap与实参列表绑定后,通过va_arg指令获取下一个指定类型的实参的地址。va_arg指令的语法是:x = va_arg(ap, type)。
517 void GraphBuilder::visitVAArgInst(VAArgInst&I) {
518 Module *M = FB->getParent();
519 Triple TargetTriple(M->getTargetTriple());
520 Triple::ArchType Arch =TargetTriple.getArch();
521 switch(Arch){
522 caseTriple::x86_64: {
523 // On x86_64, wehave va_list as a struct {i32, i32, i8*, i8* }
524 // The first i8* is where argumentsgenerally go, but the second i8* can
525 // be used alsoto pass arguments by register.
526 // We modelthis by having both the i8*'s point to an array of pointers
527 // to thearguments.
528 DSNodeHandle Ptr = G.getVANodeFor(*FB);
529 DSNodeHandle Dest = getValueDest(&I);
530 if (Ptr.isNull()) return;
531
532 // Make thatthe node is read and written
533 Ptr.getNode()->setReadMarker()->setModifiedMarker();
534
535 // Not updatingtype info, as it is already a collapsed node
536
537 if (isa<PointerType>(I.getType()))
538 Dest.mergeWith(Ptr);
539 return;
540 }
541
542 default: {
543 assert(0&& "What frontend generates this?");
544 DSNodeHandle Ptr = getValueDest(I.getOperand(0));
545
546 //FIXME: alsoupdates the argument
547 if (Ptr.isNull()) return;
548
549 // Make thatthe node is read and written
550 Ptr.getNode()->setReadMarker()->setModifiedMarker();
551
552 // Ensure atype record exists.
553 DSNode *PtrN = Ptr.getNode();
554 PtrN->mergeTypeInfo(I.getType(),Ptr.getOffset());
555
556 if (isa<PointerType>(I.getType()))
557 setDestTo(I,getLink(Ptr));
558 }
559 }
560 }
因为前面看到,对于32位x86机器,va_list是指向变长实参指针数组的指针,而且这个数组实际上已经缩合了(visitVAStartNode的940行),因此,在这里不需要进一步的处理。对于64位x86机器,528行的Ptr是前面va_start的ap实参,它已经指向实参列表。在537行,va_arg的类型就是返回的实参的类型,如果该类型是指针,那么它也指向实参列表,这反映在538行与Ptr进行的简并。
而va_end,va_copy则在visitIntrinsic中处理。
1.3.3.4.1.1.9. 对intrinsic指令的处理
Llvm支持intrinsic函数的概念。这些函数都有广为人知的名字及语义,并要求遵循一定的约束。总之,这些intrinsic函数代表了llvm语言的一个扩展机制,在添加入语言(或字节码读写器,解析器等等)时,不需要改变llvm中所有的转换(transformation)。
Llvm定义了如下的intrinsic函数(详情参考llvm语言在线手册):
Llvm.va_start,它的作用与C宏va_start相同。
Llvm.va_end,它的作用与C宏va_end相同,销毁va_start初始化的va_list。
Llvm.va_copy,它的作用与C宏va_copy相同,将源va_list拷贝到目标va_list。
Llvm.returnaddress,它返回表示指定调用框的返回地址的指针,在不能识别时,返回0。这仅用于调试。
Llvm.frameaddress,它返回表示指定调用框的框地址的指针,在不能识别时,返回0。这仅用于调试。
Llvm.stacksave,它返回一个可以传递给llvm.restore的不透明度的指针。当llvm.stackrestore以llvm.stacksave保存的值执行时,它实际上把栈恢复到执行llvm.stacksave时的状态。
Llvm.prefetch,它暗示代码生成器,如果支持,插入一个预取指令。
Llvm.lifetime.start,它表示在代码中该点之前,指定内存的值是无用的。这意味着已知该内存不会被用到且有未定义的值。
Llvm.lifetime.end,它表示在代码中该点之后,指定内存的值是无用的。这意味着已知该内存不会被用到且有未定义的值。
Llvm.invariant.start,它表示直到使用其返回值的llvm.invariant.end,期间所引用的内存位置是不变的。
Llvm.eh.typeid.for,它返回在当前函数异常表中的type info索引。
1000 bool GraphBuilder::visitIntrinsic(CallSiteCS, Function *F) {
1001 ++NumIntrinsicCall;
1002
1003 //
1004 // If this is adebug intrinsic, then don't do any special processing.
1005 //
1006 if(isa<DbgInfoIntrinsic>(CS.getInstruction()))
1007 returntrue;
1008
1009 switch(F->getIntrinsicID()) {
1010 caseIntrinsic::vastart: {
1011 visitVAStart(CS);
1012 returntrue;
1013 }
1014 caseIntrinsic::vacopy: {
1015 // Simply mergethe two arguments to va_copy.
1016 // This resultsin loss of precision on the temporaries used to manipulate
1017 // the va_list,and so isn't a big deal. In theory wewould build a
1018 // separategraph for this (like the one created in visitVAStartNode)
1019 // and onlymerge the node containing the variable arguments themselves.
1020 DSNodeHandle destNH =getValueDest(CS.getArgument(0));
1021 DSNodeHandle srcNH = getValueDest(CS.getArgument(1));
1022 destNH.mergeWith(srcNH);
1023 returntrue;
1024 }
1025 caseIntrinsic::stacksave: {
1026 DSNode * Node = createNode();
1027 Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
1028 Node->foldNodeCompletely();
1029 setDestTo(*(CS.getInstruction()), Node);
1030 returntrue;
1031 }
1032 caseIntrinsic::stackrestore:
1033 getValueDest(CS.getInstruction()).getNode()->setAllocaMarker()
1034 ->setIncompleteMarker()
1035 ->setUnknownMarker()
1036 ->foldNodeCompletely();
1037 returntrue;
1038 caseIntrinsic::vaend:
1039 // TODO: Whatto do here?
1040 returntrue;
1041 caseIntrinsic::memcpy:
1042 caseIntrinsic::memmove: {
1043 // Merge thefirst & second arguments, and mark the memory read and
1044 // modified.
1045 DSNodeHandle RetNH = getValueDest(CS.getArgument(0));
1046 RetNH.mergeWith(getValueDest(CS.getArgument(1)));
1047 if (DSNode *N = RetNH.getNode())
1048 N->setModifiedMarker()->setReadMarker();
1049 returntrue;
1050 }
1051 caseIntrinsic::memset:
1052 // Mark thememory modified.
1053 if (DSNode *N = getValueDest(CS.getArgument(0)).getNode())
1054 N->setModifiedMarker();
1055 returntrue;
1056
1057 // TODO: Addsupport for the new EH system
1058 #if 0
1059 case Intrinsic::eh_exception: {
1060 DSNode * Node = createNode();
1061 Node->setIncompleteMarker();
1062 Node->foldNodeCompletely();
1063 setDestTo (*(CS.getInstruction()), Node);
1064 return true;
1065 }
1066
1067 case Intrinsic::eh_selector: {
1068 for (CallSite::arg_iterator I =CS.arg_begin(), E = CS.arg_end();
1069 I != E; ++I) {
1070 if(isa<PointerType>((*I)->getType())) {
1071 DSNodeHandle Ptr = getValueDest(*I);
1072 if(Ptr.getNode()) {
1073 Ptr.getNode()->setReadMarker();
1074 Ptr.getNode()->setIncompleteMarker();
1075 }
1076 }
1077 }
1078 return true;
1079 }
1080 #endif
1081
1082 caseIntrinsic::eh_typeid_for: {
1083 DSNodeHandle Ptr = getValueDest(CS.getArgument(0));
1084 Ptr.getNode()->setReadMarker();
1085 Ptr.getNode()->setIncompleteMarker();
1086 returntrue;
1087 }
1088
1089 caseIntrinsic::prefetch:
1090 returntrue;
1091
1092 caseIntrinsic::objectsize:
1093 returntrue;
1094
1095 //
1096 // The returnaddress/frame address aliases with the stack,
1097 // istype-unknown, and should
1098 // have theunknown flag set since we don't know where it goes.
1099 //
1100 caseIntrinsic::returnaddress:
1101 caseIntrinsic::frameaddress: {
1102 DSNode * Node = createNode();
1103 Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
1104 Node->foldNodeCompletely();
1105 setDestTo(*(CS.getInstruction()), Node);
1106 returntrue;
1107 }
1108
1109 // Process lifetime intrinsics
1110 caseIntrinsic::lifetime_start:
1111 caseIntrinsic::lifetime_end:
1112 caseIntrinsic::invariant_start:
1113 caseIntrinsic::invariant_end:
1114 returntrue;
1115
1116 default: {
1117 //ignorepointer free intrinsics
1118 if (!isa<PointerType>(F->getReturnType())){
1119 bool hasPtr = false;
1120 for(Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
1121 I != E && !hasPtr; ++I)
1122 if(isa<PointerType>(I->getType()))
1123 hasPtr = true;
1124 if (!hasPtr)
1125 returntrue;
1126 }
1127
1128 DEBUG(errs() << "[dsa:local]Unhandled intrinsic: " << F->getName() << "\n");
1129 assert(0&& "Unhandled intrinsic");
1130 returnfalse;
1131 }
1132 }
1133 }
注意1033行,llvm.stackrestore被视为通过alloca从栈上分配。
1.3.3.4.1.1.10. 对整数ßà指针指令的处理
IntToPtrInst代表把一个整数转换到一个指针。由于Value是IntToPtrInst的基类之一,如果这个Value只有一个用户(llvm的User类),hasOneUse返回true。如果该用户是ICmpInst——整数/指针比较语句,那么566行的NumBoringIntToPtr用于统计这种事件。在其他情况,由于得到的指针所指向的内存对象未知,在571行进行标记。
562 void GraphBuilder::visitIntToPtrInst(IntToPtrInst&I) {
563 DSNode *N = createNode();
564 if(I.hasOneUse()) {
565 if(isa<ICmpInst>(*(I.use_begin()))) {
566 NumBoringIntToPtr++;
567 return;
568 }
569 } else {
570 N->setIntToPtrMarker();
571 N->setUnknownMarker();
572 }
573 setDestTo(I,N);
574 }
类似的,PtrToIntInst代表把一个指针转换到一个整数。586行的DenseSet是llvm定义的容器,其在588行的insert方法返回std::pair<iterator, bool>,在插入成功或对象已在容器中时,返回pair的第二个元素是true。那么587行while循环的作用就是沿着用户链,发掘类型为BranchInst的用户,进行统计。NumBoringIntToPtr统记了仅用在cmp的inttoptr的数目。
576 void GraphBuilder::visitPtrToIntInst(PtrToIntInst&I) {
577 DSNode* N = getValueDest(I.getOperand(0)).getNode();
578 if(I.hasOneUse()) {
579 if(isa<ICmpInst>(*(I.use_begin()))) {
580 NumBoringIntToPtr++;
581 return;
582 }
583 }
584 if(I.hasOneUse()) {
585 Value *V = dyn_cast<Value>(*(I.use_begin()));
586 DenseSet<Value *> Seen;
587 while(V&& V->hasOneUse() &&
588 Seen.insert(V).second) {
589 if(isa<LoadInst>(V))
590 break;
591 if(isa<StoreInst>(V))
592 break;
593 if(isa<CallInst>(V))
594 break;
595 V =dyn_cast<Value>(*(V->use_begin()));
596 }
597 if(isa<BranchInst>(V)){
598 NumBoringIntToPtr++;
599 return;
600 }
601 }
602 if(N)
603 N->setPtrToIntMarker();
604 }
1.3.3.4.1.1.11. 对bitcast指令的处理
BitCastInst代表一个空操作转换,因为这个转换没有比特位的改变。显然对于DSA,这个转换在涉及指针时才有价值。
607 void GraphBuilder::visitBitCastInst(BitCastInst&I) {
608 if (!isa<PointerType>(I.getType())) return; // Only pointers
609 DSNodeHandle Ptr = getValueDest(I.getOperand(0));
610 if (Ptr.isNull()) return;
611 setDestTo(I,Ptr);
612 }
1.3.3.4.1.1.12. 对insertvalue指令的处理
InsertValueInst向一个聚集类型(struct/class/union或数组)值的一个数据成员插入值,并返回更新后的聚集类型值。InsertValueInst带至少三个参数,第一个是聚集类型值,第二个是插入的值,第三个是指示插入位置的常量。
648 void GraphBuilder::visitInsertValueInst(InsertValueInst&I) {
649 setDestTo(I,createNode()->setAllocaMarker());
650
651 Type *StoredTy =I.getInsertedValueOperand()->getType();
652 DSNodeHandle Dest = getValueDest(&I);
653 Dest.mergeWith(getValueDest(I.getAggregateOperand()));
654
655 // Mark that thenode is written to...
656 Dest.getNode()->setModifiedMarker();
657 Type* STy =I.getAggregateOperand()->getType();
658
659 unsigned Offset = getValueOffset(STy,I.getIndices(), TD);
660
661 // Ensure atype-record exists...
662 Dest.getNode()->mergeTypeInfo(StoredTy, Offset);
663
664 // Avoid addingedges from null, or processing non-"pointer" stores
665 if (isa<PointerType>(StoredTy))
666 Dest.addEdgeTo(getValueDest(I.getInsertedValueOperand()));
667 }
在649行,为InsertValueInst创建了DSNodeHandle,并指向同一行构建的标记为alloca的DSNode(代表其在栈上构建的返回值)。这个DSNodeHandle在652行通过getValueDesc给出。接着在653行,它与第一个参数的节点发生了简并(因为它们的指针域都要指向相同的地方)。因为llvm IR要求操作数的类型必须严格匹配,因此662行确保要保存的值的类型存在于结构体指定的位置上(至于这个位置所代表的多个类型是否相容就是另一个问题了)。最后,如果插入的值是个指针,在666行让Dest有指向该指针指向对象的一条边。
1.3.3.4.1.1.13. 对extractvalue指令的处理
ExtractValueInst则是InsertValueInst的相反操作——从一个聚集类型值的指定域提取值。它也类似地带至少三个参数,第一个是聚集类型值,第二个是提取的值,第三个是指示提取位置的常量。
669 void GraphBuilder::visitExtractValueInst(ExtractValueInst&I) {
670 DSNodeHandle Ptr = getValueDest(I.getAggregateOperand());
671
672 // Make that thenode is read from...
673 Ptr.getNode()->setReadMarker();
674 Type* STy =I.getAggregateOperand()->getType();
675
676 unsigned Offset = getValueOffset(STy,I.getIndices(), TD);
677
678 // Ensure atyperecord exists...
679 Ptr.getNode()->mergeTypeInfo(I.getType(), Offset);
680
681 if (isa<PointerType>(I.getType()))
682 setDestTo(I,getLink(Ptr));
683 }
这里的处理与InsertValueInst类似,且更简单。
1.3.3.4.1.1.14. 对GetElementPtr指令的处理
参考1.3.3.2.2.2. 对GetElementPtr指令的处理一节。
1.3.3.4.1.1.15. 对调用指令的处理
在llvm IR中,CallInst来自call指令,InvokeInst来自invoke指令。两者都是对函数的调用,主要的区别在于,invoke指令会创建与一个标记的关联,该关联被运行时用于回滚栈。不过,对于DSA这两者没有区别。
904 void GraphBuilder::visitCallInst(CallInst&CI) {
904 visitCallSite(&CI);
904 }
904 void GraphBuilder::visitInvokeInst(InvokeInst&II) {
904 visitCallSite(&II);
904 }
要以相同的方式处理CallInst及InvokeInst,就要用到CallSite。它是llvm专门提供的一个便利的封装类。Intrinsic函数由1143行的visitIntrinsic处理。而对于内联汇编函数,采用保守的处理,把所有的指针视为互为别名,进行简并,并缩合返回值节点,如果它是指针。
1135 void GraphBuilder::visitCallSite(CallSite CS){
1136 //
1137 // Get the calledvalue. Strip off any casts which arelossless.
1138 //
1139 Value *Callee =CS.getCalledValue()->stripPointerCasts();
1140
1141 // Special case handlingof certain libc allocation functions here.
1142 if (Function *F =dyn_cast<Function>(Callee))
1143 if (F->isIntrinsic() && visitIntrinsic(CS, F))
1144 return;
1145
1146 //Can't do muchabout inline asm (yet!)
1147 if (isa<InlineAsm> (Callee)) {
1148 ++NumAsmCall;
1149 DSNodeHandle RetVal;
1150 Instruction *I = CS.getInstruction();
1151 if (isa<PointerType >(I->getType()))
1152 RetVal = getValueDest(I);
1153
1154 // Calculatethe arguments vector...
1155 for(CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I)
1156 if (isa<PointerType >((*I)->getType()))
1157 RetVal.mergeWith(getValueDest(*I));
1158 if (!RetVal.isNull())
1159 RetVal.getNode()->foldNodeCompletely();
1160 return;
1161 }
1162
1163 // Set up thereturn value...
1164 DSNodeHandle RetVal;
1165 Instruction *I = CS.getInstruction();
1166 if (isa<PointerType>(I->getType()))
1167 RetVal = getValueDest(I);
1168
1169 DSNode *CalleeNode = 0;
1170 if (!isa<Function>(Callee)) {
1171 CalleeNode = getValueDest(Callee).getNode();
1172 if (CalleeNode == 0) {
1173 DEBUG(errs() << "WARNING:Program is calling through a null pointer?\n" << *I);
1174 return; // Calling a nullpointer?
1175 }
1176 }
1177
1178 // NOTE: Thiscode is identical to 'DSGraph::getDSCallSiteForCallSite',
1179 // the reasonit's duplicated is because this calls getValueDest instead
1180 // ofgetNodeForValue to get the DSNodes for the arguments. Since we're in
1181 // local it'spossible that we need to create a DSNode for the argument, as
1182 // opposed togetNodeForValue which simply retrieves the existing node.
1183
1184
1185 //Get theFunctionType for the called function
1186 constFunctionType *CalleeFuncType = DSCallSite::FunctionTypeOfCallSite(CS);
1187 int NumFixedArgs =CalleeFuncType->getNumParams();
1188
1189 // Sanitycheck--this really, really shouldn't happen
1190 if (!CalleeFuncType->isVarArg())
1191 assert(CS.arg_size()== static_cast<unsigned>(NumFixedArgs)&&
1192 "Too many arguments/incorrectfunction signature!");
1193
1194 std::vector<DSNodeHandle> Args;
1195 Args.reserve(CS.arg_size());
1196 DSNodeHandle VarArgNH;
1197
1198 // Calculate thearguments vector...
1199 // Add all fixedpointer arguments, then merge the rest together
1200 for(CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
1201 I != E; ++I)
1202 if(isa<PointerType>((*I)->getType())) {
1203 DSNodeHandle ArgNode = getValueDest(*I);
1204 if (I - CS.arg_begin() < NumFixedArgs){
1205 Args.push_back(ArgNode);
1206 } else {
1207 VarArgNH.mergeWith(ArgNode);
1208 }
1209 }
1210
1211 // Add a newfunction call entry...
1212 if (CalleeNode) {
1213 ++NumIndirectCall;
1214 G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH,CalleeNode,
1215 Args));
1216 } else {
1217 ++NumDirectCall;
1218 G.getFunctionCalls().push_back(DSCallSite(CS,RetVal, VarArgNH,
1219 cast<Function>(Callee),
1220 Args));
1221 }
1222
1223
1224 }
在DSGraph值专门有一个域FunctionCalls记录有关函数调用的DSA节点。这个域的类型是std::list<DSCallSite>,而类型DSCallSite有如下成员:
160 typedefstd::set<CallSite> MappedSites_t;
161 private:
162 CallSite Site; //Actual call site
163 constFunction *CalleeF; // The functioncalled (direct call)
164 DSNodeHandle CalleeN; // Thefunction node called (indirect call)
165 DSNodeHandle RetVal; //Returned value
166 DSNodeHandle VarArgVal; // Mergedvar-arg val
167 std::vector<DSNodeHandle> CallArgs; // The pointer arguments
168 MappedSites_t MappedSites; // Themerged callsites
这些成员的含义,注释已经说得很清楚。1214及1218行调用了下面这两个构造函数:
199 DSCallSite(CallSite CS, const DSNodeHandle &rv, constDSNodeHandle &va,
200 DSNode *Callee,std::vector<DSNodeHandle> &Args)
201 : Site(CS), CalleeF(0), CalleeN(Callee),RetVal(rv), VarArgVal(va) {
202 assert(Callee&& "Null callee node specified for call site!");
203 Args.swap(CallArgs);
204 }
205 DSCallSite(CallSite CS, const DSNodeHandle &rv, constDSNodeHandle &va,
206 constFunction *Callee, std::vector<DSNodeHandle> &Args)
207 : Site(CS), CalleeF(Callee), RetVal(rv),VarArgVal(va) {
208 assert(Callee&& "Null callee function specified for call site!");
209 Args.swap(CallArgs);
210 }
在1214行CalleeNode被设置到CalleeN,而在1218行,Callee被设置到CalleeF。
1.3.3.4.1.1.16. 对其他指令的处理
根据基类InstVisitor的安排,所有没有重载的visit*函数,都最终会进入visitInstruction函数。对于DSA,只关心Inst的类型。如果它是指针类型,意味着其返回值与其指针类型的操作数可能互为别名,于是将它们简并起来。
1229 void GraphBuilder::visitInstruction(Instruction&Inst) {
1230 DSNodeHandle CurNode;
1231 if (isa<PointerType>(Inst.getType()))
1232 CurNode = getValueDest(&Inst);
1233 for(User::op_iterator I = Inst.op_begin(), E = Inst.op_end(); I != E; ++I)
1234 if(isa<PointerType>((*I)->getType()))
1235 CurNode.mergeWith(getValueDest(*I));
1236
1237 if (DSNode *N = CurNode.getNode())
1238 N->setUnknownMarker();
1239 }
如果CurNode不是指向null,把这个DSNode标记为unknown,而不是Incomplete。这是Chris在论文中强调过的。
相同,是宽度不小于8、不大于平台上限、为2的指数的整数,访问内存的指针必须指向这个类型。不管成功与否,AtomicCmpXchg指令都将返回指针所指向的值,因此AtomicCmpXchg指令的类型是由指针所指向值的类型决定。438~441行比较奇怪,参考visitAtomicRMWInst,似乎应该去掉 。
437 voidGraphBuilder::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
438 if (isa<PointerType>(I.getType())) {
439 visitInstruction (I);
440 return;
441 }
442
443 //
444 // Create a DSNodefor the dereferenced pointer . If theDSNode is NULL, do
445 // nothing more(this can occur if the pointer is a NULL constant; bugpoint
446 // can generatesuch code).
447 //
448 DSNodeHandle Ptr = getValueDest(I.getPointerOperand());
449 if (Ptr.isNull()) return;
450
451 //
452 // Make that thememory object is read and written.
453 //
454 Ptr.getNode()->setReadMarker();
455 Ptr.getNode()->setModifiedMarker();
456
457 //
458 // If the result ofthe compare-and-swap is a pointer, then we need to do
459 // a few things:
460 // o Merge the compare and swap values (whichare pointers) with the result
461 // o Merge the DSNode of the pointer *within*the memory object with the
462 // DSNode of the compare, swap, and resultDSNode.
463 //
464 if (isa<PointerType>(I.getType())) {
465 //
466 // Get the DSNodeHandle of the memory objectreturned from the load. Make
467 // it the DSNodeHandle of the instruction'sresult.
468 //
469 DSNodeHandle FieldPtr = getLink (Ptr);
470 setDestTo(I,getLink(Ptr));
471
472 //
473 // Merge the result, compare, and swap valuesof the instruction.
474 //
475 FieldPtr.mergeWith(getValueDest (I.getCompareOperand()));
476 FieldPtr.mergeWith (getValueDest(I.getNewValOperand()));
477 }
478
479 //
480 // Modify theDSNode so that it has the loaded/written type at the
481 // appropriateoffset.
482 //
483 Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset());
484 Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset());
485 return;
486 }
如果指针所指向的值本身也是一个指针类型,该值与给定值及新值构成别名,因此需要把它们指向的对象的DSNode节点进行简并(475~476行)。
1.3.3.4.1.1.6. 对AtomicRMW指令的处理
AtomicRMW指令是原子性地从内存中载入一个值,修改,然后回写。指令返回内存的初值。修改操作由指令的参数指定。
488 void GraphBuilder::visitAtomicRMWInst(AtomicRMWInst&I) {
489 //
490 // Create a DSNodefor the dereferenced pointer . If theDSNode is NULL, do
491 // nothing more(this can occur if the pointer is a NULL constant; bugpoint
492 // can generatesuch code).
493 //
494 DSNodeHandle Ptr = getValueDest(I.getPointerOperand());
495 if (Ptr.isNull()) return;
496
497 //
498 // Make that thememory object is read and written.
499 //
500 Ptr.getNode()->setReadMarker();
501 Ptr.getNode()->setModifiedMarker();
502
503 //
504 // Modify theDSNode so that it has the loaded/written type at the
505 // appropriateoffset.
506 //
507 Ptr.getNode()->growSizeForType(I.getType(), Ptr.getOffset());
508 Ptr.getNode()->mergeTypeInfo(I.getType(), Ptr.getOffset());
509 return;
510 }
同样,必须通过一个指针访问这个内存。指针指向对象的类型与指令本身的类型是一致的,但这个内存有可能是结构体的一部分,508行让这个结构体知道这个情况。
1.3.3.4.1.1.7. 对Return指令的处理
这是函数返回值的抽象。514行的FB是这个GraphBuilder所对应的Function实例,如果返回值是一个指针类型,把返回值节点与函数中代表返回语句的节点进行简并。
512 void GraphBuilder::visitReturnInst(ReturnInst&RI) {
513 if (RI.getNumOperands() &&isa<PointerType>(RI.getOperand(0)->getType()))
514 G.getOrCreateReturnNodeFor(*FB).mergeWith(getValueDest(RI.getOperand(0)));
515 }
DSGraph中的成员ReturnNodes(类型std::map<constFunction*, DSNodeHandle>)专门用于保存函数的返回值,上面的getOrCreateReturnNodeFor就是为该函数在ReturnNodes中返回对应的DSNodeHandle,如果不存在就新创建(不过,函数的GraphBuilder在构造函数中已经创建了ReturnNodes)。
显然,如果函数没有返回值(void),ReturnNodes将是空的。
1.3.3.4.1.1.8. 对变长参数的处理
CallSite在llvm中代表调用点。这里是对va_start的调用(va_start是llvm的内置函数,而不是定义为宏,参考clang,va_start被定义为__builtin_va_start)。va_start的一般调用形式为:va_start (ap, param)。
912 void GraphBuilder::visitVAStart(CallSite CS) {
913 // Build outDSNodes for the va_list depending on the target arch
914 // And assosiatethe right node with the VANode for this function
915 // so it can bemerged with the right arguments from callsites
916
917 DSNodeHandle RetNH = getValueDest(CS.getArgument(0));
918
919 if (DSNode *N = RetNH.getNode())
920 visitVAStartNode(N);
921 }
Va_start的第一个参数具有va_list*类型,va_start使得这个参数指向实参列表。上面为ap的实参创建在DSGraph中的代表——DSNode及DSNodeHandle。
在DSGraph中VANodes域专门为每个函数提供变长参数的绑定。VANodes的类型是std::map<const Function*, DSNodeHandle>,getVANodeFor返回在其中与指定Function*关联的DSNodeHandle。
VAArray则是GraphBuilder的成员,初始化为0。每个函数都有自己的GraphBuilder,因此VAArray实例是与函数对应的。它代表可变实参列表。在941行,va_start的ap实参指向了实参列表(VANH是DSNodeHandle,VAArray是DSNode,在DSA算法中DSNodeHandle视为指向DSNode的指针)。
922 void GraphBuilder::visitVAStartNode(DSNode*N) {
923 assert(N&& "Null node as argument");
924 assert(FB&& "No function for this graph?");
925 Module *M = FB->getParent();
926 assert(M&& "No module for function");
927 Triple TargetTriple(M->getTargetTriple());
928 Triple::ArchType Arch =TargetTriple.getArch();
929
930 // Fetch theVANode associated with the func containing the call to va_start
931 DSNodeHandle & VANH =G.getVANodeFor(*FB);
932 // Make sure thisNodeHandle has a node to go with it
933 if (VANH.isNull()) VANH.mergeWith(createNode());
934
935 // Create adsnode for an array of pointers to the VAInfo for this func
936 // We create onesuch array for each function analyzed, as all
937 // calls tova_start will populate their argument with the same data.
938 if (!VAArray) VAArray = createNode();
939 VAArray->setArrayMarker();
940 VAArray->foldNodeCompletely();
941 VAArray->setLink(0,VANH);
942
943 //VAStartmodifies its argument
944 N->setModifiedMarker();
945
946 // For thearchitectures we support, build dsnodes that match
947 // how we knowva_list is used.
948 switch (Arch){
949 caseTriple::x86:
950 // On x86, wehave:
951 // va_list as apointer to an array of pointers to the variable arguments
952 if (N->getSize() < 1)
953 N->growSize(1);
954 N->setLink(0, VAArray);
955 break;
956 caseTriple::x86_64:
957 // On x86_64,we have va_list as a struct {i32, i32, i8*, i8* }
958 // The firsti8* is where arguments generally go, but the second i8* can
959 // be used alsoto pass arguments by register.
960 // We modelthis by having both the i8*'s point to an array of pointers
961 // to thearguments.
962 if (N->getSize() < 24)
963 N->growSize(24); //sizeof the va_list struct mentioned above
964 N->setLink(8,VAArray); //first i8*
965 N->setLink(16,VAArray); //second i8*
966
967 break;
968 default:
969 // FIXME: Fornow we abort if we don't know how to handle this arch
970 // Either addsupport for other architectures, or at least mark the
971 // nodesunknown/incomplete or whichever results in the correct
972 // conservativebehavior in the general case
973 assert(0&& "VAstart not supported on this architecture!");
974 //XXX: Thismight be good enough in those cases that we don't know
975 //what the archdoes
976 N->setIncompleteMarker()->setUnknownMarker()->foldNodeCompletely();
977 }
978
979 // XXX: We usedto set the alloca marker for the DSNode passed to va_start.
980 // Seems to methat you could allocate the va_list on the heap, so ignoring
981 // for now.
982 N->setModifiedMarker()->setVAStartMarker();
983 }
接下来,让ap的实参指向这个实参列表,在这一块DSA目前只支持x86系列机器。对于32位的x86机器,va_list类型是指向变长实参指针数组的指针,而对于64位x86机器,va_list的类型则是{i32, i32, i8*, i8*}。这里的N代表ap的实参,因此952~955,962~965行都是在DSGraph中表示ap实参指向实参列表。
在使用va_start将ap与实参列表绑定后,通过va_arg指令获取下一个指定类型的实参的地址。va_arg指令的语法是:x = va_arg(ap, type)。
517 void GraphBuilder::visitVAArgInst(VAArgInst&I) {
518 Module *M = FB->getParent();
519 Triple TargetTriple(M->getTargetTriple());
520 Triple::ArchType Arch =TargetTriple.getArch();
521 switch(Arch){
522 caseTriple::x86_64: {
523 // On x86_64, wehave va_list as a struct {i32, i32, i8*, i8* }
524 // The first i8* is where argumentsgenerally go, but the second i8* can
525 // be used alsoto pass arguments by register.
526 // We modelthis by having both the i8*'s point to an array of pointers
527 // to thearguments.
528 DSNodeHandle Ptr = G.getVANodeFor(*FB);
529 DSNodeHandle Dest = getValueDest(&I);
530 if (Ptr.isNull()) return;
531
532 // Make thatthe node is read and written
533 Ptr.getNode()->setReadMarker()->setModifiedMarker();
534
535 // Not updatingtype info, as it is already a collapsed node
536
537 if (isa<PointerType>(I.getType()))
538 Dest.mergeWith(Ptr);
539 return;
540 }
541
542 default: {
543 assert(0&& "What frontend generates this?");
544 DSNodeHandle Ptr = getValueDest(I.getOperand(0));
545
546 //FIXME: alsoupdates the argument
547 if (Ptr.isNull()) return;
548
549 // Make thatthe node is read and written
550 Ptr.getNode()->setReadMarker()->setModifiedMarker();
551
552 // Ensure atype record exists.
553 DSNode *PtrN = Ptr.getNode();
554 PtrN->mergeTypeInfo(I.getType(),Ptr.getOffset());
555
556 if (isa<PointerType>(I.getType()))
557 setDestTo(I,getLink(Ptr));
558 }
559 }
560 }
因为前面看到,对于32位x86机器,va_list是指向变长实参指针数组的指针,而且这个数组实际上已经缩合了(visitVAStartNode的940行),因此,在这里不需要进一步的处理。对于64位x86机器,528行的Ptr是前面va_start的ap实参,它已经指向实参列表。在537行,va_arg的类型就是返回的实参的类型,如果该类型是指针,那么它也指向实参列表,这反映在538行与Ptr进行的简并。
而va_end,va_copy则在visitIntrinsic中处理。
1.3.3.4.1.1.9. 对intrinsic指令的处理
Llvm支持intrinsic函数的概念。这些函数都有广为人知的名字及语义,并要求遵循一定的约束。总之,这些intrinsic函数代表了llvm语言的一个扩展机制,在添加入语言(或字节码读写器,解析器等等)时,不需要改变llvm中所有的转换(transformation)。
Llvm定义了如下的intrinsic函数(详情参考llvm语言在线手册):
Llvm.va_start,它的作用与C宏va_start相同。
Llvm.va_end,它的作用与C宏va_end相同,销毁va_start初始化的va_list。
Llvm.va_copy,它的作用与C宏va_copy相同,将源va_list拷贝到目标va_list。
Llvm.returnaddress,它返回表示指定调用框的返回地址的指针,在不能识别时,返回0。这仅用于调试。
Llvm.frameaddress,它返回表示指定调用框的框地址的指针,在不能识别时,返回0。这仅用于调试。
Llvm.stacksave,它返回一个可以传递给llvm.restore的不透明度的指针。当llvm.stackrestore以llvm.stacksave保存的值执行时,它实际上把栈恢复到执行llvm.stacksave时的状态。
Llvm.prefetch,它暗示代码生成器,如果支持,插入一个预取指令。
Llvm.lifetime.start,它表示在代码中该点之前,指定内存的值是无用的。这意味着已知该内存不会被用到且有未定义的值。
Llvm.lifetime.end,它表示在代码中该点之后,指定内存的值是无用的。这意味着已知该内存不会被用到且有未定义的值。
Llvm.invariant.start,它表示直到使用其返回值的llvm.invariant.end,期间所引用的内存位置是不变的。
Llvm.eh.typeid.for,它返回在当前函数异常表中的type info索引。
1000 bool GraphBuilder::visitIntrinsic(CallSiteCS, Function *F) {
1001 ++NumIntrinsicCall;
1002
1003 //
1004 // If this is adebug intrinsic, then don't do any special processing.
1005 //
1006 if(isa<DbgInfoIntrinsic>(CS.getInstruction()))
1007 returntrue;
1008
1009 switch(F->getIntrinsicID()) {
1010 caseIntrinsic::vastart: {
1011 visitVAStart(CS);
1012 returntrue;
1013 }
1014 caseIntrinsic::vacopy: {
1015 // Simply mergethe two arguments to va_copy.
1016 // This resultsin loss of precision on the temporaries used to manipulate
1017 // the va_list,and so isn't a big deal. In theory wewould build a
1018 // separategraph for this (like the one created in visitVAStartNode)
1019 // and onlymerge the node containing the variable arguments themselves.
1020 DSNodeHandle destNH =getValueDest(CS.getArgument(0));
1021 DSNodeHandle srcNH = getValueDest(CS.getArgument(1));
1022 destNH.mergeWith(srcNH);
1023 returntrue;
1024 }
1025 caseIntrinsic::stacksave: {
1026 DSNode * Node = createNode();
1027 Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
1028 Node->foldNodeCompletely();
1029 setDestTo(*(CS.getInstruction()), Node);
1030 returntrue;
1031 }
1032 caseIntrinsic::stackrestore:
1033 getValueDest(CS.getInstruction()).getNode()->setAllocaMarker()
1034 ->setIncompleteMarker()
1035 ->setUnknownMarker()
1036 ->foldNodeCompletely();
1037 returntrue;
1038 caseIntrinsic::vaend:
1039 // TODO: Whatto do here?
1040 returntrue;
1041 caseIntrinsic::memcpy:
1042 caseIntrinsic::memmove: {
1043 // Merge thefirst & second arguments, and mark the memory read and
1044 // modified.
1045 DSNodeHandle RetNH = getValueDest(CS.getArgument(0));
1046 RetNH.mergeWith(getValueDest(CS.getArgument(1)));
1047 if (DSNode *N = RetNH.getNode())
1048 N->setModifiedMarker()->setReadMarker();
1049 returntrue;
1050 }
1051 caseIntrinsic::memset:
1052 // Mark thememory modified.
1053 if (DSNode *N = getValueDest(CS.getArgument(0)).getNode())
1054 N->setModifiedMarker();
1055 returntrue;
1056
1057 // TODO: Addsupport for the new EH system
1058 #if 0
1059 case Intrinsic::eh_exception: {
1060 DSNode * Node = createNode();
1061 Node->setIncompleteMarker();
1062 Node->foldNodeCompletely();
1063 setDestTo (*(CS.getInstruction()), Node);
1064 return true;
1065 }
1066
1067 case Intrinsic::eh_selector: {
1068 for (CallSite::arg_iterator I =CS.arg_begin(), E = CS.arg_end();
1069 I != E; ++I) {
1070 if(isa<PointerType>((*I)->getType())) {
1071 DSNodeHandle Ptr = getValueDest(*I);
1072 if(Ptr.getNode()) {
1073 Ptr.getNode()->setReadMarker();
1074 Ptr.getNode()->setIncompleteMarker();
1075 }
1076 }
1077 }
1078 return true;
1079 }
1080 #endif
1081
1082 caseIntrinsic::eh_typeid_for: {
1083 DSNodeHandle Ptr = getValueDest(CS.getArgument(0));
1084 Ptr.getNode()->setReadMarker();
1085 Ptr.getNode()->setIncompleteMarker();
1086 returntrue;
1087 }
1088
1089 caseIntrinsic::prefetch:
1090 returntrue;
1091
1092 caseIntrinsic::objectsize:
1093 returntrue;
1094
1095 //
1096 // The returnaddress/frame address aliases with the stack,
1097 // istype-unknown, and should
1098 // have theunknown flag set since we don't know where it goes.
1099 //
1100 caseIntrinsic::returnaddress:
1101 caseIntrinsic::frameaddress: {
1102 DSNode * Node = createNode();
1103 Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
1104 Node->foldNodeCompletely();
1105 setDestTo(*(CS.getInstruction()), Node);
1106 returntrue;
1107 }
1108
1109 // Process lifetime intrinsics
1110 caseIntrinsic::lifetime_start:
1111 caseIntrinsic::lifetime_end:
1112 caseIntrinsic::invariant_start:
1113 caseIntrinsic::invariant_end:
1114 returntrue;
1115
1116 default: {
1117 //ignorepointer free intrinsics
1118 if (!isa<PointerType>(F->getReturnType())){
1119 bool hasPtr = false;
1120 for(Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
1121 I != E && !hasPtr; ++I)
1122 if(isa<PointerType>(I->getType()))
1123 hasPtr = true;
1124 if (!hasPtr)
1125 returntrue;
1126 }
1127
1128 DEBUG(errs() << "[dsa:local]Unhandled intrinsic: " << F->getName() << "\n");
1129 assert(0&& "Unhandled intrinsic");
1130 returnfalse;
1131 }
1132 }
1133 }
注意1033行,llvm.stackrestore被视为通过alloca从栈上分配。