8293996: C2: fix and simplify IdealLoopTree::do_remove_empty_loop

Reviewed-by: roland, thartmann, chagedorn
This commit is contained in:
Emanuel Peter 2022-09-27 08:52:19 +00:00
parent 14c6ac457d
commit dd51f7e0b7
2 changed files with 48 additions and 27 deletions
src/hotspot/share/opto
test/hotspot/jtreg/compiler/loopopts

@ -3701,29 +3701,21 @@ bool IdealLoopTree::do_remove_empty_loop(PhaseIdealLoop *phase) {
}
// Replace the phi at loop head with the final value of the last
// iteration. Then the CountedLoopEnd will collapse (backedge never
// taken) and all loop-invariant uses of the exit values will be correct.
Node *phi = cl->phi();
Node *exact_limit = phase->exact_limit(this);
if (exact_limit != cl->limit()) {
// We also need to replace the original limit to collapse loop exit.
Node* cmp = cl->loopexit()->cmp_node();
assert(cl->limit() == cmp->in(2), "sanity");
// Duplicate cmp node if it has other users
if (cmp->outcnt() > 1) {
cmp = cmp->clone();
cmp = phase->_igvn.register_new_node_with_optimizer(cmp);
BoolNode *bol = cl->loopexit()->in(CountedLoopEndNode::TestValue)->as_Bool();
phase->_igvn.replace_input_of(bol, 1, cmp); // put bol on worklist
}
phase->_igvn._worklist.push(cmp->in(2)); // put limit on worklist
phase->_igvn.replace_input_of(cmp, 2, exact_limit); // put cmp on worklist
}
// iteration (exact_limit - stride), to make sure the loop exit value
// is correct, for any users after the loop.
// Note: the final value after increment should not overflow since
// counted loop has limit check predicate.
Node *final = new SubINode(exact_limit, cl->stride());
phase->register_new_node(final,cl->in(LoopNode::EntryControl));
phase->_igvn.replace_node(phi,final);
Node* phi = cl->phi();
Node* exact_limit = phase->exact_limit(this);
Node* final_iv = new SubINode(exact_limit, cl->stride());
phase->register_new_node(final_iv, cl->in(LoopNode::EntryControl));
phase->_igvn.replace_node(phi, final_iv);
// Set loop-exit condition to false. Then the CountedLoopEnd will collapse,
// because the back edge is never taken.
Node* zero = phase->_igvn.intcon(0);
phase->_igvn.replace_input_of(cl->loopexit(), CountedLoopEndNode::TestValue, zero);
phase->C->set_major_progress();
return true;
}

@ -1,5 +1,6 @@
/*
* Copyright (c) 2019, Huawei Technologies Co., Ltd. All rights reserved.
* 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
@ -23,7 +24,7 @@
/**
* @test
* @bug 8231988
* @bug 8231988 8293996
* @summary Unexpected test result caused by C2 IdealLoopTree::do_remove_empty_loop
*
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation
@ -34,9 +35,11 @@ package compiler.loopopts;
public class TestRemoveEmptyLoop {
public void test() {
public void test_cmp_helper() {
int i = 34;
// The empty loop that collapses
for (; i > 0; i -= 11);
// If uses same Cmp node as the loop condition
if (i < 0) {
// do nothing
} else {
@ -44,12 +47,38 @@ public class TestRemoveEmptyLoop {
}
}
public static void main(String[] args) {
TestRemoveEmptyLoop _instance = new TestRemoveEmptyLoop();
public void test_cmp() {
// Loop is OSR compiled, and test_cmp_helper inlined
for (int i = 0; i < 50000; i++) {
_instance.test();
test_cmp_helper();
}
System.out.println("Test passed.");
}
void test_collapse_helper() {
int o = 11;
int e = 43542;
for (int i = 524; i < 19325; i += 1) {
// The empty loop that is supposed to collapse
for (int j = 0; j < 32767; j++) {
o++;
}
for (int k = 0; k < o; k++) {
e++;
}
}
}
public void test_collapse() {
// Loop is OSR compiled, and test_collapse_helper inlined
for (int i = 0; i < 50000; i++) {
test_collapse_helper();
}
}
public static void main(String[] args) {
TestRemoveEmptyLoop _instance = new TestRemoveEmptyLoop();
_instance.test_cmp();
_instance.test_collapse();
System.out.println("Test passed.");
}
}