Skip to content

Commit 275cb9f

Browse files
committed
8360510: C2: Template Assertion Predicates are not cloned to the inner counted loop with -XX:+StressDuplicateBackedge
Reviewed-by: epeter, roland
1 parent 46ee8d5 commit 275cb9f

File tree

4 files changed

+149
-4
lines changed

4 files changed

+149
-4
lines changed

src/hotspot/share/opto/loopopts.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4180,6 +4180,33 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
41804180
return true;
41814181
}
41824182

4183+
#ifdef ASSERT
4184+
4185+
// Moves Template Assertion Predicates to a target loop by cloning and killing the old ones. The target loop is the
4186+
// original, not-cloned loop. This is currently only used with StressLoopBackedge which is a develop flag only and
4187+
// false with product builds. We can therefore guard it with an ifdef. More details can be found at the use-site.
4188+
class MoveAssertionPredicatesVisitor : public PredicateVisitor {
4189+
ClonePredicateToTargetLoop _clone_predicate_to_loop;
4190+
PhaseIdealLoop* const _phase;
4191+
4192+
public:
4193+
MoveAssertionPredicatesVisitor(LoopNode* target_loop_head,
4194+
const NodeInSingleLoopBody &node_in_loop_body,
4195+
PhaseIdealLoop* phase)
4196+
: _clone_predicate_to_loop(target_loop_head, node_in_loop_body, phase),
4197+
_phase(phase) {
4198+
}
4199+
NONCOPYABLE(MoveAssertionPredicatesVisitor);
4200+
4201+
using PredicateVisitor::visit;
4202+
4203+
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override {
4204+
_clone_predicate_to_loop.clone_template_assertion_predicate(template_assertion_predicate);
4205+
template_assertion_predicate.kill(_phase->igvn());
4206+
}
4207+
};
4208+
#endif // ASSERT
4209+
41834210
// Transform:
41844211
//
41854212
// loop<-----------------+
@@ -4248,6 +4275,7 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
42484275
IfNode* exit_test = nullptr;
42494276
uint inner;
42504277
float f;
4278+
#ifdef ASSERT
42514279
if (StressDuplicateBackedge) {
42524280
if (head->is_strip_mined()) {
42534281
return false;
@@ -4266,7 +4294,9 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
42664294
}
42674295

42684296
inner = 1;
4269-
} else {
4297+
} else
4298+
#endif //ASSERT
4299+
{
42704300
// Is the shape of the loop that of a counted loop...
42714301
Node* back_control = loop_exit_control(head, loop);
42724302
if (back_control == nullptr) {
@@ -4457,6 +4487,19 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
44574487
}
44584488
}
44594489

4490+
#ifdef ASSERT
4491+
if (StressDuplicateBackedge && head->is_CountedLoop()) {
4492+
// The Template Assertion Predicates from the old counted loop are now at the new outer loop - clone them to
4493+
// the inner counted loop and kill the old ones. We only need to do this with debug builds because
4494+
// StressDuplicateBackedge is a devlop flag and false by default. Without StressDuplicateBackedge 'head' will be a
4495+
// non-counted loop, and thus we have no Template Assertion Predicates above the old loop to move down.
4496+
PredicateIterator predicate_iterator(outer_head->in(LoopNode::EntryControl));
4497+
NodeInSingleLoopBody node_in_body(this, loop);
4498+
MoveAssertionPredicatesVisitor move_assertion_predicates_visitor(head, node_in_body, this);
4499+
predicate_iterator.for_each(move_assertion_predicates_visitor);
4500+
}
4501+
#endif // ASSERT
4502+
44604503
C->set_major_progress();
44614504

44624505
C->print_method(PHASE_AFTER_DUPLICATE_LOOP_BACKEDGE, 4, outer_head);

test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@
3737
* -XX:CompileCommand=memlimit,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test,100M~crash
3838
* -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0
3939
* -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations
40-
* -XX:StressSeed=1870557292
40+
* -XX:StressSeed=1870557292 -XX:-StressDuplicateBackedge
4141
* compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
4242
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
4343
* -XX:CompileCommand=compileonly,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test
4444
* -XX:CompileCommand=memlimit,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test,100M~crash
4545
* -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0
46-
* -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations
46+
* -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations -XX:-StressDuplicateBackedge
4747
* compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
48-
* @run main compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
48+
* @run main/othervm -XX:-StressDuplicateBackedge compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
4949
*/
5050

5151
public class TestVerifyLoopOptimizationsHitsMemLimit {

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,19 @@
144144
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
145145
*/
146146

147+
/*
148+
* @test id=DataUpdateZGC
149+
* @key randomness
150+
* @bug 8288981 8350577 0360510
151+
* @requires vm.compiler2.enabled
152+
* @requires vm.gc.Z
153+
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure -XX:+UseZGC
154+
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
155+
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
156+
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
157+
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
158+
*/
159+
147160
/*
148161
* @test id=CloneDown
149162
* @bug 8288981 8350577
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8360510
27+
* @summary Test that StressDuplicateBackedge correctly clones Template Assertion Predicates to the inner counted loop.
28+
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+StressDuplicateBackedge
29+
* compiler.predicates.assertion.TestStressDuplicateBackedgeWithAssertionPredicate
30+
* @run main compiler.predicates.assertion.TestStressDuplicateBackedgeWithAssertionPredicate
31+
*/
32+
33+
package compiler.predicates.assertion;
34+
35+
public class TestStressDuplicateBackedgeWithAssertionPredicate {
36+
static int[] iArr = new int[100];
37+
static int iFld;
38+
static long lFld;
39+
40+
public static void main(String[] strArr) {
41+
for (int i = 0; i < 10000; i++) {
42+
test();
43+
}
44+
}
45+
46+
static void test() {
47+
// 5) Once the inner empty loop is removed (step 4), we can apply the "duplicate backedge
48+
// optimization" to the initial outer counted loop which is now the only loop left. Note
49+
// that we can do that even though it is a counted loop: This is stressed with
50+
// StressDuplicateLoopBackedge.
51+
// 6) We do the following "duplicate loop backedge" transformation with current mainline:
52+
//
53+
// Template Assertion
54+
// Template Assertion Predicates
55+
// Predicates |
56+
// | ====> ...
57+
// ... |
58+
// | Loop # Outer Non-Counted Loop (newly added)
59+
// CountedLoop |
60+
// CountedLoop # Inner Counted Loop (old)
61+
//
62+
// 7) After the transformation, the Template Assertion Predicates are still at the Outer Non-Counted Loop.
63+
// As a result, we find them to be useless in the next predicate elimination call with
64+
// EliminateUselessPredicates because they cannot be found from the Inner Counted Loop (we stop at
65+
// Loop which is not a predicate). However, we have verification code in place that checks that we
66+
// can only find useless Template Assertion Predicates if the associated counted loop node is dead.
67+
// This is not the case and we crash with an assertion failure.
68+
//
69+
// The fix is to move the Template Assertion Predicates to the Inner Counted Loop again.
70+
for (int i = 0; i < 100; i++) {
71+
// 3) Loop Predication will hoist this range checkout out of the loop with Template
72+
// Assertion Predicates.
73+
iArr[i] = 34;
74+
75+
// 1) We need an inner empty loop to make sure the outer counter loop is not strip mined.
76+
// Otherwise, we cannot apply the duplicate backedge optimization to the outer loop.
77+
// 4) Found to be empty and removed.
78+
for (int j = 0; j < 10; j++) {}
79+
80+
// 2) We need some region inside the outer loop, otherwise, we cannot apply the duplicate
81+
// backedge optimization.
82+
if (i == 3) {
83+
lFld = 34;
84+
} else {
85+
iFld = 2;
86+
}
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)