1 /*
   2  * Copyright (c) 2009, 2018, 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 package org.graalvm.compiler.nodes;
  26 
  27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
  28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  29 
  30 import java.util.ArrayList;
  31 import java.util.Arrays;
  32 import java.util.Iterator;
  33 import java.util.List;
  34 import java.util.Objects;
  35 
  36 import jdk.internal.vm.compiler.collections.EconomicMap;
  37 import jdk.internal.vm.compiler.collections.Equivalence;
  38 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
  39 import org.graalvm.compiler.bytecode.Bytecodes;
  40 import org.graalvm.compiler.bytecode.Bytes;
  41 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
  42 import org.graalvm.compiler.core.common.calc.Condition;
  43 import org.graalvm.compiler.core.common.type.IntegerStamp;
  44 import org.graalvm.compiler.core.common.type.Stamp;
  45 import org.graalvm.compiler.core.common.type.StampFactory;
  46 import org.graalvm.compiler.debug.CounterKey;
  47 import org.graalvm.compiler.debug.DebugCloseable;
  48 import org.graalvm.compiler.debug.DebugContext;
  49 import org.graalvm.compiler.debug.GraalError;
  50 import org.graalvm.compiler.graph.Node;
  51 import org.graalvm.compiler.graph.NodeClass;
  52 import org.graalvm.compiler.graph.NodeSourcePosition;
  53 import org.graalvm.compiler.graph.iterators.NodeIterable;
  54 import org.graalvm.compiler.graph.spi.Canonicalizable;
  55 import org.graalvm.compiler.graph.spi.Simplifiable;
  56 import org.graalvm.compiler.graph.spi.SimplifierTool;
  57 import org.graalvm.compiler.nodeinfo.InputType;
  58 import org.graalvm.compiler.nodeinfo.NodeInfo;
  59 import org.graalvm.compiler.nodes.calc.CompareNode;
  60 import org.graalvm.compiler.nodes.calc.ConditionalNode;
  61 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
  62 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
  63 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
  64 import org.graalvm.compiler.nodes.calc.IsNullNode;
  65 import org.graalvm.compiler.nodes.calc.NormalizeCompareNode;
  66 import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
  67 import org.graalvm.compiler.nodes.extended.UnboxNode;
  68 import org.graalvm.compiler.nodes.java.InstanceOfNode;
  69 import org.graalvm.compiler.nodes.java.LoadFieldNode;
  70 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  71 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  72 import org.graalvm.compiler.nodes.util.GraphUtil;
  73 
  74 import jdk.vm.ci.meta.Constant;
  75 import jdk.vm.ci.meta.JavaConstant;
  76 import jdk.vm.ci.meta.JavaKind;
  77 import jdk.vm.ci.meta.MetaAccessProvider;
  78 import jdk.vm.ci.meta.PrimitiveConstant;
  79 import jdk.vm.ci.meta.ResolvedJavaMethod;
  80 import jdk.vm.ci.meta.ResolvedJavaType;
  81 import jdk.vm.ci.meta.TriState;
  82 
  83 /**
  84  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
  85  * of a comparison.
  86  */
  87 @NodeInfo(cycles = CYCLES_1, size = SIZE_2, sizeRationale = "2 jmps")
  88 public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
  89     public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
  90 
  91     private static final CounterKey CORRECTED_PROBABILITIES = DebugContext.counter("CorrectedProbabilities");
  92 
  93     @Successor AbstractBeginNode trueSuccessor;
  94     @Successor AbstractBeginNode falseSuccessor;
  95     @Input(InputType.Condition) LogicNode condition;
  96     protected double trueSuccessorProbability;
  97 
  98     public LogicNode condition() {
  99         return condition;
 100     }
 101 
 102     public void setCondition(LogicNode x) {
 103         updateUsages(condition, x);
 104         condition = x;
 105     }
 106 
 107     public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) {
 108         this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability);
 109     }
 110 
 111     public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) {
 112         super(TYPE, StampFactory.forVoid());
 113         this.condition = condition;
 114         this.falseSuccessor = falseSuccessor;
 115         this.trueSuccessor = trueSuccessor;
 116         setTrueSuccessorProbability(trueSuccessorProbability);
 117     }
 118 
 119     /**
 120      * Gets the true successor.
 121      *
 122      * @return the true successor
 123      */
 124     public AbstractBeginNode trueSuccessor() {
 125         return trueSuccessor;
 126     }
 127 
 128     /**
 129      * Gets the false successor.
 130      *
 131      * @return the false successor
 132      */
 133     public AbstractBeginNode falseSuccessor() {
 134         return falseSuccessor;
 135     }
 136 
 137     public double getTrueSuccessorProbability() {
 138         return this.trueSuccessorProbability;
 139     }
 140 
 141     public void setTrueSuccessor(AbstractBeginNode node) {
 142         updatePredecessor(trueSuccessor, node);
 143         trueSuccessor = node;
 144     }
 145 
 146     public void setFalseSuccessor(AbstractBeginNode node) {
 147         updatePredecessor(falseSuccessor, node);
 148         falseSuccessor = node;
 149     }
 150 
 151     /**
 152      * Gets the node corresponding to the specified outcome of the branch.
 153      *
 154      * @param istrue {@code true} if the true successor is requested, {@code false} otherwise
 155      * @return the corresponding successor
 156      */
 157     public AbstractBeginNode successor(boolean istrue) {
 158         return istrue ? trueSuccessor : falseSuccessor;
 159     }
 160 
 161     public void setTrueSuccessorProbability(double prob) {
 162         assert prob >= -0.000000001 && prob <= 1.000000001 : "Probability out of bounds: " + prob;
 163         trueSuccessorProbability = Math.min(1.0, Math.max(0.0, prob));
 164     }
 165 
 166     @Override
 167     public double probability(AbstractBeginNode successor) {
 168         return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability;
 169     }
 170 
 171     @Override
 172     public void generate(NodeLIRBuilderTool gen) {
 173         gen.emitIf(this);
 174     }
 175 
 176     @Override
 177     public boolean verify() {
 178         assertTrue(condition() != null, "missing condition");
 179         assertTrue(trueSuccessor() != null, "missing trueSuccessor");
 180         assertTrue(falseSuccessor() != null, "missing falseSuccessor");
 181         return super.verify();
 182     }
 183 
 184     private boolean compareCallContext(NodeSourcePosition successorPosition) {
 185         NodeSourcePosition position = getNodeSourcePosition();
 186         NodeSourcePosition successor = successorPosition;
 187         while (position != null) {
 188             assertTrue(Objects.equals(position.getMethod(), successor.getMethod()), "method mismatch");
 189             position = position.getCaller();
 190             successor = successor.getCaller();
 191         }
 192         assertTrue(successor == null, "successor position has more methods");
 193         return true;
 194     }
 195 
 196     @Override
 197     public boolean verifySourcePosition() {
 198         NodeSourcePosition sourcePosition = getNodeSourcePosition();
 199         assertTrue(sourcePosition != null, "missing IfNode source position");
 200 
 201         NodeSourcePosition trueSuccessorPosition = trueSuccessor.getNodeSourcePosition();
 202         assertTrue(trueSuccessorPosition != null, "missing IfNode true successor source position");
 203 
 204         NodeSourcePosition falseSuccessorPosition = falseSuccessor.getNodeSourcePosition();
 205         assertTrue(falseSuccessorPosition != null, "missing IfNode false successor source position");
 206 
 207         int bci = sourcePosition.getBCI();
 208         ResolvedJavaMethod method = sourcePosition.getMethod();
 209         int bytecode = BytecodeDisassembler.getBytecodeAt(method, bci);
 210 
 211         if (!Bytecodes.isIfBytecode(bytecode)) {
 212             return true;
 213         }
 214 
 215         byte[] code = (new ResolvedJavaMethodBytecode(method)).getCode();
 216         int targetBCI = bci + Bytes.beS2(code, bci + 1);
 217         int nextBCI = bci + Bytecodes.lengthOf(bytecode);
 218 
 219         // At least one successor should have the correct BCI to indicate any possible negation that
 220         // occurred after bytecode parsing
 221         boolean matchingSuccessorFound = false;
 222         if (trueSuccessorPosition.getBCI() == nextBCI || trueSuccessorPosition.getBCI() == targetBCI) {
 223             assertTrue(compareCallContext(trueSuccessorPosition), "call context different from IfNode in trueSuccessor");
 224             matchingSuccessorFound = true;
 225         }
 226 
 227         if (falseSuccessorPosition.getBCI() == nextBCI || falseSuccessorPosition.getBCI() == targetBCI) {
 228             assertTrue(compareCallContext(falseSuccessorPosition), "call context different from IfNode in falseSuccessor");
 229             matchingSuccessorFound = true;
 230         }
 231 
 232         assertTrue(matchingSuccessorFound, "no matching successor position found in IfNode");
 233         assertTrue(trueSuccessorPosition.getBCI() != falseSuccessorPosition.getBCI(), "successor positions same in IfNode");
 234 
 235         return true;
 236     }
 237 
 238     public void eliminateNegation() {
 239         AbstractBeginNode oldTrueSuccessor = trueSuccessor;
 240         AbstractBeginNode oldFalseSuccessor = falseSuccessor;
 241         trueSuccessor = oldFalseSuccessor;
 242         falseSuccessor = oldTrueSuccessor;
 243         trueSuccessorProbability = 1 - trueSuccessorProbability;
 244         setCondition(((LogicNegationNode) condition).getValue());
 245     }
 246 
 247     @Override
 248     public void simplify(SimplifierTool tool) {
 249         if (trueSuccessor().next() instanceof DeoptimizeNode) {
 250             if (trueSuccessorProbability != 0) {
 251                 CORRECTED_PROBABILITIES.increment(getDebug());
 252                 trueSuccessorProbability = 0;
 253             }
 254         } else if (falseSuccessor().next() instanceof DeoptimizeNode) {
 255             if (trueSuccessorProbability != 1) {
 256                 CORRECTED_PROBABILITIES.increment(getDebug());
 257                 trueSuccessorProbability = 1;
 258             }
 259         }
 260 
 261         if (condition() instanceof LogicNegationNode) {
 262             eliminateNegation();
 263         }
 264         if (condition() instanceof LogicConstantNode) {
 265             LogicConstantNode c = (LogicConstantNode) condition();
 266             if (c.getValue()) {
 267                 tool.deleteBranch(falseSuccessor());
 268                 tool.addToWorkList(trueSuccessor());
 269                 graph().removeSplit(this, trueSuccessor());
 270             } else {
 271                 tool.deleteBranch(trueSuccessor());
 272                 tool.addToWorkList(falseSuccessor());
 273                 graph().removeSplit(this, falseSuccessor());
 274             }
 275             return;
 276         }
 277         if (tool.allUsagesAvailable() && trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages()) {
 278 
 279             pushNodesThroughIf(tool);
 280 
 281             if (checkForUnsignedCompare(tool) || removeOrMaterializeIf(tool)) {
 282                 return;
 283             }
 284         }
 285 
 286         if (removeIntermediateMaterialization(tool)) {
 287             return;
 288         }
 289 
 290         if (splitIfAtPhi(tool)) {
 291             return;
 292         }
 293 
 294         if (conditionalNodeOptimization(tool)) {
 295             return;
 296         }
 297 
 298         if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
 299             AbstractBeginNode intermediateBegin = falseSuccessor();
 300             IfNode nextIf = (IfNode) intermediateBegin.next();
 301             double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
 302             if (this.trueSuccessorProbability < probabilityB) {
 303                 // Reordering of those two if statements is beneficial from the point of view of
 304                 // their probabilities.
 305                 if (prepareForSwap(tool, condition(), nextIf.condition())) {
 306                     // Reordering is allowed from (if1 => begin => if2) to (if2 => begin => if1).
 307                     assert intermediateBegin.next() == nextIf;
 308                     AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor();
 309                     nextIf.setFalseSuccessor(null);
 310                     intermediateBegin.setNext(null);
 311                     this.setFalseSuccessor(null);
 312 
 313                     this.replaceAtPredecessor(nextIf);
 314                     nextIf.setFalseSuccessor(intermediateBegin);
 315                     intermediateBegin.setNext(this);
 316                     this.setFalseSuccessor(bothFalseBegin);
 317 
 318                     NodeSourcePosition intermediateBeginPosition = intermediateBegin.getNodeSourcePosition();
 319                     intermediateBegin.setNodeSourcePosition(bothFalseBegin.getNodeSourcePosition());
 320                     bothFalseBegin.setNodeSourcePosition(intermediateBeginPosition);
 321 
 322                     nextIf.setTrueSuccessorProbability(probabilityB);
 323                     if (probabilityB == 1.0) {
 324                         this.setTrueSuccessorProbability(0.0);
 325                     } else {
 326                         double newProbability = this.trueSuccessorProbability / (1.0 - probabilityB);
 327                         this.setTrueSuccessorProbability(Math.min(1.0, newProbability));
 328                     }
 329                     return;
 330                 }
 331             }
 332         }
 333 
 334         if (tryEliminateBoxedReferenceEquals(tool)) {
 335             return;
 336         }
 337     }
 338 
 339     private boolean isUnboxedFrom(MetaAccessProvider meta, NodeView view, ValueNode x, ValueNode src) {
 340         if (x == src) {
 341             return true;
 342         } else if (x instanceof UnboxNode) {
 343             return isUnboxedFrom(meta, view, ((UnboxNode) x).getValue(), src);
 344         } else if (x instanceof PiNode) {
 345             PiNode pi = (PiNode) x;
 346             return isUnboxedFrom(meta, view, pi.getOriginalNode(), src);
 347         } else if (x instanceof LoadFieldNode) {
 348             LoadFieldNode load = (LoadFieldNode) x;
 349             ResolvedJavaType integerType = meta.lookupJavaType(Integer.class);
 350             if (load.getValue().stamp(view).javaType(meta).equals(integerType)) {
 351                 return isUnboxedFrom(meta, view, load.getValue(), src);
 352             } else {
 353                 return false;
 354             }
 355         } else {
 356             return false;
 357         }
 358     }
 359 
 360     /**
 361      * Attempts to replace the following pattern:
 362      *
 363      * <pre>
 364      * Integer x = ...;
 365      * Integer y = ...;
 366      * if ((x == y) || x.equals(y)) { ... }
 367      * </pre>
 368      *
 369      * with:
 370      *
 371      * <pre>
 372      * Integer x = ...;
 373      * Integer y = ...;
 374      * if (x.equals(y)) { ... }
 375      * </pre>
 376      *
 377      * whenever the probability that the reference check will pass is relatively small.
 378      *
 379      * See GR-1315 for more information.
 380      */
 381     private boolean tryEliminateBoxedReferenceEquals(SimplifierTool tool) {
 382         if (!(condition instanceof ObjectEqualsNode)) {
 383             return false;
 384         }
 385 
 386         MetaAccessProvider meta = tool.getMetaAccess();
 387         ObjectEqualsNode equalsCondition = (ObjectEqualsNode) condition;
 388         ValueNode x = equalsCondition.getX();
 389         ValueNode y = equalsCondition.getY();
 390         ResolvedJavaType integerType = meta.lookupJavaType(Integer.class);
 391 
 392         // At least one argument for reference equal must be a boxed primitive.
 393         NodeView view = NodeView.from(tool);
 394         if (!x.stamp(view).javaType(meta).equals(integerType) && !y.stamp(view).javaType(meta).equals(integerType)) {
 395             return false;
 396         }
 397 
 398         // The reference equality check is usually more efficient compared to a boxing check.
 399         // The success of the reference equals must therefore be relatively rare, otherwise it makes
 400         // no sense to eliminate it.
 401         if (getTrueSuccessorProbability() > 0.4) {
 402             return false;
 403         }
 404 
 405         // True branch must be empty.
 406         if (trueSuccessor instanceof BeginNode || trueSuccessor instanceof LoopExitNode) {
 407             if (trueSuccessor.next() instanceof EndNode) {
 408                 // Empty true branch.
 409             } else {
 410                 return false;
 411             }
 412         } else {
 413             return false;
 414         }
 415 
 416         // False branch must only check the unboxed values.
 417         UnboxNode unbox = null;
 418         FixedGuardNode unboxCheck = null;
 419         for (FixedNode node : falseSuccessor.getBlockNodes()) {
 420             if (!(node instanceof BeginNode || node instanceof UnboxNode || node instanceof FixedGuardNode || node instanceof EndNode ||
 421                             node instanceof LoadFieldNode || node instanceof LoopExitNode)) {
 422                 return false;
 423             }
 424             if (node instanceof UnboxNode) {
 425                 if (unbox == null) {
 426                     unbox = (UnboxNode) node;
 427                 } else {
 428                     return false;
 429                 }
 430             }
 431             if (!(node instanceof FixedGuardNode)) {
 432                 continue;
 433             }
 434             FixedGuardNode fixed = (FixedGuardNode) node;
 435             if (!(fixed.condition() instanceof IntegerEqualsNode)) {
 436                 continue;
 437             }
 438             IntegerEqualsNode equals = (IntegerEqualsNode) fixed.condition();
 439             if ((isUnboxedFrom(meta, view, equals.getX(), x) && isUnboxedFrom(meta, view, equals.getY(), y)) ||
 440                             (isUnboxedFrom(meta, view, equals.getX(), y) && isUnboxedFrom(meta, view, equals.getY(), x))) {
 441                 unboxCheck = fixed;
 442             }
 443         }
 444         if (unbox == null || unboxCheck == null) {
 445             return false;
 446         }
 447 
 448         // Falsify the reference check.
 449         setCondition(graph().addOrUniqueWithInputs(LogicConstantNode.contradiction()));
 450 
 451         return true;
 452     }
 453 
 454     /**
 455      * Try to optimize this as if it were a {@link ConditionalNode}.
 456      */
 457     private boolean conditionalNodeOptimization(SimplifierTool tool) {
 458         if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
 459             AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
 460             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
 461             if (trueEnd.merge() != falseEnd.merge()) {
 462                 return false;
 463             }
 464             if (!(trueEnd.merge() instanceof MergeNode)) {
 465                 return false;
 466             }
 467             MergeNode merge = (MergeNode) trueEnd.merge();
 468             if (merge.usages().count() != 1 || merge.phis().count() != 1) {
 469                 return false;
 470             }
 471 
 472             if (trueSuccessor().anchored().isNotEmpty() || falseSuccessor().anchored().isNotEmpty()) {
 473                 return false;
 474             }
 475 
 476             PhiNode phi = merge.phis().first();
 477             ValueNode falseValue = phi.valueAt(falseEnd);
 478             ValueNode trueValue = phi.valueAt(trueEnd);
 479 
 480             NodeView view = NodeView.from(tool);
 481             ValueNode result = ConditionalNode.canonicalizeConditional(condition, trueValue, falseValue, phi.stamp(view), view);
 482             if (result != null) {
 483                 /*
 484                  * canonicalizeConditional returns possibly new nodes so add them to the graph.
 485                  */
 486                 if (result.graph() == null) {
 487                     result = graph().addOrUniqueWithInputs(result);
 488                 }
 489                 result = proxyReplacement(result);
 490                 /*
 491                  * This optimization can be performed even if multiple values merge at this phi
 492                  * since the two inputs get simplified into one.
 493                  */
 494                 phi.setValueAt(trueEnd, result);
 495                 removeThroughFalseBranch(tool, merge);
 496                 return true;
 497             }
 498         }
 499 
 500         return false;
 501     }
 502 
 503     private void pushNodesThroughIf(SimplifierTool tool) {
 504         assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
 505         // push similar nodes upwards through the if, thereby deduplicating them
 506         do {
 507             AbstractBeginNode trueSucc = trueSuccessor();
 508             AbstractBeginNode falseSucc = falseSuccessor();
 509             if (trueSucc instanceof BeginNode && falseSucc instanceof BeginNode && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
 510                 FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
 511                 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
 512                 NodeClass<?> nodeClass = trueNext.getNodeClass();
 513                 if (trueNext.getClass() == falseNext.getClass()) {
 514                     if (trueNext instanceof AbstractBeginNode) {
 515                         // Cannot do this optimization for begin nodes, because it could
 516                         // move guards above the if that need to stay below a branch.
 517                     } else if (nodeClass.equalInputs(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
 518                         falseNext.replaceAtUsages(trueNext);
 519                         graph().removeFixed(falseNext);
 520                         GraphUtil.unlinkFixedNode(trueNext);
 521                         graph().addBeforeFixed(this, trueNext);
 522                         for (Node usage : trueNext.usages().snapshot()) {
 523                             if (usage.isAlive()) {
 524                                 NodeClass<?> usageNodeClass = usage.getNodeClass();
 525                                 if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) {
 526                                     Node newNode = graph().findDuplicate(usage);
 527                                     if (newNode != null) {
 528                                         usage.replaceAtUsagesAndDelete(newNode);
 529                                     }
 530                                 }
 531                                 if (usage.isAlive()) {
 532                                     tool.addToWorkList(usage);
 533                                 }
 534                             }
 535                         }
 536                         continue;
 537                     }
 538                 }
 539             }
 540             break;
 541         } while (true);
 542     }
 543 
 544     /**
 545      * Recognize a couple patterns that can be merged into an unsigned compare.
 546      *
 547      * @param tool
 548      * @return true if a replacement was done.
 549      */
 550     @SuppressWarnings("try")
 551     private boolean checkForUnsignedCompare(SimplifierTool tool) {
 552         assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
 553         if (condition() instanceof IntegerLessThanNode) {
 554             NodeView view = NodeView.from(tool);
 555             IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
 556             Constant y = lessThan.getY().stamp(view).asConstant();
 557             if (y instanceof PrimitiveConstant && ((PrimitiveConstant) y).asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
 558                 IfNode ifNode2 = (IfNode) falseSuccessor().next();
 559                 if (ifNode2.condition() instanceof IntegerLessThanNode) {
 560                     IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
 561                     AbstractBeginNode falseSucc = ifNode2.falseSuccessor();
 562                     AbstractBeginNode trueSucc = ifNode2.trueSuccessor();
 563                     IntegerBelowNode below = null;
 564                     /*
 565                      * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
 566                      * <positive> into an unsigned compare.
 567                      */
 568                     if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp(view) instanceof IntegerStamp &&
 569                                     ((IntegerStamp) lessThan2.getY().stamp(view)).isPositive() &&
 570                                     sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
 571                         below = graph().unique(new IntegerBelowNode(lessThan2.getX(), lessThan2.getY()));
 572                         // swap direction
 573                         AbstractBeginNode tmp = falseSucc;
 574                         falseSucc = trueSucc;
 575                         trueSucc = tmp;
 576                     } else if (lessThan2.getY() == lessThan.getX() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
 577                         /*
 578                          * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
 579                          * !(<positive> > x), into x <| positive + 1. This can only be done for
 580                          * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
 581                          * appear to be interesting.
 582                          */
 583                         JavaConstant positive = lessThan2.getX().asJavaConstant();
 584                         if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getJavaKind().getMaxValue()) {
 585                             ConstantNode newLimit = ConstantNode.forIntegerStamp(lessThan2.getX().stamp(view), positive.asLong() + 1, graph());
 586                             below = graph().unique(new IntegerBelowNode(lessThan.getX(), newLimit));
 587                         }
 588                     }
 589                     if (below != null) {
 590                         try (DebugCloseable position = ifNode2.withNodeSourcePosition()) {
 591                             ifNode2.setTrueSuccessor(null);
 592                             ifNode2.setFalseSuccessor(null);
 593 
 594                             IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
 595                             // Remove the < 0 test.
 596                             tool.deleteBranch(trueSuccessor);
 597                             graph().removeSplit(this, falseSuccessor);
 598 
 599                             // Replace the second test with the new one.
 600                             ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
 601                             ifNode2.safeDelete();
 602                             return true;
 603                         }
 604                     }
 605                 }
 606             }
 607         }
 608         return false;
 609     }
 610 
 611     /**
 612      * Check it these two blocks end up at the same place. Meeting at the same merge, or
 613      * deoptimizing in the same way.
 614      */
 615     private static boolean sameDestination(AbstractBeginNode succ1, AbstractBeginNode succ2) {
 616         Node next1 = succ1.next();
 617         Node next2 = succ2.next();
 618         if (next1 instanceof EndNode && next2 instanceof EndNode) {
 619             EndNode end1 = (EndNode) next1;
 620             EndNode end2 = (EndNode) next2;
 621             if (end1.merge() == end2.merge()) {
 622                 for (PhiNode phi : end1.merge().phis()) {
 623                     if (phi.valueAt(end1) != phi.valueAt(end2)) {
 624                         return false;
 625                     }
 626                 }
 627                 // They go to the same MergeNode and merge the same values
 628                 return true;
 629             }
 630         } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
 631             DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
 632             DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
 633             if (deopt1.getReason() == deopt2.getReason() && deopt1.getAction() == deopt2.getAction()) {
 634                 // Same deoptimization reason and action.
 635                 return true;
 636             }
 637         } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) {
 638             LoopExitNode exit1 = (LoopExitNode) next1;
 639             LoopExitNode exit2 = (LoopExitNode) next2;
 640             if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) {
 641                 // Exit the same loop and end up at the same place.
 642                 return true;
 643             }
 644         } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) {
 645             ReturnNode exit1 = (ReturnNode) next1;
 646             ReturnNode exit2 = (ReturnNode) next2;
 647             if (exit1.result() == exit2.result()) {
 648                 // Exit the same loop and end up at the same place.
 649                 return true;
 650             }
 651         }
 652         return false;
 653     }
 654 
 655     private static boolean prepareForSwap(SimplifierTool tool, LogicNode a, LogicNode b) {
 656         DebugContext debug = a.getDebug();
 657         if (a instanceof InstanceOfNode) {
 658             InstanceOfNode instanceOfA = (InstanceOfNode) a;
 659             if (b instanceof IsNullNode) {
 660                 IsNullNode isNullNode = (IsNullNode) b;
 661                 if (isNullNode.getValue() == instanceOfA.getValue()) {
 662                     debug.log("Can swap instanceof and isnull if");
 663                     return true;
 664                 }
 665             } else if (b instanceof InstanceOfNode) {
 666                 InstanceOfNode instanceOfB = (InstanceOfNode) b;
 667                 if (instanceOfA.getValue() == instanceOfB.getValue() && !instanceOfA.type().getType().isInterface() && !instanceOfB.type().getType().isInterface() &&
 668                                 !instanceOfA.type().getType().isAssignableFrom(instanceOfB.type().getType()) && !instanceOfB.type().getType().isAssignableFrom(instanceOfA.type().getType())) {
 669                     // Two instanceof on the same value with mutually exclusive types.
 670                     debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type());
 671                     return true;
 672                 }
 673             }
 674         } else if (a instanceof CompareNode) {
 675             CompareNode compareA = (CompareNode) a;
 676             Condition conditionA = compareA.condition().asCondition();
 677             if (compareA.unorderedIsTrue()) {
 678                 return false;
 679             }
 680             if (b instanceof CompareNode) {
 681                 CompareNode compareB = (CompareNode) b;
 682                 if (compareA == compareB) {
 683                     debug.log("Same conditions => do not swap and leave the work for global value numbering.");
 684                     return false;
 685                 }
 686                 if (compareB.unorderedIsTrue()) {
 687                     return false;
 688                 }
 689                 Condition comparableCondition = null;
 690                 Condition conditionB = compareB.condition().asCondition();
 691                 if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) {
 692                     comparableCondition = conditionB;
 693                 } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) {
 694                     comparableCondition = conditionB.mirror();
 695                 }
 696 
 697                 if (comparableCondition != null) {
 698                     Condition combined = conditionA.join(comparableCondition);
 699                     if (combined == null) {
 700                         // The two conditions are disjoint => can reorder.
 701                         debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition);
 702                         return true;
 703                     }
 704                 } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) {
 705                     boolean canSwap = false;
 706                     if ((compareA.getX() == compareB.getX() && valuesDistinct(tool, compareA.getY(), compareB.getY()))) {
 707                         canSwap = true;
 708                     } else if ((compareA.getX() == compareB.getY() && valuesDistinct(tool, compareA.getY(), compareB.getX()))) {
 709                         canSwap = true;
 710                     } else if ((compareA.getY() == compareB.getX() && valuesDistinct(tool, compareA.getX(), compareB.getY()))) {
 711                         canSwap = true;
 712                     } else if ((compareA.getY() == compareB.getY() && valuesDistinct(tool, compareA.getX(), compareB.getX()))) {
 713                         canSwap = true;
 714                     }
 715 
 716                     if (canSwap) {
 717                         debug.log("Can swap equality condition with one shared and one disjoint value.");
 718                         return true;
 719                     }
 720                 }
 721             }
 722         }
 723 
 724         return false;
 725     }
 726 
 727     private static boolean valuesDistinct(SimplifierTool tool, ValueNode a, ValueNode b) {
 728         if (a.isConstant() && b.isConstant()) {
 729             Boolean equal = tool.getConstantReflection().constantEquals(a.asConstant(), b.asConstant());
 730             if (equal != null) {
 731                 return !equal.booleanValue();
 732             }
 733         }
 734 
 735         NodeView view = NodeView.from(tool);
 736         Stamp stampA = a.stamp(view);
 737         Stamp stampB = b.stamp(view);
 738         return stampA.alwaysDistinct(stampB);
 739     }
 740 
 741     /**
 742      * Tries to remove an empty if construct or replace an if construct with a materialization.
 743      *
 744      * @return true if a transformation was made, false otherwise
 745      */
 746     private boolean removeOrMaterializeIf(SimplifierTool tool) {
 747         assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
 748         if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
 749             AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
 750             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
 751             AbstractMergeNode merge = trueEnd.merge();
 752             if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
 753                 PhiNode singlePhi = null;
 754                 int distinct = 0;
 755                 for (PhiNode phi : merge.phis()) {
 756                     ValueNode trueValue = phi.valueAt(trueEnd);
 757                     ValueNode falseValue = phi.valueAt(falseEnd);
 758                     if (trueValue != falseValue) {
 759                         distinct++;
 760                         singlePhi = phi;
 761                     }
 762                 }
 763                 if (distinct == 0) {
 764                     /*
 765                      * Multiple phis but merging same values for true and false, so simply delete
 766                      * the path
 767                      */
 768                     removeThroughFalseBranch(tool, merge);
 769                     return true;
 770                 } else if (distinct == 1) {
 771                     ValueNode trueValue = singlePhi.valueAt(trueEnd);
 772                     ValueNode falseValue = singlePhi.valueAt(falseEnd);
 773                     ValueNode conditional = canonicalizeConditionalCascade(tool, trueValue, falseValue);
 774                     if (conditional != null) {
 775                         conditional = proxyReplacement(conditional);
 776                         singlePhi.setValueAt(trueEnd, conditional);
 777                         removeThroughFalseBranch(tool, merge);
 778                         return true;
 779                     }
 780                 }
 781             }
 782         }
 783         if (trueSuccessor().next() instanceof ReturnNode && falseSuccessor().next() instanceof ReturnNode) {
 784             ReturnNode trueEnd = (ReturnNode) trueSuccessor().next();
 785             ReturnNode falseEnd = (ReturnNode) falseSuccessor().next();
 786             ValueNode trueValue = trueEnd.result();
 787             ValueNode falseValue = falseEnd.result();
 788             ValueNode value = null;
 789             if (trueValue != null) {
 790                 if (trueValue == falseValue) {
 791                     value = trueValue;
 792                 } else {
 793                     value = canonicalizeConditionalCascade(tool, trueValue, falseValue);
 794                     if (value == null) {
 795                         return false;
 796                     }
 797                 }
 798             }
 799             ReturnNode newReturn = graph().add(new ReturnNode(value));
 800             replaceAtPredecessor(newReturn);
 801             GraphUtil.killCFG(this);
 802             return true;
 803         }
 804         return false;
 805     }
 806 
 807     private ValueNode proxyReplacement(ValueNode replacement) {
 808         /*
 809          * Special case: Every empty diamond we collapse to a conditional node can potentially
 810          * contain loop exit nodes on both branches. See the graph below: The two loop exits
 811          * (instanceof begin node) exit the same loop. The resulting phi is defined outside the
 812          * loop, but the resulting conditional node will be inside the loop, so we need to proxy the
 813          * resulting conditional node. Callers of this method ensure that true and false successor
 814          * have no usages, therefore a and b in the graph below can never be proxies themselves.
 815          */
 816         // @formatter:off
 817         //              +--+
 818         //              |If|
 819         //              +--+      +-----+ +-----+
 820         //         +----+  +----+ |  a  | |  b  |
 821         //         |Lex |  |Lex | +----^+ +^----+
 822         //         +----+  +----+      |   |
 823         //           +-------+         +---+
 824         //           | Merge +---------+Phi|
 825         //           +-------+         +---+
 826         // @formatter:on
 827         if (this.graph().hasValueProxies()) {
 828             if (trueSuccessor instanceof LoopExitNode && falseSuccessor instanceof LoopExitNode) {
 829                 assert ((LoopExitNode) trueSuccessor).loopBegin() == ((LoopExitNode) falseSuccessor).loopBegin();
 830                 /*
 831                  * we can collapse all proxy nodes on one loop exit, the surviving one, which will
 832                  * be the true successor
 833                  */
 834                 if (falseSuccessor.anchored().isEmpty() && falseSuccessor.usages().isNotEmpty()) {
 835                     for (Node n : falseSuccessor.usages().snapshot()) {
 836                         assert n instanceof ProxyNode;
 837                         ((ProxyNode) n).setProxyPoint((LoopExitNode) trueSuccessor);
 838                     }
 839                 }
 840                 /*
 841                  * The true successor (surviving loop exit) can have usages, namely proxy nodes, the
 842                  * false successor however, must not have usages any more after the code above
 843                  */
 844                 assert trueSuccessor.anchored().isEmpty() && falseSuccessor.usages().isEmpty();
 845                 return this.graph().addOrUnique(new ValueProxyNode(replacement, (LoopExitNode) trueSuccessor));
 846             }
 847         }
 848         return replacement;
 849     }
 850 
 851     protected void removeThroughFalseBranch(SimplifierTool tool, AbstractMergeNode merge) {
 852         AbstractBeginNode trueBegin = trueSuccessor();
 853         LogicNode conditionNode = condition();
 854         graph().removeSplitPropagate(this, trueBegin);
 855         tool.addToWorkList(trueBegin);
 856         if (conditionNode != null) {
 857             GraphUtil.tryKillUnused(conditionNode);
 858         }
 859         if (merge.isAlive() && merge.forwardEndCount() > 1) {
 860             for (FixedNode end : merge.forwardEnds()) {
 861                 Node cur = end;
 862                 while (cur != null && cur.predecessor() instanceof BeginNode) {
 863                     cur = cur.predecessor();
 864                 }
 865                 if (cur != null && cur.predecessor() instanceof IfNode) {
 866                     tool.addToWorkList(cur.predecessor());
 867                 }
 868             }
 869         }
 870     }
 871 
 872     private ValueNode canonicalizeConditionalViaImplies(ValueNode trueValue, ValueNode falseValue) {
 873         ValueNode collapsedTrue = trueValue;
 874         ValueNode collapsedFalse = falseValue;
 875         boolean simplify = false;
 876         if (trueValue instanceof ConditionalNode) {
 877             TriState result = condition().implies(false, ((ConditionalNode) trueValue).condition());
 878             if (result.isKnown()) {
 879                 simplify = true;
 880                 collapsedTrue = result.toBoolean() ? ((ConditionalNode) trueValue).trueValue() : ((ConditionalNode) trueValue).falseValue();
 881             }
 882         }
 883         if (falseValue instanceof ConditionalNode) {
 884             TriState result = condition().implies(true, ((ConditionalNode) falseValue).condition());
 885             if (result.isKnown()) {
 886                 simplify = true;
 887                 collapsedFalse = result.toBoolean() ? ((ConditionalNode) falseValue).trueValue() : ((ConditionalNode) falseValue).falseValue();
 888             }
 889         }
 890         if (simplify) {
 891             return graph().unique(new ConditionalNode(condition(), collapsedTrue, collapsedFalse));
 892         }
 893         return null;
 894     }
 895 
 896     private ValueNode canonicalizeConditionalCascade(SimplifierTool tool, ValueNode trueValue, ValueNode falseValue) {
 897         if (trueValue.getStackKind() != falseValue.getStackKind()) {
 898             return null;
 899         }
 900         if (trueValue.getStackKind() != JavaKind.Int && trueValue.getStackKind() != JavaKind.Long) {
 901             return null;
 902         }
 903         if (trueValue.isConstant() && falseValue.isConstant()) {
 904             return graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
 905         }
 906         ValueNode value = canonicalizeConditionalViaImplies(trueValue, falseValue);
 907         if (value != null) {
 908             return value;
 909         }
 910         if (!graph().isAfterExpandLogic()) {
 911             /*
 912              * !isAfterExpandLogic() => Cannot spawn NormalizeCompareNodes after lowering in the
 913              * ExpandLogicPhase.
 914              */
 915             ConditionalNode conditional = null;
 916             ValueNode constant = null;
 917             boolean negateCondition;
 918             if (trueValue instanceof ConditionalNode && falseValue.isConstant()) {
 919                 conditional = (ConditionalNode) trueValue;
 920                 constant = falseValue;
 921                 negateCondition = true;
 922             } else if (falseValue instanceof ConditionalNode && trueValue.isConstant()) {
 923                 conditional = (ConditionalNode) falseValue;
 924                 constant = trueValue;
 925                 negateCondition = false;
 926             } else {
 927                 return null;
 928             }
 929             boolean negateConditionalCondition = false;
 930             ValueNode otherValue = null;
 931             if (constant == conditional.trueValue()) {
 932                 otherValue = conditional.falseValue();
 933                 negateConditionalCondition = false;
 934             } else if (constant == conditional.falseValue()) {
 935                 otherValue = conditional.trueValue();
 936                 negateConditionalCondition = true;
 937             }
 938             if (otherValue != null && otherValue.isConstant()) {
 939                 double shortCutProbability = probability(trueSuccessor());
 940                 LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability);
 941                 return graph().unique(new ConditionalNode(newCondition, constant, otherValue));
 942             }
 943 
 944             if (constant.isJavaConstant() && conditional.trueValue().isJavaConstant() && conditional.falseValue().isJavaConstant() && condition() instanceof CompareNode &&
 945                             conditional.condition() instanceof CompareNode) {
 946 
 947                 Condition cond1 = ((CompareNode) condition()).condition().asCondition();
 948                 if (negateCondition) {
 949                     cond1 = cond1.negate();
 950                 }
 951                 // cond1 is EQ, NE, LT, or GE
 952                 Condition cond2 = ((CompareNode) conditional.condition()).condition().asCondition();
 953                 ValueNode x = ((CompareNode) condition()).getX();
 954                 ValueNode y = ((CompareNode) condition()).getY();
 955                 ValueNode x2 = ((CompareNode) conditional.condition()).getX();
 956                 ValueNode y2 = ((CompareNode) conditional.condition()).getY();
 957                 // `x cond1 y ? c1 : (x2 cond2 y2 ? c2 : c3)`
 958                 boolean sameVars = x == x2 && y == y2;
 959                 if (!sameVars && x == y2 && y == x2) {
 960                     sameVars = true;
 961                     cond2 = cond2.mirror();
 962                 }
 963                 if (sameVars) {
 964                     JavaKind stackKind = conditional.trueValue().stamp(NodeView.from(tool)).getStackKind();
 965                     assert !stackKind.isNumericFloat();
 966 
 967                     ValueNode v1 = constant;
 968                     ValueNode v2 = conditional.trueValue();
 969                     ValueNode v3 = conditional.falseValue();
 970 
 971                     long c1 = v1.asJavaConstant().asLong();
 972                     long c2 = v2.asJavaConstant().asLong();
 973                     long c3 = v3.asJavaConstant().asLong();
 974 
 975                     if (cond1 == Condition.LT && cond2 == Condition.EQ && c1 == -1 && c2 == 0 && c3 == 1) {
 976                         // x < y ? -1 : (x == y ? 0 : 1) => x cmp y
 977                         return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
 978                     } else if (cond1 == Condition.LT && cond2 == Condition.EQ && c1 == 1 && c2 == 0 && c3 == -1) {
 979                         // x < y ? 1 : (x == y ? 0 : -1) => y cmp x
 980                         return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
 981                     } else if (cond1 == Condition.EQ && cond2 == Condition.LT && c1 == 0 && c2 == -1 && c3 == 1) {
 982                         // x == y ? 0 : (x < y ? -1 : 1) => x cmp y
 983                         return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
 984                     } else if (cond1 == Condition.EQ && cond2 == Condition.LT && c1 == 0 && c2 == 1 && c3 == -1) {
 985                         // x == y ? 0 : (x < y ? 1 : -1) => y cmp x
 986                         return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
 987                     } else if (cond1 == Condition.EQ && cond2 == Condition.GT && c1 == 0 && c2 == -1 && c3 == 1) {
 988                         // x == y ? 0 : (x > y ? -1 : 1) => y cmp x
 989                         return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
 990                     } else if (cond1 == Condition.EQ && cond2 == Condition.GT && c1 == 0 && c2 == 1 && c3 == -1) {
 991                         // x == y ? 0 : (x > y ? 1 : -1) => x cmp y
 992                         return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
 993                     } else if (cond1 == Condition.LT && cond2 == Condition.GT && c1 == 1 && c2 == -1 && c3 == 0) {
 994                         // x < y ? 1 : (x > y ? -1 : 0) => y cmp x
 995                         return graph().unique(new NormalizeCompareNode(y, x, stackKind, false));
 996                     } else if (cond1 == Condition.LT && cond2 == Condition.GT && c1 == -1 && c2 == 1 && c3 == 0) {
 997                         // x < y ? -1 : (x > y ? 1 : 0) => x cmp y
 998                         return graph().unique(new NormalizeCompareNode(x, y, stackKind, false));
 999                     }
1000                 }
1001             }
1002         }
1003         return null;
1004     }
1005 
1006     /**
1007      * Take an if that is immediately dominated by a merge with a single phi and split off any paths
1008      * where the test would be statically decidable creating a new merge below the approriate side
1009      * of the IfNode. Any undecidable tests will continue to use the original IfNode.
1010      *
1011      * @param tool
1012      */
1013     @SuppressWarnings("try")
1014     private boolean splitIfAtPhi(SimplifierTool tool) {
1015         if (graph().getGuardsStage().areFrameStatesAtSideEffects()) {
1016             // Disabled until we make sure we have no FrameState-less merges at this stage
1017             return false;
1018         }
1019 
1020         if (!(predecessor() instanceof MergeNode)) {
1021             return false;
1022         }
1023         MergeNode merge = (MergeNode) predecessor();
1024         if (merge.forwardEndCount() == 1) {
1025             // Don't bother.
1026             return false;
1027         }
1028         if (merge.usages().count() != 1 || merge.phis().count() != 1) {
1029             return false;
1030         }
1031         if (merge.stateAfter() != null) {
1032             /* We'll get the chance to simplify this after frame state assignment. */
1033             return false;
1034         }
1035         PhiNode phi = merge.phis().first();
1036         if (phi.usages().count() != 1) {
1037             /*
1038              * For simplicity the below code assumes assumes the phi goes dead at the end so skip
1039              * this case.
1040              */
1041             return false;
1042         }
1043 
1044         /*
1045          * Check that the condition uses the phi and that there is only one user of the condition
1046          * expression.
1047          */
1048         if (!conditionUses(condition(), phi)) {
1049             return false;
1050         }
1051 
1052         /*
1053          * We could additionally filter for the case that at least some of the Phi inputs or one of
1054          * the condition inputs are constants but there are cases where a non-constant is
1055          * simplifiable, usually where the stamp allows the question to be answered.
1056          */
1057 
1058         /* Each successor of the if gets a new merge if needed. */
1059         MergeNode trueMerge = null;
1060         MergeNode falseMerge = null;
1061         assert merge.stateAfter() == null;
1062 
1063         for (EndNode end : merge.forwardEnds().snapshot()) {
1064             Node value = phi.valueAt(end);
1065             LogicNode result = computeCondition(tool, condition, phi, value);
1066             if (result instanceof LogicConstantNode) {
1067                 merge.removeEnd(end);
1068                 if (((LogicConstantNode) result).getValue()) {
1069                     if (trueMerge == null) {
1070                         trueMerge = insertMerge(trueSuccessor());
1071                     }
1072                     trueMerge.addForwardEnd(end);
1073                 } else {
1074                     if (falseMerge == null) {
1075                         falseMerge = insertMerge(falseSuccessor());
1076                     }
1077                     falseMerge.addForwardEnd(end);
1078                 }
1079             } else if (result != condition) {
1080                 // Build a new IfNode using the new condition
1081                 BeginNode trueBegin = graph().add(new BeginNode());
1082                 trueBegin.setNodeSourcePosition(trueSuccessor().getNodeSourcePosition());
1083                 BeginNode falseBegin = graph().add(new BeginNode());
1084                 falseBegin.setNodeSourcePosition(falseSuccessor().getNodeSourcePosition());
1085 
1086                 if (result.graph() == null) {
1087                     result = graph().addOrUniqueWithInputs(result);
1088                     result.setNodeSourcePosition(condition.getNodeSourcePosition());
1089                 }
1090                 IfNode newIfNode = graph().add(new IfNode(result, trueBegin, falseBegin, trueSuccessorProbability));
1091                 newIfNode.setNodeSourcePosition(getNodeSourcePosition());
1092                 merge.removeEnd(end);
1093                 ((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
1094 
1095                 if (trueMerge == null) {
1096                     trueMerge = insertMerge(trueSuccessor());
1097                 }
1098                 trueBegin.setNext(graph().add(new EndNode()));
1099                 trueMerge.addForwardEnd((EndNode) trueBegin.next());
1100 
1101                 if (falseMerge == null) {
1102                     falseMerge = insertMerge(falseSuccessor());
1103                 }
1104                 falseBegin.setNext(graph().add(new EndNode()));
1105                 falseMerge.addForwardEnd((EndNode) falseBegin.next());
1106 
1107                 end.safeDelete();
1108             }
1109         }
1110 
1111         transferProxies(trueSuccessor(), trueMerge);
1112         transferProxies(falseSuccessor(), falseMerge);
1113 
1114         cleanupMerge(merge);
1115         cleanupMerge(trueMerge);
1116         cleanupMerge(falseMerge);
1117 
1118         return true;
1119     }
1120 
1121     /**
1122      * @param condition
1123      * @param phi
1124      * @return true if the passed in {@code condition} uses {@code phi} and the condition is only
1125      *         used once. Since the phi will go dead the condition using it will also have to be
1126      *         dead after the optimization.
1127      */
1128     private static boolean conditionUses(LogicNode condition, PhiNode phi) {
1129         if (condition.usages().count() != 1) {
1130             return false;
1131         }
1132         if (condition instanceof ShortCircuitOrNode) {
1133             if (condition.graph().getGuardsStage().areDeoptsFixed()) {
1134                 /*
1135                  * It can be unsafe to simplify a ShortCircuitOr before deopts are fixed because
1136                  * conversion to guards assumes that all the required conditions are being tested.
1137                  * Simplfying the condition based on context before this happens may lose a
1138                  * condition.
1139                  */
1140                 ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
1141                 return (conditionUses(orNode.x, phi) || conditionUses(orNode.y, phi));
1142             }
1143         } else if (condition instanceof Canonicalizable.Unary<?>) {
1144             Canonicalizable.Unary<?> unary = (Canonicalizable.Unary<?>) condition;
1145             return unary.getValue() == phi;
1146         } else if (condition instanceof Canonicalizable.Binary<?>) {
1147             Canonicalizable.Binary<?> binary = (Canonicalizable.Binary<?>) condition;
1148             return binary.getX() == phi || binary.getY() == phi;
1149         }
1150         return false;
1151     }
1152 
1153     /**
1154      * Canonicalize {@code} condition using {@code value} in place of {@code phi}.
1155      *
1156      * @param tool
1157      * @param condition
1158      * @param phi
1159      * @param value
1160      * @return an improved LogicNode or the original condition
1161      */
1162     @SuppressWarnings("unchecked")
1163     private static LogicNode computeCondition(SimplifierTool tool, LogicNode condition, PhiNode phi, Node value) {
1164         if (condition instanceof ShortCircuitOrNode) {
1165             if (condition.graph().getGuardsStage().areDeoptsFixed() && !condition.graph().isAfterExpandLogic()) {
1166                 ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
1167                 LogicNode resultX = computeCondition(tool, orNode.x, phi, value);
1168                 LogicNode resultY = computeCondition(tool, orNode.y, phi, value);
1169                 if (resultX != orNode.x || resultY != orNode.y) {
1170                     LogicNode result = orNode.canonical(tool, resultX, resultY);
1171                     if (result != orNode) {
1172                         return result;
1173                     }
1174                     /*
1175                      * Create a new node to carry the optimized inputs.
1176                      */
1177                     ShortCircuitOrNode newOr = new ShortCircuitOrNode(resultX, orNode.xNegated, resultY,
1178                                     orNode.yNegated, orNode.getShortCircuitProbability());
1179                     return newOr.canonical(tool);
1180                 }
1181                 return orNode;
1182             }
1183         } else if (condition instanceof Canonicalizable.Binary<?>) {
1184             Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition;
1185             if (compare.getX() == phi) {
1186                 return (LogicNode) compare.canonical(tool, value, compare.getY());
1187             } else if (compare.getY() == phi) {
1188                 return (LogicNode) compare.canonical(tool, compare.getX(), value);
1189             }
1190         } else if (condition instanceof Canonicalizable.Unary<?>) {
1191             Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition;
1192             if (compare.getValue() == phi) {
1193                 return (LogicNode) compare.canonical(tool, value);
1194             }
1195         }
1196         if (condition instanceof Canonicalizable) {
1197             return (LogicNode) ((Canonicalizable) condition).canonical(tool);
1198         }
1199         return condition;
1200     }
1201 
1202     private static void transferProxies(AbstractBeginNode successor, MergeNode falseMerge) {
1203         if (successor instanceof LoopExitNode && falseMerge != null) {
1204             LoopExitNode loopExitNode = (LoopExitNode) successor;
1205             for (ProxyNode proxy : loopExitNode.proxies().snapshot()) {
1206                 proxy.replaceFirstInput(successor, falseMerge);
1207             }
1208         }
1209     }
1210 
1211     private void cleanupMerge(MergeNode merge) {
1212         if (merge != null && merge.isAlive()) {
1213             if (merge.forwardEndCount() == 0) {
1214                 GraphUtil.killCFG(merge);
1215             } else if (merge.forwardEndCount() == 1) {
1216                 graph().reduceTrivialMerge(merge);
1217             }
1218         }
1219     }
1220 
1221     @SuppressWarnings("try")
1222     private MergeNode insertMerge(AbstractBeginNode begin) {
1223         MergeNode merge = graph().add(new MergeNode());
1224         if (!begin.anchored().isEmpty()) {
1225             Object before = null;
1226             before = begin.anchored().snapshot();
1227             begin.replaceAtUsages(InputType.Guard, merge);
1228             begin.replaceAtUsages(InputType.Anchor, merge);
1229             assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot();
1230         }
1231 
1232         AbstractBeginNode theBegin = begin;
1233         if (begin instanceof LoopExitNode) {
1234             // Insert an extra begin to make it easier.
1235             try (DebugCloseable position = begin.withNodeSourcePosition()) {
1236                 theBegin = graph().add(new BeginNode());
1237                 begin.replaceAtPredecessor(theBegin);
1238                 theBegin.setNext(begin);
1239             }
1240         }
1241         FixedNode next = theBegin.next();
1242         next.replaceAtPredecessor(merge);
1243         theBegin.setNext(graph().add(new EndNode()));
1244         merge.addForwardEnd((EndNode) theBegin.next());
1245         merge.setNext(next);
1246         return merge;
1247     }
1248 
1249     /**
1250      * Tries to connect code that initializes a variable directly with the successors of an if
1251      * construct that switches on the variable. For example, the pseudo code below:
1252      *
1253      * <pre>
1254      * contains(list, e, yes, no) {
1255      *     if (list == null || e == null) {
1256      *         condition = false;
1257      *     } else {
1258      *         condition = false;
1259      *         for (i in list) {
1260      *             if (i.equals(e)) {
1261      *                 condition = true;
1262      *                 break;
1263      *             }
1264      *         }
1265      *     }
1266      *     if (condition) {
1267      *         return yes;
1268      *     } else {
1269      *         return no;
1270      *     }
1271      * }
1272      * </pre>
1273      *
1274      * will be transformed into:
1275      *
1276      * <pre>
1277      * contains(list, e, yes, no) {
1278      *     if (list == null || e == null) {
1279      *         return no;
1280      *     } else {
1281      *         condition = false;
1282      *         for (i in list) {
1283      *             if (i.equals(e)) {
1284      *                 return yes;
1285      *             }
1286      *         }
1287      *         return no;
1288      *     }
1289      * }
1290      * </pre>
1291      *
1292      * @return true if a transformation was made, false otherwise
1293      */
1294     private boolean removeIntermediateMaterialization(SimplifierTool tool) {
1295         if (!(predecessor() instanceof AbstractMergeNode) || predecessor() instanceof LoopBeginNode) {
1296             return false;
1297         }
1298         AbstractMergeNode merge = (AbstractMergeNode) predecessor();
1299 
1300         if (!(condition() instanceof CompareNode)) {
1301             return false;
1302         }
1303 
1304         CompareNode compare = (CompareNode) condition();
1305         if (compare.getUsageCount() != 1) {
1306             return false;
1307         }
1308 
1309         // Only consider merges with a single usage that is both a phi and an operand of the
1310         // comparison
1311         NodeIterable<Node> mergeUsages = merge.usages();
1312         if (mergeUsages.count() != 1) {
1313             return false;
1314         }
1315         Node singleUsage = mergeUsages.first();
1316         if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.getX() && singleUsage != compare.getY())) {
1317             return false;
1318         }
1319 
1320         // Ensure phi is used by at most the comparison and the merge's frame state (if any)
1321         ValuePhiNode phi = (ValuePhiNode) singleUsage;
1322         NodeIterable<Node> phiUsages = phi.usages();
1323         if (phiUsages.count() > 2) {
1324             return false;
1325         }
1326         for (Node usage : phiUsages) {
1327             if (usage != compare && usage != merge.stateAfter()) {
1328                 return false;
1329             }
1330         }
1331 
1332         List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
1333         assert phi.valueCount() == merge.forwardEndCount();
1334 
1335         Constant[] xs = constantValues(compare.getX(), merge, false);
1336         Constant[] ys = constantValues(compare.getY(), merge, false);
1337         if (xs == null || ys == null) {
1338             return false;
1339         }
1340 
1341         // Sanity check that both ends are not followed by a merge without frame state.
1342         if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) {
1343             return false;
1344         }
1345 
1346         List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
1347         List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
1348         EconomicMap<AbstractEndNode, ValueNode> phiValues = EconomicMap.create(Equivalence.IDENTITY, mergePredecessors.size());
1349 
1350         AbstractBeginNode oldFalseSuccessor = falseSuccessor();
1351         AbstractBeginNode oldTrueSuccessor = trueSuccessor();
1352 
1353         setFalseSuccessor(null);
1354         setTrueSuccessor(null);
1355 
1356         Iterator<EndNode> ends = mergePredecessors.iterator();
1357         for (int i = 0; i < xs.length; i++) {
1358             EndNode end = ends.next();
1359             phiValues.put(end, phi.valueAt(end));
1360             if (compare.condition().foldCondition(xs[i], ys[i], tool.getConstantReflection(), compare.unorderedIsTrue())) {
1361                 trueEnds.add(end);
1362             } else {
1363                 falseEnds.add(end);
1364             }
1365         }
1366         assert !ends.hasNext();
1367         assert falseEnds.size() + trueEnds.size() == xs.length;
1368 
1369         connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool);
1370         connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool);
1371 
1372         if (this.trueSuccessorProbability == 0.0) {
1373             for (AbstractEndNode endNode : trueEnds) {
1374                 propagateZeroProbability(endNode);
1375             }
1376         }
1377 
1378         if (this.trueSuccessorProbability == 1.0) {
1379             for (AbstractEndNode endNode : falseEnds) {
1380                 propagateZeroProbability(endNode);
1381             }
1382         }
1383 
1384         /*
1385          * Remove obsolete ends only after processing all ends, otherwise oldTrueSuccessor or
1386          * oldFalseSuccessor might have been removed if it is a LoopExitNode.
1387          */
1388         if (falseEnds.isEmpty()) {
1389             GraphUtil.killCFG(oldFalseSuccessor);
1390         }
1391         if (trueEnds.isEmpty()) {
1392             GraphUtil.killCFG(oldTrueSuccessor);
1393         }
1394         GraphUtil.killCFG(merge);
1395 
1396         assert !merge.isAlive() : merge;
1397         assert !phi.isAlive() : phi;
1398         assert !compare.isAlive() : compare;
1399         assert !this.isAlive() : this;
1400 
1401         return true;
1402     }
1403 
1404     private void propagateZeroProbability(FixedNode startNode) {
1405         Node prev = null;
1406         for (FixedNode node : GraphUtil.predecessorIterable(startNode)) {
1407             if (node instanceof IfNode) {
1408                 IfNode ifNode = (IfNode) node;
1409                 if (ifNode.trueSuccessor() == prev) {
1410                     if (ifNode.trueSuccessorProbability == 0.0) {
1411                         return;
1412                     } else if (ifNode.trueSuccessorProbability == 1.0) {
1413                         continue;
1414                     } else {
1415                         ifNode.setTrueSuccessorProbability(0.0);
1416                         return;
1417                     }
1418                 } else if (ifNode.falseSuccessor() == prev) {
1419                     if (ifNode.trueSuccessorProbability == 1.0) {
1420                         return;
1421                     } else if (ifNode.trueSuccessorProbability == 0.0) {
1422                         continue;
1423                     } else {
1424                         ifNode.setTrueSuccessorProbability(1.0);
1425                         return;
1426                     }
1427                 } else {
1428                     throw new GraalError("Illegal state");
1429                 }
1430             } else if (node instanceof AbstractMergeNode && !(node instanceof LoopBeginNode)) {
1431                 for (AbstractEndNode endNode : ((AbstractMergeNode) node).cfgPredecessors()) {
1432                     propagateZeroProbability(endNode);
1433                 }
1434                 return;
1435             }
1436             prev = node;
1437         }
1438     }
1439 
1440     private static boolean checkFrameState(FixedNode start) {
1441         FixedNode node = start;
1442         while (true) {
1443             if (node instanceof AbstractMergeNode) {
1444                 AbstractMergeNode mergeNode = (AbstractMergeNode) node;
1445                 if (mergeNode.stateAfter() == null) {
1446                     return false;
1447                 } else {
1448                     return true;
1449                 }
1450             } else if (node instanceof StateSplit) {
1451                 StateSplit stateSplitNode = (StateSplit) node;
1452                 if (stateSplitNode.stateAfter() != null) {
1453                     return true;
1454                 }
1455             }
1456 
1457             if (node instanceof ControlSplitNode) {
1458                 ControlSplitNode controlSplitNode = (ControlSplitNode) node;
1459                 for (Node succ : controlSplitNode.cfgSuccessors()) {
1460                     if (checkFrameState((FixedNode) succ)) {
1461                         return true;
1462                     }
1463                 }
1464                 return false;
1465             } else if (node instanceof FixedWithNextNode) {
1466                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
1467                 node = fixedWithNextNode.next();
1468             } else if (node instanceof AbstractEndNode) {
1469                 AbstractEndNode endNode = (AbstractEndNode) node;
1470                 node = endNode.merge();
1471             } else if (node instanceof ControlSinkNode) {
1472                 return true;
1473             } else {
1474                 return false;
1475             }
1476         }
1477     }
1478 
1479     /**
1480      * Connects a set of ends to a given successor, inserting a merge node if there is more than one
1481      * end. If {@code ends} is not empty, then {@code successor} is added to {@code tool}'s
1482      * {@linkplain SimplifierTool#addToWorkList(org.graalvm.compiler.graph.Node) work list}.
1483      *
1484      * @param oldMerge the merge being removed
1485      * @param phiValues the values of the phi at the merge, keyed by the merge ends
1486      */
1487     private void connectEnds(List<EndNode> ends, EconomicMap<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) {
1488         if (!ends.isEmpty()) {
1489             if (ends.size() == 1) {
1490                 AbstractEndNode end = ends.get(0);
1491                 ((FixedWithNextNode) end.predecessor()).setNext(successor);
1492                 oldMerge.removeEnd(end);
1493                 GraphUtil.killCFG(end);
1494             } else {
1495                 // Need a new phi in case the frame state is used by more than the merge being
1496                 // removed.
1497                 NodeView view = NodeView.from(tool);
1498                 AbstractMergeNode newMerge = graph().add(new MergeNode());
1499                 PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
1500                 PhiNode newPhi = graph().addWithoutUnique(new ValuePhiNode(oldPhi.stamp(view), newMerge));
1501 
1502                 for (EndNode end : ends) {
1503                     newPhi.addInput(phiValues.get(end));
1504                     newMerge.addForwardEnd(end);
1505                 }
1506 
1507                 FrameState stateAfter = oldMerge.stateAfter();
1508                 if (stateAfter != null) {
1509                     stateAfter = stateAfter.duplicate();
1510                     stateAfter.replaceFirstInput(oldPhi, newPhi);
1511                     newMerge.setStateAfter(stateAfter);
1512                 }
1513 
1514                 newMerge.setNext(successor);
1515             }
1516             tool.addToWorkList(successor);
1517         }
1518     }
1519 
1520     /**
1521      * Gets an array of constants derived from a node that is either a {@link ConstantNode} or a
1522      * {@link PhiNode} whose input values are all constants. The length of the returned array is
1523      * equal to the number of ends terminating in a given merge node.
1524      *
1525      * @return null if {@code node} is neither a {@link ConstantNode} nor a {@link PhiNode} whose
1526      *         input values are all constants
1527      */
1528     public static Constant[] constantValues(ValueNode node, AbstractMergeNode merge, boolean allowNull) {
1529         if (node.isConstant()) {
1530             Constant[] result = new Constant[merge.forwardEndCount()];
1531             Arrays.fill(result, node.asConstant());
1532             return result;
1533         }
1534 
1535         if (node instanceof PhiNode) {
1536             PhiNode phi = (PhiNode) node;
1537             if (phi.merge() == merge && phi instanceof ValuePhiNode && phi.valueCount() == merge.forwardEndCount()) {
1538                 Constant[] result = new Constant[merge.forwardEndCount()];
1539                 int i = 0;
1540                 for (ValueNode n : phi.values()) {
1541                     if (!allowNull && !n.isConstant()) {
1542                         return null;
1543                     }
1544                     result[i++] = n.asConstant();
1545                 }
1546                 return result;
1547             }
1548         }
1549 
1550         return null;
1551     }
1552 
1553     @Override
1554     public AbstractBeginNode getPrimarySuccessor() {
1555         return null;
1556     }
1557 
1558     public AbstractBeginNode getSuccessor(boolean result) {
1559         return result ? this.trueSuccessor() : this.falseSuccessor();
1560     }
1561 
1562     @Override
1563     public boolean setProbability(AbstractBeginNode successor, double value) {
1564         if (successor == this.trueSuccessor()) {
1565             this.setTrueSuccessorProbability(value);
1566             return true;
1567         } else if (successor == this.falseSuccessor()) {
1568             this.setTrueSuccessorProbability(1.0 - value);
1569             return true;
1570         }
1571         return false;
1572     }
1573 
1574     @Override
1575     public int getSuccessorCount() {
1576         return 2;
1577     }
1578 }