1 /*
   2  * Copyright (c) 2009, 2015, 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 package org.graalvm.compiler.nodes;
  24 
  25 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  26 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.Iterator;
  31 import java.util.List;
  32 
  33 import org.graalvm.compiler.core.common.calc.Condition;
  34 import org.graalvm.compiler.core.common.type.IntegerStamp;
  35 import org.graalvm.compiler.core.common.type.Stamp;
  36 import org.graalvm.compiler.core.common.type.StampFactory;
  37 import org.graalvm.compiler.debug.CounterKey;
  38 import org.graalvm.compiler.debug.DebugContext;
  39 import org.graalvm.compiler.debug.GraalError;
  40 import org.graalvm.compiler.graph.Node;
  41 import org.graalvm.compiler.graph.NodeClass;
  42 import org.graalvm.compiler.graph.iterators.NodeIterable;
  43 import org.graalvm.compiler.graph.spi.Canonicalizable;
  44 import org.graalvm.compiler.graph.spi.Simplifiable;
  45 import org.graalvm.compiler.graph.spi.SimplifierTool;
  46 import org.graalvm.compiler.nodeinfo.InputType;
  47 import org.graalvm.compiler.nodeinfo.NodeInfo;
  48 import org.graalvm.compiler.nodes.calc.CompareNode;
  49 import org.graalvm.compiler.nodes.calc.ConditionalNode;
  50 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
  51 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
  52 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
  53 import org.graalvm.compiler.nodes.calc.IsNullNode;
  54 import org.graalvm.compiler.nodes.calc.NormalizeCompareNode;
  55 import org.graalvm.compiler.nodes.java.InstanceOfNode;
  56 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  57 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  58 import org.graalvm.compiler.nodes.util.GraphUtil;
  59 import org.graalvm.util.EconomicMap;
  60 import org.graalvm.util.Equivalence;
  61 
  62 import jdk.vm.ci.meta.Constant;
  63 import jdk.vm.ci.meta.ConstantReflectionProvider;
  64 import jdk.vm.ci.meta.JavaConstant;
  65 import jdk.vm.ci.meta.JavaKind;
  66 import jdk.vm.ci.meta.PrimitiveConstant;
  67 
  68 /**
  69  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
  70  * of a comparison.
  71  */
  72 @NodeInfo(cycles = CYCLES_2, size = SIZE_2, sizeRationale = "2 jmps")
  73 public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
  74     public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
  75 
  76     private static final CounterKey CORRECTED_PROBABILITIES = DebugContext.counter("CorrectedProbabilities");
  77 
  78     @Successor AbstractBeginNode trueSuccessor;
  79     @Successor AbstractBeginNode falseSuccessor;
  80     @Input(InputType.Condition) LogicNode condition;
  81     protected double trueSuccessorProbability;
  82 
  83     public LogicNode condition() {
  84         return condition;
  85     }
  86 
  87     public void setCondition(LogicNode x) {
  88         updateUsages(condition, x);
  89         condition = x;
  90     }
  91 
  92     public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) {
  93         this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability);
  94     }
  95 
  96     public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) {
  97         super(TYPE, StampFactory.forVoid());
  98         this.condition = condition;
  99         this.falseSuccessor = falseSuccessor;
 100         this.trueSuccessor = trueSuccessor;
 101         setTrueSuccessorProbability(trueSuccessorProbability);
 102     }
 103 
 104     /**
 105      * Gets the true successor.
 106      *
 107      * @return the true successor
 108      */
 109     public AbstractBeginNode trueSuccessor() {
 110         return trueSuccessor;
 111     }
 112 
 113     /**
 114      * Gets the false successor.
 115      *
 116      * @return the false successor
 117      */
 118     public AbstractBeginNode falseSuccessor() {
 119         return falseSuccessor;
 120     }
 121 
 122     public double getTrueSuccessorProbability() {
 123         return this.trueSuccessorProbability;
 124     }
 125 
 126     public void setTrueSuccessor(AbstractBeginNode node) {
 127         updatePredecessor(trueSuccessor, node);
 128         trueSuccessor = node;
 129     }
 130 
 131     public void setFalseSuccessor(AbstractBeginNode node) {
 132         updatePredecessor(falseSuccessor, node);
 133         falseSuccessor = node;
 134     }
 135 
 136     /**
 137      * Gets the node corresponding to the specified outcome of the branch.
 138      *
 139      * @param istrue {@code true} if the true successor is requested, {@code false} otherwise
 140      * @return the corresponding successor
 141      */
 142     public AbstractBeginNode successor(boolean istrue) {
 143         return istrue ? trueSuccessor : falseSuccessor;
 144     }
 145 
 146     public void setTrueSuccessorProbability(double prob) {
 147         assert prob >= -0.000000001 && prob <= 1.000000001 : "Probability out of bounds: " + prob;
 148         trueSuccessorProbability = Math.min(1.0, Math.max(0.0, prob));
 149     }
 150 
 151     @Override
 152     public double probability(AbstractBeginNode successor) {
 153         return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability;
 154     }
 155 
 156     @Override
 157     public void generate(NodeLIRBuilderTool gen) {
 158         gen.emitIf(this);
 159     }
 160 
 161     @Override
 162     public boolean verify() {
 163         assertTrue(condition() != null, "missing condition");
 164         assertTrue(trueSuccessor() != null, "missing trueSuccessor");
 165         assertTrue(falseSuccessor() != null, "missing falseSuccessor");
 166         return super.verify();
 167     }
 168 
 169     public void eliminateNegation() {
 170         AbstractBeginNode oldTrueSuccessor = trueSuccessor;
 171         AbstractBeginNode oldFalseSuccessor = falseSuccessor;
 172         trueSuccessor = oldFalseSuccessor;
 173         falseSuccessor = oldTrueSuccessor;
 174         trueSuccessorProbability = 1 - trueSuccessorProbability;
 175         setCondition(((LogicNegationNode) condition).getValue());
 176     }
 177 
 178     @Override
 179     public void simplify(SimplifierTool tool) {
 180         if (trueSuccessor().next() instanceof DeoptimizeNode) {
 181             if (trueSuccessorProbability != 0) {
 182                 CORRECTED_PROBABILITIES.increment(getDebug());
 183                 trueSuccessorProbability = 0;
 184             }
 185         } else if (falseSuccessor().next() instanceof DeoptimizeNode) {
 186             if (trueSuccessorProbability != 1) {
 187                 CORRECTED_PROBABILITIES.increment(getDebug());
 188                 trueSuccessorProbability = 1;
 189             }
 190         }
 191 
 192         if (condition() instanceof LogicNegationNode) {
 193             eliminateNegation();
 194         }
 195         if (condition() instanceof LogicConstantNode) {
 196             LogicConstantNode c = (LogicConstantNode) condition();
 197             if (c.getValue()) {
 198                 tool.deleteBranch(falseSuccessor());
 199                 tool.addToWorkList(trueSuccessor());
 200                 graph().removeSplit(this, trueSuccessor());
 201             } else {
 202                 tool.deleteBranch(trueSuccessor());
 203                 tool.addToWorkList(falseSuccessor());
 204                 graph().removeSplit(this, falseSuccessor());
 205             }
 206             return;
 207         }
 208         if (tool.allUsagesAvailable() && trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages()) {
 209 
 210             pushNodesThroughIf(tool);
 211 
 212             if (checkForUnsignedCompare(tool) || removeOrMaterializeIf(tool)) {
 213                 return;
 214             }
 215         }
 216 
 217         if (removeIntermediateMaterialization(tool)) {
 218             return;
 219         }
 220 
 221         if (splitIfAtPhi(tool)) {
 222             return;
 223         }
 224 
 225         if (conditionalNodeOptimization(tool)) {
 226             return;
 227         }
 228 
 229         if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
 230             AbstractBeginNode intermediateBegin = falseSuccessor();
 231             IfNode nextIf = (IfNode) intermediateBegin.next();
 232             double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
 233             if (this.trueSuccessorProbability < probabilityB) {
 234                 // Reordering of those two if statements is beneficial from the point of view of
 235                 // their probabilities.
 236                 if (prepareForSwap(tool.getConstantReflection(), condition(), nextIf.condition())) {
 237                     // Reordering is allowed from (if1 => begin => if2) to (if2 => begin => if1).
 238                     assert intermediateBegin.next() == nextIf;
 239                     AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor();
 240                     nextIf.setFalseSuccessor(null);
 241                     intermediateBegin.setNext(null);
 242                     this.setFalseSuccessor(null);
 243 
 244                     this.replaceAtPredecessor(nextIf);
 245                     nextIf.setFalseSuccessor(intermediateBegin);
 246                     intermediateBegin.setNext(this);
 247                     this.setFalseSuccessor(bothFalseBegin);
 248                     nextIf.setTrueSuccessorProbability(probabilityB);
 249                     if (probabilityB == 1.0) {
 250                         this.setTrueSuccessorProbability(0.0);
 251                     } else {
 252                         double newProbability = this.trueSuccessorProbability / (1.0 - probabilityB);
 253                         this.setTrueSuccessorProbability(Math.min(1.0, newProbability));
 254                     }
 255                     return;
 256                 }
 257             }
 258         }
 259     }
 260 
 261     /**
 262      * Try to optimize this as if it were a {@link ConditionalNode}.
 263      */
 264     private boolean conditionalNodeOptimization(SimplifierTool tool) {
 265         if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
 266             AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
 267             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
 268             if (trueEnd.merge() != falseEnd.merge()) {
 269                 return false;
 270             }
 271             if (!(trueEnd.merge() instanceof MergeNode)) {
 272                 return false;
 273             }
 274             MergeNode merge = (MergeNode) trueEnd.merge();
 275             if (merge.usages().count() != 1 || merge.phis().count() != 1) {
 276                 return false;
 277             }
 278 
 279             if (trueSuccessor().anchored().isNotEmpty() || falseSuccessor().anchored().isNotEmpty()) {
 280                 return false;
 281             }
 282 
 283             PhiNode phi = merge.phis().first();
 284             ValueNode falseValue = phi.valueAt(falseEnd);
 285             ValueNode trueValue = phi.valueAt(trueEnd);
 286 
 287             ValueNode result = ConditionalNode.canonicalizeConditional(condition, trueValue, falseValue, phi.stamp());
 288             if (result != null) {
 289                 /*
 290                  * canonicalizeConditional returns possibly new nodes so add them to the graph.
 291                  */
 292                 if (result.graph() == null) {
 293                     result = graph().addOrUniqueWithInputs(result);
 294                 }
 295                 /*
 296                  * This optimization can be performed even if multiple values merge at this phi
 297                  * since the two inputs get simplified into one.
 298                  */
 299                 phi.setValueAt(trueEnd, result);
 300                 removeThroughFalseBranch(tool, merge);
 301                 return true;
 302             }
 303         }
 304 
 305         return false;
 306     }
 307 
 308     private void pushNodesThroughIf(SimplifierTool tool) {
 309         assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
 310         // push similar nodes upwards through the if, thereby deduplicating them
 311         do {
 312             AbstractBeginNode trueSucc = trueSuccessor();
 313             AbstractBeginNode falseSucc = falseSuccessor();
 314             if (trueSucc instanceof BeginNode && falseSucc instanceof BeginNode && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
 315                 FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
 316                 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
 317                 NodeClass<?> nodeClass = trueNext.getNodeClass();
 318                 if (trueNext.getClass() == falseNext.getClass()) {
 319                     if (trueNext instanceof AbstractBeginNode) {
 320                         // Cannot do this optimization for begin nodes, because it could
 321                         // move guards above the if that need to stay below a branch.
 322                     } else if (nodeClass.equalInputs(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
 323                         falseNext.replaceAtUsages(trueNext);
 324                         graph().removeFixed(falseNext);
 325                         GraphUtil.unlinkFixedNode(trueNext);
 326                         graph().addBeforeFixed(this, trueNext);
 327                         for (Node usage : trueNext.usages().snapshot()) {
 328                             if (usage.isAlive()) {
 329                                 NodeClass<?> usageNodeClass = usage.getNodeClass();
 330                                 if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) {
 331                                     Node newNode = graph().findDuplicate(usage);
 332                                     if (newNode != null) {
 333                                         usage.replaceAtUsagesAndDelete(newNode);
 334                                     }
 335                                 }
 336                                 if (usage.isAlive()) {
 337                                     tool.addToWorkList(usage);
 338                                 }
 339                             }
 340                         }
 341                         continue;
 342                     }
 343                 }
 344             }
 345             break;
 346         } while (true);
 347     }
 348 
 349     /**
 350      * Recognize a couple patterns that can be merged into an unsigned compare.
 351      *
 352      * @param tool
 353      * @return true if a replacement was done.
 354      */
 355     private boolean checkForUnsignedCompare(SimplifierTool tool) {
 356         assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
 357         if (condition() instanceof IntegerLessThanNode) {
 358             IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
 359             Constant y = lessThan.getY().stamp().asConstant();
 360             if (y instanceof PrimitiveConstant && ((PrimitiveConstant) y).asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
 361                 IfNode ifNode2 = (IfNode) falseSuccessor().next();
 362                 if (ifNode2.condition() instanceof IntegerLessThanNode) {
 363                     IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
 364                     AbstractBeginNode falseSucc = ifNode2.falseSuccessor();
 365                     AbstractBeginNode trueSucc = ifNode2.trueSuccessor();
 366                     IntegerBelowNode below = null;
 367                     /*
 368                      * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
 369                      * <positive> into an unsigned compare.
 370                      */
 371                     if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.getY().stamp()).isPositive() &&
 372                                     sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
 373                         below = graph().unique(new IntegerBelowNode(lessThan2.getX(), lessThan2.getY()));
 374                         // swap direction
 375                         AbstractBeginNode tmp = falseSucc;
 376                         falseSucc = trueSucc;
 377                         trueSucc = tmp;
 378                     } else if (lessThan2.getY() == lessThan.getX() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
 379                         /*
 380                          * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
 381                          * !(<positive> > x), into x <| positive + 1. This can only be done for
 382                          * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
 383                          * appear to be interesting.
 384                          */
 385                         JavaConstant positive = lessThan2.getX().asJavaConstant();
 386                         if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getJavaKind().getMaxValue()) {
 387                             ConstantNode newLimit = ConstantNode.forIntegerStamp(lessThan2.getX().stamp(), positive.asLong() + 1, graph());
 388                             below = graph().unique(new IntegerBelowNode(lessThan.getX(), newLimit));
 389                         }
 390                     }
 391                     if (below != null) {
 392                         ifNode2.setTrueSuccessor(null);
 393                         ifNode2.setFalseSuccessor(null);
 394 
 395                         IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
 396                         // Remove the < 0 test.
 397                         tool.deleteBranch(trueSuccessor);
 398                         graph().removeSplit(this, falseSuccessor);
 399 
 400                         // Replace the second test with the new one.
 401                         ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
 402                         ifNode2.safeDelete();
 403                         return true;
 404                     }
 405                 }
 406             }
 407         }
 408         return false;
 409     }
 410 
 411     /**
 412      * Check it these two blocks end up at the same place. Meeting at the same merge, or
 413      * deoptimizing in the same way.
 414      */
 415     private static boolean sameDestination(AbstractBeginNode succ1, AbstractBeginNode succ2) {
 416         Node next1 = succ1.next();
 417         Node next2 = succ2.next();
 418         if (next1 instanceof EndNode && next2 instanceof EndNode) {
 419             EndNode end1 = (EndNode) next1;
 420             EndNode end2 = (EndNode) next2;
 421             if (end1.merge() == end2.merge()) {
 422                 for (PhiNode phi : end1.merge().phis()) {
 423                     if (phi.valueAt(end1) != phi.valueAt(end2)) {
 424                         return false;
 425                     }
 426                 }
 427                 // They go to the same MergeNode and merge the same values
 428                 return true;
 429             }
 430         } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
 431             DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
 432             DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
 433             if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) {
 434                 // Same deoptimization reason and action.
 435                 return true;
 436             }
 437         } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) {
 438             LoopExitNode exit1 = (LoopExitNode) next1;
 439             LoopExitNode exit2 = (LoopExitNode) next2;
 440             if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) {
 441                 // Exit the same loop and end up at the same place.
 442                 return true;
 443             }
 444         } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) {
 445             ReturnNode exit1 = (ReturnNode) next1;
 446             ReturnNode exit2 = (ReturnNode) next2;
 447             if (exit1.result() == exit2.result()) {
 448                 // Exit the same loop and end up at the same place.
 449                 return true;
 450             }
 451         }
 452         return false;
 453     }
 454 
 455     private static boolean prepareForSwap(ConstantReflectionProvider constantReflection, LogicNode a, LogicNode b) {
 456         DebugContext debug = a.getDebug();
 457         if (a instanceof InstanceOfNode) {
 458             InstanceOfNode instanceOfA = (InstanceOfNode) a;
 459             if (b instanceof IsNullNode) {
 460                 IsNullNode isNullNode = (IsNullNode) b;
 461                 if (isNullNode.getValue() == instanceOfA.getValue()) {
 462                     debug.log("Can swap instanceof and isnull if");
 463                     return true;
 464                 }
 465             } else if (b instanceof InstanceOfNode) {
 466                 InstanceOfNode instanceOfB = (InstanceOfNode) b;
 467                 if (instanceOfA.getValue() == instanceOfB.getValue() && !instanceOfA.type().getType().isInterface() && !instanceOfB.type().getType().isInterface() &&
 468                                 !instanceOfA.type().getType().isAssignableFrom(instanceOfB.type().getType()) && !instanceOfB.type().getType().isAssignableFrom(instanceOfA.type().getType())) {
 469                     // Two instanceof on the same value with mutually exclusive types.
 470                     debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type());
 471                     return true;
 472                 }
 473             }
 474         } else if (a instanceof CompareNode) {
 475             CompareNode compareA = (CompareNode) a;
 476             Condition conditionA = compareA.condition();
 477             if (compareA.unorderedIsTrue()) {
 478                 return false;
 479             }
 480             if (b instanceof CompareNode) {
 481                 CompareNode compareB = (CompareNode) b;
 482                 if (compareA == compareB) {
 483                     debug.log("Same conditions => do not swap and leave the work for global value numbering.");
 484                     return false;
 485                 }
 486                 if (compareB.unorderedIsTrue()) {
 487                     return false;
 488                 }
 489                 Condition comparableCondition = null;
 490                 Condition conditionB = compareB.condition();
 491                 if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) {
 492                     comparableCondition = conditionB;
 493                 } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) {
 494                     comparableCondition = conditionB.mirror();
 495                 }
 496 
 497                 if (comparableCondition != null) {
 498                     Condition combined = conditionA.join(comparableCondition);
 499                     if (combined == null) {
 500                         // The two conditions are disjoint => can reorder.
 501                         debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition);
 502                         return true;
 503                     }
 504                 } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) {
 505                     boolean canSwap = false;
 506                     if ((compareA.getX() == compareB.getX() && valuesDistinct(constantReflection, compareA.getY(), compareB.getY()))) {
 507                         canSwap = true;
 508                     } else if ((compareA.getX() == compareB.getY() && valuesDistinct(constantReflection, compareA.getY(), compareB.getX()))) {
 509                         canSwap = true;
 510                     } else if ((compareA.getY() == compareB.getX() && valuesDistinct(constantReflection, compareA.getX(), compareB.getY()))) {
 511                         canSwap = true;
 512                     } else if ((compareA.getY() == compareB.getY() && valuesDistinct(constantReflection, compareA.getX(), compareB.getX()))) {
 513                         canSwap = true;
 514                     }
 515 
 516                     if (canSwap) {
 517                         debug.log("Can swap equality condition with one shared and one disjoint value.");
 518                         return true;
 519                     }
 520                 }
 521             }
 522         }
 523 
 524         return false;
 525     }
 526 
 527     private static boolean valuesDistinct(ConstantReflectionProvider constantReflection, ValueNode a, ValueNode b) {
 528         if (a.isConstant() && b.isConstant()) {
 529             Boolean equal = constantReflection.constantEquals(a.asConstant(), b.asConstant());
 530             if (equal != null) {
 531                 return !equal.booleanValue();
 532             }
 533         }
 534 
 535         Stamp stampA = a.stamp();
 536         Stamp stampB = b.stamp();
 537         return stampA.alwaysDistinct(stampB);
 538     }
 539 
 540     /**
 541      * Tries to remove an empty if construct or replace an if construct with a materialization.
 542      *
 543      * @return true if a transformation was made, false otherwise
 544      */
 545     private boolean removeOrMaterializeIf(SimplifierTool tool) {
 546         assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
 547         if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
 548             AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
 549             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
 550             AbstractMergeNode merge = trueEnd.merge();
 551             if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
 552                 PhiNode singlePhi = null;
 553                 int distinct = 0;
 554                 for (PhiNode phi : merge.phis()) {
 555                     ValueNode trueValue = phi.valueAt(trueEnd);
 556                     ValueNode falseValue = phi.valueAt(falseEnd);
 557                     if (trueValue != falseValue) {
 558                         distinct++;
 559                         singlePhi = phi;
 560                     }
 561                 }
 562                 if (distinct == 0) {
 563                     /*
 564                      * Multiple phis but merging same values for true and false, so simply delete
 565                      * the path
 566                      */
 567                     removeThroughFalseBranch(tool, merge);
 568                     return true;
 569                 } else if (distinct == 1) {
 570                     ValueNode trueValue = singlePhi.valueAt(trueEnd);
 571                     ValueNode falseValue = singlePhi.valueAt(falseEnd);
 572                     ValueNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
 573                     if (conditional != null) {
 574                         singlePhi.setValueAt(trueEnd, conditional);
 575                         removeThroughFalseBranch(tool, merge);
 576                         return true;
 577                     }
 578                 }
 579             }
 580         }
 581         if (trueSuccessor().next() instanceof ReturnNode && falseSuccessor().next() instanceof ReturnNode) {
 582             ReturnNode trueEnd = (ReturnNode) trueSuccessor().next();
 583             ReturnNode falseEnd = (ReturnNode) falseSuccessor().next();
 584             ValueNode trueValue = trueEnd.result();
 585             ValueNode falseValue = falseEnd.result();
 586             ValueNode value = null;
 587             if (trueValue != null) {
 588                 if (trueValue == falseValue) {
 589                     value = trueValue;
 590                 } else {
 591                     value = canonicalizeConditionalCascade(trueValue, falseValue);
 592                     if (value == null) {
 593                         return false;
 594                     }
 595                 }
 596             }
 597             ReturnNode newReturn = graph().add(new ReturnNode(value));
 598             replaceAtPredecessor(newReturn);
 599             GraphUtil.killCFG(this);
 600             return true;
 601         }
 602         return false;
 603     }
 604 
 605     protected void removeThroughFalseBranch(SimplifierTool tool, AbstractMergeNode merge) {
 606         AbstractBeginNode trueBegin = trueSuccessor();
 607         graph().removeSplitPropagate(this, trueBegin);
 608         tool.addToWorkList(trueBegin);
 609         if (condition() != null) {
 610             GraphUtil.tryKillUnused(condition());
 611         }
 612         if (merge.isAlive() && merge.forwardEndCount() > 1) {
 613             for (FixedNode end : merge.forwardEnds()) {
 614                 Node cur = end;
 615                 while (cur != null && cur.predecessor() instanceof BeginNode) {
 616                     cur = cur.predecessor();
 617                 }
 618                 if (cur != null && cur.predecessor() instanceof IfNode) {
 619                     tool.addToWorkList(cur.predecessor());
 620                 }
 621             }
 622         }
 623     }
 624 
 625     private ValueNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) {
 626         if (trueValue.getStackKind() != falseValue.getStackKind()) {
 627             return null;
 628         }
 629         if (trueValue.getStackKind() != JavaKind.Int && trueValue.getStackKind() != JavaKind.Long) {
 630             return null;
 631         }
 632         if (trueValue.isConstant() && falseValue.isConstant()) {
 633             return graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
 634         } else if (!graph().isAfterExpandLogic()) {
 635             ConditionalNode conditional = null;
 636             ValueNode constant = null;
 637             boolean negateCondition;
 638             if (trueValue instanceof ConditionalNode && falseValue.isConstant()) {
 639                 conditional = (ConditionalNode) trueValue;
 640                 constant = falseValue;
 641                 negateCondition = true;
 642             } else if (falseValue instanceof ConditionalNode && trueValue.isConstant()) {
 643                 conditional = (ConditionalNode) falseValue;
 644                 constant = trueValue;
 645                 negateCondition = false;
 646             } else {
 647                 return null;
 648             }
 649             boolean negateConditionalCondition = false;
 650             ValueNode otherValue = null;
 651             if (constant == conditional.trueValue()) {
 652                 otherValue = conditional.falseValue();
 653                 negateConditionalCondition = false;
 654             } else if (constant == conditional.falseValue()) {
 655                 otherValue = conditional.trueValue();
 656                 negateConditionalCondition = true;
 657             }
 658             if (otherValue != null && otherValue.isConstant()) {
 659                 double shortCutProbability = probability(trueSuccessor());
 660                 LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability);
 661                 return graph().unique(new ConditionalNode(newCondition, constant, otherValue));
 662             } else if (!negateCondition && constant.isJavaConstant() && conditional.trueValue().isJavaConstant() && conditional.falseValue().isJavaConstant()) {
 663                 IntegerLessThanNode lessThan = null;
 664                 IntegerEqualsNode equals = null;
 665                 if (condition() instanceof IntegerLessThanNode && conditional.condition() instanceof IntegerEqualsNode && constant.asJavaConstant().asLong() == -1 &&
 666                                 conditional.trueValue().asJavaConstant().asLong() == 0 && conditional.falseValue().asJavaConstant().asLong() == 1) {
 667                     lessThan = (IntegerLessThanNode) condition();
 668                     equals = (IntegerEqualsNode) conditional.condition();
 669                 } else if (condition() instanceof IntegerEqualsNode && conditional.condition() instanceof IntegerLessThanNode && constant.asJavaConstant().asLong() == 0 &&
 670                                 conditional.trueValue().asJavaConstant().asLong() == -1 && conditional.falseValue().asJavaConstant().asLong() == 1) {
 671                     lessThan = (IntegerLessThanNode) conditional.condition();
 672                     equals = (IntegerEqualsNode) condition();
 673                 }
 674                 if (lessThan != null) {
 675                     assert equals != null;
 676                     if ((lessThan.getX() == equals.getX() && lessThan.getY() == equals.getY()) || (lessThan.getX() == equals.getY() && lessThan.getY() == equals.getX())) {
 677                         return graph().unique(new NormalizeCompareNode(lessThan.getX(), lessThan.getY(), conditional.trueValue().stamp().getStackKind(), false));
 678                     }
 679                 }
 680             }
 681         }
 682         return null;
 683     }
 684 
 685     /**
 686      * Take an if that is immediately dominated by a merge with a single phi and split off any paths
 687      * where the test would be statically decidable creating a new merge below the approriate side
 688      * of the IfNode. Any undecidable tests will continue to use the original IfNode.
 689      *
 690      * @param tool
 691      */
 692     private boolean splitIfAtPhi(SimplifierTool tool) {
 693         if (graph().getGuardsStage().areFrameStatesAtSideEffects()) {
 694             // Disabled until we make sure we have no FrameState-less merges at this stage
 695             return false;
 696         }
 697 
 698         if (!(predecessor() instanceof MergeNode)) {
 699             return false;
 700         }
 701         MergeNode merge = (MergeNode) predecessor();
 702         if (merge.forwardEndCount() == 1) {
 703             // Don't bother.
 704             return false;
 705         }
 706         if (merge.usages().count() != 1 || merge.phis().count() != 1) {
 707             return false;
 708         }
 709         if (merge.stateAfter() != null) {
 710             /* We'll get the chance to simplify this after frame state assignment. */
 711             return false;
 712         }
 713         PhiNode phi = merge.phis().first();
 714         if (phi.usages().count() != 1) {
 715             /*
 716              * For simplicity the below code assumes assumes the phi goes dead at the end so skip
 717              * this case.
 718              */
 719             return false;
 720         }
 721 
 722         /*
 723          * Check that the condition uses the phi and that there is only one user of the condition
 724          * expression.
 725          */
 726         if (!conditionUses(condition(), phi)) {
 727             return false;
 728         }
 729 
 730         /*
 731          * We could additionally filter for the case that at least some of the Phi inputs or one of
 732          * the condition inputs are constants but there are cases where a non-constant is
 733          * simplifiable, usually where the stamp allows the question to be answered.
 734          */
 735 
 736         /* Each successor of the if gets a new merge if needed. */
 737         MergeNode trueMerge = null;
 738         MergeNode falseMerge = null;
 739         assert merge.stateAfter() == null;
 740 
 741         for (EndNode end : merge.forwardEnds().snapshot()) {
 742             Node value = phi.valueAt(end);
 743             LogicNode result = computeCondition(tool, condition, phi, value);
 744             if (result instanceof LogicConstantNode) {
 745                 merge.removeEnd(end);
 746                 if (((LogicConstantNode) result).getValue()) {
 747                     if (trueMerge == null) {
 748                         trueMerge = insertMerge(trueSuccessor());
 749                     }
 750                     trueMerge.addForwardEnd(end);
 751                 } else {
 752                     if (falseMerge == null) {
 753                         falseMerge = insertMerge(falseSuccessor());
 754                     }
 755                     falseMerge.addForwardEnd(end);
 756                 }
 757             } else if (result != condition) {
 758                 // Build a new IfNode using the new condition
 759                 BeginNode trueBegin = graph().add(new BeginNode());
 760                 BeginNode falseBegin = graph().add(new BeginNode());
 761 
 762                 if (result.graph() == null) {
 763                     result = graph().addOrUniqueWithInputs(result);
 764                 }
 765                 IfNode newIfNode = graph().add(new IfNode(result, trueBegin, falseBegin, trueSuccessorProbability));
 766                 merge.removeEnd(end);
 767                 ((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
 768 
 769                 if (trueMerge == null) {
 770                     trueMerge = insertMerge(trueSuccessor());
 771                 }
 772                 trueBegin.setNext(graph().add(new EndNode()));
 773                 trueMerge.addForwardEnd((EndNode) trueBegin.next());
 774 
 775                 if (falseMerge == null) {
 776                     falseMerge = insertMerge(falseSuccessor());
 777                 }
 778                 falseBegin.setNext(graph().add(new EndNode()));
 779                 falseMerge.addForwardEnd((EndNode) falseBegin.next());
 780 
 781                 end.safeDelete();
 782             }
 783         }
 784 
 785         transferProxies(trueSuccessor(), trueMerge);
 786         transferProxies(falseSuccessor(), falseMerge);
 787 
 788         cleanupMerge(merge);
 789         cleanupMerge(trueMerge);
 790         cleanupMerge(falseMerge);
 791 
 792         return true;
 793     }
 794 
 795     /**
 796      * @param condition
 797      * @param phi
 798      * @return true if the passed in {@code condition} uses {@code phi} and the condition is only
 799      *         used once. Since the phi will go dead the condition using it will also have to be
 800      *         dead after the optimization.
 801      */
 802     private static boolean conditionUses(LogicNode condition, PhiNode phi) {
 803         if (condition.usages().count() != 1) {
 804             return false;
 805         }
 806         if (condition instanceof ShortCircuitOrNode) {
 807             if (condition.graph().getGuardsStage().areDeoptsFixed()) {
 808                 /*
 809                  * It can be unsafe to simplify a ShortCircuitOr before deopts are fixed because
 810                  * conversion to guards assumes that all the required conditions are being tested.
 811                  * Simplfying the condition based on context before this happens may lose a
 812                  * condition.
 813                  */
 814                 ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
 815                 return (conditionUses(orNode.x, phi) || conditionUses(orNode.y, phi));
 816             }
 817         } else if (condition instanceof Canonicalizable.Unary<?>) {
 818             Canonicalizable.Unary<?> unary = (Canonicalizable.Unary<?>) condition;
 819             return unary.getValue() == phi;
 820         } else if (condition instanceof Canonicalizable.Binary<?>) {
 821             Canonicalizable.Binary<?> binary = (Canonicalizable.Binary<?>) condition;
 822             return binary.getX() == phi || binary.getY() == phi;
 823         }
 824         return false;
 825     }
 826 
 827     /**
 828      * Canonicalize {@code} condition using {@code value} in place of {@code phi}.
 829      *
 830      * @param tool
 831      * @param condition
 832      * @param phi
 833      * @param value
 834      * @return an improved LogicNode or the original condition
 835      */
 836     @SuppressWarnings("unchecked")
 837     private static LogicNode computeCondition(SimplifierTool tool, LogicNode condition, PhiNode phi, Node value) {
 838         if (condition instanceof ShortCircuitOrNode) {
 839             if (condition.graph().getGuardsStage().areDeoptsFixed() && !condition.graph().isAfterExpandLogic()) {
 840                 ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
 841                 LogicNode resultX = computeCondition(tool, orNode.x, phi, value);
 842                 LogicNode resultY = computeCondition(tool, orNode.y, phi, value);
 843                 if (resultX != orNode.x || resultY != orNode.y) {
 844                     LogicNode result = orNode.canonical(tool, resultX, resultY);
 845                     if (result != orNode) {
 846                         return result;
 847                     }
 848                     /*
 849                      * Create a new node to carry the optimized inputs.
 850                      */
 851                     ShortCircuitOrNode newOr = new ShortCircuitOrNode(resultX, orNode.xNegated, resultY,
 852                                     orNode.yNegated, orNode.getShortCircuitProbability());
 853                     return newOr.canonical(tool);
 854                 }
 855                 return orNode;
 856             }
 857         } else if (condition instanceof Canonicalizable.Binary<?>) {
 858             Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition;
 859             if (compare.getX() == phi) {
 860                 return (LogicNode) compare.canonical(tool, value, compare.getY());
 861             } else if (compare.getY() == phi) {
 862                 return (LogicNode) compare.canonical(tool, compare.getX(), value);
 863             }
 864         } else if (condition instanceof Canonicalizable.Unary<?>) {
 865             Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition;
 866             if (compare.getValue() == phi) {
 867                 return (LogicNode) compare.canonical(tool, value);
 868             }
 869         }
 870         if (condition instanceof Canonicalizable) {
 871             return (LogicNode) ((Canonicalizable) condition).canonical(tool);
 872         }
 873         return condition;
 874     }
 875 
 876     private static void transferProxies(AbstractBeginNode successor, MergeNode falseMerge) {
 877         if (successor instanceof LoopExitNode && falseMerge != null) {
 878             LoopExitNode loopExitNode = (LoopExitNode) successor;
 879             for (ProxyNode proxy : loopExitNode.proxies().snapshot()) {
 880                 proxy.replaceFirstInput(successor, falseMerge);
 881             }
 882         }
 883     }
 884 
 885     private void cleanupMerge(MergeNode merge) {
 886         if (merge != null && merge.isAlive()) {
 887             if (merge.forwardEndCount() == 0) {
 888                 GraphUtil.killCFG(merge);
 889             } else if (merge.forwardEndCount() == 1) {
 890                 graph().reduceTrivialMerge(merge);
 891             }
 892         }
 893     }
 894 
 895     private MergeNode insertMerge(AbstractBeginNode begin) {
 896         MergeNode merge = graph().add(new MergeNode());
 897         if (!begin.anchored().isEmpty()) {
 898             Object before = null;
 899             before = begin.anchored().snapshot();
 900             begin.replaceAtUsages(InputType.Guard, merge);
 901             begin.replaceAtUsages(InputType.Anchor, merge);
 902             assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot();
 903         }
 904 
 905         AbstractBeginNode theBegin = begin;
 906         if (begin instanceof LoopExitNode) {
 907             // Insert an extra begin to make it easier.
 908             theBegin = graph().add(new BeginNode());
 909             begin.replaceAtPredecessor(theBegin);
 910             theBegin.setNext(begin);
 911         }
 912         FixedNode next = theBegin.next();
 913         next.replaceAtPredecessor(merge);
 914         theBegin.setNext(graph().add(new EndNode()));
 915         merge.addForwardEnd((EndNode) theBegin.next());
 916         merge.setNext(next);
 917         return merge;
 918     }
 919 
 920     /**
 921      * Tries to connect code that initializes a variable directly with the successors of an if
 922      * construct that switches on the variable. For example, the pseudo code below:
 923      *
 924      * <pre>
 925      * contains(list, e, yes, no) {
 926      *     if (list == null || e == null) {
 927      *         condition = false;
 928      *     } else {
 929      *         condition = false;
 930      *         for (i in list) {
 931      *             if (i.equals(e)) {
 932      *                 condition = true;
 933      *                 break;
 934      *             }
 935      *         }
 936      *     }
 937      *     if (condition) {
 938      *         return yes;
 939      *     } else {
 940      *         return no;
 941      *     }
 942      * }
 943      * </pre>
 944      *
 945      * will be transformed into:
 946      *
 947      * <pre>
 948      * contains(list, e, yes, no) {
 949      *     if (list == null || e == null) {
 950      *         return no;
 951      *     } else {
 952      *         condition = false;
 953      *         for (i in list) {
 954      *             if (i.equals(e)) {
 955      *                 return yes;
 956      *             }
 957      *         }
 958      *         return no;
 959      *     }
 960      * }
 961      * </pre>
 962      *
 963      * @return true if a transformation was made, false otherwise
 964      */
 965     private boolean removeIntermediateMaterialization(SimplifierTool tool) {
 966         if (!(predecessor() instanceof AbstractMergeNode) || predecessor() instanceof LoopBeginNode) {
 967             return false;
 968         }
 969         AbstractMergeNode merge = (AbstractMergeNode) predecessor();
 970 
 971         if (!(condition() instanceof CompareNode)) {
 972             return false;
 973         }
 974 
 975         CompareNode compare = (CompareNode) condition();
 976         if (compare.getUsageCount() != 1) {
 977             return false;
 978         }
 979 
 980         // Only consider merges with a single usage that is both a phi and an operand of the
 981         // comparison
 982         NodeIterable<Node> mergeUsages = merge.usages();
 983         if (mergeUsages.count() != 1) {
 984             return false;
 985         }
 986         Node singleUsage = mergeUsages.first();
 987         if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.getX() && singleUsage != compare.getY())) {
 988             return false;
 989         }
 990 
 991         // Ensure phi is used by at most the comparison and the merge's frame state (if any)
 992         ValuePhiNode phi = (ValuePhiNode) singleUsage;
 993         NodeIterable<Node> phiUsages = phi.usages();
 994         if (phiUsages.count() > 2) {
 995             return false;
 996         }
 997         for (Node usage : phiUsages) {
 998             if (usage != compare && usage != merge.stateAfter()) {
 999                 return false;
1000             }
1001         }
1002 
1003         List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
1004         assert phi.valueCount() == merge.forwardEndCount();
1005 
1006         Constant[] xs = constantValues(compare.getX(), merge, false);
1007         Constant[] ys = constantValues(compare.getY(), merge, false);
1008         if (xs == null || ys == null) {
1009             return false;
1010         }
1011 
1012         // Sanity check that both ends are not followed by a merge without frame state.
1013         if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) {
1014             return false;
1015         }
1016 
1017         List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
1018         List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
1019         EconomicMap<AbstractEndNode, ValueNode> phiValues = EconomicMap.create(Equivalence.IDENTITY, mergePredecessors.size());
1020 
1021         AbstractBeginNode oldFalseSuccessor = falseSuccessor();
1022         AbstractBeginNode oldTrueSuccessor = trueSuccessor();
1023 
1024         setFalseSuccessor(null);
1025         setTrueSuccessor(null);
1026 
1027         Iterator<EndNode> ends = mergePredecessors.iterator();
1028         for (int i = 0; i < xs.length; i++) {
1029             EndNode end = ends.next();
1030             phiValues.put(end, phi.valueAt(end));
1031             if (compare.condition().foldCondition(xs[i], ys[i], tool.getConstantReflection(), compare.unorderedIsTrue())) {
1032                 trueEnds.add(end);
1033             } else {
1034                 falseEnds.add(end);
1035             }
1036         }
1037         assert !ends.hasNext();
1038         assert falseEnds.size() + trueEnds.size() == xs.length;
1039 
1040         connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool);
1041         connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool);
1042 
1043         if (this.trueSuccessorProbability == 0.0) {
1044             for (AbstractEndNode endNode : trueEnds) {
1045                 propagateZeroProbability(endNode);
1046             }
1047         }
1048 
1049         if (this.trueSuccessorProbability == 1.0) {
1050             for (AbstractEndNode endNode : falseEnds) {
1051                 propagateZeroProbability(endNode);
1052             }
1053         }
1054 
1055         /*
1056          * Remove obsolete ends only after processing all ends, otherwise oldTrueSuccessor or
1057          * oldFalseSuccessor might have been removed if it is a LoopExitNode.
1058          */
1059         if (falseEnds.isEmpty()) {
1060             GraphUtil.killCFG(oldFalseSuccessor);
1061         }
1062         if (trueEnds.isEmpty()) {
1063             GraphUtil.killCFG(oldTrueSuccessor);
1064         }
1065         GraphUtil.killCFG(merge);
1066 
1067         assert !merge.isAlive() : merge;
1068         assert !phi.isAlive() : phi;
1069         assert !compare.isAlive() : compare;
1070         assert !this.isAlive() : this;
1071 
1072         return true;
1073     }
1074 
1075     private void propagateZeroProbability(FixedNode startNode) {
1076         Node prev = null;
1077         for (FixedNode node : GraphUtil.predecessorIterable(startNode)) {
1078             if (node instanceof IfNode) {
1079                 IfNode ifNode = (IfNode) node;
1080                 if (ifNode.trueSuccessor() == prev) {
1081                     if (ifNode.trueSuccessorProbability == 0.0) {
1082                         return;
1083                     } else if (ifNode.trueSuccessorProbability == 1.0) {
1084                         continue;
1085                     } else {
1086                         ifNode.setTrueSuccessorProbability(0.0);
1087                         return;
1088                     }
1089                 } else if (ifNode.falseSuccessor() == prev) {
1090                     if (ifNode.trueSuccessorProbability == 1.0) {
1091                         return;
1092                     } else if (ifNode.trueSuccessorProbability == 0.0) {
1093                         continue;
1094                     } else {
1095                         ifNode.setTrueSuccessorProbability(1.0);
1096                         return;
1097                     }
1098                 } else {
1099                     throw new GraalError("Illegal state");
1100                 }
1101             } else if (node instanceof AbstractMergeNode && !(node instanceof LoopBeginNode)) {
1102                 for (AbstractEndNode endNode : ((AbstractMergeNode) node).cfgPredecessors()) {
1103                     propagateZeroProbability(endNode);
1104                 }
1105                 return;
1106             }
1107             prev = node;
1108         }
1109     }
1110 
1111     private static boolean checkFrameState(FixedNode start) {
1112         FixedNode node = start;
1113         while (true) {
1114             if (node instanceof AbstractMergeNode) {
1115                 AbstractMergeNode mergeNode = (AbstractMergeNode) node;
1116                 if (mergeNode.stateAfter() == null) {
1117                     return false;
1118                 } else {
1119                     return true;
1120                 }
1121             } else if (node instanceof StateSplit) {
1122                 StateSplit stateSplitNode = (StateSplit) node;
1123                 if (stateSplitNode.stateAfter() != null) {
1124                     return true;
1125                 }
1126             }
1127 
1128             if (node instanceof ControlSplitNode) {
1129                 ControlSplitNode controlSplitNode = (ControlSplitNode) node;
1130                 for (Node succ : controlSplitNode.cfgSuccessors()) {
1131                     if (checkFrameState((FixedNode) succ)) {
1132                         return true;
1133                     }
1134                 }
1135                 return false;
1136             } else if (node instanceof FixedWithNextNode) {
1137                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
1138                 node = fixedWithNextNode.next();
1139             } else if (node instanceof AbstractEndNode) {
1140                 AbstractEndNode endNode = (AbstractEndNode) node;
1141                 node = endNode.merge();
1142             } else if (node instanceof ControlSinkNode) {
1143                 return true;
1144             } else {
1145                 return false;
1146             }
1147         }
1148     }
1149 
1150     /**
1151      * Connects a set of ends to a given successor, inserting a merge node if there is more than one
1152      * end. If {@code ends} is not empty, then {@code successor} is added to {@code tool}'s
1153      * {@linkplain SimplifierTool#addToWorkList(org.graalvm.compiler.graph.Node) work list}.
1154      *
1155      * @param oldMerge the merge being removed
1156      * @param phiValues the values of the phi at the merge, keyed by the merge ends
1157      */
1158     private void connectEnds(List<EndNode> ends, EconomicMap<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) {
1159         if (!ends.isEmpty()) {
1160             if (ends.size() == 1) {
1161                 AbstractEndNode end = ends.get(0);
1162                 ((FixedWithNextNode) end.predecessor()).setNext(successor);
1163                 oldMerge.removeEnd(end);
1164                 GraphUtil.killCFG(end);
1165             } else {
1166                 // Need a new phi in case the frame state is used by more than the merge being
1167                 // removed
1168                 AbstractMergeNode newMerge = graph().add(new MergeNode());
1169                 PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
1170                 PhiNode newPhi = graph().addWithoutUnique(new ValuePhiNode(oldPhi.stamp(), newMerge));
1171 
1172                 for (EndNode end : ends) {
1173                     newPhi.addInput(phiValues.get(end));
1174                     newMerge.addForwardEnd(end);
1175                 }
1176 
1177                 FrameState stateAfter = oldMerge.stateAfter();
1178                 if (stateAfter != null) {
1179                     stateAfter = stateAfter.duplicate();
1180                     stateAfter.replaceFirstInput(oldPhi, newPhi);
1181                     newMerge.setStateAfter(stateAfter);
1182                 }
1183 
1184                 newMerge.setNext(successor);
1185             }
1186             tool.addToWorkList(successor);
1187         }
1188     }
1189 
1190     /**
1191      * Gets an array of constants derived from a node that is either a {@link ConstantNode} or a
1192      * {@link PhiNode} whose input values are all constants. The length of the returned array is
1193      * equal to the number of ends terminating in a given merge node.
1194      *
1195      * @return null if {@code node} is neither a {@link ConstantNode} nor a {@link PhiNode} whose
1196      *         input values are all constants
1197      */
1198     public static Constant[] constantValues(ValueNode node, AbstractMergeNode merge, boolean allowNull) {
1199         if (node.isConstant()) {
1200             Constant[] result = new Constant[merge.forwardEndCount()];
1201             Arrays.fill(result, node.asConstant());
1202             return result;
1203         }
1204 
1205         if (node instanceof PhiNode) {
1206             PhiNode phi = (PhiNode) node;
1207             if (phi.merge() == merge && phi instanceof ValuePhiNode && phi.valueCount() == merge.forwardEndCount()) {
1208                 Constant[] result = new Constant[merge.forwardEndCount()];
1209                 int i = 0;
1210                 for (ValueNode n : phi.values()) {
1211                     if (!allowNull && !n.isConstant()) {
1212                         return null;
1213                     }
1214                     result[i++] = n.asConstant();
1215                 }
1216                 return result;
1217             }
1218         }
1219 
1220         return null;
1221     }
1222 
1223     @Override
1224     public AbstractBeginNode getPrimarySuccessor() {
1225         return this.trueSuccessor();
1226     }
1227 
1228     public AbstractBeginNode getSuccessor(boolean result) {
1229         return result ? this.trueSuccessor() : this.falseSuccessor();
1230     }
1231 
1232     @Override
1233     public boolean setProbability(AbstractBeginNode successor, double value) {
1234         if (successor == this.trueSuccessor()) {
1235             this.setTrueSuccessorProbability(value);
1236             return true;
1237         } else if (successor == this.falseSuccessor()) {
1238             this.setTrueSuccessorProbability(1.0 - value);
1239             return true;
1240         }
1241         return false;
1242     }
1243 
1244     @Override
1245     public int getSuccessorCount() {
1246         return 2;
1247     }
1248 }