diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 2286b304534..453622b4473 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -2894,7 +2894,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { limit_ctrl = ensure_node_and_inputs_are_above_pre_end(pre_end, limit); // offset and limit could have control below new_limit_ctrl if they are not loop invariant in the pre loop. - new_limit_ctrl = dominated_node(new_limit_ctrl, offset_ctrl, limit_ctrl); + Node* next_limit_ctrl = dominated_node(new_limit_ctrl, offset_ctrl, limit_ctrl); #ifdef ASSERT if (TraceRangeLimitCheck) { @@ -2915,16 +2915,16 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { jlong lscale_con = scale_con; Node* int_offset = offset; offset = new ConvI2LNode(offset); - register_new_node(offset, new_limit_ctrl); + register_new_node(offset, next_limit_ctrl); Node* int_limit = limit; limit = new ConvI2LNode(limit); - register_new_node(limit, new_limit_ctrl); + register_new_node(limit, next_limit_ctrl); // Adjust pre and main loop limits to guard the correct iteration set if (cmp->Opcode() == Op_CmpU) { // Unsigned compare is really 2 tests if (b_test._test == BoolTest::lt) { // Range checks always use lt // The underflow and overflow limits: 0 <= scale*I+offset < limit - add_constraint(stride_con, lscale_con, offset, zero, limit, new_limit_ctrl, &pre_limit, &main_limit); + add_constraint(stride_con, lscale_con, offset, zero, limit, next_limit_ctrl, &pre_limit, &main_limit); Node* init = cl->init_trip(); Node* opaque_init = new OpaqueLoopInitNode(C, init); register_new_node(opaque_init, loop_entry); @@ -2977,22 +2977,22 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // Convert (I*scale+offset) >= Limit to (I*(-scale)+(-offset)) <= -Limit lscale_con = -lscale_con; offset = new SubLNode(zero, offset); - register_new_node(offset, new_limit_ctrl); + register_new_node(offset, next_limit_ctrl); limit = new SubLNode(zero, limit); - register_new_node(limit, new_limit_ctrl); + register_new_node(limit, next_limit_ctrl); // Fall into LE case case BoolTest::le: if (b_test._test != BoolTest::gt) { // Convert X <= Y to X < Y+1 limit = new AddLNode(limit, one); - register_new_node(limit, new_limit_ctrl); + register_new_node(limit, next_limit_ctrl); } // Fall into LT case case BoolTest::lt: // The underflow and overflow limits: MIN_INT <= scale*I+offset < limit // Note: (MIN_INT+1 == -MAX_INT) is used instead of MIN_INT here // to avoid problem with scale == -1: MIN_INT/(-1) == MIN_INT. - add_constraint(stride_con, lscale_con, offset, mini, limit, new_limit_ctrl, &pre_limit, &main_limit); + add_constraint(stride_con, lscale_con, offset, mini, limit, next_limit_ctrl, &pre_limit, &main_limit); break; default: if (PrintOpto) { @@ -3001,6 +3001,9 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { continue; // Unhandled case } } + // Only update variable tracking control for new nodes if it's indeed a range check that can be eliminated (and + // limits are updated) + new_limit_ctrl = next_limit_ctrl; // Kill the eliminated test C->set_major_progress(); diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestLimitControlWhenNoRCEliminated.java b/test/hotspot/jtreg/compiler/rangechecks/TestLimitControlWhenNoRCEliminated.java new file mode 100644 index 00000000000..1d8d947c982 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestLimitControlWhenNoRCEliminated.java @@ -0,0 +1,61 @@ +/* + * 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 8341407 + * @summary C2: assert(main_limit == cl->limit() || get_ctrl(main_limit) == new_limit_ctrl) failed: wrong control for added limit + * + * @run main/othervm -XX:CompileCommand=compileonly,TestLimitControlWhenNoRCEliminated::* -Xcomp TestLimitControlWhenNoRCEliminated + * + */ + +public class TestLimitControlWhenNoRCEliminated { + static long[] lArr; + static int iFld; + + public static void main(String[] strArr) { + try { + test(); + } catch (NullPointerException npe) {} + } + + static void test() { + int x = iFld; + int i = 1; + do { + lArr[i - 1] = 9; + x += 1; + iFld += x; + if (x != 0) { + A.foo(); + } + } while (++i < 23); + } +} + +class A { + static void foo() { + } +} +