mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-19 01:47:52 +00:00
8039425: Code cleanup: PhaseIterGVN::optimize()
This code cleanup aims at improving code readability. Reviewed-by: kvn, roland
This commit is contained in:
parent
d7b640b3ce
commit
e2305182b5
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user