8004640: C2 assert failure in memnode.cpp: NULL+offs not RAW address
Always transform AddP nodes in IdealKit by calling _gvn.transform(). Reviewed-by: roland, twisti
This commit is contained in:
parent
143a0039a3
commit
848ccdbdfe
@ -3445,7 +3445,6 @@ void GraphKit::sync_kit(IdealKit& ideal) {
|
||||
|
||||
void GraphKit::final_sync(IdealKit& ideal) {
|
||||
// Final sync IdealKit and graphKit.
|
||||
__ drain_delay_transform();
|
||||
sync_kit(ideal);
|
||||
}
|
||||
|
||||
|
@ -48,9 +48,9 @@ IdealKit::IdealKit(GraphKit* gkit, bool delay_all_transforms, bool has_declarati
|
||||
_cvstate = NULL;
|
||||
// We can go memory state free or else we need the entire memory state
|
||||
assert(_initial_memory == NULL || _initial_memory->Opcode() == Op_MergeMem, "memory must be pre-split");
|
||||
assert(!_gvn.is_IterGVN(), "IdealKit can't be used during Optimize phase");
|
||||
int init_size = 5;
|
||||
_pending_cvstates = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
|
||||
_delay_transform = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
|
||||
DEBUG_ONLY(_state = new (C->node_arena()) GrowableArray<int>(C->node_arena(), init_size, 0, 0));
|
||||
if (!has_declarations) {
|
||||
declarations_done();
|
||||
@ -296,19 +296,16 @@ Node* IdealKit::transform(Node* n) {
|
||||
return delay_transform(n);
|
||||
} else {
|
||||
n = gvn().transform(n);
|
||||
if (!gvn().is_IterGVN()) {
|
||||
C->record_for_igvn(n);
|
||||
}
|
||||
C->record_for_igvn(n);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------delay_transform-----------------------------------
|
||||
Node* IdealKit::delay_transform(Node* n) {
|
||||
if (!gvn().is_IterGVN() || !gvn().is_IterGVN()->delay_transform()) {
|
||||
gvn().set_type(n, n->bottom_type());
|
||||
}
|
||||
_delay_transform->push(n);
|
||||
// Delay transform until IterativeGVN
|
||||
gvn().set_type(n, n->bottom_type());
|
||||
C->record_for_igvn(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -332,17 +329,6 @@ void IdealKit::clear(Node* m) {
|
||||
for (uint i = 0; i < m->req(); i++) m->set_req(i, NULL);
|
||||
}
|
||||
|
||||
//-----------------------------drain_delay_transform----------------------------
|
||||
void IdealKit::drain_delay_transform() {
|
||||
while (_delay_transform->length() > 0) {
|
||||
Node* n = _delay_transform->pop();
|
||||
gvn().transform(n);
|
||||
if (!gvn().is_IterGVN()) {
|
||||
C->record_for_igvn(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------IdealVariable----------------------------
|
||||
IdealVariable::IdealVariable(IdealKit &k) {
|
||||
k.declare(this);
|
||||
@ -351,9 +337,7 @@ IdealVariable::IdealVariable(IdealKit &k) {
|
||||
Node* IdealKit::memory(uint alias_idx) {
|
||||
MergeMemNode* mem = merged_memory();
|
||||
Node* p = mem->memory_at(alias_idx);
|
||||
if (!gvn().is_IterGVN() || !gvn().is_IterGVN()->delay_transform()) {
|
||||
_gvn.set_type(p, Type::MEMORY); // must be mapped
|
||||
}
|
||||
_gvn.set_type(p, Type::MEMORY); // must be mapped
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,6 @@ class IdealKit: public StackObj {
|
||||
Compile * const C;
|
||||
PhaseGVN &_gvn;
|
||||
GrowableArray<Node*>* _pending_cvstates; // stack of cvstates
|
||||
GrowableArray<Node*>* _delay_transform; // delay invoking gvn.transform until drain
|
||||
Node* _cvstate; // current cvstate (control, memory and variables)
|
||||
uint _var_ct; // number of variables
|
||||
bool _delay_all_transforms; // flag forcing all transforms to be delayed
|
||||
@ -121,7 +120,7 @@ class IdealKit: public StackObj {
|
||||
void clear(Node* m); // clear a cvstate
|
||||
void stop() { clear(_cvstate); } // clear current cvstate
|
||||
Node* delay_transform(Node* n);
|
||||
Node* transform(Node* n); // gvn.transform or push node on delay list
|
||||
Node* transform(Node* n); // gvn.transform or skip it
|
||||
Node* promote_to_phi(Node* n, Node* reg);// Promote "n" to a phi on region "reg"
|
||||
bool was_promoted_to_phi(Node* n, Node* reg) {
|
||||
return (n->is_Phi() && n->in(0) == reg);
|
||||
@ -146,7 +145,6 @@ class IdealKit: public StackObj {
|
||||
IdealKit(GraphKit* gkit, bool delay_all_transforms = false, bool has_declarations = false);
|
||||
~IdealKit() {
|
||||
stop();
|
||||
drain_delay_transform();
|
||||
}
|
||||
void sync_kit(GraphKit* gkit);
|
||||
|
||||
@ -173,7 +171,6 @@ class IdealKit: public StackObj {
|
||||
void bind(Node* lab);
|
||||
void goto_(Node* lab, bool bind = false);
|
||||
void declarations_done();
|
||||
void drain_delay_transform();
|
||||
|
||||
Node* IfTrue(IfNode* iff) { return transform(new (C) IfTrueNode(iff)); }
|
||||
Node* IfFalse(IfNode* iff) { return transform(new (C) IfFalseNode(iff)); }
|
||||
@ -198,7 +195,11 @@ class IdealKit: public StackObj {
|
||||
Node* thread() { return gvn().transform(new (C) ThreadLocalNode()); }
|
||||
|
||||
// Pointers
|
||||
Node* AddP(Node *base, Node *ptr, Node *off) { return transform(new (C) AddPNode(base, ptr, off)); }
|
||||
|
||||
// Raw address should be transformed regardless 'delay_transform' flag
|
||||
// to produce canonical form CastX2P(offset).
|
||||
Node* AddP(Node *base, Node *ptr, Node *off) { return _gvn.transform(new (C) AddPNode(base, ptr, off)); }
|
||||
|
||||
Node* CmpP(Node* l, Node* r) { return transform(new (C) CmpPNode(l, r)); }
|
||||
#ifdef _LP64
|
||||
Node* XorX(Node* l, Node* r) { return transform(new (C) XorLNode(l, r)); }
|
||||
@ -208,8 +209,6 @@ class IdealKit: public StackObj {
|
||||
Node* URShiftX(Node* l, Node* r) { return transform(new (C) URShiftXNode(l, r)); }
|
||||
Node* ConX(jint k) { return (Node*)gvn().MakeConX(k); }
|
||||
Node* CastPX(Node* ctl, Node* p) { return transform(new (C) CastP2XNode(ctl, p)); }
|
||||
// Add a fixed offset to a pointer
|
||||
Node* basic_plus_adr(Node* base, Node* ptr, intptr_t offset);
|
||||
|
||||
// Memory operations
|
||||
|
||||
|
@ -2251,6 +2251,11 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
|
||||
return;
|
||||
}
|
||||
|
||||
// clear out the dead code after build_loop_late
|
||||
while (_deadlist.size()) {
|
||||
_igvn.remove_globally_dead_node(_deadlist.pop());
|
||||
}
|
||||
|
||||
if (stop_early) {
|
||||
assert(do_expensive_nodes, "why are we here?");
|
||||
if (process_expensive_nodes()) {
|
||||
@ -2260,9 +2265,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
|
||||
// nodes again.
|
||||
C->set_major_progress();
|
||||
}
|
||||
|
||||
_igvn.optimize();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2273,11 +2276,6 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
|
||||
eliminate_useless_predicates();
|
||||
}
|
||||
|
||||
// clear out the dead code
|
||||
while(_deadlist.size()) {
|
||||
_igvn.remove_globally_dead_node(_deadlist.pop());
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
C->verify_graph_edges();
|
||||
if (_verify_me) { // Nested verify pass?
|
||||
|
@ -1166,31 +1166,30 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) {
|
||||
if (progress_state == PROCESS_INPUTS) {
|
||||
// After following inputs, continue to outputs
|
||||
_stack.set_index(PROCESS_OUTPUTS);
|
||||
// Remove from iterative worklist
|
||||
_worklist.remove(dead);
|
||||
if (!dead->is_Con()) { // Don't kill cons but uses
|
||||
bool recurse = false;
|
||||
// Remove from hash table
|
||||
_table.hash_delete( dead );
|
||||
// Smash all inputs to 'dead', isolating him completely
|
||||
for( uint i = 0; i < dead->req(); i++ ) {
|
||||
for (uint i = 0; i < dead->req(); i++) {
|
||||
Node *in = dead->in(i);
|
||||
if( in ) { // Points to something?
|
||||
dead->set_req(i,NULL); // Kill the edge
|
||||
if (in->outcnt() == 0 && in != C->top()) {// Made input go dead?
|
||||
if (in != NULL && in != C->top()) { // Points to something?
|
||||
int nrep = dead->replace_edge(in, NULL); // Kill edges
|
||||
assert((nrep > 0), "sanity");
|
||||
if (in->outcnt() == 0) { // Made input go dead?
|
||||
_stack.push(in, PROCESS_INPUTS); // Recursively remove
|
||||
recurse = true;
|
||||
} else if (in->outcnt() == 1 &&
|
||||
in->has_special_unique_user()) {
|
||||
_worklist.push(in->unique_out());
|
||||
} else if (in->outcnt() <= 2 && dead->is_Phi()) {
|
||||
if( in->Opcode() == Op_Region )
|
||||
if (in->Opcode() == Op_Region) {
|
||||
_worklist.push(in);
|
||||
else if( in->is_Store() ) {
|
||||
} else if (in->is_Store()) {
|
||||
DUIterator_Fast imax, i = in->fast_outs(imax);
|
||||
_worklist.push(in->fast_out(i));
|
||||
i++;
|
||||
if(in->outcnt() == 2) {
|
||||
if (in->outcnt() == 2) {
|
||||
_worklist.push(in->fast_out(i));
|
||||
i++;
|
||||
}
|
||||
@ -1209,38 +1208,42 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
C->record_dead_node(dead->_idx);
|
||||
if (dead->is_macro()) {
|
||||
C->remove_macro_node(dead);
|
||||
}
|
||||
if (dead->is_expensive()) {
|
||||
C->remove_expensive_node(dead);
|
||||
}
|
||||
|
||||
} // if (in != NULL && in != C->top())
|
||||
} // for (uint i = 0; i < dead->req(); i++)
|
||||
if (recurse) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 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
|
||||
// as dead to be conservative about the dead node count at any
|
||||
// given time.
|
||||
}
|
||||
} // if (!dead->is_Con())
|
||||
} // if (progress_state == PROCESS_INPUTS)
|
||||
|
||||
// Aggressively kill globally dead uses
|
||||
// (Rather than pushing all the outs at once, we push one at a time,
|
||||
// plus the parent to resume later, because of the indefinite number
|
||||
// of edge deletions per loop trip.)
|
||||
if (dead->outcnt() > 0) {
|
||||
// Recursively remove
|
||||
// Recursively remove output edges
|
||||
_stack.push(dead->raw_out(0), PROCESS_INPUTS);
|
||||
} else {
|
||||
// Finished disconnecting all input and output edges.
|
||||
_stack.pop();
|
||||
// Remove dead node from iterative worklist
|
||||
_worklist.remove(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
|
||||
// as dead to be conservative about the dead node count at any
|
||||
// given time.
|
||||
if (!dead->is_Con()) {
|
||||
C->record_dead_node(dead->_idx);
|
||||
}
|
||||
if (dead->is_macro()) {
|
||||
C->remove_macro_node(dead);
|
||||
}
|
||||
if (dead->is_expensive()) {
|
||||
C->remove_expensive_node(dead);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // while (_stack.is_nonempty())
|
||||
}
|
||||
|
||||
//------------------------------subsume_node-----------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user