Skip to content

Commit

Permalink
8292660: C2: blocks made unreachable by NeverBranch-to-Goto conversio…
Browse files Browse the repository at this point in the history
…n are removed incorrectly

Backport-of: 730ced9a109953ca1c3b7bfd6a3eeac5b85892c5
  • Loading branch information
GoeLin committed Dec 27, 2022
1 parent 9729dad commit 8b0c5b9
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 15 deletions.
59 changes: 45 additions & 14 deletions src/hotspot/share/opto/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ bool Block::contains(const Node *n) const {
return _nodes.contains(n);
}

bool Block::is_trivially_unreachable() const {
return num_preds() <= 1 && !head()->is_Root() && !head()->is_Start();
}

// Return empty status of a block. Empty blocks contain only the head, other
// ideal nodes, and an optional trailing goto.
int Block::is_Empty() const {
Expand All @@ -170,7 +174,7 @@ int Block::is_Empty() const {
}

// Unreachable blocks are considered empty
if (num_preds() <= 1) {
if (is_trivially_unreachable()) {
return success_result;
}

Expand Down Expand Up @@ -608,19 +612,6 @@ void PhaseCFG::convert_NeverBranch_to_Goto(Block *b) {
for (int k = 1; dead->get_node(k)->is_Phi(); k++) {
dead->get_node(k)->del_req(j);
}
// If the fake exit block becomes unreachable, remove it from the block list.
if (dead->num_preds() == 1) {
for (uint i = 0; i < number_of_blocks(); i++) {
Block* block = get_block(i);
if (block == dead) {
_blocks.remove(i);
} else if (block->_pre_order > dead->_pre_order) {
// Enforce contiguous pre-order indices (assumed by PhaseBlockLayout).
block->_pre_order--;
}
}
_number_of_blocks--;
}
}

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

void PhaseCFG::remove_unreachable_blocks() {
ResourceMark rm;
Block_List unreachable;
// Initialize worklist of unreachable blocks to be removed.
for (uint i = 0; i < number_of_blocks(); i++) {
Block* block = get_block(i);
assert(block->_pre_order == i, "Block::pre_order does not match block index");
if (block->is_trivially_unreachable()) {
unreachable.push(block);
}
}
// Now remove all blocks that are transitively unreachable.
while (unreachable.size() > 0) {
Block* dead = unreachable.pop();
// When this code runs (after PhaseCFG::fixup_flow()), Block::_pre_order
// does not contain pre-order but block-list indices. Ensure they stay
// contiguous by decrementing _pre_order for all elements after 'dead'.
// Block::_rpo does not contain valid reverse post-order indices anymore
// (they are invalidated by block insertions in PhaseCFG::fixup_flow()),
// so there is no need to update them.
for (uint i = dead->_pre_order + 1; i < number_of_blocks(); i++) {
get_block(i)->_pre_order--;
}
_blocks.remove(dead->_pre_order);
_number_of_blocks--;
// Update the successors' predecessor list and push new unreachable blocks.
for (uint i = 0; i < dead->_num_succs; i++) {
Block* succ = dead->_succs[i];
Node* head = succ->head();
for (int j = head->req() - 1; j >= 1; j--) {
if (get_block_for_node(head->in(j)) == dead) {
head->del_req(j);
}
}
if (succ->is_trivially_unreachable()) {
unreachable.push(succ);
}
}
}
}

// postalloc_expand: Expand nodes after register allocation.
//
Expand Down
9 changes: 8 additions & 1 deletion src/hotspot/share/opto/block.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
Expand Down Expand Up @@ -321,6 +321,9 @@ class Block : public CFGElement {
// Check whether the node is in the block.
bool contains (const Node *n) const;

// Whether the block is not root-like and does not have any predecessors.
bool is_trivially_unreachable() const;

// Return the empty status of a block
enum { not_empty, empty_with_goto, completely_empty };
int is_Empty() const;
Expand Down Expand Up @@ -604,6 +607,10 @@ class PhaseCFG : public Phase {
void remove_empty_blocks();
Block *fixup_trap_based_check(Node *branch, Block *block, int block_pos, Block *bnext);
void fixup_flow();
// Remove all blocks that are transitively unreachable. Such blocks can be
// found e.g. after PhaseCFG::convert_NeverBranch_to_Goto(). This function
// assumes post-fixup_flow() block indices (Block::_pre_order, Block::_rpo).
void remove_unreachable_blocks();

// Insert a node into a block at index and map the node to the block
void insert(Block *b, uint idx, Node *n) {
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/opto/compile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2756,6 +2756,7 @@ void Compile::Code_Gen() {
cfg.set_loop_alignment();
}
cfg.fixup_flow();
cfg.remove_unreachable_blocks();
}

// Apply peephole optimizations
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2022, 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
* @bug 8292660
* @summary Test that blocks made unreachable after processing multiple infinite
* loops in the block ordering phase are removed correctly.
*
* @run main/othervm -Xcomp -XX:CompileOnly=compiler.loopopts.TestMultipleInfiniteLoops::test
* compiler.loopopts.TestMultipleInfiniteLoops
*/

package compiler.loopopts;

public class TestMultipleInfiniteLoops {

static int foo;

static void test() {
int i = 5, j;
while (i > 0) {
for (j = i; 1 > j; ) {
switch (i) {
case 4:
foo = j;
}
}
i++;
}
}

public static void main(String[] args) {
test();
}
}

1 comment on commit 8b0c5b9

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.