001/*
002 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.nodes;
024
025import java.util.*;
026
027import jdk.internal.jvmci.common.*;
028import com.oracle.graal.debug.*;
029import jdk.internal.jvmci.meta.*;
030import jdk.internal.jvmci.meta.JavaTypeProfile.*;
031
032import com.oracle.graal.compiler.common.*;
033import com.oracle.graal.compiler.common.calc.*;
034import com.oracle.graal.compiler.common.type.*;
035import com.oracle.graal.graph.*;
036import com.oracle.graal.graph.iterators.*;
037import com.oracle.graal.graph.spi.*;
038import com.oracle.graal.nodeinfo.*;
039import com.oracle.graal.nodes.calc.*;
040import com.oracle.graal.nodes.java.*;
041import com.oracle.graal.nodes.spi.*;
042import com.oracle.graal.nodes.util.*;
043
044/**
045 * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
046 * of a comparison.
047 */
048@NodeInfo
049public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
050    public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
051
052    private static final DebugMetric CORRECTED_PROBABILITIES = Debug.metric("CorrectedProbabilities");
053
054    @Successor AbstractBeginNode trueSuccessor;
055    @Successor AbstractBeginNode falseSuccessor;
056    @Input(InputType.Condition) LogicNode condition;
057    protected double trueSuccessorProbability;
058
059    public LogicNode condition() {
060        return condition;
061    }
062
063    public void setCondition(LogicNode x) {
064        updateUsages(condition, x);
065        condition = x;
066    }
067
068    public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) {
069        this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability);
070    }
071
072    public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) {
073        super(TYPE, StampFactory.forVoid());
074        this.condition = condition;
075        this.falseSuccessor = falseSuccessor;
076        this.trueSuccessor = trueSuccessor;
077        setTrueSuccessorProbability(trueSuccessorProbability);
078    }
079
080    /**
081     * Gets the true successor.
082     *
083     * @return the true successor
084     */
085    public AbstractBeginNode trueSuccessor() {
086        return trueSuccessor;
087    }
088
089    /**
090     * Gets the false successor.
091     *
092     * @return the false successor
093     */
094    public AbstractBeginNode falseSuccessor() {
095        return falseSuccessor;
096    }
097
098    public double getTrueSuccessorProbability() {
099        return this.trueSuccessorProbability;
100    }
101
102    public void setTrueSuccessor(AbstractBeginNode node) {
103        updatePredecessor(trueSuccessor, node);
104        trueSuccessor = node;
105    }
106
107    public void setFalseSuccessor(AbstractBeginNode node) {
108        updatePredecessor(falseSuccessor, node);
109        falseSuccessor = node;
110    }
111
112    /**
113     * Gets the node corresponding to the specified outcome of the branch.
114     *
115     * @param istrue {@code true} if the true successor is requested, {@code false} otherwise
116     * @return the corresponding successor
117     */
118    public AbstractBeginNode successor(boolean istrue) {
119        return istrue ? trueSuccessor : falseSuccessor;
120    }
121
122    public void setTrueSuccessorProbability(double prob) {
123        assert prob >= -0.000000001 && prob <= 1.000000001 : "Probability out of bounds: " + prob;
124        trueSuccessorProbability = Math.min(1.0, Math.max(0.0, prob));
125    }
126
127    @Override
128    public double probability(AbstractBeginNode successor) {
129        return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability;
130    }
131
132    @Override
133    public void generate(NodeLIRBuilderTool gen) {
134        gen.emitIf(this);
135    }
136
137    @Override
138    public boolean verify() {
139        assertTrue(condition() != null, "missing condition");
140        assertTrue(trueSuccessor() != null, "missing trueSuccessor");
141        assertTrue(falseSuccessor() != null, "missing falseSuccessor");
142        return super.verify();
143    }
144
145    public void eliminateNegation() {
146        AbstractBeginNode oldTrueSuccessor = trueSuccessor;
147        AbstractBeginNode oldFalseSuccessor = falseSuccessor;
148        trueSuccessor = oldFalseSuccessor;
149        falseSuccessor = oldTrueSuccessor;
150        trueSuccessorProbability = 1 - trueSuccessorProbability;
151        setCondition(((LogicNegationNode) condition).getValue());
152    }
153
154    @Override
155    public void simplify(SimplifierTool tool) {
156        if (trueSuccessor().next() instanceof DeoptimizeNode) {
157            if (trueSuccessorProbability != 0) {
158                CORRECTED_PROBABILITIES.increment();
159                trueSuccessorProbability = 0;
160            }
161        } else if (falseSuccessor().next() instanceof DeoptimizeNode) {
162            if (trueSuccessorProbability != 1) {
163                CORRECTED_PROBABILITIES.increment();
164                trueSuccessorProbability = 1;
165            }
166        }
167
168        if (condition() instanceof LogicNegationNode) {
169            eliminateNegation();
170        }
171        if (condition() instanceof LogicConstantNode) {
172            LogicConstantNode c = (LogicConstantNode) condition();
173            if (c.getValue()) {
174                tool.deleteBranch(falseSuccessor());
175                tool.addToWorkList(trueSuccessor());
176                graph().removeSplit(this, trueSuccessor());
177            } else {
178                tool.deleteBranch(trueSuccessor());
179                tool.addToWorkList(falseSuccessor());
180                graph().removeSplit(this, falseSuccessor());
181            }
182            return;
183        }
184        if (tool.allUsagesAvailable() && trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages()) {
185
186            pushNodesThroughIf(tool);
187
188            if (checkForUnsignedCompare(tool) || removeOrMaterializeIf(tool)) {
189                return;
190            }
191        }
192
193        if (removeIntermediateMaterialization(tool)) {
194            return;
195        }
196
197        if (splitIfAtPhi(tool)) {
198            return;
199        }
200
201        if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
202            AbstractBeginNode intermediateBegin = falseSuccessor();
203            IfNode nextIf = (IfNode) intermediateBegin.next();
204            double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
205            if (this.trueSuccessorProbability < probabilityB) {
206                // Reordering of those two if statements is beneficial from the point of view of
207                // their probabilities.
208                if (prepareForSwap(tool.getConstantReflection(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) {
209                    // Reordering is allowed from (if1 => begin => if2) to (if2 => begin => if1).
210                    assert intermediateBegin.next() == nextIf;
211                    AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor();
212                    nextIf.setFalseSuccessor(null);
213                    intermediateBegin.setNext(null);
214                    this.setFalseSuccessor(null);
215
216                    this.replaceAtPredecessor(nextIf);
217                    nextIf.setFalseSuccessor(intermediateBegin);
218                    intermediateBegin.setNext(this);
219                    this.setFalseSuccessor(bothFalseBegin);
220                    nextIf.setTrueSuccessorProbability(probabilityB);
221                    if (probabilityB == 1.0) {
222                        this.setTrueSuccessorProbability(0.0);
223                    } else {
224                        double newProbability = this.trueSuccessorProbability / (1.0 - probabilityB);
225                        this.setTrueSuccessorProbability(Math.min(1.0, newProbability));
226                    }
227                    return;
228                }
229            }
230        }
231    }
232
233    private void pushNodesThroughIf(SimplifierTool tool) {
234        assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
235        // push similar nodes upwards through the if, thereby deduplicating them
236        do {
237            AbstractBeginNode trueSucc = trueSuccessor();
238            AbstractBeginNode falseSucc = falseSuccessor();
239            if (trueSucc instanceof BeginNode && falseSucc instanceof BeginNode && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
240                FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
241                FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
242                NodeClass<?> nodeClass = trueNext.getNodeClass();
243                if (trueNext.getClass() == falseNext.getClass()) {
244                    if (nodeClass.getInputEdges().areEqualIn(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
245                        falseNext.replaceAtUsages(trueNext);
246                        graph().removeFixed(falseNext);
247                        GraphUtil.unlinkFixedNode(trueNext);
248                        graph().addBeforeFixed(this, trueNext);
249                        for (Node usage : trueNext.usages().snapshot()) {
250                            if (usage.isAlive()) {
251                                NodeClass<?> usageNodeClass = usage.getNodeClass();
252                                if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) {
253                                    Node newNode = graph().findDuplicate(usage);
254                                    if (newNode != null) {
255                                        usage.replaceAtUsages(newNode);
256                                        usage.safeDelete();
257                                    }
258                                }
259                                if (usage.isAlive()) {
260                                    tool.addToWorkList(usage);
261                                }
262                            }
263                        }
264                        continue;
265                    }
266                }
267            }
268            break;
269        } while (true);
270    }
271
272    /**
273     * Recognize a couple patterns that can be merged into an unsigned compare.
274     *
275     * @param tool
276     * @return true if a replacement was done.
277     */
278    private boolean checkForUnsignedCompare(SimplifierTool tool) {
279        assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
280        if (condition() instanceof IntegerLessThanNode) {
281            IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
282            Constant y = lessThan.getY().stamp().asConstant();
283            if (y instanceof PrimitiveConstant && ((PrimitiveConstant) y).asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
284                IfNode ifNode2 = (IfNode) falseSuccessor().next();
285                if (ifNode2.condition() instanceof IntegerLessThanNode) {
286                    IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
287                    AbstractBeginNode falseSucc = ifNode2.falseSuccessor();
288                    AbstractBeginNode trueSucc = ifNode2.trueSuccessor();
289                    IntegerBelowNode below = null;
290                    /*
291                     * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
292                     * <positive> into an unsigned compare.
293                     */
294                    if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.getY().stamp()).isPositive() &&
295                                    sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
296                        below = graph().unique(new IntegerBelowNode(lessThan2.getX(), lessThan2.getY()));
297                        // swap direction
298                        AbstractBeginNode tmp = falseSucc;
299                        falseSucc = trueSucc;
300                        trueSucc = tmp;
301                    } else if (lessThan2.getY() == lessThan.getX() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
302                        /*
303                         * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
304                         * !(<positive> > x), into x <| positive + 1. This can only be done for
305                         * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
306                         * appear to be interesting.
307                         */
308                        JavaConstant positive = lessThan2.getX().asJavaConstant();
309                        if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getKind().getMaxValue()) {
310                            ConstantNode newLimit = ConstantNode.forIntegerStamp(lessThan2.getX().stamp(), positive.asLong() + 1, graph());
311                            below = graph().unique(new IntegerBelowNode(lessThan.getX(), newLimit));
312                        }
313                    }
314                    if (below != null) {
315                        ifNode2.setTrueSuccessor(null);
316                        ifNode2.setFalseSuccessor(null);
317
318                        IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
319                        // Remove the < 0 test.
320                        tool.deleteBranch(trueSuccessor);
321                        graph().removeSplit(this, falseSuccessor);
322
323                        // Replace the second test with the new one.
324                        ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
325                        ifNode2.safeDelete();
326                        return true;
327                    }
328                }
329            }
330        }
331        return false;
332    }
333
334    /**
335     * Check it these two blocks end up at the same place. Meeting at the same merge, or
336     * deoptimizing in the same way.
337     */
338    private static boolean sameDestination(AbstractBeginNode succ1, AbstractBeginNode succ2) {
339        Node next1 = succ1.next();
340        Node next2 = succ2.next();
341        if (next1 instanceof EndNode && next2 instanceof EndNode) {
342            EndNode end1 = (EndNode) next1;
343            EndNode end2 = (EndNode) next2;
344            if (end1.merge() == end2.merge()) {
345                for (PhiNode phi : end1.merge().phis()) {
346                    if (phi.valueAt(end1) != phi.valueAt(end2)) {
347                        return false;
348                    }
349                }
350                // They go to the same MergeNode and merge the same values
351                return true;
352            }
353        } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
354            DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
355            DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
356            if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) {
357                // Same deoptimization reason and action.
358                return true;
359            }
360        } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) {
361            LoopExitNode exit1 = (LoopExitNode) next1;
362            LoopExitNode exit2 = (LoopExitNode) next2;
363            if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) {
364                // Exit the same loop and end up at the same place.
365                return true;
366            }
367        } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) {
368            ReturnNode exit1 = (ReturnNode) next1;
369            ReturnNode exit2 = (ReturnNode) next2;
370            if (exit1.result() == exit2.result()) {
371                // Exit the same loop and end up at the same place.
372                return true;
373            }
374        }
375        return false;
376    }
377
378    private static final class MutableProfiledType {
379        final ResolvedJavaType type;
380        double probability;
381
382        public MutableProfiledType(ResolvedJavaType type, double probability) {
383            this.type = type;
384            this.probability = probability;
385        }
386    }
387
388    private static boolean prepareForSwap(ConstantReflectionProvider constantReflection, LogicNode a, LogicNode b, double probabilityA, double probabilityB) {
389        if (a instanceof InstanceOfNode) {
390            InstanceOfNode instanceOfA = (InstanceOfNode) a;
391            if (b instanceof IsNullNode) {
392                IsNullNode isNullNode = (IsNullNode) b;
393                if (isNullNode.getValue() == instanceOfA.getValue()) {
394                    if (instanceOfA.profile() != null && instanceOfA.profile().getNullSeen() != TriState.FALSE) {
395                        instanceOfA.setProfile(new JavaTypeProfile(TriState.FALSE, instanceOfA.profile().getNotRecordedProbability(), instanceOfA.profile().getTypes()));
396                    }
397                    Debug.log("Can swap instanceof and isnull if");
398                    return true;
399                }
400            } else if (b instanceof InstanceOfNode) {
401                InstanceOfNode instanceOfB = (InstanceOfNode) b;
402                if (instanceOfA.getValue() == instanceOfB.getValue() && !instanceOfA.type().isInterface() && !instanceOfB.type().isInterface() &&
403                                !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) {
404                    // Two instanceof on the same value with mutually exclusive types.
405                    Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type());
406                    swapInstanceOfProfiles(probabilityA, probabilityB, instanceOfA, instanceOfB);
407                    return true;
408                }
409            }
410        } else if (a instanceof CompareNode) {
411            CompareNode compareA = (CompareNode) a;
412            Condition conditionA = compareA.condition();
413            if (compareA.unorderedIsTrue()) {
414                return false;
415            }
416            if (b instanceof CompareNode) {
417                CompareNode compareB = (CompareNode) b;
418                if (compareA == compareB) {
419                    Debug.log("Same conditions => do not swap and leave the work for global value numbering.");
420                    return false;
421                }
422                if (compareB.unorderedIsTrue()) {
423                    return false;
424                }
425                Condition comparableCondition = null;
426                Condition conditionB = compareB.condition();
427                if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) {
428                    comparableCondition = conditionB;
429                } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) {
430                    comparableCondition = conditionB.mirror();
431                }
432
433                if (comparableCondition != null) {
434                    Condition combined = conditionA.join(comparableCondition);
435                    if (combined == null) {
436                        // The two conditions are disjoint => can reorder.
437                        Debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition);
438                        return true;
439                    }
440                } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) {
441                    boolean canSwap = false;
442                    if ((compareA.getX() == compareB.getX() && valuesDistinct(constantReflection, compareA.getY(), compareB.getY()))) {
443                        canSwap = true;
444                    } else if ((compareA.getX() == compareB.getY() && valuesDistinct(constantReflection, compareA.getY(), compareB.getX()))) {
445                        canSwap = true;
446                    } else if ((compareA.getY() == compareB.getX() && valuesDistinct(constantReflection, compareA.getX(), compareB.getY()))) {
447                        canSwap = true;
448                    } else if ((compareA.getY() == compareB.getY() && valuesDistinct(constantReflection, compareA.getX(), compareB.getX()))) {
449                        canSwap = true;
450                    }
451
452                    if (canSwap) {
453                        Debug.log("Can swap equality condition with one shared and one disjoint value.");
454                        return true;
455                    }
456                }
457            }
458        }
459
460        return false;
461    }
462
463    /**
464     * Arbitrary fraction of not recorded types that we'll guess are sub-types of B.
465     *
466     * This is is used because we can not check if the unrecorded types are sub-types of B or not.
467     */
468    private static final double NOT_RECORDED_SUBTYPE_B = 0.5;
469
470    /**
471     * If the not-recorded fraction of types for the new profile of <code>instanceOfA</code> is
472     * above this threshold, no profile is used for this <code>instanceof</code> after the swap.
473     *
474     * The idea is that the reconstructed profile would contain too much unknowns to be of any use.
475     */
476    private static final double NOT_RECORDED_CUTOFF = 0.4;
477
478    /**
479     * Tries to reconstruct profiles for the swapped <code>instanceof</code> checks.
480     *
481     * The tested types must be mutually exclusive.
482     */
483    private static void swapInstanceOfProfiles(double probabilityA, double probabilityB, InstanceOfNode instanceOfA, InstanceOfNode instanceOfB) {
484        JavaTypeProfile profileA = instanceOfA.profile();
485        JavaTypeProfile profileB = instanceOfB.profile();
486
487        JavaTypeProfile newProfileA = null;
488        JavaTypeProfile newProfileB = null;
489        if (profileA != null || profileB != null) {
490            List<MutableProfiledType> newProfiledTypesA = new ArrayList<>();
491            List<MutableProfiledType> newProfiledTypesB = new ArrayList<>();
492            double totalProbabilityA = 0.0;
493            double totalProbabilityB = 0.0;
494            double newNotRecordedA = 0.0;
495            double newNotRecordedB = 0.0;
496            TriState nullSeen = TriState.UNKNOWN;
497            if (profileA != null) {
498                for (ProfiledType profiledType : profileA.getTypes()) {
499                    newProfiledTypesB.add(new MutableProfiledType(profiledType.getType(), profiledType.getProbability()));
500                    totalProbabilityB += profiledType.getProbability();
501                    if (!instanceOfB.type().isAssignableFrom(profiledType.getType())) {
502                        double typeProbabilityA = profiledType.getProbability() / (1 - probabilityB);
503                        newProfiledTypesA.add(new MutableProfiledType(profiledType.getType(), typeProbabilityA));
504                        totalProbabilityA += typeProbabilityA;
505                    }
506                }
507                newNotRecordedB += profileA.getNotRecordedProbability();
508                newNotRecordedA += NOT_RECORDED_SUBTYPE_B * profileA.getNotRecordedProbability() / (1 - probabilityB);
509                nullSeen = profileA.getNullSeen();
510            }
511            int searchA = newProfiledTypesA.size();
512            int searchB = newProfiledTypesB.size();
513            if (profileB != null) {
514                for (ProfiledType profiledType : profileB.getTypes()) {
515                    double typeProbabilityB = profiledType.getProbability() * (1 - probabilityA);
516                    appendOrMerge(profiledType.getType(), typeProbabilityB, searchB, newProfiledTypesB);
517                    totalProbabilityB += typeProbabilityB;
518                    if (!instanceOfB.type().isAssignableFrom(profiledType.getType())) {
519                        double typeProbabilityA = typeProbabilityB / (1 - probabilityB);
520                        appendOrMerge(profiledType.getType(), typeProbabilityA, searchA, newProfiledTypesA);
521                        totalProbabilityA += typeProbabilityA;
522                    }
523                }
524                newNotRecordedB += profileB.getNotRecordedProbability() * (1 - probabilityA);
525                newNotRecordedA += NOT_RECORDED_SUBTYPE_B * profileB.getNotRecordedProbability() * (1 - probabilityA) / (1 - probabilityB);
526                nullSeen = TriState.merge(nullSeen, profileB.getNullSeen());
527            }
528            totalProbabilityA += newNotRecordedA;
529            totalProbabilityB += newNotRecordedB;
530
531            if (newNotRecordedA / NOT_RECORDED_SUBTYPE_B > NOT_RECORDED_CUTOFF) {
532                // too much unknown
533                newProfileA = null;
534            } else {
535                newProfileA = makeProfile(totalProbabilityA, newNotRecordedA, newProfiledTypesA, nullSeen);
536            }
537            newProfileB = makeProfile(totalProbabilityB, newNotRecordedB, newProfiledTypesB, nullSeen);
538        }
539
540        instanceOfB.setProfile(newProfileB);
541        instanceOfA.setProfile(newProfileA);
542    }
543
544    private static JavaTypeProfile makeProfile(double totalProbability, double notRecorded, List<MutableProfiledType> profiledTypes, TriState nullSeen) {
545        // protect against NaNs and empty profiles
546        if (totalProbability > 0.0) {
547            // normalize
548            ProfiledType[] profiledTypesArray = new ProfiledType[profiledTypes.size()];
549            int i = 0;
550            for (MutableProfiledType profiledType : profiledTypes) {
551                profiledTypesArray[i++] = new ProfiledType(profiledType.type, profiledType.probability / totalProbability);
552            }
553
554            // sort
555            Arrays.sort(profiledTypesArray);
556
557            return new JavaTypeProfile(nullSeen, notRecorded / totalProbability, profiledTypesArray);
558        }
559        return null;
560    }
561
562    private static void appendOrMerge(ResolvedJavaType type, double probability, int searchUntil, List<MutableProfiledType> list) {
563        for (int i = 0; i < searchUntil; i++) {
564            MutableProfiledType profiledType = list.get(i);
565            if (profiledType.type.equals(type)) {
566                profiledType.probability += probability;
567                return;
568            }
569        }
570        list.add(new MutableProfiledType(type, probability));
571    }
572
573    private static boolean valuesDistinct(ConstantReflectionProvider constantReflection, ValueNode a, ValueNode b) {
574        if (a.isConstant() && b.isConstant()) {
575            Boolean equal = constantReflection.constantEquals(a.asConstant(), b.asConstant());
576            if (equal != null) {
577                return !equal.booleanValue();
578            }
579        }
580
581        Stamp stampA = a.stamp();
582        Stamp stampB = b.stamp();
583        return stampA.alwaysDistinct(stampB);
584    }
585
586    /**
587     * Tries to remove an empty if construct or replace an if construct with a materialization.
588     *
589     * @return true if a transformation was made, false otherwise
590     */
591    private boolean removeOrMaterializeIf(SimplifierTool tool) {
592        assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
593        if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
594            AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
595            AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
596            AbstractMergeNode merge = trueEnd.merge();
597            if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
598                PhiNode singlePhi = null;
599                int distinct = 0;
600                for (PhiNode phi : merge.phis()) {
601                    ValueNode trueValue = phi.valueAt(trueEnd);
602                    ValueNode falseValue = phi.valueAt(falseEnd);
603                    if (trueValue != falseValue) {
604                        distinct++;
605                        singlePhi = phi;
606                    }
607                }
608                if (distinct == 0) {
609                    /*
610                     * Multiple phis but merging same values for true and false, so simply delete
611                     * the path
612                     */
613                    removeThroughFalseBranch(tool);
614                    return true;
615                } else if (distinct == 1) {
616                    ValueNode trueValue = singlePhi.valueAt(trueEnd);
617                    ValueNode falseValue = singlePhi.valueAt(falseEnd);
618                    ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
619                    if (conditional != null) {
620                        singlePhi.setValueAt(trueEnd, conditional);
621                        removeThroughFalseBranch(tool);
622                        return true;
623                    }
624                }
625            }
626        }
627        if (trueSuccessor().next() instanceof ReturnNode && falseSuccessor().next() instanceof ReturnNode) {
628            ReturnNode trueEnd = (ReturnNode) trueSuccessor().next();
629            ReturnNode falseEnd = (ReturnNode) falseSuccessor().next();
630            ValueNode trueValue = trueEnd.result();
631            ValueNode falseValue = falseEnd.result();
632            ValueNode value = null;
633            if (trueValue != null) {
634                if (trueValue == falseValue) {
635                    value = trueValue;
636                } else {
637                    value = canonicalizeConditionalCascade(trueValue, falseValue);
638                    if (value == null) {
639                        return false;
640                    }
641                }
642            }
643            ReturnNode newReturn = graph().add(new ReturnNode(value));
644            replaceAtPredecessor(newReturn);
645            GraphUtil.killCFG(this);
646            return true;
647        }
648        return false;
649    }
650
651    protected void removeThroughFalseBranch(SimplifierTool tool) {
652        AbstractBeginNode trueBegin = trueSuccessor();
653        graph().removeSplitPropagate(this, trueBegin, tool);
654        tool.addToWorkList(trueBegin);
655        if (condition().isAlive() && condition().hasNoUsages()) {
656            GraphUtil.killWithUnusedFloatingInputs(condition());
657        }
658    }
659
660    private ConditionalNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) {
661        if (trueValue.getKind() != falseValue.getKind()) {
662            return null;
663        }
664        if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
665            return null;
666        }
667        if (trueValue.isConstant() && falseValue.isConstant()) {
668            return graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
669        } else {
670            ConditionalNode conditional = null;
671            ValueNode constant = null;
672            boolean negateCondition;
673            if (trueValue instanceof ConditionalNode && falseValue.isConstant()) {
674                conditional = (ConditionalNode) trueValue;
675                constant = falseValue;
676                negateCondition = true;
677            } else if (falseValue instanceof ConditionalNode && trueValue.isConstant()) {
678                conditional = (ConditionalNode) falseValue;
679                constant = trueValue;
680                negateCondition = false;
681            } else {
682                return null;
683            }
684            boolean negateConditionalCondition;
685            ValueNode otherValue;
686            if (constant == conditional.trueValue()) {
687                otherValue = conditional.falseValue();
688                negateConditionalCondition = false;
689            } else if (constant == conditional.falseValue()) {
690                otherValue = conditional.trueValue();
691                negateConditionalCondition = true;
692            } else {
693                return null;
694            }
695            if (otherValue.isConstant()) {
696                double shortCutProbability = probability(trueSuccessor());
697                LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability);
698                return graph().unique(new ConditionalNode(newCondition, constant, otherValue));
699            }
700        }
701        return null;
702    }
703
704    /**
705     * Take an if that is immediately dominated by a merge with a single phi and split off any paths
706     * where the test would be statically decidable creating a new merge below the approriate side
707     * of the IfNode. Any undecidable tests will continue to use the original IfNode.
708     *
709     * @param tool
710     */
711    @SuppressWarnings("unchecked")
712    private boolean splitIfAtPhi(SimplifierTool tool) {
713        if (!(predecessor() instanceof MergeNode)) {
714            return false;
715        }
716        MergeNode merge = (MergeNode) predecessor();
717        if (merge.forwardEndCount() == 1) {
718            // Don't bother.
719            return false;
720        }
721        if (merge.usages().count() != 1 || merge.phis().count() != 1) {
722            return false;
723        }
724        if (merge.stateAfter() != null) {
725            /* We'll get the chance to simplify this after frame state assignment. */
726            return false;
727        }
728        PhiNode phi = merge.phis().first();
729        if (phi.usages().count() != 1 || condition().usages().count() != 1) {
730            /*
731             * For simplicity the below code assumes assumes the phi goes dead at the end so skip
732             * this case.
733             */
734            return false;
735        }
736
737        if (condition() instanceof Canonicalizable.Unary<?>) {
738            Canonicalizable.Unary<?> unary = (Canonicalizable.Unary<?>) condition();
739            if (unary.getValue() != phi) {
740                return false;
741            }
742        } else if (condition() instanceof Canonicalizable.Binary<?>) {
743            Canonicalizable.Binary<?> binary = (Canonicalizable.Binary<?>) condition();
744            if (binary.getX() != phi && binary.getY() != phi) {
745                return false;
746            }
747        } else {
748            return false;
749        }
750
751        /*
752         * We could additionally filter for the case that at least some of the Phi inputs or one of
753         * the condition inputs are constants but there are cases where a non-constant is
754         * simplifiable, usually where the stamp allows the question to be answered.
755         */
756
757        /* Each successor of the if gets a new merge if needed. */
758        MergeNode trueMerge = null;
759        MergeNode falseMerge = null;
760        assert merge.stateAfter() == null;
761
762        for (EndNode end : merge.forwardEnds().snapshot()) {
763            Node value = phi.valueAt(end);
764            Node result = null;
765            if (condition() instanceof Canonicalizable.Binary<?>) {
766                Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition;
767                if (compare.getX() == phi) {
768                    result = compare.canonical(tool, value, compare.getY());
769                } else {
770                    result = compare.canonical(tool, compare.getX(), value);
771                }
772            } else {
773                assert condition() instanceof Canonicalizable.Unary<?>;
774                Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition;
775                result = compare.canonical(tool, value);
776            }
777            if (result instanceof LogicConstantNode) {
778                merge.removeEnd(end);
779                if (((LogicConstantNode) result).getValue()) {
780                    if (trueMerge == null) {
781                        trueMerge = insertMerge(trueSuccessor());
782                    }
783                    trueMerge.addForwardEnd(end);
784                } else {
785                    if (falseMerge == null) {
786                        falseMerge = insertMerge(falseSuccessor());
787                    }
788                    falseMerge.addForwardEnd(end);
789                }
790            }
791        }
792        transferProxies(trueSuccessor(), trueMerge);
793        transferProxies(falseSuccessor(), falseMerge);
794
795        cleanupMerge(tool, merge);
796        cleanupMerge(tool, trueMerge);
797        cleanupMerge(tool, falseMerge);
798
799        return true;
800    }
801
802    private static void transferProxies(AbstractBeginNode successor, MergeNode falseMerge) {
803        if (falseMerge != null) {
804            for (ProxyNode proxy : successor.proxies().snapshot()) {
805                proxy.replaceFirstInput(successor, falseMerge);
806            }
807        }
808    }
809
810    private void cleanupMerge(SimplifierTool tool, MergeNode merge) {
811        if (merge != null && merge.isAlive()) {
812            if (merge.forwardEndCount() == 0) {
813                GraphUtil.killCFG(merge, tool);
814            } else if (merge.forwardEndCount() == 1) {
815                graph().reduceTrivialMerge(merge);
816            }
817        }
818    }
819
820    private MergeNode insertMerge(AbstractBeginNode begin) {
821        MergeNode merge = graph().add(new MergeNode());
822        if (!begin.anchored().isEmpty()) {
823            Object before = null;
824            before = begin.anchored().snapshot();
825            begin.replaceAtUsages(InputType.Guard, merge);
826            begin.replaceAtUsages(InputType.Anchor, merge);
827            assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot();
828        }
829
830        AbstractBeginNode theBegin = begin;
831        if (begin instanceof LoopExitNode) {
832            // Insert an extra begin to make it easier.
833            theBegin = graph().add(new BeginNode());
834            begin.replaceAtPredecessor(theBegin);
835            theBegin.setNext(begin);
836        }
837        FixedNode next = theBegin.next();
838        next.replaceAtPredecessor(merge);
839        theBegin.setNext(graph().add(new EndNode()));
840        merge.addForwardEnd((EndNode) theBegin.next());
841        merge.setNext(next);
842        return merge;
843    }
844
845    /**
846     * Tries to connect code that initializes a variable directly with the successors of an if
847     * construct that switches on the variable. For example, the pseudo code below:
848     *
849     * <pre>
850     * contains(list, e, yes, no) {
851     *     if (list == null || e == null) {
852     *         condition = false;
853     *     } else {
854     *         condition = false;
855     *         for (i in list) {
856     *             if (i.equals(e)) {
857     *                 condition = true;
858     *                 break;
859     *             }
860     *         }
861     *     }
862     *     if (condition) {
863     *         return yes;
864     *     } else {
865     *         return no;
866     *     }
867     * }
868     * </pre>
869     *
870     * will be transformed into:
871     *
872     * <pre>
873     * contains(list, e, yes, no) {
874     *     if (list == null || e == null) {
875     *         return no;
876     *     } else {
877     *         condition = false;
878     *         for (i in list) {
879     *             if (i.equals(e)) {
880     *                 return yes;
881     *             }
882     *         }
883     *         return no;
884     *     }
885     * }
886     * </pre>
887     *
888     * @return true if a transformation was made, false otherwise
889     */
890    private boolean removeIntermediateMaterialization(SimplifierTool tool) {
891        if (!(predecessor() instanceof AbstractMergeNode) || predecessor() instanceof LoopBeginNode) {
892            return false;
893        }
894        AbstractMergeNode merge = (AbstractMergeNode) predecessor();
895
896        if (!(condition() instanceof CompareNode)) {
897            return false;
898        }
899
900        CompareNode compare = (CompareNode) condition();
901        if (compare.getUsageCount() != 1) {
902            return false;
903        }
904
905        // Only consider merges with a single usage that is both a phi and an operand of the
906        // comparison
907        NodeIterable<Node> mergeUsages = merge.usages();
908        if (mergeUsages.count() != 1) {
909            return false;
910        }
911        Node singleUsage = mergeUsages.first();
912        if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.getX() && singleUsage != compare.getY())) {
913            return false;
914        }
915
916        // Ensure phi is used by at most the comparison and the merge's frame state (if any)
917        ValuePhiNode phi = (ValuePhiNode) singleUsage;
918        NodeIterable<Node> phiUsages = phi.usages();
919        if (phiUsages.count() > 2) {
920            return false;
921        }
922        for (Node usage : phiUsages) {
923            if (usage != compare && usage != merge.stateAfter()) {
924                return false;
925            }
926        }
927
928        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
929        assert phi.valueCount() == merge.forwardEndCount();
930
931        Constant[] xs = constantValues(compare.getX(), merge, false);
932        Constant[] ys = constantValues(compare.getY(), merge, false);
933        if (xs == null || ys == null) {
934            return false;
935        }
936
937        // Sanity check that both ends are not followed by a merge without frame state.
938        if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) {
939            return false;
940        }
941
942        List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
943        List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
944        Map<AbstractEndNode, ValueNode> phiValues = CollectionsFactory.newMap(mergePredecessors.size());
945
946        AbstractBeginNode oldFalseSuccessor = falseSuccessor();
947        AbstractBeginNode oldTrueSuccessor = trueSuccessor();
948
949        setFalseSuccessor(null);
950        setTrueSuccessor(null);
951
952        Iterator<EndNode> ends = mergePredecessors.iterator();
953        for (int i = 0; i < xs.length; i++) {
954            EndNode end = ends.next();
955            phiValues.put(end, phi.valueAt(end));
956            if (compare.condition().foldCondition(xs[i], ys[i], tool.getConstantReflection(), compare.unorderedIsTrue())) {
957                trueEnds.add(end);
958            } else {
959                falseEnds.add(end);
960            }
961        }
962        assert !ends.hasNext();
963        assert falseEnds.size() + trueEnds.size() == xs.length;
964
965        connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool);
966        connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool);
967
968        if (this.trueSuccessorProbability == 0.0) {
969            for (AbstractEndNode endNode : trueEnds) {
970                propagateZeroProbability(endNode);
971            }
972        }
973
974        if (this.trueSuccessorProbability == 1.0) {
975            for (AbstractEndNode endNode : falseEnds) {
976                propagateZeroProbability(endNode);
977            }
978        }
979
980        /*
981         * Remove obsolete ends only after processing all ends, otherwise oldTrueSuccessor or
982         * oldFalseSuccessor might have been removed if it is a LoopExitNode.
983         */
984        if (falseEnds.isEmpty()) {
985            GraphUtil.killCFG(oldFalseSuccessor);
986        }
987        if (trueEnds.isEmpty()) {
988            GraphUtil.killCFG(oldTrueSuccessor);
989        }
990
991        GraphUtil.killCFG(merge);
992
993        assert !merge.isAlive() : merge;
994        assert !phi.isAlive() : phi;
995        assert !compare.isAlive() : compare;
996        assert !this.isAlive() : this;
997
998        return true;
999    }
1000
1001    private void propagateZeroProbability(FixedNode startNode) {
1002        Node prev = null;
1003        for (FixedNode node : GraphUtil.predecessorIterable(startNode)) {
1004            if (node instanceof IfNode) {
1005                IfNode ifNode = (IfNode) node;
1006                if (ifNode.trueSuccessor() == prev) {
1007                    if (ifNode.trueSuccessorProbability == 0.0) {
1008                        return;
1009                    } else if (ifNode.trueSuccessorProbability == 1.0) {
1010                        continue;
1011                    } else {
1012                        ifNode.setTrueSuccessorProbability(0.0);
1013                        return;
1014                    }
1015                } else if (ifNode.falseSuccessor() == prev) {
1016                    if (ifNode.trueSuccessorProbability == 1.0) {
1017                        return;
1018                    } else if (ifNode.trueSuccessorProbability == 0.0) {
1019                        continue;
1020                    } else {
1021                        ifNode.setTrueSuccessorProbability(1.0);
1022                        return;
1023                    }
1024                } else {
1025                    throw new JVMCIError("Illegal state");
1026                }
1027            } else if (node instanceof AbstractMergeNode && !(node instanceof LoopBeginNode)) {
1028                for (AbstractEndNode endNode : ((AbstractMergeNode) node).cfgPredecessors()) {
1029                    propagateZeroProbability(endNode);
1030                }
1031                return;
1032            }
1033            prev = node;
1034        }
1035    }
1036
1037    private static boolean checkFrameState(FixedNode start) {
1038        FixedNode node = start;
1039        while (true) {
1040            if (node instanceof AbstractMergeNode) {
1041                AbstractMergeNode mergeNode = (AbstractMergeNode) node;
1042                if (mergeNode.stateAfter() == null) {
1043                    return false;
1044                } else {
1045                    return true;
1046                }
1047            } else if (node instanceof StateSplit) {
1048                StateSplit stateSplitNode = (StateSplit) node;
1049                if (stateSplitNode.stateAfter() != null) {
1050                    return true;
1051                }
1052            }
1053
1054            if (node instanceof ControlSplitNode) {
1055                ControlSplitNode controlSplitNode = (ControlSplitNode) node;
1056                for (Node succ : controlSplitNode.cfgSuccessors()) {
1057                    if (checkFrameState((FixedNode) succ)) {
1058                        return true;
1059                    }
1060                }
1061                return false;
1062            } else if (node instanceof FixedWithNextNode) {
1063                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
1064                node = fixedWithNextNode.next();
1065            } else if (node instanceof AbstractEndNode) {
1066                AbstractEndNode endNode = (AbstractEndNode) node;
1067                node = endNode.merge();
1068            } else if (node instanceof ControlSinkNode) {
1069                return true;
1070            } else {
1071                return false;
1072            }
1073        }
1074    }
1075
1076    /**
1077     * Connects a set of ends to a given successor, inserting a merge node if there is more than one
1078     * end. If {@code ends} is not empty, then {@code successor} is added to {@code tool}'s
1079     * {@linkplain SimplifierTool#addToWorkList(com.oracle.graal.graph.Node) work list}.
1080     *
1081     * @param oldMerge the merge being removed
1082     * @param phiValues the values of the phi at the merge, keyed by the merge ends
1083     */
1084    private void connectEnds(List<EndNode> ends, Map<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) {
1085        if (!ends.isEmpty()) {
1086            if (ends.size() == 1) {
1087                AbstractEndNode end = ends.get(0);
1088                ((FixedWithNextNode) end.predecessor()).setNext(successor);
1089                oldMerge.removeEnd(end);
1090                GraphUtil.killCFG(end);
1091            } else {
1092                // Need a new phi in case the frame state is used by more than the merge being
1093                // removed
1094                AbstractMergeNode newMerge = graph().add(new MergeNode());
1095                PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
1096                PhiNode newPhi = graph().addWithoutUnique(new ValuePhiNode(oldPhi.stamp(), newMerge));
1097
1098                for (EndNode end : ends) {
1099                    newPhi.addInput(phiValues.get(end));
1100                    newMerge.addForwardEnd(end);
1101                }
1102
1103                FrameState stateAfter = oldMerge.stateAfter();
1104                if (stateAfter != null) {
1105                    stateAfter = stateAfter.duplicate();
1106                    stateAfter.replaceFirstInput(oldPhi, newPhi);
1107                    newMerge.setStateAfter(stateAfter);
1108                }
1109
1110                newMerge.setNext(successor);
1111            }
1112            tool.addToWorkList(successor);
1113        }
1114    }
1115
1116    /**
1117     * Gets an array of constants derived from a node that is either a {@link ConstantNode} or a
1118     * {@link PhiNode} whose input values are all constants. The length of the returned array is
1119     * equal to the number of ends terminating in a given merge node.
1120     *
1121     * @return null if {@code node} is neither a {@link ConstantNode} nor a {@link PhiNode} whose
1122     *         input values are all constants
1123     */
1124    public static Constant[] constantValues(ValueNode node, AbstractMergeNode merge, boolean allowNull) {
1125        if (node.isConstant()) {
1126            JavaConstant[] result = new JavaConstant[merge.forwardEndCount()];
1127            Arrays.fill(result, node.asConstant());
1128            return result;
1129        }
1130
1131        if (node instanceof PhiNode) {
1132            PhiNode phi = (PhiNode) node;
1133            if (phi.merge() == merge && phi instanceof ValuePhiNode && phi.valueCount() == merge.forwardEndCount()) {
1134                Constant[] result = new Constant[merge.forwardEndCount()];
1135                int i = 0;
1136                for (ValueNode n : phi.values()) {
1137                    if (!allowNull && !n.isConstant()) {
1138                        return null;
1139                    }
1140                    result[i++] = n.asConstant();
1141                }
1142                return result;
1143            }
1144        }
1145
1146        return null;
1147    }
1148
1149    @Override
1150    public AbstractBeginNode getPrimarySuccessor() {
1151        return this.trueSuccessor();
1152    }
1153
1154    public AbstractBeginNode getSuccessor(boolean result) {
1155        return result ? this.trueSuccessor() : this.falseSuccessor();
1156    }
1157}