1 /*
   2  * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.nodes;
  24 
  25 import static org.graalvm.compiler.nodeinfo.InputType.Association;
  26 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
  27 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
  28 
  29 import java.util.Iterator;
  30 
  31 import org.graalvm.compiler.core.common.type.Stamp;
  32 import org.graalvm.compiler.graph.Node;
  33 import org.graalvm.compiler.graph.NodeClass;
  34 import org.graalvm.compiler.graph.NodeInputList;
  35 import org.graalvm.compiler.graph.iterators.NodeIterable;
  36 import org.graalvm.compiler.graph.spi.Canonicalizable;
  37 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  38 import org.graalvm.compiler.nodeinfo.NodeInfo;
  39 import org.graalvm.compiler.nodeinfo.Verbosity;
  40 import org.graalvm.compiler.nodes.calc.FloatingNode;
  41 
  42 /**
  43  * {@code PhiNode}s represent the merging of edges at a control flow merges (
  44  * {@link AbstractMergeNode} or {@link LoopBeginNode}). For a {@link AbstractMergeNode}, the order
  45  * of the values corresponds to the order of the ends. For {@link LoopBeginNode}s, the first value
  46  * corresponds to the loop's predecessor, while the rest of the values correspond to the
  47  * {@link LoopEndNode}s.
  48  */
  49 @NodeInfo(cycles = CYCLES_0, size = SIZE_1)
  50 public abstract class PhiNode extends FloatingNode implements Canonicalizable {
  51 
  52     public static final NodeClass<PhiNode> TYPE = NodeClass.create(PhiNode.class);
  53     @Input(Association) protected AbstractMergeNode merge;
  54 
  55     protected PhiNode(NodeClass<? extends PhiNode> c, Stamp stamp, AbstractMergeNode merge) {
  56         super(c, stamp);
  57         this.merge = merge;
  58     }
  59 
  60     public abstract NodeInputList<ValueNode> values();
  61 
  62     public AbstractMergeNode merge() {
  63         return merge;
  64     }
  65 
  66     public void setMerge(AbstractMergeNode x) {
  67         updateUsages(merge, x);
  68         merge = x;
  69     }
  70 
  71     @Override
  72     public boolean verify() {
  73         assertTrue(merge() != null, "missing merge");
  74         assertTrue(merge().phiPredecessorCount() == valueCount(), "mismatch between merge predecessor count and phi value count: %d != %d", merge().phiPredecessorCount(), valueCount());
  75         return super.verify();
  76     }
  77 
  78     /**
  79      * Get the instruction that produces the value associated with the i'th predecessor of the
  80      * merge.
  81      *
  82      * @param i the index of the predecessor
  83      * @return the instruction that produced the value in the i'th predecessor
  84      */
  85     public ValueNode valueAt(int i) {
  86         return values().get(i);
  87     }
  88 
  89     /**
  90      * Sets the value at the given index and makes sure that the values list is large enough.
  91      *
  92      * @param i the index at which to set the value
  93      * @param x the new phi input value for the given location
  94      */
  95     public void initializeValueAt(int i, ValueNode x) {
  96         while (values().size() <= i) {
  97             values().add(null);
  98         }
  99         values().set(i, x);
 100     }
 101 
 102     public void setValueAt(int i, ValueNode x) {
 103         values().set(i, x);
 104     }
 105 
 106     public void setValueAt(AbstractEndNode end, ValueNode x) {
 107         setValueAt(merge().phiPredecessorIndex(end), x);
 108     }
 109 
 110     public ValueNode valueAt(AbstractEndNode pred) {
 111         return valueAt(merge().phiPredecessorIndex(pred));
 112     }
 113 
 114     /**
 115      * Get the number of inputs to this phi (i.e. the number of predecessors to the merge).
 116      *
 117      * @return the number of inputs in this phi
 118      */
 119     public int valueCount() {
 120         return values().size();
 121     }
 122 
 123     public void clearValues() {
 124         values().clear();
 125     }
 126 
 127     @Override
 128     public String toString(Verbosity verbosity) {
 129         if (verbosity == Verbosity.Name) {
 130             StringBuilder str = new StringBuilder();
 131             for (int i = 0; i < valueCount(); ++i) {
 132                 if (i != 0) {
 133                     str.append(' ');
 134                 }
 135                 str.append(valueAt(i) == null ? "-" : valueAt(i).toString(Verbosity.Id));
 136             }
 137             return super.toString(Verbosity.Name) + "(" + str + ")";
 138         } else {
 139             return super.toString(verbosity);
 140         }
 141     }
 142 
 143     public void addInput(ValueNode x) {
 144         assert !(x instanceof ValuePhiNode) || ((ValuePhiNode) x).merge() instanceof LoopBeginNode || ((ValuePhiNode) x).merge() != this.merge();
 145         assert !(this instanceof ValuePhiNode) || x.stamp().isCompatible(stamp());
 146         values().add(x);
 147     }
 148 
 149     public void removeInput(int index) {
 150         values().remove(index);
 151     }
 152 
 153     public NodeIterable<ValueNode> backValues() {
 154         return values().subList(merge().forwardEndCount());
 155     }
 156 
 157     @NodeInfo
 158     static final class MultipleValuesNode extends ValueNode {
 159 
 160         public static final NodeClass<MultipleValuesNode> TYPE = NodeClass.create(MultipleValuesNode.class);
 161 
 162         protected MultipleValuesNode() {
 163             super(TYPE, null);
 164         }
 165 
 166     }
 167 
 168     public static final ValueNode MULTIPLE_VALUES = new MultipleValuesNode();
 169 
 170     /**
 171      * If all inputs are the same value, this value is returned, otherwise {@link #MULTIPLE_VALUES}.
 172      * Note that {@code null} is a valid return value, since {@link GuardPhiNode}s can have
 173      * {@code null} inputs.
 174      */
 175     public ValueNode singleValue() {
 176         ValueNode singleValue = valueAt(0);
 177         int count = valueCount();
 178         for (int i = 1; i < count; ++i) {
 179             ValueNode value = valueAt(i);
 180             if (value != this) {
 181                 if (value != singleValue) {
 182                     return MULTIPLE_VALUES;
 183                 }
 184             }
 185         }
 186         return singleValue;
 187     }
 188 
 189     /**
 190      * If all inputs (but the first one) are the same value, this value is returned, otherwise
 191      * {@link #MULTIPLE_VALUES}. Note that {@code null} is a valid return value, since
 192      * {@link GuardPhiNode}s can have {@code null} inputs.
 193      */
 194     public ValueNode singleBackValue() {
 195         assert merge() instanceof LoopBeginNode;
 196         Iterator<ValueNode> iterator = values().iterator();
 197         iterator.next();
 198         ValueNode singleValue = iterator.next();
 199         while (iterator.hasNext()) {
 200             if (iterator.next() != singleValue) {
 201                 return MULTIPLE_VALUES;
 202             }
 203         }
 204         return singleValue;
 205     }
 206 
 207     @Override
 208     public ValueNode canonical(CanonicalizerTool tool) {
 209 
 210         if (isLoopPhi()) {
 211             if (singleBackValue() == this) {
 212                 return firstValue();
 213             }
 214 
 215             boolean onlySelfUsage = true;
 216             for (Node n : this.usages()) {
 217                 if (n != this) {
 218                     onlySelfUsage = false;
 219                     break;
 220                 }
 221             }
 222 
 223             if (onlySelfUsage) {
 224                 return null;
 225             }
 226         }
 227 
 228         ValueNode singleValue = singleValue();
 229         if (singleValue != MULTIPLE_VALUES) {
 230             return singleValue;
 231         }
 232         return this;
 233     }
 234 
 235     public ValueNode firstValue() {
 236         return valueAt(0);
 237     }
 238 
 239     public boolean isLoopPhi() {
 240         return merge() instanceof LoopBeginNode;
 241     }
 242 
 243     public boolean hasValidInput() {
 244         for (ValueNode n : values()) {
 245             if (n != null) {
 246                 return true;
 247             }
 248         }
 249         return false;
 250     }
 251 }