zoukankan      html  css  js  c++  java
  • C2 CCP

    image
    常量传播的lattice有三级,buttom表示不能保证是常量,中间表示常量,top表示变量可能未确定/未初始化。CCP处理之后,所有值不是常量就是buttom。

    一般有两种算法,一种是SSC(Sparse Simple Constant Propagation,Reif and Lewis),一种是SCC(Sparse Conditional Constant Propagation),C2是后者。

    PhaseCCP是PhaseItreGVN的子类,他在Optimize中有两步:

    ...
      // Conditional Constant Propagation;
      PhaseCCP ccp( &igvn );
      assert( true, "Break here to ccp.dump_nodes_and_types(_root,999,1)");
      {
        TracePhase tp("ccp", &timers[_t_ccp]);
        ccp.do_transform();
      }
      print_method(PHASE_CPP1, 2);
    
      assert( true, "Break here to ccp.dump_old2new_map()");
    
      // Iterative Global Value Numbering, including ideal transforms
      {
        TracePhase tp("iterGVN2", &timers[_t_iterGVN2]);
        igvn = ccp;
        igvn.optimize();
      }
      print_method(PHASE_ITER_GVN2, 2);
    ...
    

    构造PhaseCCP的时候会执行PhaseCCP::analyze,然后做ccp.do_transofrm,再然后使用igvn.optimize做ccp的transform。

    PhaseCCP::analyze

    void PhaseCCP::analyze() {
      // Initialize all types to TOP, optimistic analysis
      for (int i = C->unique() - 1; i >= 0; i--)  {
        _types.map(i,Type::TOP);
      }
    
      // Push root onto worklist
      Unique_Node_List worklist;
      worklist.push(C->root());
    
      // Pull from worklist; compute new value; push changes out.
      // This loop is the meat of CCP.
      while( worklist.size() ) {
        Node* n; // Node to be examined in this iteration
        if (StressCCP) {
          n = worklist.remove(C->random() % worklist.size());
        } else {
          n = worklist.pop();
        }
        const Type *t = n->Value(this);
        if (t != type(n)) {
          assert(ccp_type_widens(t, type(n)), "ccp type must widen");
    #ifndef PRODUCT
          if( TracePhaseCCP ) {
            t->dump();
            do { tty->print("\t"); } while (tty->position() < 16);
            n->dump();
          }
    #endif
          set_type(n, t);
          for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
            Node* m = n->fast_out(i);   // Get user
            if (m->is_Region()) {  // New path to Region?  Must recheck Phis too
              for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) {
                Node* p = m->fast_out(i2); // Propagate changes to uses
                if (p->bottom_type() != type(p)) { // If not already bottomed out
                  worklist.push(p); // Propagate change to user
                }
              }
            }
            // If we changed the receiver type to a call, we need to revisit
            // the Catch following the call.  It's looking for a non-NULL
            // receiver to know when to enable the regular fall-through path
            // in addition to the NullPtrException path
            if (m->is_Call()) {
              for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) {
                Node* p = m->fast_out(i2);  // Propagate changes to uses
                if (p->is_Proj() && p->as_Proj()->_con == TypeFunc::Control) {
                  Node* catch_node = p->find_out_with(Op_Catch);
                  if (catch_node != NULL) {
                    worklist.push(catch_node);
                  }
                }
              }
            }
            if (m->bottom_type() != type(m)) { // If not already bottomed out
              worklist.push(m);     // Propagate change to user
            }
    
            // CmpU nodes can get their type information from two nodes up in the
            // graph (instead of from the nodes immediately above). Make sure they
            // are added to the worklist if nodes they depend on are updated, since
            // they could be missed and get wrong types otherwise.
            uint m_op = m->Opcode();
            if (m_op == Op_AddI || m_op == Op_SubI) {
              for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) {
                Node* p = m->fast_out(i2); // Propagate changes to uses
                if (p->Opcode() == Op_CmpU) {
                  // Got a CmpU which might need the new type information from node n.
                  if(p->bottom_type() != type(p)) { // If not already bottomed out
                    worklist.push(p); // Propagate change to user
                  }
                }
              }
            }
            // If n is used in a counted loop exit condition then the type
            // of the counted loop's Phi depends on the type of n. See
            // PhiNode::Value().
            if (m_op == Op_CmpI) {
              PhiNode* phi = countedloop_phi_from_cmp((CmpINode*)m, n);
              if (phi != NULL) {
                worklist.push(phi);
              }
            }
            // Loading the java mirror from a Klass requires two loads and the type
            // of the mirror load depends on the type of 'n'. See LoadNode::Value().
            BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
            bool has_load_barrier_nodes = bs->has_load_barrier_nodes();
    
            if (m_op == Op_LoadP && m->bottom_type()->isa_rawptr()) {
              for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) {
                Node* u = m->fast_out(i2);
                const Type* ut = u->bottom_type();
                if (u->Opcode() == Op_LoadP && ut->isa_instptr() && ut != type(u)) {
                  if (has_load_barrier_nodes) {
                    // Search for load barriers behind the load
                    for (DUIterator_Fast i3max, i3 = u->fast_outs(i3max); i3 < i3max; i3++) {
                      Node* b = u->fast_out(i3);
                      if (bs->is_gc_barrier_node(b)) {
                        worklist.push(b);
                      }
                    }
                  }
                  worklist.push(u);
                }
              }
            }
          }
        }
      }
    }
    

    看着这么多,其实吧中间的for省略一下,就很直白了:

    void PhaseCCP::analyze() {
      // 乐观分析,即最开始将所有types都初始化为TOP
      for (int i = C->unique() - 1; i >= 0; i--)  {
        _types.map(i,Type::TOP);
      }
    
      // ROOT放到worklist里
      Unique_Node_List worklist;
      worklist.push(C->root());
    
      // 1)worklsit取值 2)算新type 3)然后如果新type和之前记录的不一样,就更新
      while( worklist.size() ) {
        Node* n; // Node to be examined in this iteration
        if (StressCCP) {
          n = worklist.remove(C->random() % worklist.size());
        } else {
          // 1)worklsit取值
          n = worklist.pop();
        }
        // 2)算新type
        const Type *t = n->Value(this);
        // 3)如果新type和之前记录的不一样
        if (t != type(n)) {
          assert(ccp_type_widens(t, type(n)), "ccp type must widen");
          // 就更新
          set_type(n, t);
          
          // 处理一下当前node的use,特殊处理一些cases
          for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
          	... // 某些特殊情况需要加入worklist
            // 看当前节点的use的type是不是最坏情况,如果不是,就加到worklist
            if (m->bottom_type() != type(m)) {
              worklist.push(m);
            }
            ... // 某些特殊情况需要加入worklist
          }
        }
      }
    }
    

    analyze就是把整个图的所有节点都先初始化成TOP,然后从ROOT出发,计算当前节点的新type,如果新type和之前记录的不一样(如果是第一次就是新type不是TOP),那么就记录新type,然后看看当前节点的use,如果use的type不是最坏情况,那么把它加入worklist,等待下一次使用。

    或者更简洁来说,analyze就是把ir所有node的type初始化为TOP(最好情况),然后为所有node再算一次type,直到type不改变,或者type已经是bottom(最坏情况)。

    PhaseCCP::transform

    //------------------------------do_transform-----------------------------------
    // Top level driver for the recursive transformer
    void PhaseCCP::do_transform() {
      // Correct leaves of new-space Nodes; they point to old-space.
      C->set_root( transform(C->root())->as_Root() );
      assert( C->top(),  "missing TOP node" );
      assert( C->root(), "missing root" );
    }
    
    //------------------------------transform--------------------------------------
    // Given a Node in old-space, clone him into new-space.
    // Convert any of his old-space children into new-space children.
    Node *PhaseCCP::transform( Node *n ) {
      Node *new_node = _nodes[n->_idx]; // Check for transformed node
      if( new_node != NULL )
        return new_node;                // Been there, done that, return old answer
      new_node = transform_once(n);     // Check for constant
      _nodes.map( n->_idx, new_node );  // Flag as having been cloned
    
      // Allocate stack of size _nodes.Size()/2 to avoid frequent realloc
      GrowableArray <Node *> trstack(C->live_nodes() >> 1);
    
      trstack.push(new_node);           // Process children of cloned node
      while ( trstack.is_nonempty() ) {
        Node *clone = trstack.pop();
        uint cnt = clone->req();
        for( uint i = 0; i < cnt; i++ ) {          // For all inputs do
          Node *input = clone->in(i);
          if( input != NULL ) {                    // Ignore NULLs
            Node *new_input = _nodes[input->_idx]; // Check for cloned input node
            if( new_input == NULL ) {
              new_input = transform_once(input);   // Check for constant
              _nodes.map( input->_idx, new_input );// Flag as having been cloned
              trstack.push(new_input);
            }
            assert( new_input == clone->in(i), "insanity check");
          }
        }
      }
      return new_node;
    }
    

    do_transform从root出发,对整个ir的node挨个调用一次transform_once,所以,变形的核心是transform_once:

    Node *PhaseCCP::transform_once( Node *n ) {
      const Type *t = type(n);
      // Constant?  Use constant Node instead
      if( t->singleton() ) {
        Node *nn = n;               // Default is to return the original constant
        if( t == Type::TOP ) {
          // cache my top node on the Compile instance
          if( C->cached_top_node() == NULL || C->cached_top_node()->in(0) == NULL ) {
            C->set_cached_top_node(ConNode::make(Type::TOP));
            set_type(C->top(), Type::TOP);
          }
          nn = C->top();
        }
        if( !n->is_Con() ) {
          if( t != Type::TOP ) {
            nn = makecon(t);        // ConNode::make(t);
            NOT_PRODUCT( inc_constants(); )
          } else if( n->is_Region() ) { // Unreachable region
            // Note: nn == C->top()
            n->set_req(0, NULL);        // Cut selfreference
            bool progress = true;
            uint max = n->outcnt();
            DUIterator i;
            while (progress) {
              progress = false;
              // Eagerly remove dead phis to avoid phis copies creation.
              for (i = n->outs(); n->has_out(i); i++) {
                Node* m = n->out(i);
                if (m->is_Phi()) {
                  assert(type(m) == Type::TOP, "Unreachable region should not have live phis.");
                  replace_node(m, nn);
                  if (max != n->outcnt()) {
                    progress = true;
                    i = n->refresh_out_pos(i);
                    max = n->outcnt();
                  }
                }
              }
            }
          }
          replace_node(n,nn);       // Update DefUse edges for new constant
        }
        return nn;
      }
    
      // If x is a TypeNode, capture any more-precise type permanently into Node
      if (t != n->bottom_type()) {
        hash_delete(n);             // changing bottom type may force a rehash
        n->raise_bottom_type(t);
        _worklist.push(n);          // n re-enters the hash table via the worklist
      }
    
      // TEMPORARY fix to ensure that 2nd GVN pass eliminates NULL checks
      switch( n->Opcode() ) {
      case Op_FastLock:      // Revisit FastLocks for lock coarsening
      case Op_If:
      case Op_CountedLoopEnd:
      case Op_Region:
      case Op_Loop:
      case Op_CountedLoop:
      case Op_Conv2B:
      case Op_Opaque1:
      case Op_Opaque2:
        _worklist.push(n);
        break;
      default:
        break;
      }
    
      return  n;
    }
    
  • 相关阅读:
    SpringCloud高可用和高并发
    时间重要性,我们需要如何利用极致
    Spring是什么 包括SpringBean SpringMVC SpringBoot SpringCloud
    Java 线程的基本使用
    JVM 内存模型
    Java 8 ArrayList 详解
    Java 8 HashMap 源码解析
    Docker 运行 MySQL,使用 docker-compose
    Spring Boot 主从读写分离
    Spring Boot 整合 MyBatis 实现乐观锁和悲观锁
  • 原文地址:https://www.cnblogs.com/kelthuzadx/p/15718509.html
Copyright © 2011-2022 走看看