Mercurial > hg > truffle
diff src/share/vm/opto/parse1.cpp @ 367:194b8e3a2fc4
6384206: Phis which are later unneeded are impairing our ability to inline based on static types
Reviewed-by: rasbold, jrose
author | never |
---|---|
date | Wed, 17 Sep 2008 12:59:52 -0700 |
parents | d1605aabd0a1 |
children | 98cb887364d3 |
line wrap: on
line diff
--- a/src/share/vm/opto/parse1.cpp Wed Sep 17 08:29:17 2008 -0700 +++ b/src/share/vm/opto/parse1.cpp Wed Sep 17 12:59:52 2008 -0700 @@ -29,17 +29,17 @@ // the most. Some of the non-static variables are needed in bytecodeInfo.cpp // and eventually should be encapsulated in a proper class (gri 8/18/98). -int nodes_created = 0; int nodes_created_old = 0; -int methods_parsed = 0; int methods_parsed_old = 0; -int methods_seen = 0; int methods_seen_old = 0; +int nodes_created = 0; +int methods_parsed = 0; +int methods_seen = 0; +int blocks_parsed = 0; +int blocks_seen = 0; -int explicit_null_checks_inserted = 0, explicit_null_checks_inserted_old = 0; -int explicit_null_checks_elided = 0, explicit_null_checks_elided_old = 0; +int explicit_null_checks_inserted = 0; +int explicit_null_checks_elided = 0; int all_null_checks_found = 0, implicit_null_checks = 0; int implicit_null_throws = 0; -int parse_idx = 0; -size_t parse_arena = 0; int reclaim_idx = 0; int reclaim_in = 0; int reclaim_node = 0; @@ -61,6 +61,7 @@ tty->cr(); if (methods_seen != methods_parsed) tty->print_cr("Reasons for parse failures (NOT cumulative):"); + tty->print_cr("Blocks parsed: %d Blocks seen: %d", blocks_parsed, blocks_seen); if( explicit_null_checks_inserted ) tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", explicit_null_checks_inserted, explicit_null_checks_elided, (100*explicit_null_checks_elided)/explicit_null_checks_inserted, all_null_checks_found); @@ -373,6 +374,12 @@ C->record_method_not_compilable_all_tiers(_flow->failure_reason()); } +#ifndef PRODUCT + if (_flow->has_irreducible_entry()) { + C->set_parsed_irreducible_loop(true); + } +#endif + if (_expected_uses <= 0) { _prof_factor = 1; } else { @@ -556,118 +563,93 @@ set_map(entry_map); do_exits(); - // Collect a few more statistics. - parse_idx += C->unique(); - parse_arena += C->node_arena()->used(); - if (log) log->done("parse nodes='%d' memory='%d'", C->unique(), C->node_arena()->used()); } //---------------------------do_all_blocks------------------------------------- void Parse::do_all_blocks() { - _blocks_merged = 0; - _blocks_parsed = 0; + bool has_irreducible = flow()->has_irreducible_entry(); + + // Walk over all blocks in Reverse Post-Order. + while (true) { + bool progress = false; + for (int rpo = 0; rpo < block_count(); rpo++) { + Block* block = rpo_at(rpo); + + if (block->is_parsed()) continue; - int old_blocks_merged = -1; - int old_blocks_parsed = -1; + if (!block->is_merged()) { + // Dead block, no state reaches this block + continue; + } - for (int tries = 0; ; tries++) { - visit_blocks(); - if (failing()) return; // Check for bailout + // Prepare to parse this block. + load_state_from(block); + + if (stopped()) { + // Block is dead. + continue; + } + + blocks_parsed++; - // No need for a work list. The outer loop is hardly ever repeated. - // The following loop traverses the blocks in a reasonable pre-order, - // as produced by the ciTypeFlow pass. + progress = true; + if (block->is_loop_head() || block->is_handler() || has_irreducible && !block->is_ready()) { + // Not all preds have been parsed. We must build phis everywhere. + // (Note that dead locals do not get phis built, ever.) + ensure_phis_everywhere(); + + // Leave behind an undisturbed copy of the map, for future merges. + set_map(clone_map()); + } - // This loop can be taken more than once if there are two entries to - // a loop (irreduceable CFG), and the edge which ciTypeFlow chose - // as the first predecessor to the loop goes dead in the parser, - // due to parse-time optimization. (Could happen with obfuscated code.) + if (control()->is_Region() && !block->is_loop_head() && !has_irreducible && !block->is_handler()) { + // In the absence of irreducible loops, the Region and Phis + // associated with a merge that doesn't involve a backedge can + // be simplfied now since the RPO parsing order guarantees + // that any path which was supposed to reach here has already + // been parsed or must be dead. + Node* c = control(); + Node* result = _gvn.transform_no_reclaim(control()); + if (c != result && TraceOptoParse) { + tty->print_cr("Block #%d replace %d with %d", block->rpo(), c->_idx, result->_idx); + } + if (result != top()) { + record_for_igvn(result); + } + } - // Look for progress, or the lack of it: - if (_blocks_parsed == block_count()) { - // That's all, folks. - if (TraceOptoParse) { - tty->print_cr("All blocks parsed."); - } + // Parse the block. + do_one_block(); + + // Check for bailouts. + if (failing()) return; + } + + // with irreducible loops multiple passes might be necessary to parse everything + if (!has_irreducible || !progress) { break; } + } - // How much work was done this time around? - int new_blocks_merged = _blocks_merged - old_blocks_merged; - int new_blocks_parsed = _blocks_parsed - old_blocks_parsed; - if (new_blocks_merged == 0) { - if (TraceOptoParse) { - tty->print_cr("All live blocks parsed; %d dead blocks.", block_count() - _blocks_parsed); - } - // No new blocks have become parseable. Some blocks are just dead. - break; - } - assert(new_blocks_parsed > 0, "must make progress"); - assert(tries < block_count(), "the pre-order cannot be this bad!"); - - old_blocks_merged = _blocks_merged; - old_blocks_parsed = _blocks_parsed; - } + blocks_seen += block_count(); #ifndef PRODUCT // Make sure there are no half-processed blocks remaining. // Every remaining unprocessed block is dead and may be ignored now. - for (int po = 0; po < block_count(); po++) { - Block* block = pre_order_at(po); + for (int rpo = 0; rpo < block_count(); rpo++) { + Block* block = rpo_at(rpo); if (!block->is_parsed()) { if (TraceOptoParse) { - tty->print("Skipped dead block %d at bci:%d", po, block->start()); - assert(!block->is_merged(), "no half-processed blocks"); + tty->print_cr("Skipped dead block %d at bci:%d", rpo, block->start()); } + assert(!block->is_merged(), "no half-processed blocks"); } } #endif } -//---------------------------visit_blocks-------------------------------------- -void Parse::visit_blocks() { - // Walk over all blocks, parsing every one that has been reached (merged). - for (int po = 0; po < block_count(); po++) { - Block* block = pre_order_at(po); - - if (block->is_parsed()) { - // Do not parse twice. - continue; - } - - if (!block->is_merged()) { - // No state on this block. It had not yet been reached. - // Delay reaching it until later. - continue; - } - - // Prepare to parse this block. - load_state_from(block); - - if (stopped()) { - // Block is dead. - continue; - } - - if (!block->is_ready() || block->is_handler()) { - // Not all preds have been parsed. We must build phis everywhere. - // (Note that dead locals do not get phis built, ever.) - ensure_phis_everywhere(); - - // Leave behind an undisturbed copy of the map, for future merges. - set_map(clone_map()); - } - - // Ready or not, parse the block. - do_one_block(); - - // Check for bailouts. - if (failing()) return; - } -} - //-------------------------------build_exits---------------------------------- // Build normal and exceptional exit merge points. void Parse::build_exits() { @@ -1134,24 +1116,24 @@ _blocks = NEW_RESOURCE_ARRAY(Block, _block_count); Copy::zero_to_bytes(_blocks, sizeof(Block)*_block_count); - int po; + int rpo; // Initialize the structs. - for (po = 0; po < block_count(); po++) { - Block* block = pre_order_at(po); - block->init_node(this, po); + for (rpo = 0; rpo < block_count(); rpo++) { + Block* block = rpo_at(rpo); + block->init_node(this, rpo); } // Collect predecessor and successor information. - for (po = 0; po < block_count(); po++) { - Block* block = pre_order_at(po); + for (rpo = 0; rpo < block_count(); rpo++) { + Block* block = rpo_at(rpo); block->init_graph(this); } } //-------------------------------init_node------------------------------------- -void Parse::Block::init_node(Parse* outer, int po) { - _flow = outer->flow()->pre_order_at(po); +void Parse::Block::init_node(Parse* outer, int rpo) { + _flow = outer->flow()->rpo_at(rpo); _pred_count = 0; _preds_parsed = 0; _count = 0; @@ -1177,7 +1159,7 @@ int p = 0; for (int i = 0; i < ns+ne; i++) { ciTypeFlow::Block* tf2 = (i < ns) ? tfs->at(i) : tfe->at(i-ns); - Block* block2 = outer->pre_order_at(tf2->pre_order()); + Block* block2 = outer->rpo_at(tf2->rpo()); _successors[i] = block2; // Accumulate pred info for the other block, too. @@ -1368,10 +1350,11 @@ int nt = b->all_successors(); tty->print("Parsing block #%d at bci [%d,%d), successors: ", - block()->pre_order(), block()->start(), block()->limit()); + block()->rpo(), block()->start(), block()->limit()); for (int i = 0; i < nt; i++) { - tty->print((( i < ns) ? " %d" : " %d(e)"), b->successor_at(i)->pre_order()); + tty->print((( i < ns) ? " %d" : " %d(e)"), b->successor_at(i)->rpo()); } + if (b->is_loop_head()) tty->print(" lphd"); tty->print_cr(""); } @@ -1501,7 +1484,7 @@ #ifndef PRODUCT Block* b = block(); int trap_bci = b->flow()->has_trap()? b->flow()->trap_bci(): -1; - tty->print_cr("### Missing successor at bci:%d for block #%d (trap_bci:%d)", target_bci, b->pre_order(), trap_bci); + tty->print_cr("### Missing successor at bci:%d for block #%d (trap_bci:%d)", target_bci, b->rpo(), trap_bci); #endif ShouldNotReachHere(); } @@ -1509,7 +1492,7 @@ //--------------------------merge_common--------------------------------------- void Parse::merge_common(Parse::Block* target, int pnum) { if (TraceOptoParse) { - tty->print("Merging state at block #%d bci:%d", target->pre_order(), target->start()); + tty->print("Merging state at block #%d bci:%d", target->rpo(), target->start()); } // Zap extra stack slots to top @@ -1534,6 +1517,7 @@ // which must not be allowed into this block's map.) if (pnum > PhiNode::Input // Known multiple inputs. || target->is_handler() // These have unpredictable inputs. + || target->is_loop_head() // Known multiple inputs || control()->is_Region()) { // We must hide this guy. // Add a Region to start the new basic block. Phis will be added // later lazily. @@ -1575,15 +1559,21 @@ // Compute where to merge into // Merge incoming control path - r->set_req(pnum, newin->control()); + r->init_req(pnum, newin->control()); if (pnum == 1) { // Last merge for this Region? - _gvn.transform_no_reclaim(r); + if (!block()->flow()->is_irreducible_entry()) { + Node* result = _gvn.transform_no_reclaim(r); + if (r != result && TraceOptoParse) { + tty->print_cr("Block #%d replace %d with %d", block()->rpo(), r->_idx, result->_idx); + } + } record_for_igvn(r); } // Update all the non-control inputs to map: assert(TypeFunc::Parms == newin->jvms()->locoff(), "parser map should contain only youngest jvms"); + bool check_elide_phi = target->is_SEL_backedge(save_block); for (uint j = 1; j < newin->req(); j++) { Node* m = map()->in(j); // Current state of target. Node* n = newin->in(j); // Incoming change to target state. @@ -1603,7 +1593,11 @@ merge_memory_edges(n->as_MergeMem(), pnum, nophi); continue; default: // All normal stuff - if (phi == NULL) phi = ensure_phi(j, nophi); + if (phi == NULL) { + if (!check_elide_phi || !target->can_elide_SEL_phi(j)) { + phi = ensure_phi(j, nophi); + } + } break; } } @@ -1736,9 +1730,13 @@ uint nof_monitors = map()->jvms()->nof_monitors(); assert(TypeFunc::Parms == map()->jvms()->locoff(), "parser map should contain only youngest jvms"); + bool check_elide_phi = block()->is_SEL_head(); for (uint i = TypeFunc::Parms; i < monoff; i++) { - ensure_phi(i); + if (!check_elide_phi || !block()->can_elide_SEL_phi(i)) { + ensure_phi(i); + } } + // Even monitors need Phis, though they are well-structured. // This is true for OSR methods, and also for the rare cases where // a monitor object is the subject of a replace_in_map operation.