Skip to content

Commit 75e37b0

Browse files
committed
8370332: C2 SuperWord: SIGSEGV because PhaseIdealLoop::split_thru_phi left dead nodes in loop _body
Reviewed-by: chagedorn, roland
1 parent 50bb92a commit 75e37b0

File tree

5 files changed

+134
-15
lines changed

5 files changed

+134
-15
lines changed

src/hotspot/share/opto/loopnode.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,9 @@ class PhaseIdealLoop : public PhaseTransform {
17421742
}
17431743
};
17441744

1745+
1746+
void split_thru_phi_yank_old_nodes(Node* n, Node* region);
1747+
17451748
public:
17461749

17471750
// Conversion of fill/copy patterns into intrinsic versions

src/hotspot/share/opto/loopopts.cpp

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) {
228228
}
229229
}
230230

231+
split_thru_phi_yank_old_nodes(n, region);
232+
_igvn.replace_node(n, phi);
233+
231234
#ifndef PRODUCT
232235
if (TraceLoopOpts) {
233236
tty->print_cr("Split %d %s through %d Phi in %d %s",
@@ -238,6 +241,28 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) {
238241
return phi;
239242
}
240243

244+
// If the region is a Loop, we are removing the old n,
245+
// and need to yank it from the _body. If any phi we
246+
// just split through now has no use any more, it also
247+
// has to be removed.
248+
void PhaseIdealLoop::split_thru_phi_yank_old_nodes(Node* n, Node* region) {
249+
IdealLoopTree* region_loop = get_loop(region);
250+
if (region->is_Loop() && region_loop->is_innermost()) {
251+
region_loop->_body.yank(n);
252+
for (uint j = 1; j < n->req(); j++) {
253+
PhiNode* phi = n->in(j)->isa_Phi();
254+
// Check that phi belongs to the region and only has n as a use.
255+
if (phi != nullptr &&
256+
phi->in(0) == region &&
257+
phi->unique_multiple_edges_out_or_null() == n) {
258+
assert(get_ctrl(phi) == region, "sanity");
259+
assert(get_ctrl(n) == region, "sanity");
260+
region_loop->_body.yank(phi);
261+
}
262+
}
263+
}
264+
}
265+
241266
// Test whether node 'x' can move into an inner loop relative to node 'n'.
242267
// Note: The test is not exact. Returns true if 'x' COULD end up in an inner loop,
243268
// BUT it can also return true and 'x' is in the outer loop
@@ -1207,13 +1232,10 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) {
12071232

12081233
if (must_throttle_split_if()) return n;
12091234

1210-
// Split 'n' through the merge point if it is profitable
1211-
Node *phi = split_thru_phi( n, n_blk, policy );
1212-
if (!phi) return n;
1235+
// Split 'n' through the merge point if it is profitable, replacing it with a new phi.
1236+
Node* phi = split_thru_phi(n, n_blk, policy);
1237+
if (phi == nullptr) { return n; }
12131238

1214-
// Found a Phi to split thru!
1215-
// Replace 'n' with the new phi
1216-
_igvn.replace_node( n, phi );
12171239
// Moved a load around the loop, 'en-registering' something.
12181240
if (n_blk->is_Loop() && n->is_Load() &&
12191241
!phi->in(LoopNode::LoopBackControl)->is_Load())
@@ -1444,15 +1466,9 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
14441466
return;
14451467
}
14461468

1447-
// Found a Phi to split thru!
1448-
// Replace 'n' with the new phi
1449-
_igvn.replace_node(n, phi);
1450-
14511469
// Now split the bool up thru the phi
1452-
Node *bolphi = split_thru_phi(bol, n_ctrl, -1);
1470+
Node* bolphi = split_thru_phi(bol, n_ctrl, -1);
14531471
guarantee(bolphi != nullptr, "null boolean phi node");
1454-
1455-
_igvn.replace_node(bol, bolphi);
14561472
assert(iff->in(1) == bolphi, "");
14571473

14581474
if (bolphi->Value(&_igvn)->singleton()) {
@@ -1461,8 +1477,7 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
14611477

14621478
// Conditional-move? Must split up now
14631479
if (!iff->is_If()) {
1464-
Node *cmovphi = split_thru_phi(iff, n_ctrl, -1);
1465-
_igvn.replace_node(iff, cmovphi);
1480+
Node* cmovphi = split_thru_phi(iff, n_ctrl, -1);
14661481
return;
14671482
}
14681483

src/hotspot/share/opto/node.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,6 +2889,20 @@ Node* Node::find_similar(int opc) {
28892889
return nullptr;
28902890
}
28912891

2892+
Node* Node::unique_multiple_edges_out_or_null() const {
2893+
Node* use = nullptr;
2894+
for (DUIterator_Fast kmax, k = fast_outs(kmax); k < kmax; k++) {
2895+
Node* u = fast_out(k);
2896+
if (use == nullptr) {
2897+
use = u; // first use
2898+
} else if (u != use) {
2899+
return nullptr; // not unique
2900+
} else {
2901+
// secondary use
2902+
}
2903+
}
2904+
return use;
2905+
}
28922906

28932907
//--------------------------unique_ctrl_out_or_null-------------------------
28942908
// Return the unique control out if only one. Null if none or more than one.

src/hotspot/share/opto/node.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,13 @@ class Node {
422422
Node* raw_out(uint i) const { assert(i < _outcnt,"oob"); return _out[i]; }
423423
// Return the unique out edge.
424424
Node* unique_out() const { assert(_outcnt==1,"not unique"); return _out[0]; }
425+
426+
// In some cases, a node n is only used by a single use, but the use may use
427+
// n once or multiple times:
428+
// use = ConvF2I(this)
429+
// use = AddI(this, this)
430+
Node* unique_multiple_edges_out_or_null() const;
431+
425432
// Delete out edge at position 'i' by moving last out edge to position 'i'
426433
void raw_del_out(uint i) {
427434
assert(i < _outcnt,"oob");
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. 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 id=with-flags
26+
* @bug 8370332
27+
* @summary This test shows a case where split_if split a node through a phi, but left the
28+
* dead node and a dead phi in the loop _body. Subsequently, SuperWord was run, and
29+
* found the dead nodes in the _body, which is not expected.
30+
* @run main/othervm
31+
* -XX:CompileCommand=compileonly,*TestSplitThruPhiRemoveDeadNodesFromLoopBody::test
32+
* -Xbatch
33+
* compiler.loopopts.superword.TestSplitThruPhiRemoveDeadNodesFromLoopBody
34+
*/
35+
36+
/*
37+
* @test id=vanilla
38+
* @bug 8370332
39+
* @run main compiler.loopopts.superword.TestSplitThruPhiRemoveDeadNodesFromLoopBody
40+
*/
41+
42+
package compiler.loopopts.superword;
43+
44+
public class TestSplitThruPhiRemoveDeadNodesFromLoopBody {
45+
static int N = 400;
46+
static float floatZero = 0;
47+
static boolean falseFlag = false;;
48+
49+
static int fieldStore = 0;
50+
static int fieldIncr = 0;
51+
static int arrayI[] = new int[N];
52+
53+
static void inlined() {
54+
int x = 0;
55+
for (int i = 0; i < 100; i++) {
56+
fieldStore = 42;
57+
if (falseFlag) {
58+
for (int k = 0; k < 20; k++) {
59+
x += i;
60+
}
61+
}
62+
}
63+
}
64+
65+
static void test() {
66+
inlined();
67+
for (int k = 0; k < 10; k++) {
68+
for (int j = 0; j < 100; j++) {
69+
fieldIncr += floatZero;
70+
arrayI[j] = 42; // SuperWord happens here -> SIGSEGV
71+
}
72+
}
73+
}
74+
75+
public static void main(String[] strArr) {
76+
for (int i = 0; i < 1_000; i++) {
77+
test();
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)