hotspot/src/share/vm/opto/block.cpp
changeset 22872 b6902ee5bc8d
parent 22234 da823d78ad65
parent 22866 5e47c3568183
child 24425 53764d2358f9
child 24424 2658d7834c6e
--- a/hotspot/src/share/vm/opto/block.cpp	Tue Jan 28 11:21:43 2014 -0800
+++ b/hotspot/src/share/vm/opto/block.cpp	Tue Jan 28 12:25:34 2014 -0800
@@ -144,6 +144,10 @@
   remove_node(find_node(n));
 }
 
+bool Block::contains(const Node *n) const {
+  return _nodes.contains(n);
+}
+
 // Return empty status of a block.  Empty blocks contain only the head, other
 // ideal nodes, and an optional trailing goto.
 int Block::is_Empty() const {
@@ -526,18 +530,27 @@
 
 // Does this block end in a multiway branch that cannot have the default case
 // flipped for another case?
-static bool no_flip_branch( Block *b ) {
+static bool no_flip_branch(Block *b) {
   int branch_idx = b->number_of_nodes() - b->_num_succs-1;
-  if( branch_idx < 1 ) return false;
-  Node *bra = b->get_node(branch_idx);
-  if( bra->is_Catch() )
+  if (branch_idx < 1) {
+    return false;
+  }
+  Node *branch = b->get_node(branch_idx);
+  if (branch->is_Catch()) {
     return true;
-  if( bra->is_Mach() ) {
-    if( bra->is_MachNullCheck() )
+  }
+  if (branch->is_Mach()) {
+    if (branch->is_MachNullCheck()) {
       return true;
-    int iop = bra->as_Mach()->ideal_Opcode();
-    if( iop == Op_FastLock || iop == Op_FastUnlock )
+    }
+    int iop = branch->as_Mach()->ideal_Opcode();
+    if (iop == Op_FastLock || iop == Op_FastUnlock) {
       return true;
+    }
+    // Don't flip if branch has an implicit check.
+    if (branch->as_Mach()->is_TrapBasedCheckNode()) {
+      return true;
+    }
   }
   return false;
 }
@@ -696,10 +709,66 @@
   } // End of for all blocks
 }
 
+Block *PhaseCFG::fixup_trap_based_check(Node *branch, Block *block, int block_pos, Block *bnext) {
+  // Trap based checks must fall through to the successor with
+  // PROB_ALWAYS.
+  // They should be an If with 2 successors.
+  assert(branch->is_MachIf(),   "must be If");
+  assert(block->_num_succs == 2, "must have 2 successors");
+
+  // Get the If node and the projection for the first successor.
+  MachIfNode *iff   = block->get_node(block->number_of_nodes()-3)->as_MachIf();
+  ProjNode   *proj0 = block->get_node(block->number_of_nodes()-2)->as_Proj();
+  ProjNode   *proj1 = block->get_node(block->number_of_nodes()-1)->as_Proj();
+  ProjNode   *projt = (proj0->Opcode() == Op_IfTrue)  ? proj0 : proj1;
+  ProjNode   *projf = (proj0->Opcode() == Op_IfFalse) ? proj0 : proj1;
+
+  // Assert that proj0 and succs[0] match up. Similarly for proj1 and succs[1].
+  assert(proj0->raw_out(0) == block->_succs[0]->head(), "Mismatch successor 0");
+  assert(proj1->raw_out(0) == block->_succs[1]->head(), "Mismatch successor 1");
+
+  ProjNode *proj_always;
+  ProjNode *proj_never;
+  // We must negate the branch if the implicit check doesn't follow
+  // the branch's TRUE path. Then, the new TRUE branch target will
+  // be the old FALSE branch target.
+  if (iff->_prob <= 2*PROB_NEVER) {   // There are small rounding errors.
+    proj_never  = projt;
+    proj_always = projf;
+  } else {
+    // We must negate the branch if the trap doesn't follow the
+    // branch's TRUE path. Then, the new TRUE branch target will
+    // be the old FALSE branch target.
+    proj_never  = projf;
+    proj_always = projt;
+    iff->negate();
+  }
+  assert(iff->_prob <= 2*PROB_NEVER, "Trap based checks are expected to trap never!");
+  // Map the successors properly
+  block->_succs.map(0, get_block_for_node(proj_never ->raw_out(0)));   // The target of the trap.
+  block->_succs.map(1, get_block_for_node(proj_always->raw_out(0)));   // The fall through target.
+
+  if (block->get_node(block->number_of_nodes() - block->_num_succs + 1) != proj_always) {
+    block->map_node(proj_never,  block->number_of_nodes() - block->_num_succs + 0);
+    block->map_node(proj_always, block->number_of_nodes() - block->_num_succs + 1);
+  }
+
+  // Place the fall through block after this block.
+  Block *bs1 = block->non_connector_successor(1);
+  if (bs1 != bnext && move_to_next(bs1, block_pos)) {
+    bnext = bs1;
+  }
+  // If the fall through block still is not the next block, insert a goto.
+  if (bs1 != bnext) {
+    insert_goto_at(block_pos, 1);
+  }
+  return bnext;
+}
+
 // Fix up the final control flow for basic blocks.
 void PhaseCFG::fixup_flow() {
   // Fixup final control flow for the blocks.  Remove jump-to-next
-  // block.  If neither arm of a IF follows the conditional branch, we
+  // block. If neither arm of an IF follows the conditional branch, we
   // have to add a second jump after the conditional.  We place the
   // TRUE branch target in succs[0] for both GOTOs and IFs.
   for (uint i = 0; i < number_of_blocks(); i++) {
@@ -719,25 +788,39 @@
     // Check for multi-way branches where I cannot negate the test to
     // exchange the true and false targets.
     if (no_flip_branch(block)) {
-      // Find fall through case - if must fall into its target
+      // Find fall through case - if must fall into its target.
+      // Get the index of the branch's first successor.
       int branch_idx = block->number_of_nodes() - block->_num_succs;
-      for (uint j2 = 0; j2 < block->_num_succs; j2++) {
-        const ProjNode* p = block->get_node(branch_idx + j2)->as_Proj();
-        if (p->_con == 0) {
-          // successor j2 is fall through case
-          if (block->non_connector_successor(j2) != bnext) {
-            // but it is not the next block => insert a goto
-            insert_goto_at(i, j2);
+
+      // The branch is 1 before the branch's first successor.
+      Node *branch = block->get_node(branch_idx-1);
+
+      // Handle no-flip branches which have implicit checks and which require
+      // special block ordering and individual semantics of the 'fall through
+      // case'.
+      if ((TrapBasedNullChecks || TrapBasedRangeChecks) &&
+          branch->is_Mach() && branch->as_Mach()->is_TrapBasedCheckNode()) {
+        bnext = fixup_trap_based_check(branch, block, i, bnext);
+      } else {
+        // Else, default handling for no-flip branches
+        for (uint j2 = 0; j2 < block->_num_succs; j2++) {
+          const ProjNode* p = block->get_node(branch_idx + j2)->as_Proj();
+          if (p->_con == 0) {
+            // successor j2 is fall through case
+            if (block->non_connector_successor(j2) != bnext) {
+              // but it is not the next block => insert a goto
+              insert_goto_at(i, j2);
+            }
+            // Put taken branch in slot 0
+            if (j2 == 0 && block->_num_succs == 2) {
+              // Flip targets in succs map
+              Block *tbs0 = block->_succs[0];
+              Block *tbs1 = block->_succs[1];
+              block->_succs.map(0, tbs1);
+              block->_succs.map(1, tbs0);
+            }
+            break;
           }
-          // Put taken branch in slot 0
-          if (j2 == 0 && block->_num_succs == 2) {
-            // Flip targets in succs map
-            Block *tbs0 = block->_succs[0];
-            Block *tbs1 = block->_succs[1];
-            block->_succs.map(0, tbs1);
-            block->_succs.map(1, tbs0);
-          }
-          break;
         }
       }
 
@@ -844,6 +927,228 @@
 }
 
 
+// postalloc_expand: Expand nodes after register allocation.
+//
+// postalloc_expand has to be called after register allocation, just
+// before output (i.e. scheduling). It only gets called if
+// Matcher::require_postalloc_expand is true.
+//
+// Background:
+//
+// Nodes that are expandend (one compound node requiring several
+// assembler instructions to be implemented split into two or more
+// non-compound nodes) after register allocation are not as nice as
+// the ones expanded before register allocation - they don't
+// participate in optimizations as global code motion. But after
+// register allocation we can expand nodes that use registers which
+// are not spillable or registers that are not allocated, because the
+// old compound node is simply replaced (in its location in the basic
+// block) by a new subgraph which does not contain compound nodes any
+// more. The scheduler called during output can later on process these
+// non-compound nodes.
+//
+// Implementation:
+//
+// Nodes requiring postalloc expand are specified in the ad file by using
+// a postalloc_expand statement instead of ins_encode. A postalloc_expand
+// contains a single call to an encoding, as does an ins_encode
+// statement. Instead of an emit() function a postalloc_expand() function
+// is generated that doesn't emit assembler but creates a new
+// subgraph. The code below calls this postalloc_expand function for each
+// node with the appropriate attribute. This function returns the new
+// nodes generated in an array passed in the call. The old node,
+// potential MachTemps before and potential Projs after it then get
+// disconnected and replaced by the new nodes. The instruction
+// generating the result has to be the last one in the array. In
+// general it is assumed that Projs after the node expanded are
+// kills. These kills are not required any more after expanding as
+// there are now explicitly visible def-use chains and the Projs are
+// removed. This does not hold for calls: They do not only have
+// kill-Projs but also Projs defining values. Therefore Projs after
+// the node expanded are removed for all but for calls. If a node is
+// to be reused, it must be added to the nodes list returned, and it
+// will be added again.
+//
+// Implementing the postalloc_expand function for a node in an enc_class
+// is rather tedious. It requires knowledge about many node details, as
+// the nodes and the subgraph must be hand crafted. To simplify this,
+// adlc generates some utility variables into the postalloc_expand function,
+// e.g., holding the operands as specified by the postalloc_expand encoding
+// specification, e.g.:
+//  * unsigned idx_<par_name>  holding the index of the node in the ins
+//  * Node *n_<par_name>       holding the node loaded from the ins
+//  * MachOpnd *op_<par_name>  holding the corresponding operand
+//
+// The ordering of operands can not be determined by looking at a
+// rule. Especially if a match rule matches several different trees,
+// several nodes are generated from one instruct specification with
+// different operand orderings. In this case the adlc generated
+// variables are the only way to access the ins and operands
+// deterministically.
+//
+// If assigning a register to a node that contains an oop, don't
+// forget to call ra_->set_oop() for the node.
+void PhaseCFG::postalloc_expand(PhaseRegAlloc* _ra) {
+  GrowableArray <Node *> new_nodes(32); // Array with new nodes filled by postalloc_expand function of node.
+  GrowableArray <Node *> remove(32);
+  GrowableArray <Node *> succs(32);
+  unsigned int max_idx = C->unique();   // Remember to distinguish new from old nodes.
+  DEBUG_ONLY(bool foundNode = false);
+
+  // for all blocks
+  for (uint i = 0; i < number_of_blocks(); i++) {
+    Block *b = _blocks[i];
+    // For all instructions in the current block.
+    for (uint j = 0; j < b->number_of_nodes(); j++) {
+      Node *n = b->get_node(j);
+      if (n->is_Mach() && n->as_Mach()->requires_postalloc_expand()) {
+#ifdef ASSERT
+        if (TracePostallocExpand) {
+          if (!foundNode) {
+            foundNode = true;
+            tty->print("POSTALLOC EXPANDING %d %s\n", C->compile_id(),
+                       C->method() ? C->method()->name()->as_utf8() : C->stub_name());
+          }
+          tty->print("  postalloc expanding "); n->dump();
+          if (Verbose) {
+            tty->print("    with ins:\n");
+            for (uint k = 0; k < n->len(); ++k) {
+              if (n->in(k)) { tty->print("        "); n->in(k)->dump(); }
+            }
+          }
+        }
+#endif
+        new_nodes.clear();
+        // Collect nodes that have to be removed from the block later on.
+        uint req = n->req();
+        remove.clear();
+        for (uint k = 0; k < req; ++k) {
+          if (n->in(k) && n->in(k)->is_MachTemp()) {
+            remove.push(n->in(k)); // MachTemps which are inputs to the old node have to be removed.
+            n->in(k)->del_req(0);
+            j--;
+          }
+        }
+
+        // Check whether we can allocate enough nodes. We set a fix limit for
+        // the size of postalloc expands with this.
+        uint unique_limit = C->unique() + 40;
+        if (unique_limit >= _ra->node_regs_max_index()) {
+          Compile::current()->record_failure("out of nodes in postalloc expand");
+          return;
+        }
+
+        // Emit (i.e. generate new nodes).
+        n->as_Mach()->postalloc_expand(&new_nodes, _ra);
+
+        assert(C->unique() < unique_limit, "You allocated too many nodes in your postalloc expand.");
+
+        // Disconnect the inputs of the old node.
+        //
+        // We reuse MachSpillCopy nodes. If we need to expand them, there
+        // are many, so reusing pays off. If reused, the node already
+        // has the new ins. n must be the last node on new_nodes list.
+        if (!n->is_MachSpillCopy()) {
+          for (int k = req - 1; k >= 0; --k) {
+            n->del_req(k);
+          }
+        }
+
+#ifdef ASSERT
+        // Check that all nodes have proper operands.
+        for (int k = 0; k < new_nodes.length(); ++k) {
+          if (new_nodes.at(k)->_idx < max_idx || !new_nodes.at(k)->is_Mach()) continue; // old node, Proj ...
+          MachNode *m = new_nodes.at(k)->as_Mach();
+          for (unsigned int l = 0; l < m->num_opnds(); ++l) {
+            if (MachOper::notAnOper(m->_opnds[l])) {
+              outputStream *os = tty;
+              os->print("Node %s ", m->Name());
+              os->print("has invalid opnd %d: %p\n", l, m->_opnds[l]);
+              assert(0, "Invalid operands, see inline trace in hs_err_pid file.");
+            }
+          }
+        }
+#endif
+
+        // Collect succs of old node in remove (for projections) and in succs (for
+        // all other nodes) do _not_ collect projections in remove (but in succs)
+        // in case the node is a call. We need the projections for calls as they are
+        // associated with registes (i.e. they are defs).
+        succs.clear();
+        for (DUIterator k = n->outs(); n->has_out(k); k++) {
+          if (n->out(k)->is_Proj() && !n->is_MachCall() && !n->is_MachBranch()) {
+            remove.push(n->out(k));
+          } else {
+            succs.push(n->out(k));
+          }
+        }
+        // Replace old node n as input of its succs by last of the new nodes.
+        for (int k = 0; k < succs.length(); ++k) {
+          Node *succ = succs.at(k);
+          for (uint l = 0; l < succ->req(); ++l) {
+            if (succ->in(l) == n) {
+              succ->set_req(l, new_nodes.at(new_nodes.length() - 1));
+            }
+          }
+          for (uint l = succ->req(); l < succ->len(); ++l) {
+            if (succ->in(l) == n) {
+              succ->set_prec(l, new_nodes.at(new_nodes.length() - 1));
+            }
+          }
+        }
+
+        // Index of old node in block.
+        uint index = b->find_node(n);
+        // Insert new nodes into block and map them in nodes->blocks array
+        // and remember last node in n2.
+        Node *n2 = NULL;
+        for (int k = 0; k < new_nodes.length(); ++k) {
+          n2 = new_nodes.at(k);
+          b->insert_node(n2, ++index);
+          map_node_to_block(n2, b);
+        }
+
+        // Add old node n to remove and remove them all from block.
+        remove.push(n);
+        j--;
+#ifdef ASSERT
+        if (TracePostallocExpand && Verbose) {
+          tty->print("    removing:\n");
+          for (int k = 0; k < remove.length(); ++k) {
+            tty->print("        "); remove.at(k)->dump();
+          }
+          tty->print("    inserting:\n");
+          for (int k = 0; k < new_nodes.length(); ++k) {
+            tty->print("        "); new_nodes.at(k)->dump();
+          }
+        }
+#endif
+        for (int k = 0; k < remove.length(); ++k) {
+          if (b->contains(remove.at(k))) {
+            b->find_remove(remove.at(k));
+          } else {
+            assert(remove.at(k)->is_Proj() && (remove.at(k)->in(0)->is_MachBranch()), "");
+          }
+        }
+        // If anything has been inserted (n2 != NULL), continue after last node inserted.
+        // This does not always work. Some postalloc expands don't insert any nodes, if they
+        // do optimizations (e.g., max(x,x)). In this case we decrement j accordingly.
+        j = n2 ? b->find_node(n2) : j;
+      }
+    }
+  }
+
+#ifdef ASSERT
+  if (foundNode) {
+    tty->print("FINISHED %d %s\n", C->compile_id(),
+               C->method() ? C->method()->name()->as_utf8() : C->stub_name());
+    tty->flush();
+  }
+#endif
+}
+
+
+//------------------------------dump-------------------------------------------
 #ifndef PRODUCT
 void PhaseCFG::_dump_cfg( const Node *end, VectorSet &visited  ) const {
   const Node *x = end->is_block_proj();