dsa算法(13)

来源:互联网 发布:pop3协议默认端口号 编辑:程序博客网 时间:2024/05/21 09:52
1.3.3.4.1.5. 删除死节点

至此,我们结束了对当前函数的DSGraph的处理。接下来,使用可到达性分析来删除其中不可访问的节点。这样可以加速后续的处理。

 

GraphBuilder:: GraphBuilder(续)

 

205          // Remove anynodes made dead due to merging...

206          g.removeDeadNodes(DSGraph::KeepUnreachableGlobals);

207        }

 

1052  void DSGraph::removeDeadNodes(unsigned Flags) {

1053    DEBUG(AssertGraphOK(); if (GlobalsGraph) GlobalsGraph->AssertGraphOK());

1054 

1055    // Reduce theamount of work we have to do... remove dummy nodes left over by

1056    // merging...

1057    removeTriviallyDeadNodes();

 

首先是删除显而易见的死节点。死节点是没有被使用的节点,它们不需要通过可到达性分析来查找。

 

915    void DSGraph::removeTriviallyDeadNodes(){

916      /// NOTE: This codeis disabled.  This slows down DSA on177.mesa

917      /// substantially!

918   

919      // Loop over all ofthe nodes in the graph, calling getNode on each field.

920      // This will causeall nodes to update their forwarding edges, causing

921      // forwarded nodesto be delete-able.  Further, reclaim anymemory used by

922      // useless edge ortype entries

923      for(node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI)

924        for(DSNode::edge_iterator ii = NI->edge_begin(), ee = NI->edge_end();

925             ii != ee; ++ii) {

926          ii->second.getNode()->cleanEdges();

927        }

928   

929      // Likewise,forward any edges from the scalar nodes. While we are at it,

930      // clean house abit.

931      for(DSScalarMap::iterator I = ScalarMap.begin(), E = ScalarMap.end();

932           I != E; ++I)

933        I->second.getNode();

 

在923、924行的循环遍历图中每个对象(由DSNode代表)中的每个指针域(由DSNodeHandle代表),对所指向的对象进行清理整顿。我们知道为了尽可能全面地记录源语言中的对象,DSNode在TyMap中按偏移记录了对象所包含的类型,同时在Links中也按偏移记录了对象所包含的指针连同指向的对象(即下面所谓的边——edge)。那么705行的循环清除了TyMap中的空类型,而716行则清除了Links中的空指针。

 

703    void DSNode::cleanEdges(){

704      //get rid of anytype edge pointing to the null type

705      for(type_iterator ii = type_begin(); ii != type_end(); ) {

706        if (ii->second)

707          ++ii;

708        else {

709          type_iterator backup = ii;

710          ++backup;

711          TyMap.erase(ii);

712          ii = backup;

713        }

714      }

715      //get rid of anynode edge pointing to nothing

716      for(edge_iterator ii = edge_begin(); ii != edge_end(); ) {

717        if (ii->second.isNull()) {

718          edge_iterator backup = ii;

719          ++backup;

720          Links.erase(ii);

721          ii= backup;

722        } else

723          ++ii;

724      }

725    }

 

在DSGraph中ScalarMap的作用是记录对象与援引它的指针(通过DSNodeHandle)。933行的getNode方法迫使转发节点得到处理。这样,也会清理掉一些转发节点。

 

DSGraph::removeTriviallyDeadNodes(续)

 

935      bool isGlobalsGraph = !GlobalsGraph;

936   

937      for (NodeListTy::iteratorNI = Nodes.begin(), E = Nodes.end(); NI != E; ) {

938        DSNode &Node = *NI;

939   

940        // Do not remove*any* global nodes in the globals graph.

941        // This is aspecial case because such nodes may not have I, M, R flags set.

942        if(Node.isGlobalNode() && isGlobalsGraph) {

943          ++NI;

944          continue;

945        }

946   

947        if (Node.isCompleteNode() &&!Node.isModifiedNode() && !Node.isReadNode()) {

948          // This is auseless node if it has no mod/ref info (checked above),

949          // outgoingedges (which it cannot, as it is not modified in this

950          // context),and it has no incoming edges.  If it is aglobal node it may

951          // have all ofthese properties and still have incoming edges, due to the

952          // scalar map, so we check those now.

953          //

954          if (Node.getNumReferrers() ==Node.numGlobals()) {

955   

956            // Loopthrough and make sure all of the globals are referring directly

957            // to thenode...

958            for(DSNode::globals_iterator j = Node.globals_begin(), e = Node.globals_end();

959                 j != e; ++j) {

960              getNodeForValue(*j).getNode();

961              assert((getNodeForValue(*j).getNode())== &Node && "ScalarMap doesn't match globals list!");

962            }

963   

964            // Make sureNumReferrers still agrees, if so, the node is truly dead.

965            if (Node.getNumReferrers() ==Node.numGlobals()) {

966              for(DSNode::globals_iterator j = Node.globals_begin(), e = Node.globals_end();

967                   j != e; ++j)

968                if (ScalarMap.find(*j) !=ScalarMap.end())

969                  ScalarMap.erase(*j);

970              Node.makeNodeDead();

971              ++NumTrivialGlobalDNE;

972            }

973          }

974        }

975   

976        if ((Node.getNodeFlags() == 0 &&Node.hasNoReferrers())

977            || (isGlobalsGraph &&Node.hasNoReferrers() && !Node.isGlobalNode())){

978          // This node isdead!

979          NI = Nodes.erase(NI);   // Erase &remove from node list.

980          ++NumTrivialDNE;

981        } else {

982          ++NI;

983        }

984      }

985    #if 0

986    #endif

987      removeIdenticalCalls(FunctionCalls);

988      removeIdenticalCalls(AuxFunctionCalls);

989    }

 

对于函数图,935行的GlobalsGraph指向全局图(即DataStructures中的GlobalsGraph),因此它们将跳过所有的全局节点。而对于全局图,这个指针为空的,因此它会执行947~983行。这段代码只考虑完整,而且没有读写的节点。在954行,numGlobals是Globals的大小,Globals记录了该DSNode所代表的全局对象(这些对象共享这个DSNode),而getNumReferrers则返回该DSNode被援引的计数(其中Globals中的对象贡献numGlobals个计数)。如果两者相等,说明这些全局对象没有额外的引用,可以删除。首先通过getNode(960行)清除相关转发节点,然后删除。注意970行的makeNodeDead,它会使976行的getNodeFlags()== 0条件得到满足,从Nodes中删除这个节点。

最后,还要调用removeIdenticalCalls删除相同的函数调用。

 

847    static voidremoveIdenticalCalls(DSGraph::FunctionListTy&Calls) {

848      // Remove triviallyidentical function calls

849   

850      unsigned NumDeleted = 0;

851   

852      // First, scanthrough killing off useless edges and trivially dead callsites

853      for(DSGraph::FunctionListTy::iterator I = Calls.begin(), E = Calls.end();

854           I != E; ) {

855        DSCallSite &CS = *I;

856   

857        // If the returnvalue or any arguments point to a void node with no

858        // information atall in it, and the call node is the only node to point

859        // to it, removethe edge to the node (killing the node).

860        //

861        killIfUselessEdge(CS.getRetVal());

862        killIfUselessEdge(CS.getVAVal());

863        for(unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a)

864          killIfUselessEdge(CS.getPtrArg(a));

865   

866        // If this is anindirect callsite, but the Callee DSNode isn't

867        // tied to fromanything, remove it trivially.

868        if (CS.isIndirectCall()) {

869          DSNode *Callee = CS.getCalleeNode();

870          if (Callee->getNumReferrers() == 1&& Callee->isCompleteNode() &&

871              Callee->isEmptyGlobals()) { // No useful info?

872            DEBUG(errs() << "WARNING:Useless call site found.\n");

873            I = Calls.erase(I);

874            E = Calls.end();

875            ++NumDeleted;

876            continue;

877          }

878        }

879        ++I;

880      }

 

853行的Calls包含了图中的所有函数调用指令。对这些调用指令分别检查返回值、变长参数、指针参数所指向的对象是否可以删除。判断的标准由是killIfUselessEdge给出:对象只有这个引用,只有未完成标记,并且整体缺乏类型信息(TyMap完全是空的,842行),而且还不能是缩合的。

 

837    staticinlinevoid killIfUselessEdge(DSNodeHandle &Edge) {

838      if (DSNode * N = Edge.getNode())// Is there an edge?

839        if (N->getNumReferrers() == 1) // Does it point toa lonely node?

840          // Nointeresting info?

841          if ((N->getNodeFlags() &~DSNode::IncompleteNode) == 0

842              && N->hasNoType()

843              && !N->isNodeCompletelyFolded())

844            Edge.setTo(0, 0);  // Kill the edge!

845    }

 

844行的setTo会递减所指向DSNode对象的NumReferrers计数,这使得该对象成为孤悬,为后面回收做好准备。

868行,如果是完整的间接函数调用,而实际没有调用任何对象(注意isEmptyGlobals条件,如果被调用对象不是Function或GlobalValue,满足此条件),而且我们是唯一的使用者,删除这个CallSite。

 

removeIdenticalCalls(续)

 

882      // Now scan forredundant indirect callsites

883     // First, sort bycallee (using DSCallSite::operator<)

884      sort(Calls);

885   

886      // Then findadjacent callsites that are equivalent and handle accordingly

887      DSGraph::FunctionListTy::iterator I =Calls.begin();

888      while((I =std::adjacent_find(I, Calls.end())) != Calls.end()) {

889        DSGraph::FunctionListTy::iterator Second =I;

890        DSCallSite &DCS1 = *I, &DCS2 =*++Second;

891   

892        if (DCS1.isIndirectCall()) {

893          // Merge themtogether (into the first one)

894          DCS1.mergeWith(DCS2);

895        }

896   

897        // Remove thesecond one

898        ++NumDeleted;

899        Calls.erase(Second);

900   

901        // Carry on,searching from 'I' (first one)...

902      }

903   

904      // Track the numberof call nodes merged away...

905      NumCallNodesMerged += NumDeleted;

906   

907      if (NumDeleted)

908        DEBUG(errs() << "Merged "<< NumDeleted << " call nodes.\n");

909    }

 

随后,在884行对CallSite进行排序。DSCallSite定义了“<”操作符,定义间接调用“小于”直接的调用。

 

327      bool operator<(const DSCallSite &CS) const{

328        if (isDirectCall()) {     // This mustsort by callee first!

329          if (CS.isIndirectCall())return true;

330          if (CalleeF < CS.CalleeF)return true;

331          if (CalleeF > CS.CalleeF)return false;

332        } else {

333          if (CS.isDirectCall())return false;

334          if (CalleeN < CS.CalleeN)return true;

335          if (CalleeN > CS.CalleeN)return false;

336        }

337        if (RetVal < CS.RetVal)return true;

338        if (RetVal > CS.RetVal)return false;

339        if (VarArgVal < CS.VarArgVal)return true;

340        if (VarArgVal > CS.VarArgVal)return false;

341        returnCallArgs < CS.CallArgs;

342      }

 

CallSite的成员CalleeF的类型是Function*,而成员CalleeN的类型是DSNodeHandle。DSNodeHandle重载了如下的“<”操作符,首先调用的getNode方法会处理转发节点,然后在“||”的左侧就可以直接使用“N == H.N”进行比较。

 

78        bool operator<(const DSNodeHandle &H) const// Allowsorting

79          return getNode() < H.getNode() || (N == H.N&& Offset < H.Offset);

80        }

 

如果出现重复的间接函数调用(如函数指针),通过下面的方法对CallSite进行简并。DSCallSite中的MappedSites用于记录进行了简并的CallSite。对于同一个函数不同的调用点,真正需要简并的是返回值,变长参数及指针参数,DSA把不同调用点间的这些参数视为互为别名。

 

305      void mergeWith(DSCallSite&CS) {

306        getRetVal().mergeWith(CS.getRetVal());

307        getVAVal().mergeWith(CS.getVAVal());

308        unsigned MinArgs = getNumPtrArgs();

309        if (CS.getNumPtrArgs() < MinArgs)MinArgs = CS.getNumPtrArgs();

310   

311        for(unsigned a = 0; a != MinArgs; ++a)

312          getPtrArg(a).mergeWith(CS.getPtrArg(a));

313   

314        for(unsigned a = MinArgs, e = CS.getNumPtrArgs(); a != e; ++a)

315          CallArgs.push_back(CS.getPtrArg(a));

316   

317        MappedSites.insert(CS.getCallSite());

318        MappedSites.insert(CS.ms_begin(),CS.ms_end());

319      }

 

现在由可到达性分析来识别其他死节点了。这里根据Flags中标志位的设定,有KeepUnreachableGlobals及RemoveUnreachableGlobals的区别。RemoveUnreachableGlobals只保留从局部对象可到达的全局对象,而KeepUnreachableGlobals将保留从局部对象可到达的全局对象,以及可到达这些局部对象的全局对象。

在1076行的ReachabilityCloner构造函数中,目标图是GlobalsGraph,源图是当前函数图。参数Flags是KeepUnreachableGlobals,GGCloner会克隆所有的全局对象,以及调用点(RemoveUnreachableGlobals时不需要显式克隆可到达的全局对象,因为通过当前函数的局部变量可以访问它们)。

 

DSGraph::removeDeadNodes(续)

 

1059    // FIXME: Mergenon-trivially identical call nodes...

1060 

1061    // Alive - a setthat holds all nodes found to be reachable/alive.

1062    DenseSet<constDSNode*> Alive;

1063    std::vector<std::pair<const Value*, DSNode*> > GlobalNodes;

1064 

1065    // Copy and mergeall information about globals to the GlobalsGraph if this is

1066    // not a final pass(where unreachable globals are removed).

1067    //

1068    // Strip all allocabits since we are merging information into the globals

1069    // graph.

1070    // Strip allincomplete bits since they are short-lived properties and they

1071    // will becorrectly computed when rematerializing nodes into the functions.

1072    //

1073    // This code mergesinformation learned about the globals in 'this' graph

1074    // back into theglobals graph, before it deletes any such global nodes,

1075    // (with some newinformation possibly) from 'this' current function graph.

1076    ReachabilityCloner GGCloner(GlobalsGraph,this, DSGraph::StripAllocaBit |

1077                                DSGraph::StripIncompleteBit);

1078 

1079    // Mark all nodesreachable by (non-global) scalar nodes as alive...

1080    for(DSScalarMap::iterator I = ScalarMap.begin(), E = ScalarMap.end();

1081            I != E; ++I)

1082      if (isa<GlobalValue > (I->first)){// Keep track of global nodes

1083        assert(!I->second.isNull()&& "Null global node?");

1084        assert(I->second.getNode()->isGlobalNode()&& "Should be a global node!");

1085       GlobalNodes.push_back(std::make_pair(I->first,I->second.getNode()));

1086 

1087        // Make surethat all globals are cloned over as roots.

1088        if (!(Flags &DSGraph::RemoveUnreachableGlobals) && GlobalsGraph) {

1089            GGCloner.getClonedNH(I->second);

1090        }

1091      } else {

1092        I->second.getNode()->markReachableNodes(Alive);

1093      }

1094 

1095    // The returnvalues are alive as well.

1096    for(ReturnNodesTy::iterator I = ReturnNodes.begin(), E = ReturnNodes.end();

1097         I != E; ++I)

1098     I->second.getNode()->markReachableNodes(Alive);

1099 

1100    // Mark any nodesreachable by primary calls as alive...

1101    for(fc_iterator I = fc_begin(), E = fc_end(); I != E; ++I)

1102      I->markReachableNodes(Alive);

 

这里全局对象不被标记为可到达,在1085行它们暂时记录在GlobalNodes中。而局部对象、返回值及直接调用函数的指令都视为可到达(1092、1098、1102行)。

 

1167  void DSNode::markReachableNodes(DenseSet<const DSNode*> &ReachableNodes)const {

1168    if (this == 0) return;

1169    assert(!isForwarding()&& "Cannot mark a forwarded node!");

1170    if (ReachableNodes.insert(this).second)// Is newly reachable?

1171      for(DSNode::const_edge_iterator I = edge_begin(), E = edge_end();

1172           I != E; ++I)

1173       I->second.getNode()->markReachableNodes(ReachableNodes);

1174  }

 

markReachableNodes将深度遍历节点指针域所指向的对象节点,所有通过这些对象可以访问的对象都保存在Alive中。

 

DSGraph::removeDeadNodes(续)

 

1105    // Now find globalsand aux call nodes that are already live or reach a live

1106    // value (whichmakes them live in turn), and continue till no more are found.

1107    //

1108    bool Iterate;

1109    DenseSet<constDSNode*> Visited;

1110    std::set<constDSCallSite*> AuxFCallsAlive;

1111    do {

1112      Visited.clear();

1113      // If any globalnode points to a non-global that is "alive", the global is

1114      //"alive" as well...  Remove itfrom the GlobalNodes list so we only have

1115      // unreachableglobals in the list.

1116      //

1117      Iterate = false;

1118      if (!(Flags &DSGraph::RemoveUnreachableGlobals))

1119        for(unsigned i = 0; i != GlobalNodes.size(); ++i)

1120          if (CanReachAliveNodes(GlobalNodes[i].second,Alive, Visited,

1121                                 Flags &DSGraph::RemoveUnreachableGlobals)) {

1122            std::swap(GlobalNodes[i--], GlobalNodes.back());// Move to end to...

1123            GlobalNodes.pop_back();                         // erase efficiently

1124            Iterate = true;

1125          }

1126 

1127      // Mark onlyunresolvable call nodes for moving to the GlobalsGraph since

1128      // call nodesthat get resolved will be difficult to remove from that graph.

1129      // The finalunresolved call nodes must be handled specially at the end of

1130      // the BU pass(i.e., in main or other roots of the call graph).

1131      for(afc_iterator CI = afc_begin(), E = afc_end(); CI != E; ++CI)

1132        if (!AuxFCallsAlive.count(&*CI)&&

1133            (CI->isIndirectCall()

1134             || CallSiteUsesAliveArgs(*CI,Alive, Visited,

1135                                    Flags &DSGraph::RemoveUnreachableGlobals))) {

1136          CI->markReachableNodes(Alive);

1137          AuxFCallsAlive.insert(&*CI);

1138          Iterate = true;

1139        }

1140    } while(Iterate);

 

如果Flags设置了RemoveUnreachableGlobals位,直接跳过1119~1124行。而对于KeepUnreachableGlobals,CanReachAliveNodes的参数IgnoreGlobals将是false,会检查函数图中的每个全局对象是否可到达,从GlobalNodes删除中可到达的全局对象。在CanReachAliveNodes中的参数Alive记录已确认可到达的对象,Visited则记录指定的节点是否已经处理过了。

 

996    static boolCanReachAliveNodes(DSNode *N, DenseSet<const DSNode*> &Alive,

997                                   DenseSet<const DSNode*> &Visited,

998                                   boolIgnoreGlobals) {

999      if (N == 0) returnfalse;

1000    assert(N->isForwarding()== 0 && "Cannot mark a forwarded node!");

1001 

1002    // If this is aglobal node, it will end up in the globals graph anyway, so we

1003    // don't need toworry about it.

1004    if (IgnoreGlobals &&N->isGlobalNode())return false;

1005 

1006    // If we know that this node is alive, returnso!

1007    if (Alive.count(N)) returntrue;

1008 

1009    // Otherwise, wedon't think the node is alive yet, check for infinite

1010    // recursion.

1011    if (Visited.count(N)) return false;  // Found a cycle

1012    Visited.insert(N);   // No recursion,insert into Visited...

1013 

1014    for(DSNode::edge_iterator I = N->edge_begin(),E = N->edge_end(); I != E;++I)

1015      if(CanReachAliveNodes(I->second.getNode(), Alive, Visited, IgnoreGlobals)) {

1016        N->markReachableNodes(Alive);

1017        returntrue;

1018      }

1019    return false;

1020  }

 

在1015行,我们沿着DSNode的Links递归调用CanReachAliveNodes,最后要么碰到以确认可到达的节点,要么碰到的都是已访问过的节点(1014行循环在CanReachAliveNodes返回false时,不结束)。

 

1025  static boolCallSiteUsesAliveArgs(const DSCallSite &CS,

1026                                    DenseSet<const DSNode*> &Alive,

1027                                    DenseSet<const DSNode*> &Visited,

1028                                    boolIgnoreGlobals) {

1029    if (CanReachAliveNodes(CS.getRetVal().getNode(),Alive, Visited,

1030                           IgnoreGlobals))

1031      returntrue;

1032    if(CanReachAliveNodes(CS.getVAVal().getNode(), Alive, Visited, IgnoreGlobals))

1033      returntrue;

1034    if (CS.isIndirectCall() &&

1035        CanReachAliveNodes(CS.getCalleeNode(),Alive, Visited, IgnoreGlobals))

1036      returntrue;

1037    for (unsignedi = 0, e = CS.getNumPtrArgs(); i != e; ++i)

1038      if(CanReachAliveNodes(CS.getPtrArg(i).getNode(), Alive, Visited,

1039                             IgnoreGlobals))

1040        returntrue;

1041    return false;

1042  }

 

对于间接调用,我们在前面已经把重复的调用清除了,因此在这里就把它们标记为可到达。而其他情形的调用则由CallSiteUsesAliveArgs处理,其中的参数IgnoreGlobals与CanReachAliveNodes有相同的含义。

如果我们成功地标记了新的可到达节点,必须重新运行1111行的循环,直到没有新的可到达节点被发现。

 

DSGraph::removeDeadNodes(续)

 

1142    // If only some ofthe aux calls are alive

1143    if (AuxFCallsAlive.size() !=AuxFunctionCalls.size()) {

1144      // Move dead auxfunction calls to the end of the list

1145      FunctionListTy::iterator Erase =AuxFunctionCalls.end();

1146      for(FunctionListTy::iterator CI = AuxFunctionCalls.begin(); CI != Erase; )

1147        if (AuxFCallsAlive.count(&*CI))

1148          ++CI;

1149        else {

1150          // Copy andmerge global nodes and dead aux call nodes into the

1151          //GlobalsGraph, and all nodes reachable from those nodes.  Update their

1152          // targetpointers using the GGCloner.

1153          //

1154          if (!(Flags &DSGraph::RemoveUnreachableGlobals))

1155           GlobalsGraph->AuxFunctionCalls.push_back(DSCallSite(*CI, GGCloner));

1156 

1157          std::swap(*CI, *--Erase);

1158        }

1159      AuxFunctionCalls.erase(Erase,AuxFunctionCalls.end());

1160    }

1161    AuxFCallsAlive.clear();

1162 

1163    // We are finallydone with the GGCloner so we can destroy it.

1164    GGCloner.destroy();

1165 

1166    // At this point, anynodes which are visited, but not alive, are nodes

1167    // which can beremoved.  Loop over all nodes,eliminating completely

1168    // unreachablenodes.

1169    //

1170    std::vector<DSNode*> DeadNodes;

1171    DeadNodes.reserve(Nodes.size());

1172    for(NodeListTy::iterator NI = Nodes.begin(), E = Nodes.end(); NI != E;) {

1173      DSNode *N = NI++;

1174      assert(!N->isForwarding()&& "Forwarded node in nodes list?");

1175 

1176      if (!Alive.count(N)) {

1177        Nodes.remove(N);

1178        assert(!N->isForwarding()&& "Cannot remove a forwarding node!");

1179        DeadNodes.push_back(N);

1180        N->dropAllReferences();

1181        ++NumDNE;

1182      }

1183    }

1184 

1185    // Remove allunreachable globals from the ScalarMap.

1186    // If flagRemoveUnreachableGlobals is set, GlobalNodes has only dead nodes.

1187    // In either case,the dead nodes will not be in the set Alive.

1188    for (unsignedi = 0, e = GlobalNodes.size(); i != e; ++i)

1189      if (!Alive.count(GlobalNodes[i].second))

1190        ScalarMap.erase(GlobalNodes[i].first);

1191      else

1192        assert((Flags& DSGraph::RemoveUnreachableGlobals) && "non-deadglobal");

1193 

1194    // Delete all deadnodes now since their referrer counts are zero.

1195    for (unsignedi = 0, e = DeadNodes.size(); i != e; ++i)

1196      deleteDeadNodes[i];

1197 

1198    DEBUG(AssertGraphOK();GlobalsGraph->AssertGraphOK());

1199  }

 

如果在前面1131行的循环中,某些AuxFunctionCalls元素被识别为不可到达,在1146行开始的循环查找这些元素,然后在1155行把这些元素加入全局图(通过GGCloner找到全局图中对应对象,前面1089行已经准备好这些节点),并最终从函数图中删除这些元素。在前面的处理中,Alive保存了可到达节点的地址,接下来的循环则根据Alive的记录删除这些节点。如果Flags没有设置DSGraph::RemoveUnreachableGlobals标记,将删除所有从局部变量不能到达的GlobalValue。因为在RemoveUnreachableGlobals的情况下,GlobalNodes保留了所有的全局对象,因此可能不满足1189行条件。但KeepUnreachableGlobals不会。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小学三年级时间应用题 小学二年级数学应用题大全 小学三年级数学应用题上册 六年级工程问题应用题 六年级数学比例应用题 六年级数学工程应用题 五年级鸡兔同笼应用题 10以内的加减法应用题 五年级上册小数除法应用题 小学二年级数学应用题上册 小学三年级上册数学应用题 二年级数学除法应用题 小学二年级除法应用题 二年级下册奥数应用题 七年级数学方程应用题 五年级数学方程应用题 小学数学四年级应用题 小学四年级上册数学应用题 六年级数学方程应用题 二年级上学期数学应用题 小学五年级上册应用题 五年级列方程解应用题 六年级数学分数乘法应用题 三年级上学期数学应用题 小学五年级奥数应用题 小学三年级上册应用题 小学生六年级数学应用题 小学六年级分数乘法应用题 小学六年级上册数学应用题 八年级上册物理应用题 小学二年级数学加减法应用题 应多音字 应组词多音 应多音字组词语组词 应组词多音字 多音字应分别怎么组词 应字组词多音字组词语 应的多音字组词 应的拼音和组词多音 应的多音字组词两个 应的多音字怎么多组词