dsa算法(11)

来源:互联网 发布:台湾误发导弹 知乎 编辑:程序博客网 时间:2024/04/30 14:34
1.3.3.4.1.2. 导入全局常量

全局对象是程序范围内唯一的,但在DSA中为了效率上的考虑,分为了全局图与函数图。函数通常会访问(部分的)全局对象,因此函数图中也会有相应的DSNode来表示。但出于不同的角度,同一个全局对象在两者看来可能是不一样的,因此我们需要一个操作,使得同一个全局对象对于两者有相同的DSNode。这正是下面要做的,不过只是第一步——针对常量。后面还会有其他的操作。

我们知道DSGraph的ScalarMap记录在一个函数中所引用的所有DSNode。它的ValueMap域专门记录引用的所有对象及其关联的DSNodeHandler,GlobalSet则记录了该图引用的全局对象。185行的global_begin就是返回GlobalSet的第一条记录。

 

GraphBuilder:: GraphBuilder(续)

 

179          // If there areany constant globals referenced in this function, merge

180          // theirinitializers into the local graph from the globals graph.

181          // Thisresolves indirect calls in some common cases

182          // Only mergeinfo for nodes that already exist in the local pass

183          // otherwiseleaf functions could contain less collapsing than the globals

184          // graph

185          if (g.getScalarMap().global_begin() !=g.getScalarMap().global_end()) {

186            ReachabilityCloner RC(&g,g.getGlobalsGraph(), 0);

187            for(DSScalarMap::global_iterator I = g.getScalarMap().global_begin(),

188                 E = g.getScalarMap().global_end();I != E; ++I) {

189              if (constGlobalVariable * GV = dyn_cast<GlobalVariable > (*I))

190                if (GV->isConstant())

191                  RC.merge(g.getNodeForValue(GV),g.getGlobalsGraph()->getNodeForValue(GV));

192            }

193          }

 

这里,我们没有选择让全局图及函数图共享DSNode,而是让它们持有独立但相同的DSNode。这涉及DSNode的克隆及克隆节点间的简并,ReachabilityCloner提供这样的操作。其最重要的成员是NodeMap,类型为std::map<const DSNode*, DSNodeHandle>,第一部分保存源图的DSNode地址,第二部分保存目标图中援引与第一部分保存的DSNode对应的简并后DSNode的DSNodeHandle。在186行首先构建它的一个实例。

 

658      ReachabilityCloner(DSGraph* dest,const DSGraph* src, unsigned cloneFlags,

659                         bool _createDest = true)

660        : Dest(dest), Src(src),CloneFlags(cloneFlags), createDest(_createDest) {

661        assert(Dest!= Src && "Cannot clone from graph to same graph!");

662        BitsToKeep = ~DSNode::DeadNode;

663        if (CloneFlags &DSGraph::StripAllocaBit)

664          BitsToKeep &= ~DSNode::AllocaNode;

665        if (CloneFlags &DSGraph::StripModRefBits)

666          BitsToKeep &= ~(DSNode::ModifiedNode| DSNode::ReadNode);

667        if (CloneFlags &DSGraph::StripIncompleteBit)

668          BitsToKeep &=~DSNode::IncompleteNode;

669      }

 

在186行ReachabilityCloner的构造函数调用中,源图是全局对象的图GlobalsGraph,目标图是在LocalDataStructures::runOnModule的1483行构建的当前处理函数的图。下面函数的参数NH及SrcNH分别是目标图及源图中对应同一个全局对象的DSNodeHandle(即它们都指向相同的DSNode)。对于全局对象,函数图不拥有对应的DSNode节点,这些节点由全局图在1.3.3.1.全局对象声明的处理等章节根据全局对象的声明及定义来创建。那么在第一次遇到这些DSNode时,必然满足843行条件,846行的getClonedNH克隆1个DSNode(后面看其实现),通过mergeWith丢给NH。

 

840    void ReachabilityCloner::merge(const DSNodeHandle &NH,

841                                  const DSNodeHandle &SrcNH) {

842      if (SrcNH.isNull()) return// Noop

843      if (NH.isNull()) {

844        // If there isno destination node, just clone the source and assign the

845       // destinationnode to be it.

846        NH.mergeWith(getClonedNH(SrcNH));

847        return;

848      }

849   

850      // Okay, at thispoint, we know that we have both a destination and a source

851      // node that needto be merged.  Check to see if the sourcenode has already

852      // been cloned.

853      const DSNode*SN = SrcNH.getNode();

854      DSNodeHandle &SCNH = NodeMap[SN]; //SourceClonedNodeHandle

855      if (!SCNH.isNull()) {   // Node alreadycloned?

856        DSNode *SCNHN = SCNH.getNode();

857        NH.mergeWith(DSNodeHandle(SCNHN,

858                                 SCNH.getOffset()+SrcNH.getOffset()));

859        return// Nothing to do!

860      }

 

来到在854行,NH是源图里某一个DSNode的克隆。如果SrcNH所指向的DSNode还未克隆,从NodeMap得到的SCNH是由DSNodeHandle的缺省构造函数构造的,它不满足855行的条件。否则,它已被克隆,简并节点即可(简并的结果是合二为一)。

 

ReachabilityCloner::merge(续)

         

862      // Okay, so thesource node has not already been cloned. Instead of creating

863      // a new DSNode,only to merge it into the one we already have, try to perform

864      // the mergein-place.  The only case we cannot handlehere is when the offset

865      // into theexisting node is less than the offset into the virtual node we are

866      // mergingin.  In this case, we have to extend theexisting node, which

867      // requires anallocation anyway.

868      DSNode *DN = NH.getNode();  // Make sure the Offset is up-to-date

869      if (NH.getOffset() >= SrcNH.getOffset()) {

870        if(!DN->isNodeCompletelyFolded()) {

871          // Make surethe destination node is folded if the source node is folded.

872          if (SN->isNodeCompletelyFolded()) {

873            DN->foldNodeCompletely();

874            DN = NH.getNode();

875          } else if (SN->getSize() !=DN->getSize()) {

876            // If thetwo nodes are of different size, and the smaller node has the

877            // arraybit set, collapse!

878    #if COLLAPSE_ARRAYS_AGGRESSIVELY

879            if (SN->getSize() < DN->getSize()) {

880              if (SN->isArrayNode()) {

881                DN->foldNodeCompletely();

882                DN = NH.getNode();

883              }

884            } else if (DN->isArrayNode()) {

885              DN->foldNodeCompletely();

886              DN = NH.getNode();

887            }

888    #endif

889          }

890   

891   

892          // FIXME:Addcomments.

893          if(!DN->isArrayNode() &&SN->isArrayNode()) {

894            if(DN->getSize() != 0 &&SN->getSize() != 0) {

895              if((DN->getSize() !=SN->getSize() &&

896                  (NH.getOffset() != 0 ||SrcNH.getOffset() != 0)

897                  && DN->getSize() >SN->getSize())) {

898                DN->foldNodeCompletely();

899                DN = NH.getNode();

900              }

901            }

902          }

903          if(!SN->isArrayNode() &&DN->isArrayNode()) {

904            if(DN->getSize() != 0 &&SN->getSize() != 0) {

905              if((DN->getSize() !=SN->getSize() &&

906                  (NH.getOffset() != 0 ||SrcNH.getOffset() != 0)

907                  && DN->getSize() <SN->getSize())) {

908                DN->foldNodeCompletely();

909                DN = NH.getNode();

910              }

911            }

912          }

913   

914          if (SN->isArrayNode() &&DN->isArrayNode()) {

915            if((SN->getSize() !=DN->getSize()) && (SN->getSize() != 0)

916               && DN->getSize() != 0) {

917              DN->foldNodeCompletely();

918              DN = NH.getNode();

919            }

920          }

921          if (!DN->isNodeCompletelyFolded()&& DN->getSize() < SN->getSize())

922            DN->growSize(SN->getSize());

923   

924   

925          // Merge thetype entries of the two nodes together...

926          if (!DN->isNodeCompletelyFolded())

927            DN->mergeTypeInfo(SN,NH.getOffset() - SrcNH.getOffset());

928        }

929   

930        assert(!DN->isDeadNode());

 

如果目标图还未克隆SN,也不一定非要克隆SN,前提是目标图所指向的偏移超过源图(这样我们可以使用已经克隆的NH作为这个节点的克隆)。869行的if直到958行才结束,而870行的if结束在927行。870~927行首先确定DN是否需要缩合。缩合的原因无非就是要算法正确处理计算量太大、太困难,这些都涉及数组。如果DN逃过了缩合的命运,在921~928行根据SN调整DN,这几行可以放在下面。927行对offset的调整,NH.getOffset() -SrcNH.getOffset()是目标节点相对源节点的偏移差,因为927行是简并源节点与目标节点的类型信息进入目标节点,这个偏移差是必须的。

 

ReachabilityCloner::merge(续)

 

932        // Merge theNodeType information.

933        DN->mergeNodeFlags(SN->getNodeFlags()& BitsToKeep);

934   

935        // Before westart merging outgoing links and updating the scalar map, make

936        // sure it isknown that this is the representative node for the src node.

937        SCNH = DSNodeHandle(DN,NH.getOffset()-SrcNH.getOffset());

938   

939        // If thesource node contains any globals, make sure they end up in the

940        // scalar mapwith the correct offset.

941        if (SN->globals_begin() !=SN->globals_end()) {

942          // Update theglobals in the destination node itself.

943          DN->mergeGlobals(*SN);

944   

945          // Update thescalar map for the graph we are merging the source node

946          // into.

947          for(DSNode::globals_iterator I = SN->globals_begin(),

948               E = SN->globals_end(); I != E;++I) {

949            constGlobalValue *GV = *I;

950            const DSNodeHandle &SrcGNH = Src->getNodeForValue(GV);

951            DSNodeHandle &DestGNH =NodeMap[SrcGNH.getNode()];

952            assert(DestGNH.getNode()==NH.getNode()&&"Global mapping inconsistent");

953            Dest->getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(),

954                                                            DestGNH.getOffset()+SrcGNH.getOffset()));

955          }

956          NH.getNode()->mergeGlobals(*SN);

957        }

 

在937行,SCNH现在被更新为指向DN了(原来它不指向任何DSNode),而且由于它是个引用,这个改变发生在NodeMap里。另外,这里还调整了相对DSNode的偏移,这是为了方便下面953行的处理。947行的DSNode的globals_begin返回DSNode中Globals的第一个元素,Globals记录了该DSNode代表的所有全局对象。

前面看到,formGlobalECs的效果是生成同类集,并让同类集的Leader在GlobalGraph的ScalarMap及对应的DSNode的Globals中替代这个同类集的全局对象(LocalDataStructures::runOnModule的1472行),因此此时Globals里只有一个Leader元素,另外对应的DSNodeHandle是唯一的。

另一方面,在DSNode简并时,多个DSNode的Globals会合并在一起,其中每个元素代表一个同类集(但在后面的调用中,formGlobalECs会再次把它们合并为一个同类集),而且简并后只有一个DSNode,这些Globals成员共享这个DSNode(通过各自的DSNodeHandle)。

因此,在953行对Globals的每个成员构建DSNodeHandle,因为DestGNH来自NodeMap,它的偏移减去了SrcNH的偏移(927行),因此只要加上SrcGNH的偏移即可,而不是DestGNH.getOffset() +SrcGNH.getOffset()-SrcNH.getOffset()。注意,因为NodeMap只能(需要)映射一对DSNode与DSNodeHandle,获取其他DSNodeHandle的方法就是通过getNodeForValue,这会生成一个空的DSNodeHandle,而mergeWith把生成的DSNodeHandle直接拷贝给这个DSNodeHandle。

956行与943行是重复的。

 

ReachabilityCloner::merge(续)

 

958      } else {

959        // We cannothandle this case without allocating a temporary node.  Fall

960        // back onbeing simple.

961        DSNode *NewDN = newDSNode(*SN, Dest, true /* Null out all links */);

962        NewDN->maskNodeTypes(BitsToKeep);

963   

964    #ifndef NDEBUG

965        unsigned NHOffset = NH.getOffset();

966    #endif

967        NH.mergeWith(DSNodeHandle(NewDN,SrcNH.getOffset()));

968   

969    #ifndef NDEBUG

970        assert(NH.getNode()&&

971               (NH.getOffset() > NHOffset ||

972                (NH.getOffset() == 0 &&NH.getNode()->isNodeCompletelyFolded())) &&

973               "Merging did not adjust theoffset!");

974    #endif

975   

976        // Before westart merging outgoing links and updating the scalar map, make

977        // sure it isknown that this is the representative node for the src node.

978        SCNH = DSNodeHandle(NH.getNode(),NH.getOffset()-SrcNH.getOffset());

979   

980        // If thesource node contained any globals, make sure to create entries

981        // in thescalar map for them!

982        for(DSNode::globals_iterator I = SN->globals_begin(),

983             E = SN->globals_end(); I != E; ++I){

984          const GlobalValue*GV = *I;

985          constDSNodeHandle &SrcGNH = Src->getNodeForValue(GV);

986          DSNodeHandle &DestGNH =NodeMap[SrcGNH.getNode()];

987          assert(DestGNH.getNode()==NH.getNode()&&"Global mapping inconsistent");

988          assert(SrcGNH.getNode()== SN && "Global mapping inconsistent");

989          Dest->getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(),

990                                                           DestGNH.getOffset()+SrcGNH.getOffset()));

991        }

992      }

 

958行开始的else块面对的是目标节点的指向偏移小于源图节点的情形。961行DSNode的构造函数从SN拷贝大部分的内容(但Links除外),并加入图Dest。967行的mergeWith合并了NH与NewDN的Globals,TyMap(类型映射),在989行简并相关的Globals节点。987~988行的断言的原理跟前面是类似的。

 

ReachabilityCloner::merge(续)

 

994      //  DOUT << "LLVA: mergeWith: "<< SN << " becomes " << DN << "\n";

995   

996      // Next,recursively merge all outgoing links as necessary.  Note that

997      // adding theselinks can cause the destination node to collapse itself at

998      // any time, andthe current node may be merged with arbitrary other nodes.

999      // For thisreason, we must always go through NH.

1000    DN = 0;

1001    for(DSNode::const_edge_iterator ii = SN->edge_begin(), ee = SN->edge_end();

1002         ii != ee; ++ii) {

1003      constDSNodeHandle &SrcEdge = ii->second;

1004      if (!SrcEdge.isNull()) {

1005        // Computethe offset into the current node at which to

1006        // merge thislink.  In the common case, this is alinear

1007        // relationto the offset in the original node (with

1008        // wrapping),but if the current node gets collapsed due to

1009        // recursivemerging, we must make sure to merge in all remaining

1010        // links atoffset zero.

1011        DSNode *CN = SCNH.getNode();

1012        unsigned MergeOffset =(ii->first+SCNH.getOffset()) % CN->getSize();

1013 

1014        DSNodeHandle Tmp =CN->getLink(MergeOffset);

1015        if (!Tmp.isNull()) {

1016          // Performthe recursive merging.  Make sure tocreate a temporary NH,

1017          // becausethe Link can disappear in the process of recursive merging.

1018          merge(Tmp, SrcEdge);

1019        } else {

1020          Tmp.mergeWith(getClonedNH(SrcEdge));

1021          // Mergingthis could cause all kinds of recursive things to happen,

1022          //culminating in the current node being eliminated.  Since this is

1023          //possible, make sure to reaquire the link from 'CN'.

1024 

1025          unsigned MergeOffset = 0;

1026          CN = SCNH.getNode();

1027          MergeOffset = (ii->first +SCNH.getOffset()) % CN->getSize();

1028          CN->getLink(MergeOffset).mergeWith(Tmp);

1029        }

1030      }

1031    }

1032  }

 

前面处理了当前DSNode/DSNodeHandle所代表的全局对象。现在处理这个全局对象所指向的对象。这个指向关系由DSNode中的Links成员表示,Links[offset]即表示该对象偏移offset处所指向的对象。同样,这个指向关系由一个DSNodeHandle来表示。

在1011行,必须从SCNH获取DSNode节点,因为前面众多的mergeWith操作会不停地改变相关的DSNode,只有SCNH才拥有最新的DSNode节点。我们知道DSNode代表一个对象或一块内存,DSNodeHandle指向其中的对象(可能是基类对象或数组元素),Offset表示这个对象在DSNode所代表对象(内存)中的偏移。1012行的ii->first则是在DSNodeHandle表示的对象中的偏移位置,因此MergeOffset就是该位置在DSNode所代表内存中的偏移。

SCNH的DSNode节点保存在NodeMap中,因此1014行的Tmp代表这个DSNode表示对象里的指针,与它简并的源也必须来自NodeMap。因此有在1020行对getClonedNH的调用。

 

750    DSNodeHandle ReachabilityCloner::getClonedNH(const DSNodeHandle &SrcNH) {

751      if (SrcNH.isNull()) returnDSNodeHandle();

752      const DSNode*SN = SrcNH.getNode();

753   

754      DSNodeHandle &NH = NodeMap[SN];

755      if (!NH.isNull()) { //Node already mapped?

756        DSNode *NHN = NH.getNode();

757        unsigned NewOffset = NH.getOffset() +SrcNH.getOffset();

758        if (NHN) {

759          NHN->checkOffsetFoldIfNeeded(NewOffset);

760          NHN = NH.getNode();

761        }

762        returnDSNodeHandle(NHN, NewOffset);

763      }

764   

765      // If SrcNH hasglobals and the destination graph has one of the same globals,

766      // merge this nodewith the destination node, which is much more efficient.

767      if (SN->globals_begin() != SN->globals_end()){

768        DSScalarMap &DestSM =Dest->getScalarMap();

769        for(DSNode::globals_iterator I = SN->globals_begin(),E = SN->globals_end();

770             I != E; ++I) {

771          constGlobalValue *GV = *I;

772          DSScalarMap::iterator GI = DestSM.find(GV);

773          if (GI != DestSM.end() &&!GI->second.isNull()) {

774            // We foundone, use merge instead!

775            merge(GI->second,Src->getNodeForValue(GV));

776            assert(!NH.isNull()&& "Didn't merge node!");

777            DSNode *NHN = NH.getNode();

778            unsigned NewOffset = NH.getOffset() +SrcNH.getOffset();

779            if (NHN) {

780              NHN->checkOffsetFoldIfNeeded(NewOffset);

781              NHN = NH.getNode();

782            }

783            returnDSNodeHandle(NHN, NewOffset);

784          }

785        }

786      }

787   

788      if (!createDest) returnDSNodeHandle(0,0);

 

同样,如果SrcNH所指向的DSNode已经映射到NodeMap(755行条件),由于映射来的DSNodeHandle里的偏移是减去源DSNodeHandle节点偏移的,因此在757行补回这个差值来得到这个映射DSNodeHandle节点的真正偏移。

如果SrcNH所指向的DSNode还没有映射(实际上不一定是没有映射,因为NodeMap的类型是std::map<const DSNode*, DSNodeHandle>,当存在多个DSNodeHandle指向同一个DSNode时,即DSNode的Globals有多个元素,只有其中一个的DSNodeHandle被NodeMap记录,通过NodeMap是找不到其他元素的DSNodeHandle),769行遍历该DSNode所代表的内存对象,如果其中之一的DSNodeHandle已经记录在NodeMap中,说明这个DSNode实际已经映射了,那么在775行把这对DSNodeHandle节点克隆、简并起来就好了。因为merge会产生Globals中所有元素的DSNodeHandle。注释说到,这样做会效率更高。776行的NH是NodeMap的一个引用,因此775行的merge调用的结果会在其中反映出来。

788行的createDest由ReachabilityCloner的构造函数设置,默认为true。

 

ReachabilityCloner::getClonedNH(续)

 

790      DSNode *DN = newDSNode(*SN, Dest, true /* Null out all links */);

791      DN->maskNodeTypes(BitsToKeep);

792      NH = DN;

793   

794      // Next,recursively clone all outgoing links as necessary.  Note that

795      // adding theselinks can cause the node to collapse itself at any time, and

796      // the current nodemay be merged with arbitrary other nodes. For this

797      // reason, we mustalways go through NH.

798      DN = 0;

799      for(DSNode::const_edge_iterator ii = SN->edge_begin(), ee = SN->edge_end();

800           ii != ee; ++ii) {

801        constDSNodeHandle &SrcEdge = ii->second;

802        if (!SrcEdge.isNull()) {

803          constDSNodeHandle &DestEdge = getClonedNH(SrcEdge);

804          // Compute theoffset into the current node at which to

805          // merge thislink.  In the common case, this is alinear

806          // relation tothe offset in the original node (with

807          // wrapping),but if the current node gets collapsed due to

808          // recursivemerging, we must make sure to merge in all remaining

809          // links atoffset zero.

810          unsigned MergeOffset = 0;

811          DSNode *CN = NH.getNode();

812          if (CN->getSize() != 1)

813            MergeOffset = (ii->first +NH.getOffset()) % CN->getSize();

814          CN->addEdgeTo(MergeOffset,DestEdge);

815        }

816      }

817   

818      // If this nodecontains any globals, make sure they end up in the scalar

819      // map with thecorrect offset.

820      for(DSNode::globals_iterator I = SN->globals_begin(), E = SN->globals_end();

821           I != E; ++I) {

823        constGlobalValue *GV = *I;

824        constDSNodeHandle &SrcGNH = Src->getNodeForValue(GV);

825        DSNodeHandle &DestGNH =NodeMap[SrcGNH.getNode()];

826        assert(DestGNH.getNode()== NH.getNode() &&"Global mapping inconsistent");

827        Dest->getNodeForValue(GV).mergeWith(DSNodeHandle(DestGNH.getNode(),

828                                                        DestGNH.getOffset()+SrcGNH.getOffset()));

829      }

830      NH.getNode()->mergeGlobals(*SN);

831   

832      DSNode* NHN = NH.getNode();

833     unsigned NewOffset = NH.getOffset() +SrcNH.getOffset();

834      if (NHN) {

835        NHN->checkOffsetFoldIfNeeded(NewOffset);

836        NHN = NH.getNode();

837      }

838      returnDSNodeHandle(NHN, NewOffset);

839    }

 

来到这里,目标图确实没有克隆源DSNode,因此首先创建一个DSNode节点。在792行,NH实际被赋予DSNodeHandle(DN, 0)。接着在799行遍历源节点所代表的对象所指向的对象,使目标节点指向对应的映射后的DSNode。最后,在820行,更新目标节点所代表的所有全局对象的引用(DSNodeHandle)。

0 0
原创粉丝点击