From 004aaea76db091569aa88eeb6b08db3408f288cd Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 22 Oct 2024 11:19:21 +0000 Subject: [PATCH] 8342330: C2: "node pinned on loop exit test?" assert failure Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/loopopts.cpp | 9 ++- .../TestSunkRangeFromPreLoopRCE.java | 81 +++++++++++++++++++ 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 654262d21cb..5dc3bc4f6ff 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1945,10 +1945,11 @@ bool PhaseIdealLoop::ctrl_of_use_out_of_loop(const Node* n, Node* n_ctrl, IdealL // Sinking a node from a pre loop to its main loop pins the node between the pre and main loops. If that node is input // to a check that's eliminated by range check elimination, it becomes input to an expression that feeds into the exit // test of the pre loop above the point in the graph where it's pinned. - if (n_loop->_head->is_CountedLoop() && n_loop->_head->as_CountedLoop()->is_pre_loop() && - u_loop->_head->is_CountedLoop() && u_loop->_head->as_CountedLoop()->is_main_loop() && - n_loop->_next == get_loop(u_loop->_head->as_CountedLoop()->skip_strip_mined())) { - return false; + if (n_loop->_head->is_CountedLoop() && n_loop->_head->as_CountedLoop()->is_pre_loop()) { + CountedLoopNode* pre_loop = n_loop->_head->as_CountedLoop(); + if (is_dominator(pre_loop->loopexit(), ctrl)) { + return false; + } } return true; } diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java b/test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java new file mode 100644 index 00000000000..4e788df035e --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestSunkRangeFromPreLoopRCE.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. 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 8342330 + * @summary C2: "node pinned on loop exit test?" assert failure + * @requires vm.flavor == "server" + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:-TieredCompilation + * -XX:-UseLoopPredicate -XX:LoopMaxUnroll=0 TestSunkRangeFromPreLoopRCE + * + */ + + +import java.util.Arrays; + +public class TestSunkRangeFromPreLoopRCE { + private static int[] array = new int[1000]; + private static A objectField = new A(42); + + public static void main(String[] args) { + boolean[] allTrue = new boolean[1000]; + Arrays.fill(allTrue, true); + boolean[] allFalse = new boolean[1000]; + for (int i = 0; i < 20_000; i++) { + test1(array.length/4, allTrue, 1, 0); + test1(array.length/4, allFalse, 1, 0); + } + } + + private static int test1(int stop, boolean[] flags, int otherScale, int x) { + int scale; + for (scale = 0; scale < 4; scale++) { + for (int i = 0; i < 10; i++) { + + } + } + if (array == null) { + } + int v = 0; + for (int i = 0; i < stop; i++) { + v += array[i]; + v += array[scale * i]; + if (i * scale + (objectField.intField + 1) == x) { + } + v += (scale - 4) * (x-objectField.intField); + if (flags[i]) { + return (x-objectField.intField); + } + } + return v; + } + + private static class A { + A(int field) { + intField = field; + } + public int intField; + } +}