dsa算法(9)

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从栈上分配。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值