8315920: C2: "control input must dominate current control" assert failure
Reviewed-by: thartmann, chagedorn
This commit is contained in:
parent
1f7dfda705
commit
4e1e579e8b
@ -1918,6 +1918,9 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new,
|
|||||||
post_head->set_normal_loop();
|
post_head->set_normal_loop();
|
||||||
post_head->set_post_loop(main_head);
|
post_head->set_post_loop(main_head);
|
||||||
|
|
||||||
|
// clone_loop() above changes the exit projection
|
||||||
|
main_exit = outer_main_end->proj_out(false);
|
||||||
|
|
||||||
// Reduce the post-loop trip count.
|
// Reduce the post-loop trip count.
|
||||||
CountedLoopEndNode* post_end = old_new[main_end->_idx]->as_CountedLoopEnd();
|
CountedLoopEndNode* post_end = old_new[main_end->_idx]->as_CountedLoopEnd();
|
||||||
post_end->_prob = PROB_FAIR;
|
post_end->_prob = PROB_FAIR;
|
||||||
|
@ -1547,7 +1547,7 @@ private:
|
|||||||
Node *find_use_block( Node *use, Node *def, Node *old_false, Node *new_false, Node *old_true, Node *new_true );
|
Node *find_use_block( Node *use, Node *def, Node *old_false, Node *new_false, Node *old_true, Node *new_true );
|
||||||
void handle_use( Node *use, Node *def, small_cache *cache, Node *region_dom, Node *new_false, Node *new_true, Node *old_false, Node *old_true );
|
void handle_use( Node *use, Node *def, small_cache *cache, Node *region_dom, Node *new_false, Node *new_true, Node *old_false, Node *old_true );
|
||||||
bool split_up( Node *n, Node *blk1, Node *blk2 );
|
bool split_up( Node *n, Node *blk1, Node *blk2 );
|
||||||
void sink_use( Node *use, Node *post_loop );
|
|
||||||
Node* place_outside_loop(Node* useblock, IdealLoopTree* loop) const;
|
Node* place_outside_loop(Node* useblock, IdealLoopTree* loop) const;
|
||||||
Node* try_move_store_before_loop(Node* n, Node *n_ctrl);
|
Node* try_move_store_before_loop(Node* n, Node *n_ctrl);
|
||||||
void try_move_store_after_loop(Node* n);
|
void try_move_store_after_loop(Node* n);
|
||||||
|
@ -2065,17 +2065,6 @@ CmpNode*PhaseIdealLoop::clone_bool(PhiNode* phi) {
|
|||||||
return (CmpNode*)cmp;
|
return (CmpNode*)cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------sink_use---------------------------------------
|
|
||||||
// If 'use' was in the loop-exit block, it now needs to be sunk
|
|
||||||
// below the post-loop merge point.
|
|
||||||
void PhaseIdealLoop::sink_use( Node *use, Node *post_loop ) {
|
|
||||||
if (!use->is_CFG() && get_ctrl(use) == post_loop->in(2)) {
|
|
||||||
set_ctrl(use, post_loop);
|
|
||||||
for (DUIterator j = use->outs(); use->has_out(j); j++)
|
|
||||||
sink_use(use->out(j), post_loop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new,
|
void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new,
|
||||||
IdealLoopTree* loop, IdealLoopTree* outer_loop,
|
IdealLoopTree* loop, IdealLoopTree* outer_loop,
|
||||||
Node_List*& split_if_set, Node_List*& split_bool_set,
|
Node_List*& split_if_set, Node_List*& split_bool_set,
|
||||||
@ -2142,7 +2131,7 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new,
|
|||||||
while( use->in(idx) != old ) idx++;
|
while( use->in(idx) != old ) idx++;
|
||||||
Node *prev = use->is_CFG() ? use : get_ctrl(use);
|
Node *prev = use->is_CFG() ? use : get_ctrl(use);
|
||||||
assert(!loop->is_member(get_loop(prev)) && !outer_loop->is_member(get_loop(prev)), "" );
|
assert(!loop->is_member(get_loop(prev)) && !outer_loop->is_member(get_loop(prev)), "" );
|
||||||
Node *cfg = prev->_idx >= new_counter
|
Node* cfg = (prev->_idx >= new_counter && prev->is_Region())
|
||||||
? prev->in(2)
|
? prev->in(2)
|
||||||
: idom(prev);
|
: idom(prev);
|
||||||
if( use->is_Phi() ) // Phi use is in prior block
|
if( use->is_Phi() ) // Phi use is in prior block
|
||||||
@ -2166,7 +2155,7 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new,
|
|||||||
|
|
||||||
while(!outer_loop->is_member(get_loop(cfg))) {
|
while(!outer_loop->is_member(get_loop(cfg))) {
|
||||||
prev = cfg;
|
prev = cfg;
|
||||||
cfg = cfg->_idx >= new_counter ? cfg->in(2) : idom(cfg);
|
cfg = (cfg->_idx >= new_counter && cfg->is_Region()) ? cfg->in(2) : idom(cfg);
|
||||||
}
|
}
|
||||||
// If the use occurs after merging several exits from the loop, then
|
// If the use occurs after merging several exits from the loop, then
|
||||||
// old value must have dominated all those exits. Since the same old
|
// old value must have dominated all those exits. Since the same old
|
||||||
@ -2224,10 +2213,6 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new,
|
|||||||
if( hit ) // Go ahead and re-hash for hits.
|
if( hit ) // Go ahead and re-hash for hits.
|
||||||
_igvn.replace_node( use, hit );
|
_igvn.replace_node( use, hit );
|
||||||
}
|
}
|
||||||
|
|
||||||
// If 'use' was in the loop-exit block, it now needs to be sunk
|
|
||||||
// below the post-loop merge point.
|
|
||||||
sink_use( use, prev );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2594,8 +2579,6 @@ void PhaseIdealLoop::fix_ctrl_uses(const Node_List& body, const IdealLoopTree* l
|
|||||||
// We need a Region to merge the exit from the peeled body and the
|
// We need a Region to merge the exit from the peeled body and the
|
||||||
// exit from the old loop body.
|
// exit from the old loop body.
|
||||||
RegionNode *r = new RegionNode(3);
|
RegionNode *r = new RegionNode(3);
|
||||||
// Map the old use to the new merge point
|
|
||||||
old_new.map( use->_idx, r );
|
|
||||||
uint dd_r = MIN2(dom_depth(newuse), dom_depth(use));
|
uint dd_r = MIN2(dom_depth(newuse), dom_depth(use));
|
||||||
assert(dd_r >= dom_depth(dom_lca(newuse, use)), "" );
|
assert(dd_r >= dom_depth(dom_lca(newuse, use)), "" );
|
||||||
|
|
||||||
@ -2631,12 +2614,24 @@ void PhaseIdealLoop::fix_ctrl_uses(const Node_List& body, const IdealLoopTree* l
|
|||||||
l -= uses_found; // we deleted 1 or more copies of this edge
|
l -= uses_found; // we deleted 1 or more copies of this edge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(use->is_Proj(), "loop exit should be projection");
|
||||||
|
// lazy_replace() below moves all nodes that are:
|
||||||
|
// - control dependent on the loop exit or
|
||||||
|
// - have control set to the loop exit
|
||||||
|
// below the post-loop merge point. lazy_replace() takes a dead control as first input. To make it
|
||||||
|
// possible to use it, the loop exit projection is cloned and becomes the new exit projection. The initial one
|
||||||
|
// becomes dead and is "replaced" by the region.
|
||||||
|
Node* use_clone = use->clone();
|
||||||
|
register_control(use_clone, use_loop, idom(use), dom_depth(use));
|
||||||
// Now finish up 'r'
|
// Now finish up 'r'
|
||||||
r->set_req(1, newuse);
|
r->set_req(1, newuse);
|
||||||
r->set_req(2, use);
|
r->set_req(2, use_clone);
|
||||||
_igvn.register_new_node_with_optimizer(r);
|
_igvn.register_new_node_with_optimizer(r);
|
||||||
set_loop(r, use_loop);
|
set_loop(r, use_loop);
|
||||||
set_idom(r, (side_by_side_idom == nullptr) ? newuse->in(0) : side_by_side_idom, dd_r);
|
set_idom(r, (side_by_side_idom == nullptr) ? newuse->in(0) : side_by_side_idom, dd_r);
|
||||||
|
lazy_replace(use, r);
|
||||||
|
// Map the (cloned) old use to the new merge point
|
||||||
|
old_new.map(use_clone->_idx, r);
|
||||||
} // End of if a loop-exit test
|
} // End of if a loop-exit test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc. 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 8315920
|
||||||
|
* @summary C2: "control input must dominate current control" assert failure
|
||||||
|
* @requires vm.compiler2.enabled
|
||||||
|
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseLoopPredicate -XX:-DoEscapeAnalysis TestBadControlAfterPreMainPost
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TestBadControlAfterPreMainPost {
|
||||||
|
private static volatile int volatileField;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int[] array2 = new int[100];
|
||||||
|
for (int i = 0; i < 20_000; i++) {
|
||||||
|
test(1, array2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int test(int j, int[] array2) {
|
||||||
|
int[] array = new int[10];
|
||||||
|
array[j] = 42;
|
||||||
|
float f = 1;
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
for (int k = 0; k < 10; k++) {
|
||||||
|
}
|
||||||
|
f = f * 2;
|
||||||
|
}
|
||||||
|
int v = array[0];
|
||||||
|
int i = 0;
|
||||||
|
do {
|
||||||
|
synchronized (new Object()) {
|
||||||
|
}
|
||||||
|
array2[i + v] = 42;
|
||||||
|
i++;
|
||||||
|
} while (i < 100);
|
||||||
|
return (int)f;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user