diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 50b1ae0de8d3a..205241b62e9ac 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -4186,6 +4186,32 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { return true; } +#ifdef ASSERT + +// Clone Template Assertion Predicates to a target loop. The target loop is the original, not-cloned loop. +// This is currently only used for StressDuplicateLoopBackedge. +class CloneAssertionPredicatesVisitor : public PredicateVisitor { + ClonePredicateToTargetLoop _clone_predicate_to_loop; + PhaseIdealLoop* const _phase; + +public: + CloneAssertionPredicatesVisitor(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(CloneAssertionPredicatesVisitor); + + 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<-----------------+ @@ -4254,6 +4280,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; @@ -4272,7 +4299,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) { @@ -4463,6 +4492,17 @@ 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. + PredicateIterator predicate_iterator(outer_head->in(LoopNode::EntryControl)); + NodeInSingleLoopBody node_in_body(this, loop); + CloneAssertionPredicatesVisitor clone_assertion_predicates_visitor(head, node_in_body, this); + predicate_iterator.for_each(clone_assertion_predicates_visitor); + } +#endif // ASSERT + C->set_major_progress(); C->print_method(PHASE_AFTER_DUPLICATE_LOOP_BACKEDGE, 4, outer_head); diff --git a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java index a2834c26dcc4b..fbe69ad0e04a5 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestVerifyLoopOptimizationsHitsMemLimit.java @@ -37,15 +37,15 @@ * -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 { diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java index 8f30dce15bc45..5694e882f89fd 100644 --- a/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java @@ -144,6 +144,19 @@ * compiler.predicates.assertion.TestAssertionPredicates DataUpdate */ +/* + * @test id=DataUpdateZGC + * @key randomness + * @bug 8288981 8350577 + * @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 diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java new file mode 100644 index 0000000000000..0889b2333478f --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java @@ -0,0 +1,86 @@ +/* + * 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 + */ + +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 loop is removed, we can apply the duplicate backedge optimization + // even though it is a counted loop: This is stressed with StressDuplicateLoopBackedge. + // 6) We do the following transformation with current mainline: + // + // + // Template Assertion + // Template Assertion Predicates + // Predicates | + // | ====> ... + // ... | + // | Loop + // CountedLoop | + // Counted Loop + // + // The Template Assertion Predicates are still at the outer 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. 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. + 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 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; + } + } + } +}