Skip to content

Commit 730ced9

Browse files
committed
8292660: C2: blocks made unreachable by NeverBranch-to-Goto conversion are removed incorrectly
Reviewed-by: kvn, roland
1 parent 3464019 commit 730ced9

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
@@ -954,6 +945,46 @@ void PhaseCFG::fixup_flow() {
954945
} // End of for all blocks
955946
}
956947

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

958989
// postalloc_expand: Expand nodes after register allocation.
959990
//

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;
@@ -610,6 +613,10 @@ class PhaseCFG : public Phase {
610613
void remove_empty_blocks();
611614
Block *fixup_trap_based_check(Node *branch, Block *block, int block_pos, Block *bnext);
612615
void fixup_flow();
616+
// Remove all blocks that are transitively unreachable. Such blocks can be
617+
// found e.g. after PhaseCFG::convert_NeverBranch_to_Goto(). This function
618+
// assumes post-fixup_flow() block indices (Block::_pre_order, Block::_rpo).
619+
void remove_unreachable_blocks();
613620

614621
// Insert a node into a block at index and map the node to the block
615622
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
@@ -2969,6 +2969,7 @@ void Compile::Code_Gen() {
29692969
cfg.set_loop_alignment();
29702970
}
29712971
cfg.fixup_flow();
2972+
cfg.remove_unreachable_blocks();
29722973
}
29732974

29742975
// 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)