Skip to content

Commit ad07426

Browse files
committed
8356084: C2: Data is wrongly rewired to Initialized Assertion Predicates instead of Template Assertion Predicates
Reviewed-by: epeter, kvn
1 parent b47b206 commit ad07426

File tree

3 files changed

+93
-15
lines changed

3 files changed

+93
-15
lines changed

src/hotspot/share/opto/predicates.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -984,15 +984,16 @@ void CreateAssertionPredicatesVisitor::visit(const TemplateAssertionPredicate& t
984984

985985
// Create an Initialized Assertion Predicate from the provided Template Assertion Predicate.
986986
InitializedAssertionPredicate CreateAssertionPredicatesVisitor::initialize_from_template(
987-
const TemplateAssertionPredicate& template_assertion_predicate, Node* new_control) const {
987+
const TemplateAssertionPredicate& template_assertion_predicate, IfTrueNode* cloned_template_predicate_tail) const {
988988
DEBUG_ONLY(template_assertion_predicate.verify();)
989989
IfNode* template_head = template_assertion_predicate.head();
990990
InitializedAssertionPredicateCreator initialized_assertion_predicate_creator(_phase);
991991
InitializedAssertionPredicate initialized_assertion_predicate =
992-
initialized_assertion_predicate_creator.create_from_template(template_head, new_control, _init, _stride);
992+
initialized_assertion_predicate_creator.create_from_template(template_head, cloned_template_predicate_tail, _init,
993+
_stride);
993994

994995
DEBUG_ONLY(initialized_assertion_predicate.verify();)
995-
template_assertion_predicate.rewire_loop_data_dependencies(initialized_assertion_predicate.tail(),
996+
template_assertion_predicate.rewire_loop_data_dependencies(cloned_template_predicate_tail,
996997
_node_in_loop_body, _phase);
997998
rewire_to_old_predicate_chain_head(initialized_assertion_predicate.tail());
998999
return initialized_assertion_predicate;

src/hotspot/share/opto/predicates.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ class CreateAssertionPredicatesVisitor : public PredicateVisitor {
10981098
clone_template_and_replace_init_input(const TemplateAssertionPredicate& template_assertion_predicate) const;
10991099

11001100
InitializedAssertionPredicate initialize_from_template(const TemplateAssertionPredicate& template_assertion_predicate,
1101-
Node* new_control) const;
1101+
IfTrueNode* cloned_template_predicate_tail) const;
11021102
void rewire_to_old_predicate_chain_head(Node* initialized_assertion_predicate_success_proj) const;
11031103

11041104
public:

test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,18 @@
179179
* compiler.predicates.assertion.TestAssertionPredicates Stress
180180
*/
181181

182+
/*
183+
* @test id=StressXcompMaxUnroll0
184+
* @key randomness
185+
* @bug 8288981 8356084
186+
* @requires vm.compiler2.enabled
187+
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
188+
* -XX:LoopMaxUnroll=0 -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
189+
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
190+
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
191+
* compiler.predicates.assertion.TestAssertionPredicates StressXcompMaxUnroll0
192+
*/
193+
182194
/*
183195
* @test id=NoLoopPredicationXcomp
184196
* @bug 8288981 8350577
@@ -226,6 +238,7 @@ public class TestAssertionPredicates {
226238
static boolean flagFalse, flagFalse2;
227239
static int iFld = 34;
228240
static int iFld2, iFld3;
241+
static int two = 2;
229242
static long lFld, lFldOne = 1;
230243
static float fFld;
231244
static short sFld;
@@ -238,7 +251,7 @@ static class Foo {
238251
}
239252

240253
static Foo foo = new Foo();
241-
254+
static int fooArrSize = 10000001;
242255

243256
public static void main(String[] args) {
244257
switch (args[0]) {
@@ -315,14 +328,15 @@ public static void main(String[] args) {
315328
test8308504No2();
316329
}
317330
}
318-
case "DataUpdate" -> {
331+
case "DataUpdate", "StressXcompMaxUnroll0" -> {
319332
for (int i = 0; i < 10; i++) {
320333
// The following tests create large arrays. Limit the number of invocations to reduce the time spent.
321334
flag = !flag;
322335
testDataUpdateUnswitchingPeelingUnroll();
323336
testDataUpdateUnswitchUnroll();
324337
testDataUpdateUnroll();
325338
testDataUpdatePeelingUnroll();
339+
testPeelingThreeTimesDataUpdate();
326340
}
327341
}
328342
case "CloneDown" -> {
@@ -1064,18 +1078,18 @@ static void testDataUpdateUnswitchingPeelingUnroll() {
10641078
for (int i = 0; i < limit; i++) {
10651079
fooArr[10000000 * i] = foo;
10661080
}
1067-
// 9) This loop is not optimized in any way because we have a call inside the loop. This loop is only required
1081+
// 10) This loop is not optimized in any way because we have a call inside the loop. This loop is only required
10681082
// to trigger a crash.
1069-
// 10) During GCM with StressGCM, we could schedule the LoadN from the main loop before checking if we should
1083+
// 11) During GCM with StressGCM, we could schedule the LoadN from the main loop before checking if we should
10701084
// enter the main loop. When 'flag' is true, we only have an array of size 20000001. We then perform
10711085
// the LoadN[3*10000000] and crash when the memory is unmapped.
10721086
for (float f = 0; f < 1.6f; f += 0.5f) {
10731087
// 2) Loop is unswitched
1074-
// 3) Both loop are peeled (we focus on one of those since both are almost identical except for the
1088+
// 4) Both loop are peeled (we focus on one of those since both are almost identical except for the
10751089
// unswitched condition):
10761090
// Peeled iteration [i = 0]
10771091
// Loop [i = 1..4, stride = 1]
1078-
// 4) Loop unroll policy now returns true.
1092+
// 5) Loop unroll policy now returns true.
10791093
// Peeled iteration [i = 0]
10801094
// - Loop is pre-main-posted
10811095
// Loop-pre[i = 1..4, stride = 1]
@@ -1085,16 +1099,16 @@ static void testDataUpdateUnswitchingPeelingUnroll() {
10851099
// Loop-pre[i = 1..4, stride = 1]
10861100
// Loop-main[i = 2..4, stride = 2]
10871101
// Loop-post[i = 2..4, stride = 1]
1088-
// 5) During IGVN, we find that the backedge is never taken for main loop (we would over-iteratre) and it
1102+
// 6) During IGVN, we find that the backedge is never taken for main loop (we would over-iteratre) and it
10891103
// collapses to a single iteration.
1090-
// 6) After loop opts, the pre-loop is removed.
1104+
// 7) After loop opts, the pre-loop is removed.
10911105
for (int i = 0; i < limit; i++) {
10921106
// 1) Hoisted with a Hoisted Range Check Predicate
1093-
// 7) The 'i = 1' value is propagated to the single main loop iteration and we have the following
1107+
// 8) The 'i = 1' value is propagated to the single main loop iteration and we have the following
10941108
// fixed-index accesses:
10951109
// LoadN[2*10000000];
10961110
// LoadN[3*10000000];
1097-
// 8) Without explicitly pinning the LoadN from the main loop at the main loop entry (i.e. below the
1111+
// 9) Without explicitly pinning the LoadN from the main loop at the main loop entry (i.e. below the
10981112
// zero trip guard), they are still pinned below the Hoisted Range Check Predicate before the loop.
10991113
fooArr[i * 10000000].iFld += 34;
11001114
if (flagFalse) {
@@ -1327,11 +1341,74 @@ static void testDataUpdatePeelingUnroll() {
13271341
}
13281342
}
13291343

1344+
1345+
// -Xcomp -XX:LoopMaxUnroll=0 -XX:+StressGCM -XX:CompileCommand=compileonly,Test*::*
1346+
private static void testPeelingThreeTimesDataUpdate() {
1347+
Foo[] fooArr = new Foo[fooArrSize];
1348+
for (int i = 0; i < two; i++) {
1349+
fooArr[10000000 * i] = foo;
1350+
}
1351+
int x = 0;
1352+
1353+
// 2) The Hoisted Range Check Predicate is accompanied by two Template Assertion Predicates. The LoadN node,
1354+
// previously pinned at the hoisted range check, is now pinned at the Template Assertion Predicate. Note
1355+
// that the LoadN is still inside the loop body.
1356+
// 3) The loop is now peeled 3 times which also peels 3 loads from 'fooArr' out of the loop:
1357+
// // Peeled section from 1st Loop Peeling
1358+
// ...
1359+
// LoadN[0]
1360+
// ...
1361+
// <loop entry guard>
1362+
// // Peeled section from 2nd Loop Peeling
1363+
// ...
1364+
// LoadN[10000000]
1365+
// Initialized Assertion Predicate (***)
1366+
// <loop entry guard>
1367+
// // Peeled section from 3rd Loop Peeling
1368+
// ...
1369+
// LoadN[20000000]
1370+
// ...
1371+
// Initialized Assertion Predicate
1372+
// <loop entry guard>
1373+
// Template Assertion Predicate
1374+
// Initialized Assertion Predicate
1375+
// Loop:
1376+
// LoadN[i*10000000]
1377+
//
1378+
// To avoid that the peeled LoadN nodes float above the corresponding loop entry guards, we need to pin them
1379+
// below. That is done by updating the dependency of the peeled LoadN to the new Template Assertion Predicate.
1380+
// This is currently broken: We wrongly set the dependency to the Initialized Assertion Predicate instead of the
1381+
// Template Assertion Predicate. We can then no longer find the dependency and miss to update it in the next
1382+
// Loop Peeling application. As a result, all the LoadN pile up at the originally added Initialized Assertion
1383+
// Predicate of the first Loop Peeling application at (***).
1384+
//
1385+
// With GCM, we could schedule LoadN[20000000] at (***), before the loop entry corresponding loop entry guard
1386+
// for this load. We then crash during runtime because we are accessing an out-of-range index. The fix is to
1387+
// properly update the data dependencies to the Template Assertion Predicates and not the Initialized Assertion
1388+
// Predicates.
1389+
for (int i = 0; i < two; i++) {
1390+
// 1) Hoisted with a Hoisted Range Check Predicate
1391+
x += fooArr[i * 10000000].iFld;
1392+
1393+
if (iFld2 == 4) {
1394+
return;
1395+
}
1396+
1397+
if (i > 0 && iFld2 == 3) {
1398+
iFld2 = 42;
1399+
return;
1400+
}
1401+
1402+
if (i > 1 && iFld2 == 2) {
1403+
return;
1404+
}
1405+
}
1406+
}
1407+
13301408
/*
13311409
* Tests collected in JBS and duplicated issues
13321410
*/
13331411

1334-
13351412
// -Xbatch -XX:CompileCommand=compileonly,Test*::*
13361413
static void test8305428() {
13371414
int j = 1;

0 commit comments

Comments
 (0)