mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8360510: C2: Template Assertion Predicates are not cloned to the inner counted loop with -XX:+StressDuplicateBackedge
Reviewed-by: epeter, roland
This commit is contained in:
parent
46ee8d550e
commit
275cb9f287
@ -4180,6 +4180,33 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
// Moves Template Assertion Predicates to a target loop by cloning and killing the old ones. The target loop is the
|
||||
// original, not-cloned loop. This is currently only used with StressLoopBackedge which is a develop flag only and
|
||||
// false with product builds. We can therefore guard it with an ifdef. More details can be found at the use-site.
|
||||
class MoveAssertionPredicatesVisitor : public PredicateVisitor {
|
||||
ClonePredicateToTargetLoop _clone_predicate_to_loop;
|
||||
PhaseIdealLoop* const _phase;
|
||||
|
||||
public:
|
||||
MoveAssertionPredicatesVisitor(LoopNode* target_loop_head,
|
||||
const NodeInSingleLoopBody &node_in_loop_body,
|
||||
PhaseIdealLoop* phase)
|
||||
: _clone_predicate_to_loop(target_loop_head, node_in_loop_body, phase),
|
||||
_phase(phase) {
|
||||
}
|
||||
NONCOPYABLE(MoveAssertionPredicatesVisitor);
|
||||
|
||||
using PredicateVisitor::visit;
|
||||
|
||||
void visit(const TemplateAssertionPredicate& template_assertion_predicate) override {
|
||||
_clone_predicate_to_loop.clone_template_assertion_predicate(template_assertion_predicate);
|
||||
template_assertion_predicate.kill(_phase->igvn());
|
||||
}
|
||||
};
|
||||
#endif // ASSERT
|
||||
|
||||
// Transform:
|
||||
//
|
||||
// loop<-----------------+
|
||||
@ -4248,6 +4275,7 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
|
||||
IfNode* exit_test = nullptr;
|
||||
uint inner;
|
||||
float f;
|
||||
#ifdef ASSERT
|
||||
if (StressDuplicateBackedge) {
|
||||
if (head->is_strip_mined()) {
|
||||
return false;
|
||||
@ -4266,7 +4294,9 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
|
||||
}
|
||||
|
||||
inner = 1;
|
||||
} else {
|
||||
} else
|
||||
#endif //ASSERT
|
||||
{
|
||||
// Is the shape of the loop that of a counted loop...
|
||||
Node* back_control = loop_exit_control(head, loop);
|
||||
if (back_control == nullptr) {
|
||||
@ -4457,6 +4487,19 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
if (StressDuplicateBackedge && head->is_CountedLoop()) {
|
||||
// The Template Assertion Predicates from the old counted loop are now at the new outer loop - clone them to
|
||||
// the inner counted loop and kill the old ones. We only need to do this with debug builds because
|
||||
// StressDuplicateBackedge is a devlop flag and false by default. Without StressDuplicateBackedge 'head' will be a
|
||||
// non-counted loop, and thus we have no Template Assertion Predicates above the old loop to move down.
|
||||
PredicateIterator predicate_iterator(outer_head->in(LoopNode::EntryControl));
|
||||
NodeInSingleLoopBody node_in_body(this, loop);
|
||||
MoveAssertionPredicatesVisitor move_assertion_predicates_visitor(head, node_in_body, this);
|
||||
predicate_iterator.for_each(move_assertion_predicates_visitor);
|
||||
}
|
||||
#endif // ASSERT
|
||||
|
||||
C->set_major_progress();
|
||||
|
||||
C->print_method(PHASE_AFTER_DUPLICATE_LOOP_BACKEDGE, 4, outer_head);
|
||||
|
||||
@ -37,15 +37,15 @@ package compiler.loopopts;
|
||||
* -XX:CompileCommand=memlimit,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test,100M~crash
|
||||
* -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0
|
||||
* -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations
|
||||
* -XX:StressSeed=1870557292
|
||||
* -XX:StressSeed=1870557292 -XX:-StressDuplicateBackedge
|
||||
* compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:CompileCommand=compileonly,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test
|
||||
* -XX:CompileCommand=memlimit,compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit::test,100M~crash
|
||||
* -XX:-TieredCompilation -Xcomp -XX:PerMethodTrapLimit=0
|
||||
* -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations
|
||||
* -XX:+StressLoopPeeling -XX:+VerifyLoopOptimizations -XX:-StressDuplicateBackedge
|
||||
* compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
|
||||
* @run main compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
|
||||
* @run main/othervm -XX:-StressDuplicateBackedge compiler.loopopts.TestVerifyLoopOptimizationsHitsMemLimit
|
||||
*/
|
||||
|
||||
public class TestVerifyLoopOptimizationsHitsMemLimit {
|
||||
|
||||
@ -144,6 +144,19 @@
|
||||
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=DataUpdateZGC
|
||||
* @key randomness
|
||||
* @bug 8288981 8350577 0360510
|
||||
* @requires vm.compiler2.enabled
|
||||
* @requires vm.gc.Z
|
||||
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure -XX:+UseZGC
|
||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=CloneDown
|
||||
* @bug 8288981 8350577
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8360510
|
||||
* @summary Test that StressDuplicateBackedge correctly clones Template Assertion Predicates to the inner counted loop.
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+StressDuplicateBackedge
|
||||
* compiler.predicates.assertion.TestStressDuplicateBackedgeWithAssertionPredicate
|
||||
* @run main compiler.predicates.assertion.TestStressDuplicateBackedgeWithAssertionPredicate
|
||||
*/
|
||||
|
||||
package compiler.predicates.assertion;
|
||||
|
||||
public class TestStressDuplicateBackedgeWithAssertionPredicate {
|
||||
static int[] iArr = new int[100];
|
||||
static int iFld;
|
||||
static long lFld;
|
||||
|
||||
public static void main(String[] strArr) {
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
|
||||
static void test() {
|
||||
// 5) Once the inner empty loop is removed (step 4), we can apply the "duplicate backedge
|
||||
// optimization" to the initial outer counted loop which is now the only loop left. Note
|
||||
// that we can do that even though it is a counted loop: This is stressed with
|
||||
// StressDuplicateLoopBackedge.
|
||||
// 6) We do the following "duplicate loop backedge" transformation with current mainline:
|
||||
//
|
||||
// Template Assertion
|
||||
// Template Assertion Predicates
|
||||
// Predicates |
|
||||
// | ====> ...
|
||||
// ... |
|
||||
// | Loop # Outer Non-Counted Loop (newly added)
|
||||
// CountedLoop |
|
||||
// CountedLoop # Inner Counted Loop (old)
|
||||
//
|
||||
// 7) After the transformation, the Template Assertion Predicates are still at the Outer Non-Counted Loop.
|
||||
// As a result, we find them to be useless in the next predicate elimination call with
|
||||
// EliminateUselessPredicates because they cannot be found from the Inner Counted Loop (we stop at
|
||||
// Loop which is not a predicate). However, we have verification code in place that checks that we
|
||||
// can only find useless Template Assertion Predicates if the associated counted loop node is dead.
|
||||
// This is not the case and we crash with an assertion failure.
|
||||
//
|
||||
// The fix is to move the Template Assertion Predicates to the Inner Counted Loop again.
|
||||
for (int i = 0; i < 100; i++) {
|
||||
// 3) Loop Predication will hoist this range checkout out of the loop with Template
|
||||
// Assertion Predicates.
|
||||
iArr[i] = 34;
|
||||
|
||||
// 1) We need an inner empty loop to make sure the outer counter loop is not strip mined.
|
||||
// Otherwise, we cannot apply the duplicate backedge optimization to the outer loop.
|
||||
// 4) Found to be empty and removed.
|
||||
for (int j = 0; j < 10; j++) {}
|
||||
|
||||
// 2) We need some region inside the outer loop, otherwise, we cannot apply the duplicate
|
||||
// backedge optimization.
|
||||
if (i == 3) {
|
||||
lFld = 34;
|
||||
} else {
|
||||
iFld = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user