Skip to content

Commit 3cb3cde

Browse files
committed
Don't canonicalize conditional cascade meeting at a single merge
1 parent 91e3748 commit 3cb3cde

File tree

2 files changed

+55
-7
lines changed
  • compiler/src

2 files changed

+55
-7
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/EarlyGVNTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -204,6 +204,7 @@ public void test01() {
204204
public static void snippet02(@SuppressWarnings("unused") int[] arr) {
205205
int i = 0;
206206
while (true) {
207+
GraalDirectives.controlFlowAnchor();
207208
@SuppressWarnings("unused")
208209
int len = field;
209210
if (i < 10) {
@@ -287,6 +288,7 @@ public static int snippet05(Y y) {
287288
int res = 0;
288289
int i = 0;
289290
while (true) {
291+
GraalDirectives.controlFlowAnchor();
290292
res = y.y;
291293
if (i < 10) {
292294
y.y = i;

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_1;
2828
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_2;
29+
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.VERY_FAST_PATH_PROBABILITY;
2930

3031
import java.util.ArrayList;
3132
import java.util.Arrays;
@@ -1438,13 +1439,15 @@ assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages() : Asserti
14381439
if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
14391440
PhiNode singlePhi = null;
14401441
int distinct = 0;
1442+
boolean allConstant = true;
14411443
for (PhiNode phi : merge.phis()) {
14421444
ValueNode trueValue = phi.valueAt(trueEnd);
14431445
ValueNode falseValue = phi.valueAt(falseEnd);
14441446
if (trueValue != falseValue) {
14451447
distinct++;
14461448
singlePhi = phi;
14471449
}
1450+
allConstant &= (trueValue.isConstant() && falseValue.isConstant());
14481451
}
14491452
if (distinct == 0) {
14501453
/*
@@ -1457,14 +1460,57 @@ assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages() : Asserti
14571460
// Fortify: Suppress Null Dereference false positive
14581461
assert singlePhi != null;
14591462

1463+
boolean shouldTryToCanonicalizeConditional = true;
1464+
if (!allConstant &&
1465+
predecessor() instanceof AbstractBeginNode prevBegin &&
1466+
predecessor().predecessor() instanceof IfNode precedingIf &&
1467+
precedingIf.probability(prevBegin) < VERY_FAST_PATH_PROBABILITY) {
1468+
AbstractBeginNode otherSuccessor = precedingIf.successor(true) == prevBegin ? precedingIf.successor(false) : precedingIf.successor(true);
1469+
if (otherSuccessor.next() instanceof AbstractEndNode otherEnd && otherEnd.merge() == merge) {
1470+
/**
1471+
* We have a shape like this (omitting begin/end pairs):
1472+
*
1473+
* <pre>
1474+
* If // precedingIf
1475+
* | \
1476+
* | If // this
1477+
* | | \
1478+
* | | |
1479+
* Merge
1480+
* </pre>
1481+
*
1482+
* For example, fully unrolling a loop that has side exits can give this
1483+
* shape, where all the unrolled iterations' side exits meet up at one
1484+
* merge.
1485+
* <p/>
1486+
*
1487+
* If we replace this node by a floating conditional, the preceding If
1488+
* will then be in a shape where its ends meet up at the same merge, so
1489+
* we will get here and turn it into a conditional too. If there are
1490+
* more preceding ifs in the cascade, we would turn them into
1491+
* conditionals too, and so on. Overall we would move all the code
1492+
* controlled by a sequence of Ifs into one block where everything is
1493+
* computed unconditionally and we then pick out the result we want.
1494+
* This is unlikely to be worth it in general.
1495+
* <p/>
1496+
*
1497+
* We only allow this transformation if all phi inputs are constants,
1498+
* this allows us to cover some useful cases (see TrichotomyTest).
1499+
*/
1500+
shouldTryToCanonicalizeConditional = false;
1501+
}
1502+
}
1503+
14601504
ValueNode trueValue = singlePhi.valueAt(trueEnd);
14611505
ValueNode falseValue = singlePhi.valueAt(falseEnd);
1462-
ValueNode conditional = canonicalizeConditionalCascade(tool, trueValue, falseValue);
1463-
if (conditional != null) {
1464-
conditional = proxyReplacement(conditional);
1465-
singlePhi.setValueAt(trueEnd, conditional);
1466-
removeThroughFalseBranch(tool, merge);
1467-
return true;
1506+
if (shouldTryToCanonicalizeConditional) {
1507+
ValueNode conditional = canonicalizeConditionalCascade(tool, trueValue, falseValue);
1508+
if (conditional != null) {
1509+
conditional = proxyReplacement(conditional);
1510+
singlePhi.setValueAt(trueEnd, conditional);
1511+
removeThroughFalseBranch(tool, merge);
1512+
return true;
1513+
}
14681514
}
14691515
/*-
14701516
* Remove this pattern:

0 commit comments

Comments
 (0)