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;
}
原文地址:https://www.cnblogs.com/kelthuzadx/p/15718509.html