mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
8292660: C2: blocks made unreachable by NeverBranch-to-Goto conversion are removed incorrectly
Reviewed-by: kvn, roland
This commit is contained in:
@@ -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 {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -954,6 +945,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.
|
||||
//
|
||||
|
||||
@@ -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
|
||||
@@ -321,6 +321,9 @@ public:
|
||||
// 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;
|
||||
@@ -610,6 +613,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) {
|
||||
|
||||
@@ -2969,6 +2969,7 @@ void Compile::Code_Gen() {
|
||||
cfg.set_loop_alignment();
|
||||
}
|
||||
cfg.fixup_flow();
|
||||
cfg.remove_unreachable_blocks();
|
||||
}
|
||||
|
||||
// Apply peephole optimizations
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user