PhiNode.java revision 12651:6ef01bd40ce2
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 */
23package org.graalvm.compiler.nodes;
24
25import static org.graalvm.compiler.nodeinfo.InputType.Association;
26import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
27import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
28
29import java.util.Iterator;
30
31import org.graalvm.compiler.core.common.type.Stamp;
32import org.graalvm.compiler.graph.Node;
33import org.graalvm.compiler.graph.NodeClass;
34import org.graalvm.compiler.graph.NodeInputList;
35import org.graalvm.compiler.graph.iterators.NodeIterable;
36import org.graalvm.compiler.graph.spi.Canonicalizable;
37import org.graalvm.compiler.graph.spi.CanonicalizerTool;
38import org.graalvm.compiler.nodeinfo.NodeInfo;
39import org.graalvm.compiler.nodeinfo.Verbosity;
40import 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)
50public 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}
252