From a62296d8a0858d63a930e91168254a9927f06783 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 2 Dec 2025 14:00:21 +0000 Subject: [PATCH] 8371464: C2: assert(no_dead_loop) failed: dead loop detected Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/cfgnode.cpp | 13 +-- src/hotspot/share/opto/cfgnode.hpp | 2 +- .../compiler/c2/TestDeadLoopAtMergeMem.java | 83 +++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0293f42d791..0598f10b880 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -326,7 +326,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { // First, cut the simple case of fallthrough region when NONE of // region's phis references itself directly or through a data node. - if (is_possible_unsafe_loop(phase)) { + if (is_possible_unsafe_loop()) { // If we have a possible unsafe loop, check if the region node is actually unreachable from root. if (is_unreachable_from_root(phase)) { _is_unreachable_region = true; @@ -336,7 +336,7 @@ bool RegionNode::is_unreachable_region(const PhaseGVN* phase) { return false; } -bool RegionNode::is_possible_unsafe_loop(const PhaseGVN* phase) const { +bool RegionNode::is_possible_unsafe_loop() const { uint max = outcnt(); uint i; for (i = 0; i < max; i++) { @@ -634,8 +634,8 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } else if (can_reshape && cnt == 1) { // Is it dead loop? - // If it is LoopNopde it had 2 (+1 itself) inputs and - // one of them was cut. The loop is dead if it was EntryContol. + // If it is LoopNode it had 2 (+1 itself) inputs and + // one of them was cut. The loop is dead if it was EntryControl. // Loop node may have only one input because entry path // is removed in PhaseIdealLoop::Dominators(). assert(!this->is_Loop() || cnt_orig <= 3, "Loop node should have 3 or less inputs"); @@ -1392,7 +1392,7 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { } assert(is_diamond_phi() > 0, "sanity"); assert(req() == 3, "same as region"); - const Node* region = in(0); + RegionNode* region = in(0)->as_Region(); for (uint i = 1; i < 3; i++) { Node* phi_input = in(i); if (phi_input != nullptr && phi_input->is_MergeMem() && region->in(i)->outcnt() == 1) { @@ -1400,8 +1400,9 @@ bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { MergeMemNode* merge_mem = phi_input->as_MergeMem(); uint j = 3 - i; Node* other_phi_input = in(j); - if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory()) { + if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory() && !is_data_loop(region, phi_input, igvn)) { // merge_mem is a successor memory to other_phi_input, and is not pinned inside the diamond, so push it out. + // Only proceed if the transformation doesn't create a data loop // This will allow the diamond to collapse completely if there are no other phis left. igvn->replace_node(this, merge_mem); return true; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 78ad085e03d..bc0b38e2f97 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -84,7 +84,7 @@ private: bool _is_unreachable_region; LoopStatus _loop_status; - bool is_possible_unsafe_loop(const PhaseGVN* phase) const; + bool is_possible_unsafe_loop() const; bool is_unreachable_from_root(const PhaseGVN* phase) const; public: // Node layout (parallels PhiNode): diff --git a/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java new file mode 100644 index 00000000000..5c4dcc76a76 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestDeadLoopAtMergeMem.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 IBM Corporation. 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 8371464 + * @summary C2: assert(no_dead_loop) failed: dead loop detected + * @run main/othervm -Xcomp -XX:CompileOnly=TestDeadLoopAtMergeMem::test TestDeadLoopAtMergeMem + * @run main TestDeadLoopAtMergeMem + */ + +public class TestDeadLoopAtMergeMem { + static final int N = 400; + static long instanceCount; + boolean bFld; + float fArrFld[]; + static int iArrFld[] = new int[N]; + long vMeth_check_sum; + + public static void main(String[] strArr) { + TestDeadLoopAtMergeMem r = new TestDeadLoopAtMergeMem(); + for (int i = 0; i < 1000; i++) { + r.test((short) 0, instanceCount); + } + } + + void test(short s, long l) { + int i11 = 6, i12, i13 = 6, i14 = 2; + byte byArr2[] = new byte[N]; + init(byArr2, (byte) 4); + helper(66.118169, i11); + for (i12 = 3; i12 < 23; i12++) { + if (bFld) { + instanceCount = 5; + } else if (bFld) { + fArrFld[i12] = s; + do { + try { + i11 = i13 / i12 % i12; + } catch (ArithmeticException a_e) { + } + } while (i14 < 8); + } + } + for (int i15 : iArrFld) { + try { + i11 = 1 / i15; + } catch (ArithmeticException a_e) { + } + } + vMeth_check_sum += i11; + } + + void helper(double d, int i) { + int i1[] = new int[N]; + } + + public static void init(byte[] a, byte seed) { + for (int j = 0; j < a.length; j++) { + a[j] = (byte) ((j % 2 == 0) ? seed + j : seed - j); + } + } +}