Skip to content

Commit

Permalink
8293996: C2: fix and simplify IdealLoopTree::do_remove_empty_loop
Browse files Browse the repository at this point in the history
Backport-of: dd51f7e0b75d3a16403608d89cd206ac0bedf882
  • Loading branch information
GoeLin committed Jan 9, 2023
1 parent 80eecc5 commit 369dedb
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 27 deletions.
34 changes: 13 additions & 21 deletions src/hotspot/share/opto/loopTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3234,29 +3234,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;
}
Expand Down
41 changes: 35 additions & 6 deletions test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -34,22 +35,50 @@

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 {
throw new RuntimeException("Test failed.");
}
}

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();
}
}

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();
}
System.out.println("Test passed.");
}

public static void main(String[] args) {
TestRemoveEmptyLoop _instance = new TestRemoveEmptyLoop();
_instance.test_cmp();
_instance.test_collapse();
System.out.println("Test passed.");
}
}

1 comment on commit 369dedb

@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.