--- 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();