Skip to content
Permalink
Browse files
8265973: [lworld] C2 compilation fails due to infinite loop in PhaseI…
…terGVN::optimize
  • Loading branch information
TobiHartmann committed May 6, 2021
1 parent 74dbd64 commit f43fafc7d81f3d34f6e971765dbadae41ae5c393
@@ -411,7 +411,7 @@ void Compile::remove_useless_node(Node* dead) {
}

// Disconnect all useless nodes by disconnecting those at the boundary.
void Compile::remove_useless_nodes(Unique_Node_List &useful) {
void Compile::disconnect_useless_nodes(Unique_Node_List &useful, Unique_Node_List* worklist) {
uint next = 0;
while (next < useful.size()) {
Node *n = useful.at(next++);
@@ -434,14 +434,21 @@ void Compile::remove_useless_nodes(Unique_Node_List &useful) {
}
}
if (n->outcnt() == 1 && n->has_special_unique_user()) {
record_for_igvn(n->unique_out());
worklist->push(n->unique_out());
}
}

remove_useless_nodes(_macro_nodes, useful); // remove useless macro and predicate opaq nodes
remove_useless_nodes(_macro_nodes, useful); // remove useless macro nodes
remove_useless_nodes(_predicate_opaqs, useful); // remove useless predicate opaque nodes
remove_useless_nodes(_skeleton_predicate_opaqs, useful);
remove_useless_nodes(_expensive_nodes, useful); // remove useless expensive nodes
remove_useless_nodes(_for_post_loop_igvn, useful); // remove useless node recorded for post loop opts IGVN pass
remove_useless_nodes(_inline_type_nodes, useful); // remove useless inline type nodes
#ifdef ASSERT
if (_modified_nodes != NULL) {
_modified_nodes->remove_useless_nodes(useful.member_set());
}
#endif

BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
bs->eliminate_useless_gc_barriers(useful, this);
@@ -943,7 +943,7 @@ class Compile : public Phase {

void identify_useful_nodes(Unique_Node_List &useful);
void update_dead_node_list(Unique_Node_List &useful);
void remove_useless_nodes (Unique_Node_List &useful);
void disconnect_useless_nodes(Unique_Node_List &useful, Unique_Node_List* worklist);

void remove_useless_node(Node* dead);

@@ -506,6 +506,18 @@ Node* InlineTypeBaseNode::Ideal(PhaseGVN* phase, bool can_reshape) {
if (phase->C->scalarize_in_safepoints() && can_reshape) {
PhaseIterGVN* igvn = phase->is_IterGVN();
make_scalar_in_safepoints(igvn);
if (outcnt() == 0) {
return NULL;
}
}
Node* oop = get_oop();
if (oop->isa_InlineTypePtr()) {
InlineTypePtrNode* vtptr = oop->as_InlineTypePtr();
set_oop(vtptr->get_oop());
for (uint i = Values; i < vtptr->req(); ++i) {
set_req(i, vtptr->in(i));
}
return this;
}
return NULL;
}
@@ -836,14 +848,6 @@ Node* InlineTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) {
set_oop(default_oop(*phase, inline_klass()));
assert(is_allocated(phase), "should now be allocated");
return this;
} else if (oop->isa_InlineTypePtr()) {
// Can happen with late inlining
InlineTypePtrNode* vtptr = oop->as_InlineTypePtr();
set_oop(vtptr->get_oop());
for (uint i = Oop+1; i < vtptr->req(); ++i) {
set_req(i, vtptr->in(i));
}
return this;
}

if (!is_allocated(phase)) {
@@ -872,7 +876,7 @@ Node* InlineTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* res = alloc->result_cast();
if (res != NULL && res->is_CheckCastPP()) {
// Replace allocation by oop and unlink AllocateNode
replace_allocation(igvn, res, get_oop());
replace_allocation(igvn, res, oop);
igvn->replace_input_of(alloc, AllocateNode::InlineTypeNode, igvn->C->top());
--i; --imax;
}
@@ -425,7 +425,7 @@ PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN* gvn, Unique_Node_List* worklist
worklist->remove_useless_nodes(_useful.member_set());

// Disconnect 'useless' nodes that are adjacent to useful nodes
C->remove_useless_nodes(_useful);
C->disconnect_useless_nodes(_useful, worklist);
}

//=============================================================================
@@ -1756,7 +1756,7 @@ uint PhaseCCP::_total_constants = 0;
#endif
//------------------------------PhaseCCP---------------------------------------
// Conditional Constant Propagation, ala Wegman & Zadeck
PhaseCCP::PhaseCCP( PhaseIterGVN *igvn ) : PhaseIterGVN(igvn) {
PhaseCCP::PhaseCCP(PhaseIterGVN* igvn) : PhaseIterGVN(igvn), _trstack(C->live_nodes() >> 1) {
NOT_PRODUCT( clear_constants(); )
assert( _worklist.size() == 0, "" );
// Clear out _nodes from IterGVN. Must be clear to transform call.
@@ -1810,6 +1810,11 @@ void PhaseCCP::analyze() {
} else {
n = worklist.pop();
}
if (n->is_SafePoint()) {
// Make sure safepoints are processed by PhaseCCP::transform even if they are
// not reachable from the bottom. Otherwise, infinite loops would be removed.
_trstack.push(n);
}
const Type *t = n->Value(this);
if (t != type(n)) {
assert(ccp_type_widens(t, type(n)), "ccp type must widen");
@@ -1929,13 +1934,11 @@ Node *PhaseCCP::transform( Node *n ) {
return new_node; // Been there, done that, return old answer
new_node = transform_once(n); // Check for constant
_nodes.map( n->_idx, new_node ); // Flag as having been cloned
_useful.push(new_node); // Keep track of nodes that are reachable from the bottom

// Allocate stack of size _nodes.Size()/2 to avoid frequent realloc
GrowableArray <Node *> trstack(C->live_nodes() >> 1);

trstack.push(new_node); // Process children of cloned node
while ( trstack.is_nonempty() ) {
Node *clone = trstack.pop();
_trstack.push(new_node); // Process children of cloned node
while (_trstack.is_nonempty()) {
Node* clone = _trstack.pop();
uint cnt = clone->req();
for( uint i = 0; i < cnt; i++ ) { // For all inputs do
Node *input = clone->in(i);
@@ -1944,12 +1947,30 @@ Node *PhaseCCP::transform( Node *n ) {
if( new_input == NULL ) {
new_input = transform_once(input); // Check for constant
_nodes.map( input->_idx, new_input );// Flag as having been cloned
trstack.push(new_input);
_useful.push(new_input);
_trstack.push(new_input);
}
assert( new_input == clone->in(i), "insanity check");
}
}
}

// The above transformation might lead to subgraphs becoming unreachable from the
// bottom while still being reachable from the top. As a result, nodes in that
// subgraph are not transformed and their bottom types are not updated, leading to
// an inconsistency between bottom_type() and type(). In rare cases, LoadNodes in
// such a subgraph, kept alive by InlineTypePtrNodes, might be re-enqueued for IGVN
// indefinitely by MemNode::Ideal_common because their address type is inconsistent.
// Therefore, we aggressively remove all useless nodes here even before
// PhaseIdealLoop::build_loop_late gets a chance to remove them anyway.
if (C->cached_top_node()) {
_useful.push(C->cached_top_node());
}
C->update_dead_node_list(_useful);
remove_useless_nodes(_useful.member_set());
_worklist.remove_useless_nodes(_useful.member_set());
C->disconnect_useless_nodes(_useful, &_worklist);

return new_node;
}

@@ -567,6 +567,9 @@ class PhaseIterGVN : public PhaseGVN {
// Phase for performing global Conditional Constant Propagation.
// Should be replaced with combined CCP & GVN someday.
class PhaseCCP : public PhaseIterGVN {
GrowableArray<Node*> _trstack; // Stack for transform operation
Unique_Node_List _useful; // Nodes reachable from the bottom

// Non-recursive. Use analysis to transform single Node.
virtual Node *transform_once( Node *n );

@@ -311,7 +311,7 @@ public void test11_verifier(boolean warmup) {
// Array load out of bounds (upper bound) at compile time
@Test
public int test12() {
int arraySize = Math.abs(rI) % 10;;
int arraySize = Math.abs(rI) % 10;
MyValue1[] va = new MyValue1[arraySize];

for (int i = 0; i < arraySize; i++) {
@@ -333,7 +333,7 @@ public void test12_verifier(boolean warmup) {
// Array load out of bounds (lower bound) at compile time
@Test
public int test13() {
int arraySize = Math.abs(rI) % 10;;
int arraySize = Math.abs(rI) % 10;
MyValue1[] va = new MyValue1[arraySize];

for (int i = 0; i < arraySize; i++) {
@@ -381,7 +381,7 @@ public void test14_verifier(boolean warmup) {
// Array store out of bounds (upper bound) at compile time
@Test
public int test15() {
int arraySize = Math.abs(rI) % 10;;
int arraySize = Math.abs(rI) % 10;
MyValue1[] va = new MyValue1[arraySize];

try {
@@ -402,7 +402,7 @@ public void test15_verifier(boolean warmup) {
// Array store out of bounds (lower bound) at compile time
@Test
public int test16() {
int arraySize = Math.abs(rI) % 10;;
int arraySize = Math.abs(rI) % 10;
MyValue1[] va = new MyValue1[arraySize];

try {
@@ -58,6 +58,14 @@
int c = 8;
}

class MyValue4Wrapper {
public MyValue4.ref val;

public MyValue4Wrapper(MyValue4 val) {
this.val = val;
}
}

primitive class MyValue5 {
int b = 2;
}
@@ -219,6 +227,30 @@ void test14(boolean b, MyValue4 val) {
}
}

void test15() {
MyValue4 val = new MyValue4();
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
MyValue4[] array = new MyValue4[1];
for (int k = 0; k < 10; ++k) {
array[0] = val;
val = array[0];
}
}
}
}

void test16() {
MyValue4 val = MyValue4.default;
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
val = (new MyValue4Wrapper(val)).val;
for (int k = 0; k < 10; ++k) {
}
}
}
}

public static void main(String[] args) {
TestGenerated t = new TestGenerated();
EmptyValue[] array1 = { new EmptyValue() };
@@ -243,6 +275,8 @@ public static void main(String[] args) {
t.test12();
t.test13(array5);
t.test14(false, MyValue4.default);
t.test15();
t.test16();
}
}
}

0 comments on commit f43fafc

Please sign in to comment.