Skip to content

Commit 8b0c5b9

Browse files
committed
8292660: C2: blocks made unreachable by NeverBranch-to-Goto conversion are removed incorrectly
Backport-of: 730ced9a109953ca1c3b7bfd6a3eeac5b85892c5
1 parent 9729dad commit 8b0c5b9

File tree

4 files changed

+110
-15
lines changed

4 files changed

+110
-15
lines changed

src/hotspot/share/opto/block.cpp

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ bool Block::contains(const Node *n) const {
151151
return _nodes.contains(n);
152152
}
153153

154+
bool Block::is_trivially_unreachable() const {
155+
return num_preds() <= 1 && !head()->is_Root() && !head()->is_Start();
156+
}
157+
154158
// Return empty status of a block. Empty blocks contain only the head, other
155159
// ideal nodes, and an optional trailing goto.
156160
int Block::is_Empty() const {
@@ -170,7 +174,7 @@ int Block::is_Empty() const {
170174
}
171175

172176
// Unreachable blocks are considered empty
173-
if (num_preds() <= 1) {
177+
if (is_trivially_unreachable()) {
174178
return success_result;
175179
}
176180

@@ -608,19 +612,6 @@ void PhaseCFG::convert_NeverBranch_to_Goto(Block *b) {
608612
for (int k = 1; dead->get_node(k)->is_Phi(); k++) {
609613
dead->get_node(k)->del_req(j);
610614
}
611-
// If the fake exit block becomes unreachable, remove it from the block list.
612-
if (dead->num_preds() == 1) {
613-
for (uint i = 0; i < number_of_blocks(); i++) {
614-
Block* block = get_block(i);
615-
if (block == dead) {
616-
_blocks.remove(i);
617-
} else if (block->_pre_order > dead->_pre_order) {
618-
// Enforce contiguous pre-order indices (assumed by PhaseBlockLayout).
619-
block->_pre_order--;
620-
}
621-
}
622-
_number_of_blocks--;
623-
}
624615
}
625616

626617
// Helper function to move block bx to the slot following b_index. Return
@@ -957,6 +948,46 @@ void PhaseCFG::fixup_flow() {
957948
} // End of for all blocks
958949
}
959950

951+
void PhaseCFG::remove_unreachable_blocks() {
952+
ResourceMark rm;
953+
Block_List unreachable;
954+
// Initialize worklist of unreachable blocks to be removed.
955+
for (uint i = 0; i < number_of_blocks(); i++) {
956+
Block* block = get_block(i);
957+
assert(block->_pre_order == i, "Block::pre_order does not match block index");
958+
if (block->is_trivially_unreachable()) {
959+
unreachable.push(block);
960+
}
961+
}
962+
// Now remove all blocks that are transitively unreachable.
963+
while (unreachable.size() > 0) {
964+
Block* dead = unreachable.pop();
965+
// When this code runs (after PhaseCFG::fixup_flow()), Block::_pre_order
966+
// does not contain pre-order but block-list indices. Ensure they stay
967+
// contiguous by decrementing _pre_order for all elements after 'dead'.
968+
// Block::_rpo does not contain valid reverse post-order indices anymore
969+
// (they are invalidated by block insertions in PhaseCFG::fixup_flow()),
970+
// so there is no need to update them.
971+
for (uint i = dead->_pre_order + 1; i < number_of_blocks(); i++) {
972+
get_block(i)->_pre_order--;
973+
}
974+
_blocks.remove(dead->_pre_order);
975+
_number_of_blocks--;
976+
// Update the successors' predecessor list and push new unreachable blocks.
977+
for (uint i = 0; i < dead->_num_succs; i++) {
978+
Block* succ = dead->_succs[i];
979+
Node* head = succ->head();
980+
for (int j = head->req() - 1; j >= 1; j--) {
981+
if (get_block_for_node(head->in(j)) == dead) {
982+
head->del_req(j);
983+
}
984+
}
985+
if (succ->is_trivially_unreachable()) {
986+
unreachable.push(succ);
987+
}
988+
}
989+
}
990+
}
960991

961992
// postalloc_expand: Expand nodes after register allocation.
962993
//

src/hotspot/share/opto/block.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -321,6 +321,9 @@ class Block : public CFGElement {
321321
// Check whether the node is in the block.
322322
bool contains (const Node *n) const;
323323

324+
// Whether the block is not root-like and does not have any predecessors.
325+
bool is_trivially_unreachable() const;
326+
324327
// Return the empty status of a block
325328
enum { not_empty, empty_with_goto, completely_empty };
326329
int is_Empty() const;
@@ -604,6 +607,10 @@ class PhaseCFG : public Phase {
604607
void remove_empty_blocks();
605608
Block *fixup_trap_based_check(Node *branch, Block *block, int block_pos, Block *bnext);
606609
void fixup_flow();
610+
// Remove all blocks that are transitively unreachable. Such blocks can be
611+
// found e.g. after PhaseCFG::convert_NeverBranch_to_Goto(). This function
612+
// assumes post-fixup_flow() block indices (Block::_pre_order, Block::_rpo).
613+
void remove_unreachable_blocks();
607614

608615
// Insert a node into a block at index and map the node to the block
609616
void insert(Block *b, uint idx, Node *n) {

src/hotspot/share/opto/compile.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2756,6 +2756,7 @@ void Compile::Code_Gen() {
27562756
cfg.set_loop_alignment();
27572757
}
27582758
cfg.fixup_flow();
2759+
cfg.remove_unreachable_blocks();
27592760
}
27602761

27612762
// Apply peephole optimizations
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/**
25+
* @test
26+
* @bug 8292660
27+
* @summary Test that blocks made unreachable after processing multiple infinite
28+
* loops in the block ordering phase are removed correctly.
29+
*
30+
* @run main/othervm -Xcomp -XX:CompileOnly=compiler.loopopts.TestMultipleInfiniteLoops::test
31+
* compiler.loopopts.TestMultipleInfiniteLoops
32+
*/
33+
34+
package compiler.loopopts;
35+
36+
public class TestMultipleInfiniteLoops {
37+
38+
static int foo;
39+
40+
static void test() {
41+
int i = 5, j;
42+
while (i > 0) {
43+
for (j = i; 1 > j; ) {
44+
switch (i) {
45+
case 4:
46+
foo = j;
47+
}
48+
}
49+
i++;
50+
}
51+
}
52+
53+
public static void main(String[] args) {
54+
test();
55+
}
56+
}

0 commit comments

Comments
 (0)