mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-31 13:38:47 +00:00
8040213: C2 does not put all modified nodes on IGVN worklist
Verification code is added that checks if modified nodes are put on the IGVN worklist and modified nodes are processed by 'PhaseIterGVN::transform_old()' Reviewed-by: kvn, jrose
This commit is contained in:
parent
cabec1ca5e
commit
11eb4553c9
@ -108,6 +108,7 @@ static Node *merge_region(RegionNode *region, PhaseGVN *phase) {
|
||||
|
||||
rreq++; // One more input to Region
|
||||
} // Found a region to merge into Region
|
||||
igvn->_worklist.push(r);
|
||||
// Clobber pointer to the now dead 'r'
|
||||
region->set_req(i, phase->C->top());
|
||||
}
|
||||
@ -449,6 +450,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
// Remove TOP or NULL input paths. If only 1 input path remains, this Region
|
||||
// degrades to a copy.
|
||||
bool add_to_worklist = false;
|
||||
bool modified = false;
|
||||
int cnt = 0; // Count of values merging
|
||||
DEBUG_ONLY( int cnt_orig = req(); ) // Save original inputs count
|
||||
int del_it = 0; // The last input path we delete
|
||||
@ -459,6 +461,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
// Remove useless control copy inputs
|
||||
if( n->is_Region() && n->as_Region()->is_copy() ) {
|
||||
set_req(i, n->nonnull_req());
|
||||
modified = true;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
@ -466,12 +469,14 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
Node *call = n->in(0);
|
||||
if (call->is_Call() && call->as_Call()->entry_point() == OptoRuntime::rethrow_stub()) {
|
||||
set_req(i, call->in(0));
|
||||
modified = true;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( phase->type(n) == Type::TOP ) {
|
||||
set_req(i, NULL); // Ignore TOP inputs
|
||||
modified = true;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
@ -691,7 +696,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return modified ? this : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1060,6 +1060,7 @@ void Compile::Init(int aliaslevel) {
|
||||
|
||||
_node_note_array = NULL;
|
||||
_default_node_notes = NULL;
|
||||
DEBUG_ONLY( _modified_nodes = NULL; ) // Used in Optimize()
|
||||
|
||||
_immutable_memory = NULL; // filled in at first inquiry
|
||||
|
||||
@ -1268,6 +1269,18 @@ void Compile::print_missing_nodes() {
|
||||
}
|
||||
}
|
||||
}
|
||||
void Compile::record_modified_node(Node* n) {
|
||||
if (_modified_nodes != NULL && !_inlining_incrementally &&
|
||||
n->outcnt() != 0 && !n->is_Con()) {
|
||||
_modified_nodes->push(n);
|
||||
}
|
||||
}
|
||||
|
||||
void Compile::remove_modified_node(Node* n) {
|
||||
if (_modified_nodes != NULL) {
|
||||
_modified_nodes->remove(n);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -2056,6 +2069,9 @@ void Compile::Optimize() {
|
||||
// Iterative Global Value Numbering, including ideal transforms
|
||||
// Initialize IterGVN with types and values from parse-time GVN
|
||||
PhaseIterGVN igvn(initial_gvn());
|
||||
#ifdef ASSERT
|
||||
_modified_nodes = new (comp_arena()) Unique_Node_List(comp_arena());
|
||||
#endif
|
||||
{
|
||||
NOT_PRODUCT( TracePhase t2("iterGVN", &_t_iterGVN, TimeCompiler); )
|
||||
igvn.optimize();
|
||||
@ -2218,6 +2234,7 @@ void Compile::Optimize() {
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ONLY( _modified_nodes = NULL; )
|
||||
} // (End scope of igvn; run destructor if necessary for asserts.)
|
||||
|
||||
process_print_inlining();
|
||||
@ -4052,6 +4069,7 @@ void Compile::cleanup_expensive_nodes(PhaseIterGVN &igvn) {
|
||||
int j = 0;
|
||||
int identical = 0;
|
||||
int i = 0;
|
||||
bool modified = false;
|
||||
for (; i < _expensive_nodes->length()-1; i++) {
|
||||
assert(j <= i, "can't write beyond current index");
|
||||
if (_expensive_nodes->at(i)->Opcode() == _expensive_nodes->at(i+1)->Opcode()) {
|
||||
@ -4064,20 +4082,23 @@ void Compile::cleanup_expensive_nodes(PhaseIterGVN &igvn) {
|
||||
identical = 0;
|
||||
} else {
|
||||
Node* n = _expensive_nodes->at(i);
|
||||
igvn.hash_delete(n);
|
||||
n->set_req(0, NULL);
|
||||
igvn.replace_input_of(n, 0, NULL);
|
||||
igvn.hash_insert(n);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (identical > 0) {
|
||||
_expensive_nodes->at_put(j++, _expensive_nodes->at(i));
|
||||
} else if (_expensive_nodes->length() >= 1) {
|
||||
Node* n = _expensive_nodes->at(i);
|
||||
igvn.hash_delete(n);
|
||||
n->set_req(0, NULL);
|
||||
igvn.replace_input_of(n, 0, NULL);
|
||||
igvn.hash_insert(n);
|
||||
modified = true;
|
||||
}
|
||||
_expensive_nodes->trunc_to(j);
|
||||
if (modified) {
|
||||
igvn.optimize();
|
||||
}
|
||||
}
|
||||
|
||||
void Compile::add_expensive_node(Node * n) {
|
||||
|
||||
@ -344,6 +344,8 @@ class Compile : public Phase {
|
||||
VectorSet _dead_node_list; // Set of dead nodes
|
||||
uint _dead_node_count; // Number of dead nodes; VectorSet::Size() is O(N).
|
||||
// So use this to keep count and make the call O(1).
|
||||
DEBUG_ONLY( Unique_Node_List* _modified_nodes; ) // List of nodes which inputs were modified
|
||||
|
||||
debug_only(static int _debug_idx;) // Monotonic counter (not reset), use -XX:BreakAtNode=<idx>
|
||||
Arena _node_arena; // Arena for new-space Nodes
|
||||
Arena _old_arena; // Arena for old-space Nodes, lifetime during xform
|
||||
@ -766,6 +768,11 @@ class Compile : public Phase {
|
||||
void print_missing_nodes();
|
||||
#endif
|
||||
|
||||
// Record modified nodes to check that they are put on IGVN worklist
|
||||
void record_modified_node(Node* n) NOT_DEBUG_RETURN;
|
||||
void remove_modified_node(Node* n) NOT_DEBUG_RETURN;
|
||||
DEBUG_ONLY( Unique_Node_List* modified_nodes() const { return _modified_nodes; } )
|
||||
|
||||
// Constant table
|
||||
ConstantTable& constant_table() { return _constant_table; }
|
||||
|
||||
|
||||
@ -479,7 +479,10 @@ Node *DivINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
|
||||
if (i == 0) return NULL; // Dividing by zero constant does not idealize
|
||||
|
||||
set_req(0,NULL); // Dividing by a not-zero constant; no faulting
|
||||
if (in(0) != NULL) {
|
||||
phase->igvn_rehash_node_delayed(this);
|
||||
set_req(0, NULL); // Dividing by a not-zero constant; no faulting
|
||||
}
|
||||
|
||||
// Dividing by MININT does not optimize as a power-of-2 shift.
|
||||
if( i == min_jint ) return NULL;
|
||||
@ -578,7 +581,10 @@ Node *DivLNode::Ideal( PhaseGVN *phase, bool can_reshape) {
|
||||
|
||||
if (l == 0) return NULL; // Dividing by zero constant does not idealize
|
||||
|
||||
set_req(0,NULL); // Dividing by a not-zero constant; no faulting
|
||||
if (in(0) != NULL) {
|
||||
phase->igvn_rehash_node_delayed(this);
|
||||
set_req(0, NULL); // Dividing by a not-zero constant; no faulting
|
||||
}
|
||||
|
||||
// Dividing by MINLONG does not optimize as a power-of-2 shift.
|
||||
if( l == min_jlong ) return NULL;
|
||||
|
||||
@ -107,8 +107,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node*
|
||||
rgn = new RegionNode(1);
|
||||
rgn->add_req(uncommon_proj);
|
||||
register_control(rgn, loop, uncommon_proj);
|
||||
_igvn.hash_delete(call);
|
||||
call->set_req(0, rgn);
|
||||
_igvn.replace_input_of(call, 0, rgn);
|
||||
// When called from beautify_loops() idom is not constructed yet.
|
||||
if (_idom != NULL) {
|
||||
set_idom(call, rgn, dom_depth(rgn));
|
||||
@ -166,8 +165,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node*
|
||||
|
||||
if (new_entry == NULL) {
|
||||
// Attach if_cont to iff
|
||||
_igvn.hash_delete(iff);
|
||||
iff->set_req(0, if_cont);
|
||||
_igvn.replace_input_of(iff, 0, if_cont);
|
||||
if (_idom != NULL) {
|
||||
set_idom(iff, if_cont, dom_depth(iff));
|
||||
}
|
||||
@ -194,8 +192,7 @@ ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* n
|
||||
rgn = new RegionNode(1);
|
||||
register_new_node_with_optimizer(rgn);
|
||||
rgn->add_req(uncommon_proj);
|
||||
hash_delete(call);
|
||||
call->set_req(0, rgn);
|
||||
replace_input_of(call, 0, rgn);
|
||||
} else {
|
||||
// Find region's edge corresponding to uncommon_proj
|
||||
for (; proj_index < rgn->req(); proj_index++)
|
||||
|
||||
@ -924,15 +924,13 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_
|
||||
if( bol->outcnt() != 1 ) {
|
||||
bol = bol->clone();
|
||||
register_new_node(bol,main_end->in(CountedLoopEndNode::TestControl));
|
||||
_igvn.hash_delete(main_end);
|
||||
main_end->set_req(CountedLoopEndNode::TestValue, bol);
|
||||
_igvn.replace_input_of(main_end, CountedLoopEndNode::TestValue, bol);
|
||||
}
|
||||
// Need only 1 user of 'cmp' because I will be hacking the loop bounds.
|
||||
if( cmp->outcnt() != 1 ) {
|
||||
cmp = cmp->clone();
|
||||
register_new_node(cmp,main_end->in(CountedLoopEndNode::TestControl));
|
||||
_igvn.hash_delete(bol);
|
||||
bol->set_req(1, cmp);
|
||||
_igvn.replace_input_of(bol, 1, cmp);
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
@ -1118,8 +1116,7 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_
|
||||
Node* pre_bol = pre_end->in(CountedLoopEndNode::TestValue)->as_Bool();
|
||||
BoolNode* new_bol0 = new BoolNode(pre_bol->in(1), new_test);
|
||||
register_new_node( new_bol0, pre_head->in(0) );
|
||||
_igvn.hash_delete(pre_end);
|
||||
pre_end->set_req(CountedLoopEndNode::TestValue, new_bol0);
|
||||
_igvn.replace_input_of(pre_end, CountedLoopEndNode::TestValue, new_bol0);
|
||||
// Modify main loop guard condition
|
||||
assert(min_iff->in(CountedLoopEndNode::TestValue) == min_bol, "guard okay");
|
||||
BoolNode* new_bol1 = new BoolNode(min_bol->in(1), new_test);
|
||||
@ -1130,8 +1127,7 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_
|
||||
BoolNode* main_bol = main_end->in(CountedLoopEndNode::TestValue)->as_Bool();
|
||||
BoolNode* new_bol2 = new BoolNode(main_bol->in(1), new_test);
|
||||
register_new_node( new_bol2, main_end->in(CountedLoopEndNode::TestControl) );
|
||||
_igvn.hash_delete(main_end);
|
||||
main_end->set_req(CountedLoopEndNode::TestValue, new_bol2);
|
||||
_igvn.replace_input_of(main_end, CountedLoopEndNode::TestValue, new_bol2);
|
||||
}
|
||||
|
||||
// Flag main loop
|
||||
@ -1346,8 +1342,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
|
||||
Node* bol2 = loop_end->in(1)->clone();
|
||||
bol2->set_req(1, cmp2);
|
||||
register_new_node(bol2, ctrl2);
|
||||
_igvn.hash_delete(loop_end);
|
||||
loop_end->set_req(1, bol2);
|
||||
_igvn.replace_input_of(loop_end, 1, bol2);
|
||||
}
|
||||
// Step 3: Find the min-trip test guaranteed before a 'main' loop.
|
||||
// Make it a 1-trip test (means at least 2 trips).
|
||||
@ -1356,8 +1351,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
|
||||
// can edit it's inputs directly. Hammer in the new limit for the
|
||||
// minimum-trip guard.
|
||||
assert(opaq->outcnt() == 1, "");
|
||||
_igvn.hash_delete(opaq);
|
||||
opaq->set_req(1, new_limit);
|
||||
_igvn.replace_input_of(opaq, 1, new_limit);
|
||||
}
|
||||
|
||||
// Adjust max trip count. The trip count is intentionally rounded
|
||||
@ -1407,8 +1401,7 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
|
||||
register_new_node( cmp2, ctrl2 );
|
||||
Node *bol2 = new BoolNode( cmp2, loop_end->test_trip() );
|
||||
register_new_node( bol2, ctrl2 );
|
||||
_igvn.hash_delete(loop_end);
|
||||
loop_end->set_req(CountedLoopEndNode::TestValue, bol2);
|
||||
_igvn.replace_input_of(loop_end, CountedLoopEndNode::TestValue, bol2);
|
||||
|
||||
// Step 3: Find the min-trip test guaranteed before a 'main' loop.
|
||||
// Make it a 1-trip test (means at least 2 trips).
|
||||
@ -1997,8 +1990,7 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
: (Node*)new MaxINode(pre_limit, orig_limit);
|
||||
register_new_node(pre_limit, pre_ctrl);
|
||||
}
|
||||
_igvn.hash_delete(pre_opaq);
|
||||
pre_opaq->set_req(1, pre_limit);
|
||||
_igvn.replace_input_of(pre_opaq, 1, pre_limit);
|
||||
|
||||
// Note:: we are making the main loop limit no longer precise;
|
||||
// need to round up based on stride.
|
||||
|
||||
@ -133,7 +133,7 @@ Node *PhaseIdealLoop::get_early_ctrl( Node *n ) {
|
||||
// Return earliest legal location
|
||||
assert(early == find_non_split_ctrl(early), "unexpected early control");
|
||||
|
||||
if (n->is_expensive()) {
|
||||
if (n->is_expensive() && !_verify_only && !_verify_me) {
|
||||
assert(n->in(0), "should have control input");
|
||||
early = get_early_ctrl_for_expensive(n, early);
|
||||
}
|
||||
@ -226,8 +226,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) {
|
||||
}
|
||||
|
||||
if (ctl != n->in(0)) {
|
||||
_igvn.hash_delete(n);
|
||||
n->set_req(0, ctl);
|
||||
_igvn.replace_input_of(n, 0, ctl);
|
||||
_igvn.hash_insert(n);
|
||||
}
|
||||
|
||||
@ -521,8 +520,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||
assert(check_iff->in(1)->Opcode() == Op_Conv2B &&
|
||||
check_iff->in(1)->in(1)->Opcode() == Op_Opaque1, "");
|
||||
Node* opq = check_iff->in(1)->in(1);
|
||||
_igvn.hash_delete(opq);
|
||||
opq->set_req(1, bol);
|
||||
_igvn.replace_input_of(opq, 1, bol);
|
||||
// Update ctrl.
|
||||
set_ctrl(opq, check_iff->in(0));
|
||||
set_ctrl(check_iff->in(1), check_iff->in(0));
|
||||
@ -690,7 +688,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||
incr->set_req(2,stride);
|
||||
incr = _igvn.register_new_node_with_optimizer(incr);
|
||||
set_early_ctrl( incr );
|
||||
_igvn.hash_delete(phi);
|
||||
_igvn.rehash_node_delayed(phi);
|
||||
phi->set_req_X( LoopNode::LoopBackControl, incr, &_igvn );
|
||||
|
||||
// If phi type is more restrictive than Int, raise to
|
||||
@ -743,8 +741,8 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
|
||||
iffalse = iff2;
|
||||
iftrue = ift2;
|
||||
} else {
|
||||
_igvn.hash_delete(iffalse);
|
||||
_igvn.hash_delete(iftrue);
|
||||
_igvn.rehash_node_delayed(iffalse);
|
||||
_igvn.rehash_node_delayed(iftrue);
|
||||
iffalse->set_req_X( 0, le, &_igvn );
|
||||
iftrue ->set_req_X( 0, le, &_igvn );
|
||||
}
|
||||
@ -1257,6 +1255,7 @@ void IdealLoopTree::split_fall_in( PhaseIdealLoop *phase, int fall_in_cnt ) {
|
||||
_head->del_req(i);
|
||||
}
|
||||
}
|
||||
igvn.rehash_node_delayed(_head);
|
||||
// Transform landing pad
|
||||
igvn.register_new_node_with_optimizer(landing_pad, _head);
|
||||
// Insert landing pad into the header
|
||||
@ -1397,7 +1396,7 @@ void IdealLoopTree::merge_many_backedges( PhaseIdealLoop *phase ) {
|
||||
igvn.register_new_node_with_optimizer(r, _head);
|
||||
// Plug region into end of loop _head, followed by hot_tail
|
||||
while( _head->req() > 3 ) _head->del_req( _head->req()-1 );
|
||||
_head->set_req(2, r);
|
||||
igvn.replace_input_of(_head, 2, r);
|
||||
if( hot_idx ) _head->add_req(hot_tail);
|
||||
|
||||
// Split all the Phis up between '_head' loop and the Region 'r'
|
||||
@ -1419,7 +1418,7 @@ void IdealLoopTree::merge_many_backedges( PhaseIdealLoop *phase ) {
|
||||
igvn.register_new_node_with_optimizer(phi, n);
|
||||
// Add the merge phi to the old Phi
|
||||
while( n->req() > 3 ) n->del_req( n->req()-1 );
|
||||
n->set_req(2, phi);
|
||||
igvn.replace_input_of(n, 2, phi);
|
||||
if( hot_idx ) n->add_req(hot_phi);
|
||||
}
|
||||
}
|
||||
@ -1495,13 +1494,14 @@ bool IdealLoopTree::beautify_loops( PhaseIdealLoop *phase ) {
|
||||
if( fall_in_cnt > 1 ) {
|
||||
// Since I am just swapping inputs I do not need to update def-use info
|
||||
Node *tmp = _head->in(1);
|
||||
igvn.rehash_node_delayed(_head);
|
||||
_head->set_req( 1, _head->in(fall_in_cnt) );
|
||||
_head->set_req( fall_in_cnt, tmp );
|
||||
// Swap also all Phis
|
||||
for (DUIterator_Fast imax, i = _head->fast_outs(imax); i < imax; i++) {
|
||||
Node* phi = _head->fast_out(i);
|
||||
if( phi->is_Phi() ) {
|
||||
igvn.hash_delete(phi); // Yank from hash before hacking edges
|
||||
igvn.rehash_node_delayed(phi); // Yank from hash before hacking edges
|
||||
tmp = phi->in(1);
|
||||
phi->set_req( 1, phi->in(fall_in_cnt) );
|
||||
phi->set_req( fall_in_cnt, tmp );
|
||||
@ -2905,6 +2905,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
|
||||
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
|
||||
_igvn._worklist.push(cfg);
|
||||
|
||||
// Now create the never-taken loop exit
|
||||
Node *if_f = new CProjNode( iff, 1 );
|
||||
|
||||
@ -2574,7 +2574,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
new_head->set_unswitch_count(head->unswitch_count()); // Preserve
|
||||
_igvn.register_new_node_with_optimizer(new_head);
|
||||
assert(first_not_peeled->in(0) == last_peel, "last_peel <- first_not_peeled");
|
||||
first_not_peeled->set_req(0, new_head);
|
||||
_igvn.replace_input_of(first_not_peeled, 0, new_head);
|
||||
set_loop(new_head, loop);
|
||||
loop->_body.push(new_head);
|
||||
not_peel.set(new_head->_idx);
|
||||
|
||||
@ -855,6 +855,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray <Sa
|
||||
int start = jvms->debug_start();
|
||||
int end = jvms->debug_end();
|
||||
sfpt->replace_edges_in_range(res, sobj, start, end);
|
||||
_igvn._worklist.push(sfpt);
|
||||
safepoints_done.append_if_missing(sfpt); // keep it for rollback
|
||||
}
|
||||
return true;
|
||||
@ -1775,6 +1776,7 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false,
|
||||
Node *pf_region = new RegionNode(3);
|
||||
Node *pf_phi_rawmem = new PhiNode( pf_region, Type::MEMORY,
|
||||
TypeRawPtr::BOTTOM );
|
||||
transform_later(pf_region);
|
||||
|
||||
// Generate several prefetch instructions.
|
||||
uint lines = (length != NULL) ? AllocatePrefetchLines : AllocateInstancePrefetchLines;
|
||||
|
||||
@ -1471,6 +1471,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
|
||||
Node* ctrl = in(MemNode::Control);
|
||||
Node* address = in(MemNode::Address);
|
||||
bool progress = false;
|
||||
|
||||
// Skip up past a SafePoint control. Cannot do this for Stores because
|
||||
// pointer stores & cardmarks must stay on the same side of a SafePoint.
|
||||
@ -1478,6 +1479,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw ) {
|
||||
ctrl = ctrl->in(0);
|
||||
set_req(MemNode::Control,ctrl);
|
||||
progress = true;
|
||||
}
|
||||
|
||||
intptr_t ignore = 0;
|
||||
@ -1490,6 +1492,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
&& all_controls_dominate(base, phase->C->start())) {
|
||||
// A method-invariant, non-null address (constant or 'this' argument).
|
||||
set_req(MemNode::Control, NULL);
|
||||
progress = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1550,7 +1553,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // No further progress
|
||||
return progress ? this : NULL;
|
||||
}
|
||||
|
||||
// Helper to recognize certain Klass fields which are invariant across
|
||||
@ -2944,6 +2947,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool progress = false;
|
||||
// Eliminate volatile MemBars for scalar replaced objects.
|
||||
if (can_reshape && req() == (Precedent+1)) {
|
||||
bool eliminate = false;
|
||||
@ -2966,6 +2970,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
phase->is_IterGVN()->_worklist.push(my_mem); // remove dead node later
|
||||
my_mem = NULL;
|
||||
}
|
||||
progress = true;
|
||||
}
|
||||
if (my_mem != NULL && my_mem->is_Mem()) {
|
||||
const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr();
|
||||
@ -2995,7 +3000,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
return new ConINode(TypeInt::ZERO);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return progress ? this : NULL;
|
||||
}
|
||||
|
||||
//------------------------------Value------------------------------------------
|
||||
@ -3497,6 +3502,7 @@ Node* InitializeNode::capture_store(StoreNode* st, intptr_t start,
|
||||
// if it redundantly stored the same value (or zero to fresh memory).
|
||||
|
||||
// In any case, wire it in:
|
||||
phase->igvn_rehash_node_delayed(this);
|
||||
set_req(i, new_st);
|
||||
|
||||
// The caller may now kill the old guy.
|
||||
|
||||
@ -620,6 +620,7 @@ void Node::destruct() {
|
||||
*(address*)this = badAddress; // smash the C++ vtbl, probably
|
||||
_in = _out = (Node**) badAddress;
|
||||
_max = _cnt = _outmax = _outcnt = 0;
|
||||
compile->remove_modified_node(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -765,6 +766,7 @@ void Node::del_req( uint idx ) {
|
||||
if (n != NULL) n->del_out((Node *)this);
|
||||
_in[idx] = in(--_cnt); // Compact the array
|
||||
_in[_cnt] = NULL; // NULL out emptied slot
|
||||
Compile::current()->record_modified_node(this);
|
||||
}
|
||||
|
||||
//------------------------------del_req_ordered--------------------------------
|
||||
@ -780,6 +782,7 @@ void Node::del_req_ordered( uint idx ) {
|
||||
Copy::conjoint_words_to_lower((HeapWord*)&_in[idx+1], (HeapWord*)&_in[idx], ((_cnt-idx-1)*sizeof(Node*)));
|
||||
}
|
||||
_in[--_cnt] = NULL; // NULL out emptied slot
|
||||
Compile::current()->record_modified_node(this);
|
||||
}
|
||||
|
||||
//------------------------------ins_req----------------------------------------
|
||||
@ -1297,6 +1300,7 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) {
|
||||
// Done with outputs.
|
||||
igvn->hash_delete(dead);
|
||||
igvn->_worklist.remove(dead);
|
||||
igvn->C->remove_modified_node(dead);
|
||||
igvn->set_type(dead, Type::TOP);
|
||||
if (dead->is_macro()) {
|
||||
igvn->C->remove_macro_node(dead);
|
||||
|
||||
@ -398,6 +398,7 @@ protected:
|
||||
if (*p != NULL) (*p)->del_out((Node *)this);
|
||||
(*p) = n;
|
||||
if (n != NULL) n->add_out((Node *)this);
|
||||
Compile::current()->record_modified_node(this);
|
||||
}
|
||||
// Light version of set_req() to init inputs after node creation.
|
||||
void init_req( uint i, Node *n ) {
|
||||
@ -409,6 +410,7 @@ protected:
|
||||
assert( _in[i] == NULL, "sanity");
|
||||
_in[i] = n;
|
||||
if (n != NULL) n->add_out((Node *)this);
|
||||
Compile::current()->record_modified_node(this);
|
||||
}
|
||||
// Find first occurrence of n among my edges:
|
||||
int find_edge(Node* n);
|
||||
|
||||
@ -933,9 +933,32 @@ void PhaseIterGVN::init_verifyPhaseIterGVN() {
|
||||
for (int i = 0; i < _verify_window_size; i++) {
|
||||
_verify_window[i] = NULL;
|
||||
}
|
||||
#ifdef ASSERT
|
||||
// Verify that all modified nodes are on _worklist
|
||||
Unique_Node_List* modified_list = C->modified_nodes();
|
||||
while (modified_list != NULL && modified_list->size()) {
|
||||
Node* n = modified_list->pop();
|
||||
if (n->outcnt() != 0 && !n->is_Con() && !_worklist.member(n)) {
|
||||
n->dump();
|
||||
assert(false, "modified node is not on IGVN._worklist");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PhaseIterGVN::verify_PhaseIterGVN() {
|
||||
#ifdef ASSERT
|
||||
// Verify nodes with changed inputs.
|
||||
Unique_Node_List* modified_list = C->modified_nodes();
|
||||
while (modified_list != NULL && modified_list->size()) {
|
||||
Node* n = modified_list->pop();
|
||||
if (n->outcnt() != 0 && !n->is_Con()) { // skip dead and Con nodes
|
||||
n->dump();
|
||||
assert(false, "modified node was not processed by IGVN.transform_old()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
C->verify_graph_edges();
|
||||
if( VerifyOpto && allow_progress() ) {
|
||||
// Must turn off allow_progress to enable assert and break recursion
|
||||
@ -964,6 +987,14 @@ void PhaseIterGVN::verify_PhaseIterGVN() {
|
||||
(int) _verify_counter, (int) _verify_full_passes);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
while (modified_list->size()) {
|
||||
Node* n = modified_list->pop();
|
||||
n->dump();
|
||||
assert(false, "VerifyIterativeGVN: new modified node was added");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* PRODUCT */
|
||||
|
||||
@ -1066,6 +1097,7 @@ Node *PhaseIterGVN::transform_old(Node* n) {
|
||||
Node* k = n;
|
||||
DEBUG_ONLY(dead_loop_check(k);)
|
||||
DEBUG_ONLY(bool is_new = (k->outcnt() == 0);)
|
||||
C->remove_modified_node(k);
|
||||
Node* i = k->Ideal(this, /*can_reshape=*/true);
|
||||
assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes");
|
||||
#ifndef PRODUCT
|
||||
@ -1107,6 +1139,7 @@ Node *PhaseIterGVN::transform_old(Node* n) {
|
||||
DEBUG_ONLY(dead_loop_check(k);)
|
||||
// Try idealizing again
|
||||
DEBUG_ONLY(is_new = (k->outcnt() == 0);)
|
||||
C->remove_modified_node(k);
|
||||
i = k->Ideal(this, /*can_reshape=*/true);
|
||||
assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes");
|
||||
#ifndef PRODUCT
|
||||
@ -1259,6 +1292,7 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) {
|
||||
_stack.pop();
|
||||
// Remove dead node from iterative worklist
|
||||
_worklist.remove(dead);
|
||||
C->remove_modified_node(dead);
|
||||
// Constant node that has no out-edges and has only one in-edge from
|
||||
// root is usually dead. However, sometimes reshaping walk makes
|
||||
// it reachable by adding use edges. So, we will NOT count Con nodes
|
||||
@ -1288,7 +1322,7 @@ void PhaseIterGVN::subsume_node( Node *old, Node *nn ) {
|
||||
for (DUIterator_Last imin, i = old->last_outs(imin); i >= imin; ) {
|
||||
Node* use = old->last_out(i); // for each use...
|
||||
// use might need re-hashing (but it won't if it's a new node)
|
||||
bool is_in_table = _table.hash_delete( use );
|
||||
rehash_node_delayed(use);
|
||||
// Update use-def info as well
|
||||
// We remove all occurrences of old within use->in,
|
||||
// so as to avoid rehashing any node more than once.
|
||||
@ -1300,11 +1334,6 @@ void PhaseIterGVN::subsume_node( Node *old, Node *nn ) {
|
||||
++num_edges;
|
||||
}
|
||||
}
|
||||
// Insert into GVN hash table if unique
|
||||
// If a duplicate, 'use' will be cleaned up when pulled off worklist
|
||||
if( is_in_table ) {
|
||||
hash_find_insert(use);
|
||||
}
|
||||
i -= num_edges; // we deleted 1 or more copies of this edge
|
||||
}
|
||||
|
||||
|
||||
@ -311,6 +311,9 @@ public:
|
||||
const Type* limit_type) const
|
||||
{ ShouldNotCallThis(); return NULL; }
|
||||
|
||||
// Delayed node rehash if this is an IGVN phase
|
||||
virtual void igvn_rehash_node_delayed(Node* n) {}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void dump_old2new_map() const;
|
||||
void dump_new( uint new_lidx ) const;
|
||||
@ -488,6 +491,10 @@ public:
|
||||
_worklist.push(n);
|
||||
}
|
||||
|
||||
void igvn_rehash_node_delayed(Node* n) {
|
||||
rehash_node_delayed(n);
|
||||
}
|
||||
|
||||
// Replace ith edge of "n" with "in"
|
||||
void replace_input_of(Node* n, int i, Node* in) {
|
||||
rehash_node_delayed(n);
|
||||
|
||||
@ -35,10 +35,12 @@
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// Remove dead inputs
|
||||
Node *RootNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
bool modified = false;
|
||||
for( uint i = 1; i < req(); i++ ) { // For all inputs
|
||||
// Check for and remove dead inputs
|
||||
if( phase->type(in(i)) == Type::TOP ) {
|
||||
del_req(i--); // Delete TOP inputs
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +58,7 @@ Node *RootNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
// If we want to get the rest of the win later, we should pattern match
|
||||
// simple recursive call trees to closed-form solutions.
|
||||
|
||||
return NULL; // No further opportunities exposed
|
||||
return modified ? this : NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user