Skip to content

Commit

Permalink
8324121: SIGFPE in PhaseIdealLoop::extract_long_range_checks
Browse files Browse the repository at this point in the history
Reviewed-by: kvn, chagedorn
  • Loading branch information
rwestrel committed Mar 25, 2024
1 parent 0c1b254 commit cb2a671
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 9 deletions.
16 changes: 9 additions & 7 deletions src/hotspot/share/opto/loopnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<jint>(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 >=.
Expand Down Expand Up @@ -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<int>(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);
Expand Down Expand Up @@ -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<int>(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
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/opto/loopnode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1710,8 +1710,8 @@ class PhaseIdealLoop : public PhaseTransform {
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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<T1>(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);
}
}
}

1 comment on commit cb2a671

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.