6862956: PhaseIdealLoop should have a CFG verification mode
Reviewed-by: kvn, twisti
This commit is contained in:
parent
1a11be46ca
commit
c94a076d34
@ -1545,7 +1545,7 @@ void Compile::Optimize() {
|
||||
if((loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) {
|
||||
{
|
||||
TracePhase t2("idealLoop", &_t_idealLoop, true);
|
||||
PhaseIdealLoop ideal_loop( igvn, NULL, true );
|
||||
PhaseIdealLoop ideal_loop( igvn, true );
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop 1", 2);
|
||||
if (failing()) return;
|
||||
@ -1553,7 +1553,7 @@ void Compile::Optimize() {
|
||||
// Loop opts pass if partial peeling occurred in previous pass
|
||||
if(PartialPeelLoop && major_progress() && (loop_opts_cnt > 0)) {
|
||||
TracePhase t3("idealLoop", &_t_idealLoop, true);
|
||||
PhaseIdealLoop ideal_loop( igvn, NULL, false );
|
||||
PhaseIdealLoop ideal_loop( igvn, false );
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop 2", 2);
|
||||
if (failing()) return;
|
||||
@ -1561,10 +1561,15 @@ void Compile::Optimize() {
|
||||
// Loop opts pass for loop-unrolling before CCP
|
||||
if(major_progress() && (loop_opts_cnt > 0)) {
|
||||
TracePhase t4("idealLoop", &_t_idealLoop, true);
|
||||
PhaseIdealLoop ideal_loop( igvn, NULL, false );
|
||||
PhaseIdealLoop ideal_loop( igvn, false );
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop 3", 2);
|
||||
}
|
||||
if (!failing()) {
|
||||
// Verify that last round of loop opts produced a valid graph
|
||||
NOT_PRODUCT( TracePhase t2("idealLoopVerify", &_t_idealLoopVerify, TimeCompiler); )
|
||||
PhaseIdealLoop::verify(igvn);
|
||||
}
|
||||
}
|
||||
if (failing()) return;
|
||||
|
||||
@ -1597,12 +1602,20 @@ void Compile::Optimize() {
|
||||
while(major_progress() && (loop_opts_cnt > 0)) {
|
||||
TracePhase t2("idealLoop", &_t_idealLoop, true);
|
||||
assert( cnt++ < 40, "infinite cycle in loop optimization" );
|
||||
PhaseIdealLoop ideal_loop( igvn, NULL, true );
|
||||
PhaseIdealLoop ideal_loop( igvn, true );
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop iterations", 2);
|
||||
if (failing()) return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Verify that all previous optimizations produced a valid graph
|
||||
// at least to this point, even if no loop optimizations were done.
|
||||
NOT_PRODUCT( TracePhase t2("idealLoopVerify", &_t_idealLoopVerify, TimeCompiler); )
|
||||
PhaseIdealLoop::verify(igvn);
|
||||
}
|
||||
|
||||
{
|
||||
NOT_PRODUCT( TracePhase t2("macroExpand", &_t_macroExpand, TimeCompiler); )
|
||||
PhaseMacroExpand mex(igvn);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -396,7 +396,7 @@ struct NTarjan {
|
||||
// nodes (using the is_CFG() call) and places them in a dominator tree. Thus,
|
||||
// it needs a count of the CFG nodes for the mapping table. This is the
|
||||
// Lengauer & Tarjan O(E-alpha(E,V)) algorithm.
|
||||
void PhaseIdealLoop::Dominators( ) {
|
||||
void PhaseIdealLoop::Dominators() {
|
||||
ResourceMark rm;
|
||||
// Setup mappings from my Graph to Tarjan's stuff and back
|
||||
// Note: Tarjan uses 1-based arrays
|
||||
@ -454,7 +454,7 @@ void PhaseIdealLoop::Dominators( ) {
|
||||
// flow into the main graph (and hence into ROOT) but are not reachable
|
||||
// from above. Such code is dead, but requires a global pass to detect
|
||||
// it; this global pass was the 'build_loop_tree' pass run just prior.
|
||||
if( whead->is_Region() ) {
|
||||
if( !_verify_only && whead->is_Region() ) {
|
||||
for( uint i = 1; i < whead->req(); i++ ) {
|
||||
if (!has_node(whead->in(i))) {
|
||||
// Kill dead input path
|
||||
|
@ -1420,13 +1420,12 @@ static void log_loop_tree(IdealLoopTree* root, IdealLoopTree* loop, CompileLog*
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------PhaseIdealLoop---------------------------------
|
||||
//----------------------------build_and_optimize-------------------------------
|
||||
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
|
||||
// its corresponding LoopNode. If 'optimize' is true, do some loop cleanups.
|
||||
PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify_me, bool do_split_ifs )
|
||||
: PhaseTransform(Ideal_Loop),
|
||||
_igvn(igvn),
|
||||
_dom_lca_tags(C->comp_arena()) {
|
||||
void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) {
|
||||
int old_progress = C->major_progress();
|
||||
|
||||
// Reset major-progress flag for the driver's heuristics
|
||||
C->clear_major_progress();
|
||||
|
||||
@ -1465,18 +1464,20 @@ PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify
|
||||
}
|
||||
|
||||
// No loops after all
|
||||
if( !_ltree_root->_child ) C->set_has_loops(false);
|
||||
if( !_ltree_root->_child && !_verify_only ) C->set_has_loops(false);
|
||||
|
||||
// There should always be an outer loop containing the Root and Return nodes.
|
||||
// If not, we have a degenerate empty program. Bail out in this case.
|
||||
if (!has_node(C->root())) {
|
||||
C->clear_major_progress();
|
||||
C->record_method_not_compilable("empty program detected during loop optimization");
|
||||
if (!_verify_only) {
|
||||
C->clear_major_progress();
|
||||
C->record_method_not_compilable("empty program detected during loop optimization");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Nothing to do, so get out
|
||||
if( !C->has_loops() && !do_split_ifs && !verify_me) {
|
||||
if( !C->has_loops() && !do_split_ifs && !_verify_me && !_verify_only ) {
|
||||
_igvn.optimize(); // Cleanup NeverBranches
|
||||
return;
|
||||
}
|
||||
@ -1486,7 +1487,7 @@ PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify
|
||||
|
||||
// Split shared headers and insert loop landing pads.
|
||||
// Do not bother doing this on the Root loop of course.
|
||||
if( !verify_me && _ltree_root->_child ) {
|
||||
if( !_verify_me && !_verify_only && _ltree_root->_child ) {
|
||||
if( _ltree_root->_child->beautify_loops( this ) ) {
|
||||
// Re-build loop tree!
|
||||
_ltree_root->_child = NULL;
|
||||
@ -1515,23 +1516,25 @@ PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify
|
||||
|
||||
Dominators();
|
||||
|
||||
// As a side effect, Dominators removed any unreachable CFG paths
|
||||
// into RegionNodes. It doesn't do this test against Root, so
|
||||
// we do it here.
|
||||
for( uint i = 1; i < C->root()->req(); i++ ) {
|
||||
if( !_nodes[C->root()->in(i)->_idx] ) { // Dead path into Root?
|
||||
_igvn.hash_delete(C->root());
|
||||
C->root()->del_req(i);
|
||||
_igvn._worklist.push(C->root());
|
||||
i--; // Rerun same iteration on compressed edges
|
||||
if (!_verify_only) {
|
||||
// As a side effect, Dominators removed any unreachable CFG paths
|
||||
// into RegionNodes. It doesn't do this test against Root, so
|
||||
// we do it here.
|
||||
for( uint i = 1; i < C->root()->req(); i++ ) {
|
||||
if( !_nodes[C->root()->in(i)->_idx] ) { // Dead path into Root?
|
||||
_igvn.hash_delete(C->root());
|
||||
C->root()->del_req(i);
|
||||
_igvn._worklist.push(C->root());
|
||||
i--; // Rerun same iteration on compressed edges
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Given dominators, try to find inner loops with calls that must
|
||||
// always be executed (call dominates loop tail). These loops do
|
||||
// not need a separate safepoint.
|
||||
Node_List cisstack(a);
|
||||
_ltree_root->check_safepts(visited, cisstack);
|
||||
// Given dominators, try to find inner loops with calls that must
|
||||
// always be executed (call dominates loop tail). These loops do
|
||||
// not need a separate safepoint.
|
||||
Node_List cisstack(a);
|
||||
_ltree_root->check_safepts(visited, cisstack);
|
||||
}
|
||||
|
||||
// Walk the DATA nodes and place into loops. Find earliest control
|
||||
// node. For CFG nodes, the _nodes array starts out and remains
|
||||
@ -1548,11 +1551,11 @@ PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify
|
||||
// it will be processed among C->top() inputs
|
||||
worklist.push( C->top() );
|
||||
visited.set( C->top()->_idx ); // Set C->top() as visited now
|
||||
build_loop_early( visited, worklist, nstack, verify_me );
|
||||
build_loop_early( visited, worklist, nstack );
|
||||
|
||||
// Given early legal placement, try finding counted loops. This placement
|
||||
// is good enough to discover most loop invariants.
|
||||
if( !verify_me )
|
||||
if( !_verify_me && !_verify_only )
|
||||
_ltree_root->counted_loop( this );
|
||||
|
||||
// Find latest loop placement. Find ideal loop placement.
|
||||
@ -1562,16 +1565,25 @@ PhaseIdealLoop::PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify
|
||||
worklist.push( C->root() );
|
||||
NOT_PRODUCT( C->verify_graph_edges(); )
|
||||
worklist.push( C->top() );
|
||||
build_loop_late( visited, worklist, nstack, verify_me );
|
||||
build_loop_late( visited, worklist, nstack );
|
||||
|
||||
if (_verify_only) {
|
||||
// restore major progress flag
|
||||
for (int i = 0; i < old_progress; i++)
|
||||
C->set_major_progress();
|
||||
assert(C->unique() == unique, "verification mode made Nodes? ? ?");
|
||||
assert(_igvn._worklist.size() == 0, "shouldn't push anything");
|
||||
return;
|
||||
}
|
||||
|
||||
// clear out the dead code
|
||||
while(_deadlist.size()) {
|
||||
igvn.remove_globally_dead_node(_deadlist.pop());
|
||||
_igvn.remove_globally_dead_node(_deadlist.pop());
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
C->verify_graph_edges();
|
||||
if( verify_me ) { // Nested verify pass?
|
||||
if( _verify_me ) { // Nested verify pass?
|
||||
// Check to see if the verify mode is broken
|
||||
assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?");
|
||||
return;
|
||||
@ -1678,7 +1690,7 @@ static int fail; // debug only, so its multi-thread dont care
|
||||
void PhaseIdealLoop::verify() const {
|
||||
int old_progress = C->major_progress();
|
||||
ResourceMark rm;
|
||||
PhaseIdealLoop loop_verify( _igvn, this, false );
|
||||
PhaseIdealLoop loop_verify( _igvn, this );
|
||||
VectorSet visited(Thread::current()->resource_area());
|
||||
|
||||
fail = 0;
|
||||
@ -2138,54 +2150,58 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
|
||||
// optimizing an infinite loop?
|
||||
l = _ltree_root; // Oops, found infinite loop
|
||||
|
||||
// Insert the NeverBranch between 'm' and it's control user.
|
||||
NeverBranchNode *iff = new (C, 1) NeverBranchNode( m );
|
||||
_igvn.register_new_node_with_optimizer(iff);
|
||||
set_loop(iff, l);
|
||||
Node *if_t = new (C, 1) CProjNode( iff, 0 );
|
||||
_igvn.register_new_node_with_optimizer(if_t);
|
||||
set_loop(if_t, l);
|
||||
if (!_verify_only) {
|
||||
// Insert the NeverBranch between 'm' and it's control user.
|
||||
NeverBranchNode *iff = new (C, 1) NeverBranchNode( m );
|
||||
_igvn.register_new_node_with_optimizer(iff);
|
||||
set_loop(iff, l);
|
||||
Node *if_t = new (C, 1) CProjNode( iff, 0 );
|
||||
_igvn.register_new_node_with_optimizer(if_t);
|
||||
set_loop(if_t, l);
|
||||
|
||||
Node* cfg = NULL; // Find the One True Control User of m
|
||||
for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) {
|
||||
Node* x = m->fast_out(j);
|
||||
if (x->is_CFG() && x != m && x != iff)
|
||||
{ cfg = x; break; }
|
||||
Node* cfg = NULL; // Find the One True Control User of m
|
||||
for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) {
|
||||
Node* x = m->fast_out(j);
|
||||
if (x->is_CFG() && x != m && x != iff)
|
||||
{ cfg = x; break; }
|
||||
}
|
||||
assert(cfg != NULL, "must find the control user of m");
|
||||
uint k = 0; // Probably cfg->in(0)
|
||||
while( cfg->in(k) != m ) k++; // But check incase cfg is a Region
|
||||
cfg->set_req( k, if_t ); // Now point to NeverBranch
|
||||
|
||||
// Now create the never-taken loop exit
|
||||
Node *if_f = new (C, 1) CProjNode( iff, 1 );
|
||||
_igvn.register_new_node_with_optimizer(if_f);
|
||||
set_loop(if_f, l);
|
||||
// Find frame ptr for Halt. Relies on the optimizer
|
||||
// V-N'ing. Easier and quicker than searching through
|
||||
// the program structure.
|
||||
Node *frame = new (C, 1) ParmNode( C->start(), TypeFunc::FramePtr );
|
||||
_igvn.register_new_node_with_optimizer(frame);
|
||||
// Halt & Catch Fire
|
||||
Node *halt = new (C, TypeFunc::Parms) HaltNode( if_f, frame );
|
||||
_igvn.register_new_node_with_optimizer(halt);
|
||||
set_loop(halt, l);
|
||||
C->root()->add_req(halt);
|
||||
}
|
||||
assert(cfg != NULL, "must find the control user of m");
|
||||
uint k = 0; // Probably cfg->in(0)
|
||||
while( cfg->in(k) != m ) k++; // But check incase cfg is a Region
|
||||
cfg->set_req( k, if_t ); // Now point to NeverBranch
|
||||
|
||||
// Now create the never-taken loop exit
|
||||
Node *if_f = new (C, 1) CProjNode( iff, 1 );
|
||||
_igvn.register_new_node_with_optimizer(if_f);
|
||||
set_loop(if_f, l);
|
||||
// Find frame ptr for Halt. Relies on the optimizer
|
||||
// V-N'ing. Easier and quicker than searching through
|
||||
// the program structure.
|
||||
Node *frame = new (C, 1) ParmNode( C->start(), TypeFunc::FramePtr );
|
||||
_igvn.register_new_node_with_optimizer(frame);
|
||||
// Halt & Catch Fire
|
||||
Node *halt = new (C, TypeFunc::Parms) HaltNode( if_f, frame );
|
||||
_igvn.register_new_node_with_optimizer(halt);
|
||||
set_loop(halt, l);
|
||||
C->root()->add_req(halt);
|
||||
set_loop(C->root(), _ltree_root);
|
||||
}
|
||||
}
|
||||
// Weeny check for irreducible. This child was already visited (this
|
||||
// IS the post-work phase). Is this child's loop header post-visited
|
||||
// as well? If so, then I found another entry into the loop.
|
||||
while( is_postvisited(l->_head) ) {
|
||||
// found irreducible
|
||||
l->_irreducible = 1; // = true
|
||||
l = l->_parent;
|
||||
_has_irreducible_loops = true;
|
||||
// Check for bad CFG here to prevent crash, and bailout of compile
|
||||
if (l == NULL) {
|
||||
C->record_method_not_compilable("unhandled CFG detected during loop optimization");
|
||||
return pre_order;
|
||||
if (!_verify_only) {
|
||||
while( is_postvisited(l->_head) ) {
|
||||
// found irreducible
|
||||
l->_irreducible = 1; // = true
|
||||
l = l->_parent;
|
||||
_has_irreducible_loops = true;
|
||||
// Check for bad CFG here to prevent crash, and bailout of compile
|
||||
if (l == NULL) {
|
||||
C->record_method_not_compilable("unhandled CFG detected during loop optimization");
|
||||
return pre_order;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2253,7 +2269,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
|
||||
// Put Data nodes into some loop nest, by setting the _nodes[]->loop mapping.
|
||||
// First pass computes the earliest controlling node possible. This is the
|
||||
// controlling input with the deepest dominating depth.
|
||||
void PhaseIdealLoop::build_loop_early( VectorSet &visited, Node_List &worklist, Node_Stack &nstack, const PhaseIdealLoop *verify_me ) {
|
||||
void PhaseIdealLoop::build_loop_early( VectorSet &visited, Node_List &worklist, Node_Stack &nstack ) {
|
||||
while (worklist.size() != 0) {
|
||||
// Use local variables nstack_top_n & nstack_top_i to cache values
|
||||
// on nstack's top.
|
||||
@ -2285,7 +2301,7 @@ void PhaseIdealLoop::build_loop_early( VectorSet &visited, Node_List &worklist,
|
||||
// (the old code here would yank a 2nd safepoint after seeing a
|
||||
// first one, even though the 1st did not dominate in the loop body
|
||||
// and thus could be avoided indefinitely)
|
||||
if( !verify_me && ilt->_has_sfpt && n->Opcode() == Op_SafePoint &&
|
||||
if( !_verify_only && !_verify_me && ilt->_has_sfpt && n->Opcode() == Op_SafePoint &&
|
||||
is_deleteable_safept(n)) {
|
||||
Node *in = n->in(TypeFunc::Control);
|
||||
lazy_replace(n,in); // Pull safepoint now
|
||||
@ -2408,12 +2424,31 @@ Node *PhaseIdealLoop::compute_idom( Node *region ) const {
|
||||
return LCA;
|
||||
}
|
||||
|
||||
//------------------------------get_late_ctrl----------------------------------
|
||||
// Compute latest legal control.
|
||||
Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
|
||||
assert(early != NULL, "early control should not be NULL");
|
||||
bool PhaseIdealLoop::verify_dominance(Node* n, Node* use, Node* LCA, Node* early) {
|
||||
bool had_error = false;
|
||||
#ifdef ASSERT
|
||||
if (early != C->root()) {
|
||||
// Make sure that there's a dominance path from use to LCA
|
||||
Node* d = use;
|
||||
while (d != LCA) {
|
||||
d = idom(d);
|
||||
if (d == C->root()) {
|
||||
tty->print_cr("*** Use %d isn't dominated by def %s", use->_idx, n->_idx);
|
||||
n->dump();
|
||||
use->dump();
|
||||
had_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return had_error;
|
||||
}
|
||||
|
||||
|
||||
Node* PhaseIdealLoop::compute_lca_of_uses(Node* n, Node* early, bool verify) {
|
||||
// Compute LCA over list of uses
|
||||
bool had_error = false;
|
||||
Node *LCA = NULL;
|
||||
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax && LCA != early; i++) {
|
||||
Node* c = n->fast_out(i);
|
||||
@ -2423,15 +2458,34 @@ Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
|
||||
for( uint j=1; j<c->req(); j++ ) {// For all inputs
|
||||
if( c->in(j) == n ) { // Found matching input?
|
||||
Node *use = c->in(0)->in(j);
|
||||
if (_verify_only && use->is_top()) continue;
|
||||
LCA = dom_lca_for_get_late_ctrl( LCA, use, n );
|
||||
if (verify) had_error = verify_dominance(n, use, LCA, early) || had_error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For CFG data-users, use is in the block just prior
|
||||
Node *use = has_ctrl(c) ? get_ctrl(c) : c->in(0);
|
||||
LCA = dom_lca_for_get_late_ctrl( LCA, use, n );
|
||||
if (verify) had_error = verify_dominance(n, use, LCA, early) || had_error;
|
||||
}
|
||||
}
|
||||
assert(!had_error, "bad dominance");
|
||||
return LCA;
|
||||
}
|
||||
|
||||
//------------------------------get_late_ctrl----------------------------------
|
||||
// Compute latest legal control.
|
||||
Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
|
||||
assert(early != NULL, "early control should not be NULL");
|
||||
|
||||
Node* LCA = compute_lca_of_uses(n, early);
|
||||
#ifdef ASSERT
|
||||
if (LCA == C->root() && LCA != early) {
|
||||
// def doesn't dominate uses so print some useful debugging output
|
||||
compute_lca_of_uses(n, early, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
// if this is a load, check for anti-dependent stores
|
||||
// We use a conservative algorithm to identify potential interfering
|
||||
@ -2576,7 +2630,7 @@ void PhaseIdealLoop::clear_dom_lca_tags() {
|
||||
//------------------------------build_loop_late--------------------------------
|
||||
// Put Data nodes into some loop nest, by setting the _nodes[]->loop mapping.
|
||||
// Second pass finds latest legal placement, and ideal loop placement.
|
||||
void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, Node_Stack &nstack, const PhaseIdealLoop *verify_me ) {
|
||||
void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, Node_Stack &nstack ) {
|
||||
while (worklist.size() != 0) {
|
||||
Node *n = worklist.pop();
|
||||
// Only visit once
|
||||
@ -2612,7 +2666,7 @@ void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, N
|
||||
}
|
||||
} else {
|
||||
// All of n's children have been processed, complete post-processing.
|
||||
build_loop_late_post(n, verify_me);
|
||||
build_loop_late_post(n);
|
||||
if (nstack.is_empty()) {
|
||||
// Finished all nodes on stack.
|
||||
// Process next node on the worklist.
|
||||
@ -2631,9 +2685,9 @@ void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, N
|
||||
//------------------------------build_loop_late_post---------------------------
|
||||
// Put Data nodes into some loop nest, by setting the _nodes[]->loop mapping.
|
||||
// Second pass finds latest legal placement, and ideal loop placement.
|
||||
void PhaseIdealLoop::build_loop_late_post( Node *n, const PhaseIdealLoop *verify_me ) {
|
||||
void PhaseIdealLoop::build_loop_late_post( Node *n ) {
|
||||
|
||||
if (n->req() == 2 && n->Opcode() == Op_ConvI2L && !C->major_progress()) {
|
||||
if (n->req() == 2 && n->Opcode() == Op_ConvI2L && !C->major_progress() && !_verify_only) {
|
||||
_igvn._worklist.push(n); // Maybe we'll normalize it, if no more loops.
|
||||
}
|
||||
|
||||
@ -2714,6 +2768,7 @@ void PhaseIdealLoop::build_loop_late_post( Node *n, const PhaseIdealLoop *verify
|
||||
if( get_loop(legal)->_nest < get_loop(least)->_nest )
|
||||
least = legal;
|
||||
}
|
||||
assert(early == legal || legal != C->root(), "bad dominance of inputs");
|
||||
|
||||
// Try not to place code on a loop entry projection
|
||||
// which can inhibit range check elimination.
|
||||
@ -2731,8 +2786,8 @@ void PhaseIdealLoop::build_loop_late_post( Node *n, const PhaseIdealLoop *verify
|
||||
#ifdef ASSERT
|
||||
// If verifying, verify that 'verify_me' has a legal location
|
||||
// and choose it as our location.
|
||||
if( verify_me ) {
|
||||
Node *v_ctrl = verify_me->get_ctrl_no_update(n);
|
||||
if( _verify_me ) {
|
||||
Node *v_ctrl = _verify_me->get_ctrl_no_update(n);
|
||||
Node *legal = LCA;
|
||||
while( early != legal ) { // While not at earliest legal
|
||||
if( legal == v_ctrl ) break; // Check for prior good location
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -442,6 +442,9 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
uint *_preorders;
|
||||
uint _max_preorder;
|
||||
|
||||
const PhaseIdealLoop* _verify_me;
|
||||
bool _verify_only;
|
||||
|
||||
// Allocate _preorders[] array
|
||||
void allocate_preorders() {
|
||||
_max_preorder = C->unique()+8;
|
||||
@ -497,6 +500,12 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
Node_Array _dom_lca_tags;
|
||||
void init_dom_lca_tags();
|
||||
void clear_dom_lca_tags();
|
||||
|
||||
// Helper for debugging bad dominance relationships
|
||||
bool verify_dominance(Node* n, Node* use, Node* LCA, Node* early);
|
||||
|
||||
Node* compute_lca_of_uses(Node* n, Node* early, bool verify = false);
|
||||
|
||||
// Inline wrapper for frequent cases:
|
||||
// 1) only one use
|
||||
// 2) a use is the same as the current LCA passed as 'n1'
|
||||
@ -511,6 +520,7 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
return find_non_split_ctrl(n);
|
||||
}
|
||||
Node *dom_lca_for_get_late_ctrl_internal( Node *lca, Node *n, Node *tag );
|
||||
|
||||
// true if CFG node d dominates CFG node n
|
||||
bool is_dominator(Node *d, Node *n);
|
||||
|
||||
@ -621,9 +631,9 @@ private:
|
||||
IdealLoopTree *sort( IdealLoopTree *loop, IdealLoopTree *innermost );
|
||||
|
||||
// Place Data nodes in some loop nest
|
||||
void build_loop_early( VectorSet &visited, Node_List &worklist, Node_Stack &nstack, const PhaseIdealLoop *verify_me );
|
||||
void build_loop_late ( VectorSet &visited, Node_List &worklist, Node_Stack &nstack, const PhaseIdealLoop *verify_me );
|
||||
void build_loop_late_post ( Node* n, const PhaseIdealLoop *verify_me );
|
||||
void build_loop_early( VectorSet &visited, Node_List &worklist, Node_Stack &nstack );
|
||||
void build_loop_late ( VectorSet &visited, Node_List &worklist, Node_Stack &nstack );
|
||||
void build_loop_late_post ( Node* n );
|
||||
|
||||
// Array of immediate dominance info for each CFG node indexed by node idx
|
||||
private:
|
||||
@ -662,6 +672,19 @@ private:
|
||||
// Is safept not required by an outer loop?
|
||||
bool is_deleteable_safept(Node* sfpt);
|
||||
|
||||
// Perform verification that the graph is valid.
|
||||
PhaseIdealLoop( PhaseIterGVN &igvn) :
|
||||
PhaseTransform(Ideal_Loop),
|
||||
_igvn(igvn),
|
||||
_dom_lca_tags(C->comp_arena()),
|
||||
_verify_me(NULL),
|
||||
_verify_only(true) {
|
||||
build_and_optimize(false);
|
||||
}
|
||||
|
||||
// build the loop tree and perform any requested optimizations
|
||||
void build_and_optimize(bool do_split_if);
|
||||
|
||||
public:
|
||||
// Dominators for the sea of nodes
|
||||
void Dominators();
|
||||
@ -671,7 +694,32 @@ public:
|
||||
Node *dom_lca_internal( Node *n1, Node *n2 ) const;
|
||||
|
||||
// Compute the Ideal Node to Loop mapping
|
||||
PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify_me, bool do_split_ifs );
|
||||
PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs) :
|
||||
PhaseTransform(Ideal_Loop),
|
||||
_igvn(igvn),
|
||||
_dom_lca_tags(C->comp_arena()),
|
||||
_verify_me(NULL),
|
||||
_verify_only(false) {
|
||||
build_and_optimize(do_split_ifs);
|
||||
}
|
||||
|
||||
// Verify that verify_me made the same decisions as a fresh run.
|
||||
PhaseIdealLoop( PhaseIterGVN &igvn, const PhaseIdealLoop *verify_me) :
|
||||
PhaseTransform(Ideal_Loop),
|
||||
_igvn(igvn),
|
||||
_dom_lca_tags(C->comp_arena()),
|
||||
_verify_me(verify_me),
|
||||
_verify_only(false) {
|
||||
build_and_optimize(false);
|
||||
}
|
||||
|
||||
// Build and verify the loop tree without modifying the graph. This
|
||||
// is useful to verify that all inputs properly dominate their uses.
|
||||
static void verify(PhaseIterGVN& igvn) {
|
||||
#ifdef ASSERT
|
||||
PhaseIdealLoop v(igvn);
|
||||
#endif
|
||||
}
|
||||
|
||||
// True if the method has at least 1 irreducible loop
|
||||
bool _has_irreducible_loops;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -53,6 +53,7 @@ elapsedTimer Phase::_t_codeGeneration;
|
||||
elapsedTimer Phase::_t_registerMethod;
|
||||
elapsedTimer Phase::_t_temporaryTimer1;
|
||||
elapsedTimer Phase::_t_temporaryTimer2;
|
||||
elapsedTimer Phase::_t_idealLoopVerify;
|
||||
|
||||
// Subtimers for _t_optimizer
|
||||
elapsedTimer Phase::_t_iterGVN;
|
||||
@ -88,51 +89,52 @@ void Phase::print_timers() {
|
||||
tty->print_cr ("Accumulated compiler times:");
|
||||
tty->print_cr ("---------------------------");
|
||||
tty->print_cr (" Total compilation: %3.3f sec.", Phase::_t_totalCompilation.seconds());
|
||||
tty->print (" method compilation : %3.3f sec", Phase::_t_methodCompilation.seconds());
|
||||
tty->print (" method compilation : %3.3f sec", Phase::_t_methodCompilation.seconds());
|
||||
tty->print ("/%d bytes",_total_bytes_compiled);
|
||||
tty->print_cr (" (%3.0f bytes per sec) ", Phase::_total_bytes_compiled / Phase::_t_methodCompilation.seconds());
|
||||
tty->print_cr (" stub compilation : %3.3f sec.", Phase::_t_stubCompilation.seconds());
|
||||
tty->print_cr (" stub compilation : %3.3f sec.", Phase::_t_stubCompilation.seconds());
|
||||
tty->print_cr (" Phases:");
|
||||
tty->print_cr (" parse : %3.3f sec", Phase::_t_parser.seconds());
|
||||
tty->print_cr (" parse : %3.3f sec", Phase::_t_parser.seconds());
|
||||
if (DoEscapeAnalysis) {
|
||||
tty->print_cr (" escape analysis : %3.3f sec", Phase::_t_escapeAnalysis.seconds());
|
||||
tty->print_cr (" escape analysis : %3.3f sec", Phase::_t_escapeAnalysis.seconds());
|
||||
}
|
||||
tty->print_cr (" optimizer : %3.3f sec", Phase::_t_optimizer.seconds());
|
||||
tty->print_cr (" optimizer : %3.3f sec", Phase::_t_optimizer.seconds());
|
||||
if( Verbose || WizardMode ) {
|
||||
tty->print_cr (" iterGVN : %3.3f sec", Phase::_t_iterGVN.seconds());
|
||||
tty->print_cr (" idealLoop : %3.3f sec", Phase::_t_idealLoop.seconds());
|
||||
tty->print_cr (" ccp : %3.3f sec", Phase::_t_ccp.seconds());
|
||||
tty->print_cr (" iterGVN2 : %3.3f sec", Phase::_t_iterGVN2.seconds());
|
||||
tty->print_cr (" graphReshape : %3.3f sec", Phase::_t_graphReshaping.seconds());
|
||||
tty->print_cr (" iterGVN : %3.3f sec", Phase::_t_iterGVN.seconds());
|
||||
tty->print_cr (" idealLoop : %3.3f sec", Phase::_t_idealLoop.seconds());
|
||||
tty->print_cr (" idealLoopVerify: %3.3f sec", Phase::_t_idealLoopVerify.seconds());
|
||||
tty->print_cr (" ccp : %3.3f sec", Phase::_t_ccp.seconds());
|
||||
tty->print_cr (" iterGVN2 : %3.3f sec", Phase::_t_iterGVN2.seconds());
|
||||
tty->print_cr (" graphReshape : %3.3f sec", Phase::_t_graphReshaping.seconds());
|
||||
double optimizer_subtotal = Phase::_t_iterGVN.seconds() +
|
||||
Phase::_t_idealLoop.seconds() + Phase::_t_ccp.seconds() +
|
||||
Phase::_t_graphReshaping.seconds();
|
||||
double percent_of_optimizer = ((optimizer_subtotal == 0.0) ? 0.0 : (optimizer_subtotal / Phase::_t_optimizer.seconds() * 100.0));
|
||||
tty->print_cr (" subtotal : %3.3f sec, %3.2f %%", optimizer_subtotal, percent_of_optimizer);
|
||||
tty->print_cr (" subtotal : %3.3f sec, %3.2f %%", optimizer_subtotal, percent_of_optimizer);
|
||||
}
|
||||
tty->print_cr (" matcher : %3.3f sec", Phase::_t_matcher.seconds());
|
||||
tty->print_cr (" scheduler : %3.3f sec", Phase::_t_scheduler.seconds());
|
||||
tty->print_cr (" regalloc : %3.3f sec", Phase::_t_registerAllocation.seconds());
|
||||
tty->print_cr (" matcher : %3.3f sec", Phase::_t_matcher.seconds());
|
||||
tty->print_cr (" scheduler : %3.3f sec", Phase::_t_scheduler.seconds());
|
||||
tty->print_cr (" regalloc : %3.3f sec", Phase::_t_registerAllocation.seconds());
|
||||
if( Verbose || WizardMode ) {
|
||||
tty->print_cr (" ctorChaitin : %3.3f sec", Phase::_t_ctorChaitin.seconds());
|
||||
tty->print_cr (" buildIFG : %3.3f sec", Phase::_t_buildIFGphysical.seconds());
|
||||
tty->print_cr (" computeLive : %3.3f sec", Phase::_t_computeLive.seconds());
|
||||
tty->print_cr (" regAllocSplit: %3.3f sec", Phase::_t_regAllocSplit.seconds());
|
||||
tty->print_cr (" ctorChaitin : %3.3f sec", Phase::_t_ctorChaitin.seconds());
|
||||
tty->print_cr (" buildIFG : %3.3f sec", Phase::_t_buildIFGphysical.seconds());
|
||||
tty->print_cr (" computeLive : %3.3f sec", Phase::_t_computeLive.seconds());
|
||||
tty->print_cr (" regAllocSplit : %3.3f sec", Phase::_t_regAllocSplit.seconds());
|
||||
tty->print_cr (" postAllocCopyRemoval: %3.3f sec", Phase::_t_postAllocCopyRemoval.seconds());
|
||||
tty->print_cr (" fixupSpills : %3.3f sec", Phase::_t_fixupSpills.seconds());
|
||||
tty->print_cr (" fixupSpills : %3.3f sec", Phase::_t_fixupSpills.seconds());
|
||||
double regalloc_subtotal = Phase::_t_ctorChaitin.seconds() +
|
||||
Phase::_t_buildIFGphysical.seconds() + Phase::_t_computeLive.seconds() +
|
||||
Phase::_t_regAllocSplit.seconds() + Phase::_t_fixupSpills.seconds() +
|
||||
Phase::_t_postAllocCopyRemoval.seconds();
|
||||
double percent_of_regalloc = ((regalloc_subtotal == 0.0) ? 0.0 : (regalloc_subtotal / Phase::_t_registerAllocation.seconds() * 100.0));
|
||||
tty->print_cr (" subtotal : %3.3f sec, %3.2f %%", regalloc_subtotal, percent_of_regalloc);
|
||||
tty->print_cr (" subtotal : %3.3f sec, %3.2f %%", regalloc_subtotal, percent_of_regalloc);
|
||||
}
|
||||
tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds());
|
||||
tty->print_cr (" blockOrdering: %3.3f sec", Phase::_t_blockOrdering.seconds());
|
||||
tty->print_cr (" peephole : %3.3f sec", Phase::_t_peephole.seconds());
|
||||
tty->print_cr (" codeGen : %3.3f sec", Phase::_t_codeGeneration.seconds());
|
||||
tty->print_cr (" install_code : %3.3f sec", Phase::_t_registerMethod.seconds());
|
||||
tty->print_cr (" ------------ : ----------");
|
||||
tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds());
|
||||
tty->print_cr (" blockOrdering : %3.3f sec", Phase::_t_blockOrdering.seconds());
|
||||
tty->print_cr (" peephole : %3.3f sec", Phase::_t_peephole.seconds());
|
||||
tty->print_cr (" codeGen : %3.3f sec", Phase::_t_codeGeneration.seconds());
|
||||
tty->print_cr (" install_code : %3.3f sec", Phase::_t_registerMethod.seconds());
|
||||
tty->print_cr (" -------------- : ----------");
|
||||
double phase_subtotal = Phase::_t_parser.seconds() +
|
||||
(DoEscapeAnalysis ? Phase::_t_escapeAnalysis.seconds() : 0.0) +
|
||||
Phase::_t_optimizer.seconds() + Phase::_t_graphReshaping.seconds() +
|
||||
@ -143,7 +145,7 @@ void Phase::print_timers() {
|
||||
double percent_of_method_compile = ((phase_subtotal == 0.0) ? 0.0 : phase_subtotal / Phase::_t_methodCompilation.seconds()) * 100.0;
|
||||
// counters inside Compile::CodeGen include time for adapters and stubs
|
||||
// so phase-total can be greater than 100%
|
||||
tty->print_cr (" total : %3.3f sec, %3.2f %%", phase_subtotal, percent_of_method_compile);
|
||||
tty->print_cr (" total : %3.3f sec, %3.2f %%", phase_subtotal, percent_of_method_compile);
|
||||
|
||||
assert( percent_of_method_compile > expected_method_compile_coverage ||
|
||||
phase_subtotal < minimum_meaningful_method_compile,
|
||||
@ -157,8 +159,8 @@ void Phase::print_timers() {
|
||||
tty->cr();
|
||||
tty->print_cr (" temporaryTimer2: %3.3f sec", Phase::_t_temporaryTimer2.seconds());
|
||||
}
|
||||
tty->print_cr (" output : %3.3f sec", Phase::_t_output.seconds());
|
||||
tty->print_cr (" isched : %3.3f sec", Phase::_t_instrSched.seconds());
|
||||
tty->print_cr (" bldOopMaps: %3.3f sec", Phase::_t_buildOopMaps.seconds());
|
||||
tty->print_cr (" output : %3.3f sec", Phase::_t_output.seconds());
|
||||
tty->print_cr (" isched : %3.3f sec", Phase::_t_instrSched.seconds());
|
||||
tty->print_cr (" bldOopMaps : %3.3f sec", Phase::_t_buildOopMaps.seconds());
|
||||
}
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -83,6 +83,7 @@ protected:
|
||||
static elapsedTimer _t_registerMethod;
|
||||
static elapsedTimer _t_temporaryTimer1;
|
||||
static elapsedTimer _t_temporaryTimer2;
|
||||
static elapsedTimer _t_idealLoopVerify;
|
||||
|
||||
// Subtimers for _t_optimizer
|
||||
static elapsedTimer _t_iterGVN;
|
||||
|
Loading…
x
Reference in New Issue
Block a user