From d11b6c6c375c0bd432e75ec0bdafe7333d7cbbef Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Fri, 21 Nov 2025 10:55:26 +0100 Subject: [PATCH 1/2] JDK-8371146 --- ...TestAliasingCheckPreLimitNotAvailable.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java new file mode 100644 index 0000000000000..e7009e87ae226 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasingCheckPreLimitNotAvailable.java @@ -0,0 +1,116 @@ +/* + * 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 id=all-flags-fixed-stress-seed + * @bug 8371146 + * @summary Test where the pre_init was pinned before the pre-loop but after the + * Auto_Vectorization_Check, and so it should not be used for the auto + * vectorization aliasing check, to avoid a bad (circular) graph. + * @requires vm.gc == "ZGC" | vm.gc == "null" + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:+UseZGC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLoopPeeling -XX:StressSeed=4 + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=all-flags-no-stress-seed + * @bug 8371146 + * @requires vm.gc == "ZGC" | vm.gc == "null" + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:+UseZGC + * -XX:+UnlockDiagnosticVMOptions -XX:+StressLoopPeeling + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=fewer-flags + * @bug 8371146 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * -XX:LoopUnrollLimit=48 + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=minimal-flags + * @bug 8371146 + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=compileonly,*TestAliasingCheckPreLimitNotAvailable::test + * -XX:-TieredCompilation + * -Xcomp + * compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +/* + * @test id=vanilla + * @bug 8371146 + * @run main compiler.loopopts.superword.TestAliasingCheckPreLimitNotAvailable + */ + +package compiler.loopopts.superword; + +public class TestAliasingCheckPreLimitNotAvailable { + static int sum; + static boolean condition; + static int zero; + static int twoDimensional[][] = new int[20][20]; + + static void test() { + int innerCount = 0; + int conditionCount = 0; + int oneDimensional[] = new int[10]; + for (int i = 2; i > 0; --i) { + for (int j = i; j < 10; j++) { + innerCount += 1; + oneDimensional[1] += innerCount; + oneDimensional[j] += zero; + if (condition) { + conditionCount += 1; + oneDimensional[1] += conditionCount; + sum += oneDimensional[1]; + } + twoDimensional[j] = twoDimensional[j + 1]; + } + } + } + + public static void main(String[] args) { + test(); + } +} From 18dcc2a39128416ec02c66b0cf2ccf49c9a6aeff Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Fri, 21 Nov 2025 11:04:16 +0100 Subject: [PATCH 2/2] initial fix --- src/hotspot/share/opto/superword.cpp | 7 ++--- src/hotspot/share/opto/vectorization.cpp | 33 +++++++++++++++++------- src/hotspot/share/opto/vectorization.hpp | 11 ++++++++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 35b46d22732f4..487823df45eb9 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -1976,13 +1976,14 @@ void VTransform::apply() { Compile* C = phase()->C; C->print_method(PHASE_AUTO_VECTORIZATION1_BEFORE_APPLY, 4, cl()); - adjust_pre_loop_limit_to_align_main_loop_vectors(); - C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); - apply_speculative_alignment_runtime_checks(); apply_speculative_aliasing_runtime_checks(); C->print_method(PHASE_AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, 4, cl()); + // TODO: renumber + adjust_pre_loop_limit_to_align_main_loop_vectors(); + C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); + apply_vectorization(); C->print_method(PHASE_AUTO_VECTORIZATION5_AFTER_APPLY, 4, cl()); } diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 98f3d79c9f5ce..ddeb25571baab 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -1022,27 +1022,39 @@ bool VPointer::can_make_speculative_aliasing_check_with(const VPointer& other) c // or at the multiversion_if. That is before the pre-loop. From the construction of // VPointer, we already know that all its variables (except iv) are pre-loop invariant. // - // For the computation of main_init, we also need the pre_limit, and so we need - // to check that this value is pre-loop invariant. In the case of non-equal iv_scales, - // we also need the main_limit in the aliasing check, and so this value must then - // also be pre-loop invariant. + // In VPointer::make_speculative_aliasing_check_with we compute main_init in all + // cases. For this, we require pre_init and pre_limit. These values must be available + // for the speculative check, i.e. their control must dominate the speculative check. + // Further, "if vp1.iv_scale() != vp2.iv_scale()" we additionally need to have + // main_limit available for the speculative check. + // Note: no matter if the speculative check is inserted as a predicate or at the + // multiversion if, the speculative check happens before (dominates) the + // pre-loop. + Node* pre_init = _vloop.pre_loop_end()->init_trip(); Opaque1Node* pre_limit_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); Node* pre_limit = pre_limit_opaq->in(1); Node* main_limit = _vloop.cl()->limit(); - - if (!_vloop.is_pre_loop_invariant(pre_limit)) { + if (!_vloop.is_available_for_speculative_check(pre_init)) { +#ifdef ASSERT + if (_vloop.is_trace_speculative_aliasing_analysis()) { + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not available at speculative check!"); + } +#endif + return false; + } + if (!_vloop.is_available_for_speculative_check(pre_limit)) { #ifdef ASSERT if (_vloop.is_trace_speculative_aliasing_analysis()) { - tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not pre-loop independent!"); + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: pre_limit is not available at speculative check!"); } #endif return false; } - if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_pre_loop_invariant(main_limit)) { + if (vp1.iv_scale() != vp2.iv_scale() && !_vloop.is_available_for_speculative_check(main_limit)) { #ifdef ASSERT if (_vloop.is_trace_speculative_aliasing_analysis()) { - tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not pre-loop independent!"); + tty->print_cr("VPointer::can_make_speculative_aliasing_check_with: main_limit is not available at speculative check!"); } #endif return false; @@ -1119,6 +1131,8 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, Node* pre_limit = pre_limit_opaq->in(1); assert(_vloop.is_pre_loop_invariant(pre_init), "needed for aliasing check before pre-loop"); assert(_vloop.is_pre_loop_invariant(pre_limit), "needed for aliasing check before pre-loop"); + assert(phase->is_dominator(phase->get_ctrl(pre_init), ctrl), "need pre_init at ctrl of check"); + assert(phase->is_dominator(phase->get_ctrl(pre_limit), ctrl), "need pre_limit at ctrl of check"); Node* pre_initL = new ConvI2LNode(pre_init); Node* pre_limitL = new ConvI2LNode(pre_limit); @@ -1180,6 +1194,7 @@ BoolNode* VPointer::make_speculative_aliasing_check_with(const VPointer& other, jint main_iv_stride = _vloop.iv_stride(); Node* main_limit = _vloop.cl()->limit(); assert(_vloop.is_pre_loop_invariant(main_limit), "needed for aliasing check before pre-loop"); + assert(phase->is_dominator(phase->get_ctrl(main_limit), ctrl), "need main_limit at ctrl of check"); Node* main_limitL = new ConvI2LNode(main_limit); phase->register_new_node_with_ctrl_of(main_limitL, pre_init); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index f7099b5b7c0a4..7548e5b813233 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -257,6 +257,17 @@ class VLoop : public StackObj { return is_before_pre_loop(early); } + bool is_available_for_speculative_check(Node* n) const { + assert(are_speculative_checks_possible(), "meaningless without speculative check"); + ParsePredicateSuccessProj* parse_predicate_proj = auto_vectorization_parse_predicate_proj(); + // Find the control of the predicate: + ProjNode* proj = (parse_predicate_proj != nullptr) ? parse_predicate_proj : multiversioning_fast_proj(); + Node* check_ctrl = proj->in(0)->as_If()->in(0); + // The control of n must dominate that of the predicate. + Node* n_ctrl = phase()->get_ctrl(n); + return phase()->is_dominator(n_ctrl, check_ctrl); + } + // Check if the loop passes some basic preconditions for vectorization. // Return indicates if analysis succeeded. bool check_preconditions();