Skip to content

Commit bac02b6

Browse files
committed
8305189: C2 failed "assert(_outcnt==1) failed: not unique"
Reviewed-by: chagedorn, thartmann
1 parent 62537d2 commit bac02b6

File tree

5 files changed

+154
-0
lines changed

5 files changed

+154
-0
lines changed

src/hotspot/share/opto/loopnode.cpp

+46
Original file line numberDiff line numberDiff line change
@@ -4128,6 +4128,45 @@ void PhaseIdealLoop::eliminate_useless_predicates() {
41284128
}
41294129
}
41304130

4131+
// If a post or main loop is removed due to an assert predicate, the opaque that guards the loop is not needed anymore
4132+
void PhaseIdealLoop::eliminate_useless_zero_trip_guard() {
4133+
if (_zero_trip_guard_opaque_nodes.size() == 0) {
4134+
return;
4135+
}
4136+
Unique_Node_List useful_zero_trip_guard_opaques_nodes;
4137+
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
4138+
IdealLoopTree* lpt = iter.current();
4139+
if (lpt->_child == nullptr && lpt->is_counted()) {
4140+
CountedLoopNode* head = lpt->_head->as_CountedLoop();
4141+
Node* opaque = head->is_canonical_loop_entry();
4142+
if (opaque != nullptr) {
4143+
useful_zero_trip_guard_opaques_nodes.push(opaque);
4144+
}
4145+
}
4146+
}
4147+
for (uint i = 0; i < _zero_trip_guard_opaque_nodes.size(); ++i) {
4148+
OpaqueZeroTripGuardNode* opaque = ((OpaqueZeroTripGuardNode*)_zero_trip_guard_opaque_nodes.at(i));
4149+
DEBUG_ONLY(CountedLoopNode* guarded_loop = opaque->guarded_loop());
4150+
if (!useful_zero_trip_guard_opaques_nodes.member(opaque)) {
4151+
IfNode* iff = opaque->if_node();
4152+
IdealLoopTree* loop = get_loop(iff);
4153+
while (loop != _ltree_root && loop != nullptr) {
4154+
loop = loop->_parent;
4155+
}
4156+
if (loop == nullptr) {
4157+
// unreachable from _ltree_root: zero trip guard is in a newly discovered infinite loop.
4158+
// We can't tell if the opaque node is useful or not
4159+
assert(guarded_loop == nullptr || guarded_loop->is_in_infinite_subgraph(), "");
4160+
} else {
4161+
assert(guarded_loop == nullptr, "");
4162+
this->_igvn.replace_node(opaque, opaque->in(1));
4163+
}
4164+
} else {
4165+
assert(guarded_loop != nullptr, "");
4166+
}
4167+
}
4168+
}
4169+
41314170
//------------------------process_expensive_nodes-----------------------------
41324171
// Expensive nodes have their control input set to prevent the GVN
41334172
// from commoning them and as a result forcing the resulting node to
@@ -4416,6 +4455,8 @@ void PhaseIdealLoop::build_and_optimize() {
44164455
_igvn.remove_globally_dead_node(_deadlist.pop());
44174456
}
44184457

4458+
eliminate_useless_zero_trip_guard();
4459+
44194460
if (stop_early) {
44204461
assert(do_expensive_nodes, "why are we here?");
44214462
if (process_expensive_nodes()) {
@@ -6144,6 +6185,11 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
61446185
IdealLoopTree *chosen_loop = get_loop(least);
61456186
if( !chosen_loop->_child ) // Inner loop?
61466187
chosen_loop->_body.push(n);// Collect inner loops
6188+
6189+
if (!_verify_only && n->Opcode() == Op_OpaqueZeroTripGuard) {
6190+
_zero_trip_guard_opaque_nodes.push(n);
6191+
}
6192+
61476193
}
61486194

61496195
#ifdef ASSERT

src/hotspot/share/opto/loopnode.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ class PhaseIdealLoop : public PhaseTransform {
898898
private:
899899
// clear out dead code after build_loop_late
900900
Node_List _deadlist;
901+
Node_List _zero_trip_guard_opaque_nodes;
901902

902903
// Support for faster execution of get_late_ctrl()/dom_lca()
903904
// when a node has many uses and dominator depth is deep.
@@ -1386,6 +1387,7 @@ class PhaseIdealLoop : public PhaseTransform {
13861387
// Helper function to collect predicate for eliminating the useless ones
13871388
void collect_potentially_useful_predicates(IdealLoopTree *loop, Unique_Node_List &predicate_opaque1);
13881389
void eliminate_useless_predicates();
1390+
void eliminate_useless_zero_trip_guard();
13891391

13901392
// Change the control input of expensive nodes to allow commoning by
13911393
// IGVN when it is guaranteed to not result in a more frequent

src/hotspot/share/opto/opaquenode.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
#include "precompiled.hpp"
26+
#include "opto/loopnode.hpp"
2627
#include "opto/opaquenode.hpp"
2728
#include "opto/phaseX.hpp"
2829

@@ -54,6 +55,43 @@ Node* Opaque3Node::Identity(PhaseGVN* phase) {
5455
return this;
5556
}
5657

58+
#ifdef ASSERT
59+
CountedLoopNode* OpaqueZeroTripGuardNode::guarded_loop() const {
60+
Node* iff = if_node();
61+
ResourceMark rm;
62+
Unique_Node_List wq;
63+
wq.push(iff);
64+
for (uint i = 0; i < wq.size(); ++i) {
65+
Node* nn = wq.at(i);
66+
for (DUIterator_Fast imax, i = nn->fast_outs(imax); i < imax; i++) {
67+
Node* u = nn->fast_out(i);
68+
if (u->is_OuterStripMinedLoop()) {
69+
wq.push(u);
70+
}
71+
if (u->is_CountedLoop() && u->as_CountedLoop()->is_canonical_loop_entry() == this) {
72+
return u->as_CountedLoop();
73+
}
74+
if (u->is_Region()) {
75+
continue;
76+
}
77+
if (u->is_CFG()) {
78+
wq.push(u);
79+
}
80+
}
81+
}
82+
return nullptr;
83+
}
84+
#endif
85+
86+
IfNode* OpaqueZeroTripGuardNode::if_node() const {
87+
Node* cmp = unique_out();
88+
assert(cmp->Opcode() == Op_CmpI, "");
89+
Node* bol = cmp->unique_out();
90+
assert(bol->Opcode() == Op_Bool, "");
91+
Node* iff = bol->unique_out();
92+
return iff->as_If();
93+
}
94+
5795
// Do not allow value-numbering
5896
uint Opaque3Node::hash() const { return NO_HASH; }
5997
bool Opaque3Node::cmp(const Node &n) const {

src/hotspot/share/opto/opaquenode.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,14 @@ class OpaqueZeroTripGuardNode : public Opaque1Node {
7979
OpaqueZeroTripGuardNode(Compile* C, Node* n, BoolTest::mask loop_entered_test) :
8080
Opaque1Node(C, n), _loop_entered_mask(loop_entered_test) {
8181
}
82+
83+
DEBUG_ONLY(CountedLoopNode* guarded_loop() const);
8284
virtual int Opcode() const;
8385
virtual uint size_of() const {
8486
return sizeof(*this);
8587
}
88+
89+
IfNode* if_node() const;
8690
};
8791

8892
//------------------------------Opaque3Node------------------------------------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2023, Red Hat, Inc. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8305189
27+
* @summary C2 failed "assert(_outcnt==1) failed: not unique"
28+
* @library /test/lib
29+
* @run main/othervm -Xcomp -XX:CompileOnly=TestZeroTripGuardShared TestZeroTripGuardShared
30+
*/
31+
32+
import jdk.test.lib.Utils;
33+
34+
public class TestZeroTripGuardShared {
35+
static double dFld1;
36+
static int iArrFld[];
37+
38+
public static void main(String[] strArr) throws Exception {
39+
Thread thread = new Thread() {
40+
public void run() {
41+
test();
42+
}
43+
};
44+
// Give thread some time to trigger compilation
45+
thread.setDaemon(true);
46+
thread.start();
47+
Thread.sleep(Utils.adjustTimeout(500));
48+
}
49+
50+
static void test() {
51+
int i5 = 2, i8 = 2, i9, i11, i12;
52+
while (i8 < 5) {
53+
for (i9 = i8; 6 > i9; i9++) {
54+
for (i11 = 1; i11 > i9; i11 -= 2) {
55+
try {
56+
i12 = iArrFld[i11];
57+
} catch (ArithmeticException a_e) {
58+
}
59+
i5 += dFld1;
60+
}
61+
}
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)