diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 8ae1c6e6e92..58105afd9d5 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1907,6 +1907,8 @@ void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adj "odd trip count for maximally unroll"); // Don't need to adjust limit for maximally unroll since trip count is even. } else if (loop_head->has_exact_trip_count() && init->is_Con()) { + // The trip count being exact means it has been set (using CountedLoopNode::set_exact_trip_count in compute_trip_count) + assert(old_trip_count < max_juint, "sanity"); // Loop's limit is constant. Loop's init could be constant when pre-loop // become peeled iteration. jlong init_con = init->get_int(); @@ -1920,8 +1922,10 @@ void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adj int stride_m = new_stride_con - (stride_con > 0 ? 1 : -1); jlong trip_count = (limit_con - init_con + stride_m)/new_stride_con; // New trip count should satisfy next conditions. - assert(trip_count > 0 && (julong)trip_count < (julong)max_juint/2, "sanity"); + assert(trip_count > 0 && (julong)trip_count <= (julong)max_juint/2, "sanity"); uint new_trip_count = (uint)trip_count; + // Since old_trip_count has been set to < max_juint (that is at most 2^32-2), + // new_trip_count is lower than or equal to 2^31-1 and the multiplication cannot overflow. adjust_min_trip = (old_trip_count != new_trip_count*2); } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 84d8fc71f6b..0f87ed6763d 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -304,11 +304,14 @@ public: void set_post_loop (CountedLoopNode *main) { assert(is_normal_loop(),""); _loop_flags |= Post; _main_idx = main->_idx; } void set_normal_loop( ) { _loop_flags &= ~PreMainPostFlagsMask; } - void set_trip_count(uint tc) { _trip_count = tc; } + // We use max_juint for the default value of _trip_count to signal it wasn't set. + // We shouldn't set _trip_count to max_juint explicitly. + void set_trip_count(uint tc) { assert(tc < max_juint, "Cannot set trip count to max_juint"); _trip_count = tc; } uint trip_count() { return _trip_count; } bool has_exact_trip_count() const { return (_loop_flags & HasExactTripCount) != 0; } void set_exact_trip_count(uint tc) { + assert(tc < max_juint, "Cannot set trip count to max_juint"); _trip_count = tc; _loop_flags |= HasExactTripCount; } diff --git a/test/hotspot/jtreg/compiler/loopopts/UnrollWideLoopHitsTooStrictAssert.java b/test/hotspot/jtreg/compiler/loopopts/UnrollWideLoopHitsTooStrictAssert.java new file mode 100644 index 00000000000..34db2e9e9f5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/UnrollWideLoopHitsTooStrictAssert.java @@ -0,0 +1,50 @@ +/* + * 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 8356647 + * @summary C2's unrolling code has a too strict assert when a counted loop's range is as wide as int's. + * @run main/othervm -XX:CompileCommand=compileonly,compiler.loopopts.UnrollWideLoopHitsTooStrictAssert::test -Xcomp + * compiler.loopopts.UnrollWideLoopHitsTooStrictAssert + * @run main compiler.loopopts.UnrollWideLoopHitsTooStrictAssert + */ + +package compiler.loopopts; + +public class UnrollWideLoopHitsTooStrictAssert { + public static void main(String[] args) { + test(true); + } + + private static long test(boolean flag) { + long x = 0; + for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; ++i) { + x += i; + if (flag) { + break; + } + } + return x; + } +}