diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 4a262e46af9..96fd2a3b87b 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -792,13 +792,14 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { } #endif - jlong stride_con = head->stride_con(); - assert(stride_con != 0, "missed some peephole opt"); + jlong stride_con_long = head->stride_con(); + assert(stride_con_long != 0, "missed some peephole opt"); // We can't iterate for more than max int at a time. - if (stride_con != (jint)stride_con) { + if (stride_con_long != (jint)stride_con_long || stride_con_long == min_jint) { assert(bt == T_LONG, "only for long loops"); return false; } + jint stride_con = checked_cast(stride_con_long); // The number of iterations for the integer count loop: guarantee no // overflow: max_jint - stride_con max. -1 so there's no need for a // loop limit check if the exit test is <= or >=. @@ -966,7 +967,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { } // Clone the iv data nodes as an integer iv - Node* int_stride = _igvn.intcon(checked_cast(stride_con)); + Node* int_stride = _igvn.intcon(stride_con); set_ctrl(int_stride, C->root()); Node* inner_phi = new PhiNode(x->in(0), TypeInt::INT); Node* inner_incr = new AddINode(inner_phi, int_stride); @@ -1061,7 +1062,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { register_new_node(outer_phi, outer_head); } - transform_long_range_checks(checked_cast(stride_con), range_checks, outer_phi, inner_iters_actual_int, + transform_long_range_checks(stride_con, range_checks, outer_phi, inner_iters_actual_int, inner_phi, iv_add, inner_head); // Peel one iteration of the loop and use the safepoint at the end // of the peeled iteration to insert Parse Predicates. If no well @@ -1098,7 +1099,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { return true; } -int PhaseIdealLoop::extract_long_range_checks(const IdealLoopTree* loop, jlong stride_con, int iters_limit, PhiNode* phi, +int PhaseIdealLoop::extract_long_range_checks(const IdealLoopTree* loop, jint stride_con, int iters_limit, PhiNode* phi, Node_List& range_checks) { const jlong min_iters = 2; jlong reduced_iters_limit = iters_limit; @@ -1114,7 +1115,8 @@ int PhaseIdealLoop::extract_long_range_checks(const IdealLoopTree* loop, jlong s jlong scale = 0; if (loop->is_range_check_if(if_proj, this, T_LONG, phi, range, offset, scale) && loop->is_invariant(range) && loop->is_invariant(offset) && - original_iters_limit / ABS(scale * stride_con) >= min_iters) { + original_iters_limit / ABS(scale) >= min_iters * ABS(stride_con)) { + assert(scale == (jint)scale, "scale should be an int"); reduced_iters_limit = MIN2(reduced_iters_limit, original_iters_limit/ABS(scale)); range_checks.push(c); } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 72436b78530..9785bec0d0a 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1710,8 +1710,8 @@ public: LoopNode* create_inner_head(IdealLoopTree* loop, BaseCountedLoopNode* head, IfNode* exit_test); - int extract_long_range_checks(const IdealLoopTree* loop, jlong stride_con, int iters_limit, PhiNode* phi, - Node_List &range_checks); + int extract_long_range_checks(const IdealLoopTree* loop, jint stride_con, int iters_limit, PhiNode* phi, + Node_List &range_checks); void transform_long_range_checks(int stride_con, const Node_List &range_checks, Node* outer_phi, Node* inner_iters_actual_int, Node* inner_phi, diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestLargeScaleInLongRCOverflow.java b/test/hotspot/jtreg/compiler/rangechecks/TestLargeScaleInLongRCOverflow.java new file mode 100644 index 00000000000..c762b0e2fd7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestLargeScaleInLongRCOverflow.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, 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 8324121 + * @summary SIGFPE in PhaseIdealLoop::extract_long_range_checks + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLargeScaleInLongRCOverflow::test* -XX:-TieredCompilation TestLargeScaleInLongRCOverflow + * + */ + +import java.util.Objects; + +public class TestLargeScaleInLongRCOverflow { + + public static void main(String args[]) { + Objects.checkIndex(0, 1); + try { + test1(); + } catch (java.lang.IndexOutOfBoundsException e) { } + try { + test2(); + } catch (java.lang.IndexOutOfBoundsException e) { } + } + + // SIGFPE in PhaseIdealLoop::extract_long_range_checks + public static void test1() { + for (long i = 1; i < 100; i += 2) { + Objects.checkIndex(Long.MIN_VALUE * i, 10); + } + } + + // "assert(static_cast(result) == thing) failed: must be" in PhaseIdealLoop::transform_long_range_checks + public static void test2() { + for (long i = 1; i < 100; i += 2) { + Objects.checkIndex((Long.MIN_VALUE + 2) * i, 10); + } + } +}