8039425: Code cleanup: PhaseIterGVN::optimize()

This code cleanup aims at improving code readability.

Reviewed-by: kvn, roland
This commit is contained in:
Albert Noll 2014-04-14 10:57:07 +02:00
parent d7b640b3ce
commit e2305182b5
2 changed files with 214 additions and 188 deletions

View File

@ -831,154 +831,111 @@ PhaseIterGVN::PhaseIterGVN( PhaseGVN *gvn ) : PhaseGVN(gvn),
}
}
/**
* Initialize worklist for each node.
*/
void PhaseIterGVN::init_worklist(Node* first) {
Unique_Node_List to_process;
to_process.push(first);
while (to_process.size() > 0) {
Node* n = to_process.pop();
if (!_worklist.member(n)) {
_worklist.push(n);
uint cnt = n->req();
for(uint i = 0; i < cnt; i++) {
Node* m = n->in(i);
if (m != NULL) {
to_process.push(m);
}
}
}
}
}
#ifndef PRODUCT
void PhaseIterGVN::verify_step(Node* n) {
_verify_window[_verify_counter % _verify_window_size] = n;
++_verify_counter;
ResourceMark rm;
ResourceArea *area = Thread::current()->resource_area();
VectorSet old_space(area), new_space(area);
if (C->unique() < 1000 ||
0 == _verify_counter % (C->unique() < 10000 ? 10 : 100)) {
++_verify_full_passes;
Node::verify_recur(C->root(), -1, old_space, new_space);
}
const int verify_depth = 4;
for ( int i = 0; i < _verify_window_size; i++ ) {
Node* n = _verify_window[i];
if ( n == NULL ) continue;
if( n->in(0) == NodeSentinel ) { // xform_idom
_verify_window[i] = n->in(1);
--i; continue;
if (VerifyIterativeGVN) {
_verify_window[_verify_counter % _verify_window_size] = n;
++_verify_counter;
ResourceMark rm;
ResourceArea* area = Thread::current()->resource_area();
VectorSet old_space(area), new_space(area);
if (C->unique() < 1000 ||
0 == _verify_counter % (C->unique() < 10000 ? 10 : 100)) {
++_verify_full_passes;
Node::verify_recur(C->root(), -1, old_space, new_space);
}
// Typical fanout is 1-2, so this call visits about 6 nodes.
Node::verify_recur(n, verify_depth, old_space, new_space);
}
}
#endif
//------------------------------init_worklist----------------------------------
// Initialize worklist for each node.
void PhaseIterGVN::init_worklist( Node *n ) {
if( _worklist.member(n) ) return;
_worklist.push(n);
uint cnt = n->req();
for( uint i =0 ; i < cnt; i++ ) {
Node *m = n->in(i);
if( m ) init_worklist(m);
}
}
//------------------------------optimize---------------------------------------
void PhaseIterGVN::optimize() {
debug_only(uint num_processed = 0;);
#ifndef PRODUCT
{
_verify_counter = 0;
_verify_full_passes = 0;
const int verify_depth = 4;
for ( int i = 0; i < _verify_window_size; i++ ) {
_verify_window[i] = NULL;
Node* n = _verify_window[i];
if ( n == NULL ) continue;
if( n->in(0) == NodeSentinel ) { // xform_idom
_verify_window[i] = n->in(1);
--i; continue;
}
// Typical fanout is 1-2, so this call visits about 6 nodes.
Node::verify_recur(n, verify_depth, old_space, new_space);
}
}
#endif
}
#ifdef ASSERT
Node* prev = NULL;
uint rep_cnt = 0;
#endif
uint loop_count = 0;
// Pull from worklist; transform node;
// If node has changed: update edge info and put uses on worklist.
while( _worklist.size() ) {
if (C->check_node_count(NodeLimitFudgeFactor * 2,
"out of nodes optimizing method")) {
return;
}
Node *n = _worklist.pop();
if (++loop_count >= K * C->live_nodes()) {
debug_only(n->dump(4);)
assert(false, "infinite loop in PhaseIterGVN::optimize");
C->record_method_not_compilable("infinite loop in PhaseIterGVN::optimize");
return;
}
#ifdef ASSERT
if (n == prev) {
if (++rep_cnt > 3) {
n->dump(4);
assert(false, "loop in Ideal transformation");
void PhaseIterGVN::trace_PhaseIterGVN(Node* n, Node* nn, const Type* oldtype) {
if (TraceIterativeGVN) {
uint wlsize = _worklist.size();
const Type* newtype = type_or_null(n);
if (nn != n) {
// print old node
tty->print("< ");
if (oldtype != newtype && oldtype != NULL) {
oldtype->dump();
}
} else {
rep_cnt = 0;
do { tty->print("\t"); } while (tty->position() < 16);
tty->print("<");
n->dump();
}
prev = n;
#endif
if (TraceIterativeGVN && Verbose) {
tty->print(" Pop ");
NOT_PRODUCT( n->dump(); )
debug_only(if( (num_processed++ % 100) == 0 ) _worklist.print_set();)
if (oldtype != newtype || nn != n) {
// print new node and/or new type
if (oldtype == NULL) {
tty->print("* ");
} else if (nn != n) {
tty->print("> ");
} else {
tty->print("= ");
}
if (newtype == NULL) {
tty->print("null");
} else {
newtype->dump();
}
do { tty->print("\t"); } while (tty->position() < 16);
nn->dump();
}
if (n->outcnt() != 0) {
#ifndef PRODUCT
uint wlsize = _worklist.size();
const Type* oldtype = type_or_null(n);
#endif //PRODUCT
Node *nn = transform_old(n);
#ifndef PRODUCT
if (TraceIterativeGVN) {
const Type* newtype = type_or_null(n);
if (nn != n) {
// print old node
tty->print("< ");
if (oldtype != newtype && oldtype != NULL) {
oldtype->dump();
}
do { tty->print("\t"); } while (tty->position() < 16);
tty->print("<");
n->dump();
}
if (oldtype != newtype || nn != n) {
// print new node and/or new type
if (oldtype == NULL) {
tty->print("* ");
} else if (nn != n) {
tty->print("> ");
} else {
tty->print("= ");
}
if (newtype == NULL) {
tty->print("null");
} else {
newtype->dump();
}
do { tty->print("\t"); } while (tty->position() < 16);
nn->dump();
}
if (Verbose && wlsize < _worklist.size()) {
tty->print(" Push {");
while (wlsize != _worklist.size()) {
Node* pushed = _worklist.at(wlsize++);
tty->print(" %d", pushed->_idx);
}
tty->print_cr(" }");
}
if (Verbose && wlsize < _worklist.size()) {
tty->print(" Push {");
while (wlsize != _worklist.size()) {
Node* pushed = _worklist.at(wlsize++);
tty->print(" %d", pushed->_idx);
}
if( VerifyIterativeGVN && nn != n ) {
verify_step((Node*) NULL); // ignore n, it might be subsumed
}
#endif
} else if (!n->is_top()) {
remove_dead_node(n);
tty->print_cr(" }");
}
if (nn != n) {
// ignore n, it might be subsumed
verify_step((Node*) NULL);
}
}
}
#ifndef PRODUCT
void PhaseIterGVN::init_verifyPhaseIterGVN() {
_verify_counter = 0;
_verify_full_passes = 0;
for (int i = 0; i < _verify_window_size; i++) {
_verify_window[i] = NULL;
}
}
void PhaseIterGVN::verify_PhaseIterGVN() {
C->verify_graph_edges();
if( VerifyOpto && allow_progress() ) {
// Must turn off allow_progress to enable assert and break recursion
@ -998,21 +955,78 @@ void PhaseIterGVN::optimize() {
igvn2.set_allow_progress(true);
}
}
if ( VerifyIterativeGVN && PrintOpto ) {
if ( _verify_counter == _verify_full_passes )
if (VerifyIterativeGVN && PrintOpto) {
if (_verify_counter == _verify_full_passes) {
tty->print_cr("VerifyIterativeGVN: %d transforms and verify passes",
_verify_full_passes);
else
} else {
tty->print_cr("VerifyIterativeGVN: %d transforms, %d full verify passes",
_verify_counter, _verify_full_passes);
}
}
#endif
}
#endif /* PRODUCT */
#ifdef ASSERT
/**
* Dumps information that can help to debug the problem. A debug
* build fails with an assert.
*/
void PhaseIterGVN::dump_infinite_loop_info(Node* n) {
n->dump(4);
_worklist.dump();
assert(false, "infinite loop in PhaseIterGVN::optimize");
}
/**
* Prints out information about IGVN if the 'verbose' option is used.
*/
void PhaseIterGVN::trace_PhaseIterGVN_verbose(Node* n, int num_processed) {
if (TraceIterativeGVN && Verbose) {
tty->print(" Pop ");
n->dump();
if ((num_processed % 100) == 0) {
_worklist.print_set();
}
}
}
#endif /* ASSERT */
void PhaseIterGVN::optimize() {
DEBUG_ONLY(uint num_processed = 0;)
NOT_PRODUCT(init_verifyPhaseIterGVN();)
uint loop_count = 0;
// Pull from worklist and transform the node. If the node has changed,
// update edge info and put uses on worklist.
while(_worklist.size()) {
if (C->check_node_count(NodeLimitFudgeFactor * 2, "Out of nodes")) {
return;
}
Node* n = _worklist.pop();
if (++loop_count >= K * C->live_nodes()) {
DEBUG_ONLY(dump_infinite_loop_info(n);)
C->record_method_not_compilable("infinite loop in PhaseIterGVN::optimize");
return;
}
DEBUG_ONLY(trace_PhaseIterGVN_verbose(n, num_processed++);)
if (n->outcnt() != 0) {
NOT_PRODUCT(const Type* oldtype = type_or_null(n));
// Do the transformation
Node* nn = transform_old(n);
NOT_PRODUCT(trace_PhaseIterGVN(n, nn, oldtype);)
} else if (!n->is_top()) {
remove_dead_node(n);
}
}
NOT_PRODUCT(verify_PhaseIterGVN();)
}
//------------------register_new_node_with_optimizer---------------------------
// Register a new node with the optimizer. Update the types array, the def-use
// info. Put on worklist.
/**
* Register a new node with the optimizer. Update the types array, the def-use
* info. Put on worklist.
*/
Node* PhaseIterGVN::register_new_node_with_optimizer(Node* n, Node* orig) {
set_type_bottom(n);
_worklist.push(n);
@ -1038,32 +1052,29 @@ Node *PhaseIterGVN::transform( Node *n ) {
return transform_old(n);
}
//------------------------------transform_old----------------------------------
Node *PhaseIterGVN::transform_old( Node *n ) {
#ifndef PRODUCT
debug_only(uint loop_count = 0;);
set_transforms();
#endif
Node *PhaseIterGVN::transform_old(Node* n) {
DEBUG_ONLY(uint loop_count = 0;);
NOT_PRODUCT(set_transforms());
// Remove 'n' from hash table in case it gets modified
_table.hash_delete(n);
if( VerifyIterativeGVN ) {
assert( !_table.find_index(n->_idx), "found duplicate entry in table");
if (VerifyIterativeGVN) {
assert(!_table.find_index(n->_idx), "found duplicate entry in table");
}
// Apply the Ideal call in a loop until it no longer applies
Node *k = n;
Node* k = n;
DEBUG_ONLY(dead_loop_check(k);)
DEBUG_ONLY(bool is_new = (k->outcnt() == 0);)
Node *i = k->Ideal(this, /*can_reshape=*/true);
Node* i = k->Ideal(this, /*can_reshape=*/true);
assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes");
#ifndef PRODUCT
if( VerifyIterativeGVN )
verify_step(k);
if( i && VerifyOpto ) {
if( !allow_progress() ) {
if (i->is_Add() && i->outcnt() == 1) {
verify_step(k);
if (i && VerifyOpto ) {
if (!allow_progress()) {
if (i->is_Add() && (i->outcnt() == 1)) {
// Switched input to left side because this is the only use
} else if( i->is_If() && (i->in(0) == NULL) ) {
} else if (i->is_If() && (i->in(0) == NULL)) {
// This IF is dead because it is dominated by an equivalent IF When
// dominating if changed, info is not propagated sparsely to 'this'
// Propagating this info further will spuriously identify other
@ -1071,35 +1082,38 @@ Node *PhaseIterGVN::transform_old( Node *n ) {
return i;
} else
set_progress();
} else
} else {
set_progress();
}
}
#endif
while( i ) {
while (i != NULL) {
#ifndef PRODUCT
debug_only( if( loop_count >= K ) i->dump(4); )
assert(loop_count < K, "infinite loop in PhaseIterGVN::transform");
debug_only( loop_count++; )
if (loop_count >= K) {
dump_infinite_loop_info(i);
}
loop_count++;
#endif
assert((i->_idx >= k->_idx) || i->is_top(), "Idealize should return new nodes, use Identity to return old nodes");
// Made a change; put users of original Node on worklist
add_users_to_worklist( k );
add_users_to_worklist(k);
// Replacing root of transform tree?
if( k != i ) {
if (k != i) {
// Make users of old Node now use new.
subsume_node( k, i );
subsume_node(k, i);
k = i;
}
DEBUG_ONLY(dead_loop_check(k);)
// Try idealizing again
DEBUG_ONLY(is_new = (k->outcnt() == 0);)
i = k->Ideal(this, /*can_reshape=*/true);
assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes");
assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes");
#ifndef PRODUCT
if( VerifyIterativeGVN )
verify_step(k);
if( i && VerifyOpto ) set_progress();
verify_step(k);
if (i && VerifyOpto) {
set_progress();
}
#endif
}
@ -1107,48 +1121,49 @@ Node *PhaseIterGVN::transform_old( Node *n ) {
ensure_type_or_null(k);
// See what kind of values 'k' takes on at runtime
const Type *t = k->Value(this);
const Type* t = k->Value(this);
assert(t != NULL, "value sanity");
// Since I just called 'Value' to compute the set of run-time values
// for this Node, and 'Value' is non-local (and therefore expensive) I'll
// cache Value. Later requests for the local phase->type of this Node can
// use the cached Value instead of suffering with 'bottom_type'.
if (t != type_or_null(k)) {
NOT_PRODUCT( set_progress(); )
NOT_PRODUCT( inc_new_values();)
if (type_or_null(k) != t) {
#ifndef PRODUCT
inc_new_values();
set_progress();
#endif
set_type(k, t);
// If k is a TypeNode, capture any more-precise type permanently into Node
k->raise_bottom_type(t);
// Move users of node to worklist
add_users_to_worklist( k );
add_users_to_worklist(k);
}
// If 'k' computes a constant, replace it with a constant
if( t->singleton() && !k->is_Con() ) {
NOT_PRODUCT( set_progress(); )
Node *con = makecon(t); // Make a constant
add_users_to_worklist( k );
subsume_node( k, con ); // Everybody using k now uses con
if (t->singleton() && !k->is_Con()) {
NOT_PRODUCT(set_progress();)
Node* con = makecon(t); // Make a constant
add_users_to_worklist(k);
subsume_node(k, con); // Everybody using k now uses con
return con;
}
// Now check for Identities
i = k->Identity(this); // Look for a nearby replacement
if( i != k ) { // Found? Return replacement!
NOT_PRODUCT( set_progress(); )
add_users_to_worklist( k );
subsume_node( k, i ); // Everybody using k now uses i
i = k->Identity(this); // Look for a nearby replacement
if (i != k) { // Found? Return replacement!
NOT_PRODUCT(set_progress();)
add_users_to_worklist(k);
subsume_node(k, i); // Everybody using k now uses i
return i;
}
// Global Value Numbering
i = hash_find_insert(k); // Check for pre-existing node
if( i && (i != k) ) {
if (i && (i != k)) {
// Return the pre-existing node if it isn't dead
NOT_PRODUCT( set_progress(); )
add_users_to_worklist( k );
subsume_node( k, i ); // Everybody using k now uses i
NOT_PRODUCT(set_progress();)
add_users_to_worklist(k);
subsume_node(k, i); // Everybody using k now uses i
return i;
}

View File

@ -440,6 +440,17 @@ public:
// and dominator info to a fixed point.
void optimize();
#ifndef PRODUCT
void trace_PhaseIterGVN(Node* n, Node* nn, const Type* old_type);
void init_verifyPhaseIterGVN();
void verify_PhaseIterGVN();
#endif
#ifdef ASSERT
void dump_infinite_loop_info(Node* n);
void trace_PhaseIterGVN_verbose(Node* n, int num_processed);
#endif
// Register a new node with the iter GVN pass without transforming it.
// Used when we need to restructure a Region/Phi area and all the Regions
// and Phis need to complete this one big transform before any other