mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 14:11:36 +00:00
8260420: C2 compilation fails with assert(found_sfpt) failed: no node in loop that's not input to safepoint
Reviewed-by: kvn, roland, chagedorn
This commit is contained in:
parent
474dba2d8b
commit
fe407cf1b6
@ -1430,6 +1430,7 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
|
||||
// control, then the cloning of n is a pointless exercise, because
|
||||
// GVN will ensure that we end up where we started.
|
||||
if (!n->is_Load() || late_load_ctrl != n_ctrl) {
|
||||
Node* outer_loop_clone = NULL;
|
||||
for (DUIterator_Last jmin, j = n->last_outs(jmin); j >= jmin; ) {
|
||||
Node *u = n->last_out(j); // Clone private computation per use
|
||||
_igvn.rehash_node_delayed(u);
|
||||
@ -1477,16 +1478,25 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
|
||||
|
||||
IdealLoopTree* x_loop = get_loop(x_ctrl);
|
||||
Node* x_head = x_loop->_head;
|
||||
if (x_head->is_Loop() && (x_head->is_OuterStripMinedLoop() || x_head->as_Loop()->is_strip_mined()) && is_dominator(n_ctrl, x_head)) {
|
||||
// Anti dependence analysis is sometimes too
|
||||
// conservative: a store in the outer strip mined loop
|
||||
// can prevent a load from floating out of the outer
|
||||
// strip mined loop but the load may not be referenced
|
||||
// from the safepoint: loop strip mining verification
|
||||
// code reports a problem in that case. Make sure the
|
||||
// load is not moved in the outer strip mined loop in
|
||||
// that case.
|
||||
x_ctrl = x_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl);
|
||||
if (x_head->is_Loop() && (x_head->is_OuterStripMinedLoop() || x_head->as_Loop()->is_strip_mined())) {
|
||||
if (is_dominator(n_ctrl, x_head)) {
|
||||
// Anti dependence analysis is sometimes too
|
||||
// conservative: a store in the outer strip mined loop
|
||||
// can prevent a load from floating out of the outer
|
||||
// strip mined loop but the load may not be referenced
|
||||
// from the safepoint: loop strip mining verification
|
||||
// code reports a problem in that case. Make sure the
|
||||
// load is not moved in the outer strip mined loop in
|
||||
// that case.
|
||||
x_ctrl = x_head->as_Loop()->skip_strip_mined()->in(LoopNode::EntryControl);
|
||||
} else if (x_head->is_OuterStripMinedLoop()) {
|
||||
// Do not add duplicate LoadNodes to the outer strip mined loop
|
||||
if (outer_loop_clone != NULL) {
|
||||
_igvn.replace_node(x, outer_loop_clone);
|
||||
continue;
|
||||
}
|
||||
outer_loop_clone = x;
|
||||
}
|
||||
}
|
||||
assert(dom_depth(n_ctrl) <= dom_depth(x_ctrl), "n is later than its clone");
|
||||
|
||||
@ -1503,8 +1513,7 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
|
||||
// to fold a StoreP and an AddP together (as part of an
|
||||
// address expression) and the AddP and StoreP have
|
||||
// different controls.
|
||||
BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
|
||||
if (!x->is_Load() && !x->is_DecodeNarrowPtr() && !x->is_AddP() && !bs->is_gc_barrier_node(x)) {
|
||||
if (!x->is_Load() && !x->is_DecodeNarrowPtr()) {
|
||||
_igvn._worklist.yank(x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. 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
|
||||
@ -23,7 +23,8 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8249607
|
||||
* @bug 8249607 8260420
|
||||
* @library /test/lib
|
||||
* @summary A LoadNode is pinned in split_if_with_blocks_post() on a loop exit node x that is part of a strip mined loop. It has a late control y outside
|
||||
the outer strip mined loop. After pre-main-post, the dominator chain of y does not include x anymore resulting in an assertion failure.
|
||||
* @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.loopopts.TestSplitIfPinnedLoadInStripMinedLoop::*
|
||||
@ -31,6 +32,8 @@
|
||||
*/
|
||||
package compiler.loopopts;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
public class TestSplitIfPinnedLoadInStripMinedLoop {
|
||||
|
||||
public boolean bFld = false;
|
||||
@ -39,7 +42,7 @@ public class TestSplitIfPinnedLoadInStripMinedLoop {
|
||||
public static float fFld= 6.0f;
|
||||
public static int iArrFld[] = new int[400];
|
||||
|
||||
public void test() {
|
||||
public void test1() {
|
||||
int x = 7;
|
||||
int y = 8;
|
||||
int a = 9;
|
||||
@ -97,10 +100,72 @@ public class TestSplitIfPinnedLoadInStripMinedLoop {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class MyClass {
|
||||
int x = 42;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
// The obj1.x load has two uses: The 'res' store and the return. After cloning, both loads end up in the
|
||||
// OuterStripMinedLoop which triggers an assert in LoopNode::verify_strip_mined:
|
||||
// assert(found_sfpt) failed: no node in loop that's not input to safepoint
|
||||
int test2(MyClass obj1, MyClass obj2) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
obj2.x = 42; // Prevents obj1.x load from floating up because obj2 could alias obj1
|
||||
res = obj1.x;
|
||||
}
|
||||
for (int j = 0; j < 10_000; ++j) {
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Same as test2 but with reference to outer loop induction variable 'i' and different order of instructions.
|
||||
// Triggers an assert in PhaseIdealLoop::build_loop_late_post_work if loop strip mining verification is disabled:
|
||||
// assert(false) failed: Bad graph detected in build_loop_late
|
||||
int test3(MyClass obj1, MyClass obj2) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
res = obj1.x + i;
|
||||
obj2.x = 42;
|
||||
}
|
||||
for (int j = 0; j < 10_000; ++j) {
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Same as test2 but with reference to inner loop induction variable 'j' and different order of instructions.
|
||||
// Triggers an assert in PhaseCFG::insert_anti_dependences if loop strip mining verification is disabled:
|
||||
// assert(!LCA_orig->dominates(pred_block) || early->dominates(pred_block)) failed: early is high enough
|
||||
int test4(MyClass obj1, MyClass obj2) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
res = obj1.x + j;
|
||||
obj2.x = 42;
|
||||
}
|
||||
for (int j = 0; j < 10_000; ++j) {
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void main(String[] strArr) {
|
||||
TestSplitIfPinnedLoadInStripMinedLoop t = new TestSplitIfPinnedLoadInStripMinedLoop();
|
||||
MyClass obj = new MyClass();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
t.test();
|
||||
t.test1();
|
||||
int res = t.test2(obj, obj);
|
||||
Asserts.assertEquals(res, t.res);
|
||||
Asserts.assertEquals(res, 42);
|
||||
res = t.test3(obj, obj);
|
||||
Asserts.assertEquals(res, t.res);
|
||||
Asserts.assertEquals(res, 51);
|
||||
res = t.test4(obj, obj);
|
||||
Asserts.assertEquals(res, t.res);
|
||||
Asserts.assertEquals(res, 51);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user