IfNode.java revision 13264:48566d838608
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 */
23package org.graalvm.compiler.nodes;
24
25import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
26import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
27
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Iterator;
31import java.util.List;
32
33import org.graalvm.compiler.core.common.calc.Condition;
34import org.graalvm.compiler.core.common.type.IntegerStamp;
35import org.graalvm.compiler.core.common.type.Stamp;
36import org.graalvm.compiler.core.common.type.StampFactory;
37import org.graalvm.compiler.debug.CounterKey;
38import org.graalvm.compiler.debug.DebugContext;
39import org.graalvm.compiler.debug.GraalError;
40import org.graalvm.compiler.graph.Node;
41import org.graalvm.compiler.graph.NodeClass;
42import org.graalvm.compiler.graph.iterators.NodeIterable;
43import org.graalvm.compiler.graph.spi.Canonicalizable;
44import org.graalvm.compiler.graph.spi.Simplifiable;
45import org.graalvm.compiler.graph.spi.SimplifierTool;
46import org.graalvm.compiler.nodeinfo.InputType;
47import org.graalvm.compiler.nodeinfo.NodeInfo;
48import org.graalvm.compiler.nodes.calc.CompareNode;
49import org.graalvm.compiler.nodes.calc.ConditionalNode;
50import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
51import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
52import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
53import org.graalvm.compiler.nodes.calc.IsNullNode;
54import org.graalvm.compiler.nodes.calc.NormalizeCompareNode;
55import org.graalvm.compiler.nodes.java.InstanceOfNode;
56import org.graalvm.compiler.nodes.spi.LIRLowerable;
57import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
58import org.graalvm.compiler.nodes.util.GraphUtil;
59import org.graalvm.util.EconomicMap;
60import org.graalvm.util.Equivalence;
61
62import jdk.vm.ci.meta.Constant;
63import jdk.vm.ci.meta.ConstantReflectionProvider;
64import jdk.vm.ci.meta.JavaConstant;
65import jdk.vm.ci.meta.JavaKind;
66import 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")
73public 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}
1249