diff --git a/src/hotspot/share/opto/domgraph.cpp b/src/hotspot/share/opto/domgraph.cpp index db7181697e89a..42cd5f4a58c4d 100644 --- a/src/hotspot/share/opto/domgraph.cpp +++ b/src/hotspot/share/opto/domgraph.cpp @@ -384,6 +384,25 @@ struct NTarjan { #endif }; +void remove_single_entry_region(NTarjan* t, NTarjan*& tdom, Node*& dom, PhaseIterGVN& igvn) { + // remove phis: + for (DUIterator_Fast jmax, j = dom->fast_outs(jmax); j < jmax; j++) { + Node* use = dom->fast_out(j); + if (use->is_Phi()) { + igvn.replace_node(use, use->in(1)); + --j; --jmax; + } + } + // Disconnect region from dominator tree + assert(dom->unique_ctrl_out() == t->_control, "expect a single dominated node"); + tdom = tdom->_dom; + t->_dom = tdom; + assert(tdom->_control == dom->in(1), "dominator of region with single input should be that input"); + // and remove it + igvn.replace_node(dom, dom->in(1)); + dom = tdom->_control; +} + // Compute the dominator tree of the sea of nodes. This version walks all CFG // nodes (using the is_CFG() call) and places them in a dominator tree. Thus, // it needs a count of the CFG nodes for the mapping table. This is the @@ -486,7 +505,14 @@ void PhaseIdealLoop::Dominators() { assert(t->_control != nullptr,"Bad DFS walk"); NTarjan *tdom = t->_dom; // Handy access to immediate dominator if( tdom ) { // Root has no immediate dominator - _idom[t->_control->_idx] = tdom->_control; // Set immediate dominator + Node* dom = tdom->_control; + // The code that removes unreachable loops above could have left a region with a single input. Remove it. Do it + // now that we iterate over cfg nodes for the last time (doing it earlier would have left a dead cfg node behind + // that code that goes over the dfs list would have had to handle). + if (dom != C->root() && dom->is_Region() && dom->req() == 2) { + remove_single_entry_region(t, tdom, dom, _igvn); + } + _idom[t->_control->_idx] = dom; // Set immediate dominator t->_dom_next = tdom->_dom_child; // Make me a sibling of parent's child tdom->_dom_child = t; // Make me a child of my parent } else diff --git a/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelingAtSingleInputRegion.java b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelingAtSingleInputRegion.java new file mode 100644 index 0000000000000..2b2231a89f34a --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelingAtSingleInputRegion.java @@ -0,0 +1,55 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 8321278 + * @summary C2: Partial peeling fails with assert "last_peel <- first_not_peeled" + * @run main/othervm -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,TestPartialPeelingAtSingleInputRegion::test + * -XX:-TieredCompilation -Xbatch -XX:PerMethodTrapLimit=0 TestPartialPeelingAtSingleInputRegion + * + */ + +public class TestPartialPeelingAtSingleInputRegion { + + static void test() { + for (int i = 100; i > 10; --i) { + for (int j = i; j < 10; ++j) { + switch (j) { + case 1: + if (j != 0) { + return; + } + } + } + } + } + + public static void main(String[] args) { + for (int i = 0; i < 10_000; ++i) { + test(); + } + } +}