-
Enhancement
-
Resolution: Unresolved
-
P4
-
5.0u11, 9, 10
-
generic
-
generic
During the Split-If optimization, C2 should handle all invariant data uses before all the invariant control uses.
Here is a suggested fix to this problem.
==== //java/main-dev/java/hotspot5/src/share/vm/opto/loopnode.hpp#15 - /home/cliffc/HotSpot/cliffc-bugs/hotspot5/src/share/vm/opto/loopnode.hpp ====
@@ -600,6 +600,7 @@
// normal "loop-exit" condition. All uses of loop-invariant old-loop values
// now come from (one or more) Phis that merge their new-loop equivalents.
void clone_loop( IdealLoopTree *loop, Node_List &old_new, int dom_depth, bool clone_after );
+ void handle_invariant_uses( Node *old, IdealLoopTree *loop, Node_List &old_new, Node_List *worklist, Node **old_idoms, int old_idom_size, int new_counter, int loopbodysize, Node_List **split_if_set, Node_List **split_bool_set);
// If we got the effect of peeling, either by actually peeling or by
// making a pre-loop which must execute at least once, we can remove
==== //java/main-dev/java/hotspot5/src/share/vm/opto/loopopts.cpp#17 - /home/cliffc/HotSpot/cliffc-bugs/hotspot5/src/share/vm/opto/loopopts.cpp ====
@@ -1504,15 +1504,57 @@
Node_List *split_bool_set = NULL;
for( i = 0; i < loopbodysize; i++ ) {
Node* old = loop->_body.at(i);
- Node* nnn = old_new[old->_idx];
- // Copy uses to a worklist, so I can munge the def-use info
- // with impunity.
- for (DUIterator_Fast jmax, j = old->fast_outs(jmax); j < jmax; j++)
- worklist.push(old->fast_out(j));
+ if( !old->is_CFG() )
+ handle_invariant_uses(old,loop,old_new,&worklist,old_idoms,old_idom_size,new_counter,loopbodysize,&split_if_set,&split_bool_set);
+ }
+ for( i = 0; i < loopbodysize; i++ ) {
+ Node* old = loop->_body.at(i);
+ if( old->is_CFG() )
+ handle_invariant_uses(old,loop,old_new,&worklist,old_idoms,old_idom_size,new_counter,loopbodysize,&split_if_set,&split_bool_set);
+ }
+
+ // Check for IFs that need splitting/cloning. Happens if an IF outside of
+ // the loop uses a condition set in the loop. The original IF probably
+ // takes control from one or more OLD Regions (which in turn get from NEW
+ // Regions). In any case, there will be a set of Phis for each merge point
+ // from the IF up to where the original BOOL def exists the loop.
+ if( split_if_set ) {
+ while( split_if_set->size() ) {
+ Node *iff = split_if_set->pop();
+ PhiNode *phi = iff->in(1)->is_Phi();
+ if( phi ) {
+ BoolNode *b = clone_iff( phi, loop );
+ _igvn.hash_delete(iff);
+ _igvn._worklist.push(iff);
+ iff->set_req(1, b);
+ }
+ }
+ }
+ if( split_bool_set ) {
+ while( split_bool_set->size() ) {
+ Node *b = split_bool_set->pop();
+ Node *phi = b->in(1);
+ assert( phi->is_Phi(), "" );
+ CmpNode *cmp = clone_bool( (PhiNode*)phi, loop );
+ _igvn.hash_delete(b);
+ _igvn._worklist.push(b);
+ b->set_req(1, cmp);
+ }
+ }
+
+}
+
+//------------------------------handle_invariant_uses--------------------------
+void PhaseIdealLoop::handle_invariant_uses( Node *old, IdealLoopTree *loop, Node_List &old_new, Node_List *worklist, Node **old_idoms, int old_idom_size, int new_counter, int loopbodysize, Node_List **split_if_set, Node_List **split_bool_set ) {
+ Node* nnn = old_new[old->_idx];
+ // Copy uses to a worklist, so I can munge the def-use info
+ // with impunity.
+ for (DUIterator_Fast jmax, j = old->fast_outs(jmax); j < jmax; j++)
+ worklist->push(old->fast_out(j));
- while( worklist.size() ) {
+ while( worklist->size() ) {
assert0( loopbodysize == loop->_body.size() );
- Node *use = worklist.pop();
+ Node *use = worklist->pop();
if (!has_node(use)) continue; // Ignore dead nodes
if (use->in(0) == C->top()) continue;
IdealLoopTree *use_loop = get_loop( has_ctrl(use) ? get_ctrl_no_assert(use) : use );
@@ -1528,14 +1570,14 @@
if( use->is_If() || use->is_CMove() ) {
// Since this code is highly unlikely, we lazily build the worklist
// of such Nodes to go split.
- if( !split_if_set )
- split_if_set = new Node_List(area);
- split_if_set->push(use);
+ if( !*split_if_set )
+ *split_if_set = new Node_List(Thread::current()->resource_area());
+ (*split_if_set)->push(use);
}
if( use->is_Bool() ) {
- if( !split_bool_set )
- split_bool_set = new Node_List(area);
- split_bool_set->push(use);
+ if( !*split_bool_set )
+ *split_bool_set = new Node_List(Thread::current()->resource_area());
+ (*split_bool_set)->push(use);
}
// Get "block" use is in
@@ -1569,7 +1611,7 @@
phi = PhiNode::make( prev, old );
// Now recursively fix up the new uses of old!
for( uint i = 1; i < prev->req(); i++ ) {
- worklist.push(phi); // Onto worklist once for each 'old' input
+ worklist->push(phi); // Onto worklist once for each 'old' input
}
}
} else {
@@ -1626,38 +1668,8 @@
}
assert0( loopbodysize == loop->_body.size() );
}
- }
+}
- // Check for IFs that need splitting/cloning. Happens if an IF outside of
- // the loop uses a condition set in the loop. The original IF probably
- // takes control from one or more OLD Regions (which in turn get from NEW
- // Regions). In any case, there will be a set of Phis for each merge point
- // from the IF up to where the original BOOL def exists the loop.
- if( split_if_set ) {
- while( split_if_set->size() ) {
- Node *iff = split_if_set->pop();
- PhiNode *phi = iff->in(1)->is_Phi();
- if( phi ) {
- BoolNode *b = clone_iff( phi, loop );
- _igvn.hash_delete(iff);
- _igvn._worklist.push(iff);
- iff->set_req(1, b);
- }
- }
- }
- if( split_bool_set ) {
- while( split_bool_set->size() ) {
- Node *b = split_bool_set->pop();
- Node *phi = b->in(1);
- assert( phi->is_Phi(), "" );
- CmpNode *cmp = clone_bool( (PhiNode*)phi, loop );
- _igvn.hash_delete(b);
- _igvn._worklist.push(b);
- b->set_req(1, cmp);
- }
- }
-
-}
//------------------------------reorg_offsets----------------------------------
// Reorganize offset computations to lower register pressure. Mostly
Here is a suggested fix to this problem.
==== //java/main-dev/java/hotspot5/src/share/vm/opto/loopnode.hpp#15 - /home/cliffc/HotSpot/cliffc-bugs/hotspot5/src/share/vm/opto/loopnode.hpp ====
@@ -600,6 +600,7 @@
// normal "loop-exit" condition. All uses of loop-invariant old-loop values
// now come from (one or more) Phis that merge their new-loop equivalents.
void clone_loop( IdealLoopTree *loop, Node_List &old_new, int dom_depth, bool clone_after );
+ void handle_invariant_uses( Node *old, IdealLoopTree *loop, Node_List &old_new, Node_List *worklist, Node **old_idoms, int old_idom_size, int new_counter, int loopbodysize, Node_List **split_if_set, Node_List **split_bool_set);
// If we got the effect of peeling, either by actually peeling or by
// making a pre-loop which must execute at least once, we can remove
==== //java/main-dev/java/hotspot5/src/share/vm/opto/loopopts.cpp#17 - /home/cliffc/HotSpot/cliffc-bugs/hotspot5/src/share/vm/opto/loopopts.cpp ====
@@ -1504,15 +1504,57 @@
Node_List *split_bool_set = NULL;
for( i = 0; i < loopbodysize; i++ ) {
Node* old = loop->_body.at(i);
- Node* nnn = old_new[old->_idx];
- // Copy uses to a worklist, so I can munge the def-use info
- // with impunity.
- for (DUIterator_Fast jmax, j = old->fast_outs(jmax); j < jmax; j++)
- worklist.push(old->fast_out(j));
+ if( !old->is_CFG() )
+ handle_invariant_uses(old,loop,old_new,&worklist,old_idoms,old_idom_size,new_counter,loopbodysize,&split_if_set,&split_bool_set);
+ }
+ for( i = 0; i < loopbodysize; i++ ) {
+ Node* old = loop->_body.at(i);
+ if( old->is_CFG() )
+ handle_invariant_uses(old,loop,old_new,&worklist,old_idoms,old_idom_size,new_counter,loopbodysize,&split_if_set,&split_bool_set);
+ }
+
+ // Check for IFs that need splitting/cloning. Happens if an IF outside of
+ // the loop uses a condition set in the loop. The original IF probably
+ // takes control from one or more OLD Regions (which in turn get from NEW
+ // Regions). In any case, there will be a set of Phis for each merge point
+ // from the IF up to where the original BOOL def exists the loop.
+ if( split_if_set ) {
+ while( split_if_set->size() ) {
+ Node *iff = split_if_set->pop();
+ PhiNode *phi = iff->in(1)->is_Phi();
+ if( phi ) {
+ BoolNode *b = clone_iff( phi, loop );
+ _igvn.hash_delete(iff);
+ _igvn._worklist.push(iff);
+ iff->set_req(1, b);
+ }
+ }
+ }
+ if( split_bool_set ) {
+ while( split_bool_set->size() ) {
+ Node *b = split_bool_set->pop();
+ Node *phi = b->in(1);
+ assert( phi->is_Phi(), "" );
+ CmpNode *cmp = clone_bool( (PhiNode*)phi, loop );
+ _igvn.hash_delete(b);
+ _igvn._worklist.push(b);
+ b->set_req(1, cmp);
+ }
+ }
+
+}
+
+//------------------------------handle_invariant_uses--------------------------
+void PhaseIdealLoop::handle_invariant_uses( Node *old, IdealLoopTree *loop, Node_List &old_new, Node_List *worklist, Node **old_idoms, int old_idom_size, int new_counter, int loopbodysize, Node_List **split_if_set, Node_List **split_bool_set ) {
+ Node* nnn = old_new[old->_idx];
+ // Copy uses to a worklist, so I can munge the def-use info
+ // with impunity.
+ for (DUIterator_Fast jmax, j = old->fast_outs(jmax); j < jmax; j++)
+ worklist->push(old->fast_out(j));
- while( worklist.size() ) {
+ while( worklist->size() ) {
assert0( loopbodysize == loop->_body.size() );
- Node *use = worklist.pop();
+ Node *use = worklist->pop();
if (!has_node(use)) continue; // Ignore dead nodes
if (use->in(0) == C->top()) continue;
IdealLoopTree *use_loop = get_loop( has_ctrl(use) ? get_ctrl_no_assert(use) : use );
@@ -1528,14 +1570,14 @@
if( use->is_If() || use->is_CMove() ) {
// Since this code is highly unlikely, we lazily build the worklist
// of such Nodes to go split.
- if( !split_if_set )
- split_if_set = new Node_List(area);
- split_if_set->push(use);
+ if( !*split_if_set )
+ *split_if_set = new Node_List(Thread::current()->resource_area());
+ (*split_if_set)->push(use);
}
if( use->is_Bool() ) {
- if( !split_bool_set )
- split_bool_set = new Node_List(area);
- split_bool_set->push(use);
+ if( !*split_bool_set )
+ *split_bool_set = new Node_List(Thread::current()->resource_area());
+ (*split_bool_set)->push(use);
}
// Get "block" use is in
@@ -1569,7 +1611,7 @@
phi = PhiNode::make( prev, old );
// Now recursively fix up the new uses of old!
for( uint i = 1; i < prev->req(); i++ ) {
- worklist.push(phi); // Onto worklist once for each 'old' input
+ worklist->push(phi); // Onto worklist once for each 'old' input
}
}
} else {
@@ -1626,38 +1668,8 @@
}
assert0( loopbodysize == loop->_body.size() );
}
- }
+}
- // Check for IFs that need splitting/cloning. Happens if an IF outside of
- // the loop uses a condition set in the loop. The original IF probably
- // takes control from one or more OLD Regions (which in turn get from NEW
- // Regions). In any case, there will be a set of Phis for each merge point
- // from the IF up to where the original BOOL def exists the loop.
- if( split_if_set ) {
- while( split_if_set->size() ) {
- Node *iff = split_if_set->pop();
- PhiNode *phi = iff->in(1)->is_Phi();
- if( phi ) {
- BoolNode *b = clone_iff( phi, loop );
- _igvn.hash_delete(iff);
- _igvn._worklist.push(iff);
- iff->set_req(1, b);
- }
- }
- }
- if( split_bool_set ) {
- while( split_bool_set->size() ) {
- Node *b = split_bool_set->pop();
- Node *phi = b->in(1);
- assert( phi->is_Phi(), "" );
- CmpNode *cmp = clone_bool( (PhiNode*)phi, loop );
- _igvn.hash_delete(b);
- _igvn._worklist.push(b);
- b->set_req(1, cmp);
- }
- }
-
-}
//------------------------------reorg_offsets----------------------------------
// Reorganize offset computations to lower register pressure. Mostly