001/*
002 * Copyright (c) 2011, 2015, 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 static com.oracle.graal.graph.iterators.NodePredicates.*;
026
027import java.util.*;
028
029import com.oracle.graal.compiler.common.type.*;
030import com.oracle.graal.graph.*;
031import com.oracle.graal.graph.iterators.*;
032import com.oracle.graal.graph.spi.*;
033import com.oracle.graal.nodeinfo.*;
034import com.oracle.graal.nodes.calc.*;
035import com.oracle.graal.nodes.extended.*;
036import com.oracle.graal.nodes.spi.*;
037import com.oracle.graal.nodes.util.*;
038
039@NodeInfo
040public final class LoopBeginNode extends AbstractMergeNode implements IterableNodeType, LIRLowerable {
041
042    public static final NodeClass<LoopBeginNode> TYPE = NodeClass.create(LoopBeginNode.class);
043    protected double loopFrequency;
044    protected int nextEndIndex;
045    protected int unswitches;
046    protected int inversionCount;
047
048    @OptionalInput(InputType.Guard) GuardingNode overflowGuard;
049
050    public LoopBeginNode() {
051        super(TYPE);
052        loopFrequency = 1;
053    }
054
055    public double loopFrequency() {
056        return loopFrequency;
057    }
058
059    public void setLoopFrequency(double loopFrequency) {
060        assert loopFrequency >= 0;
061        this.loopFrequency = loopFrequency;
062    }
063
064    /**
065     * Returns the <b>unordered</b> set of {@link LoopEndNode} that correspond to back-edges for
066     * this loop. The order of the back-edges is unspecified, if you need to get an ordering
067     * compatible for {@link PhiNode} creation, use {@link #orderedLoopEnds()}.
068     *
069     * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
070     */
071    public NodeIterable<LoopEndNode> loopEnds() {
072        return usages().filter(LoopEndNode.class);
073    }
074
075    public NodeIterable<LoopExitNode> loopExits() {
076        return usages().filter(LoopExitNode.class);
077    }
078
079    @Override
080    public NodeIterable<Node> anchored() {
081        return super.anchored().filter(isNotA(LoopEndNode.class).nor(LoopExitNode.class));
082    }
083
084    /**
085     * Returns the set of {@link LoopEndNode} that correspond to back-edges for this loop, in
086     * increasing {@link #phiPredecessorIndex} order. This method is suited to create new loop
087     * {@link PhiNode}.<br>
088     *
089     * For example a new PhiNode may be added as follow:
090     *
091     * <pre>
092     * PhiNode phi = new ValuePhiNode(stamp, loop);
093     * phi.addInput(forwardEdgeValue);
094     * for (LoopEndNode loopEnd : loop.orderedLoopEnds()) {
095     *     phi.addInput(backEdgeValue(loopEnd));
096     * }
097     * </pre>
098     *
099     * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
100     */
101    public LoopEndNode[] orderedLoopEnds() {
102        LoopEndNode[] result = new LoopEndNode[this.getLoopEndCount()];
103        for (LoopEndNode end : loopEnds()) {
104            result[end.endIndex()] = end;
105        }
106        return result;
107    }
108
109    public AbstractEndNode forwardEnd() {
110        assert forwardEndCount() == 1;
111        return forwardEndAt(0);
112    }
113
114    @Override
115    public void generate(NodeLIRBuilderTool gen) {
116        // Nothing to emit, since this is node is used for structural purposes only.
117    }
118
119    @Override
120    protected void deleteEnd(AbstractEndNode end) {
121        if (end instanceof LoopEndNode) {
122            LoopEndNode loopEnd = (LoopEndNode) end;
123            loopEnd.setLoopBegin(null);
124            int idx = loopEnd.endIndex();
125            for (LoopEndNode le : loopEnds()) {
126                int leIdx = le.endIndex();
127                assert leIdx != idx;
128                if (leIdx > idx) {
129                    le.setEndIndex(leIdx - 1);
130                }
131            }
132            nextEndIndex--;
133        } else {
134            super.deleteEnd(end);
135        }
136    }
137
138    @Override
139    public int phiPredecessorCount() {
140        return forwardEndCount() + loopEnds().count();
141    }
142
143    @Override
144    public int phiPredecessorIndex(AbstractEndNode pred) {
145        if (pred instanceof LoopEndNode) {
146            LoopEndNode loopEnd = (LoopEndNode) pred;
147            if (loopEnd.loopBegin() == this) {
148                assert loopEnd.endIndex() < loopEnds().count() : "Invalid endIndex : " + loopEnd;
149                return loopEnd.endIndex() + forwardEndCount();
150            }
151        } else {
152            return super.forwardEndIndex((EndNode) pred);
153        }
154        throw ValueNodeUtil.shouldNotReachHere("unknown pred : " + pred);
155    }
156
157    @Override
158    public AbstractEndNode phiPredecessorAt(int index) {
159        if (index < forwardEndCount()) {
160            return forwardEndAt(index);
161        }
162        for (LoopEndNode end : loopEnds()) {
163            int idx = index - forwardEndCount();
164            assert idx >= 0;
165            if (end.endIndex() == idx) {
166                return end;
167            }
168        }
169        throw ValueNodeUtil.shouldNotReachHere();
170    }
171
172    @Override
173    public boolean verify() {
174        assertTrue(loopEnds().isNotEmpty(), "missing loopEnd");
175        return super.verify();
176    }
177
178    int nextEndIndex() {
179        return nextEndIndex++;
180    }
181
182    public int getLoopEndCount() {
183        return nextEndIndex;
184    }
185
186    public int unswitches() {
187        return unswitches;
188    }
189
190    public void incrementUnswitches() {
191        unswitches++;
192    }
193
194    public int getInversionCount() {
195        return inversionCount;
196    }
197
198    public void setInversionCount(int count) {
199        inversionCount = count;
200    }
201
202    @Override
203    public void simplify(SimplifierTool tool) {
204        removeDeadPhis();
205        canonicalizePhis(tool);
206    }
207
208    public boolean isLoopExit(AbstractBeginNode begin) {
209        return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this;
210    }
211
212    public void removeExits() {
213        for (LoopExitNode loopexit : loopExits().snapshot()) {
214            loopexit.removeProxies();
215            FrameState loopStateAfter = loopexit.stateAfter();
216            graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode()));
217            if (loopStateAfter != null && loopStateAfter.isAlive() && loopStateAfter.hasNoUsages()) {
218                GraphUtil.killWithUnusedFloatingInputs(loopStateAfter);
219            }
220        }
221    }
222
223    public GuardingNode getOverflowGuard() {
224        return overflowGuard;
225    }
226
227    public void setOverflowGuard(GuardingNode overflowGuard) {
228        updateUsagesInterface(this.overflowGuard, overflowGuard);
229        this.overflowGuard = overflowGuard;
230    }
231
232    /**
233     * Removes dead {@linkplain PhiNode phi nodes} hanging from this node.
234     *
235     * This method uses the heuristic that any node which not a phi node of this LoopBeginNode is
236     * alive. This allows the removal of dead phi loops.
237     */
238    public void removeDeadPhis() {
239        if (phis().isNotEmpty()) {
240            Set<PhiNode> alive = Node.newSet();
241            for (PhiNode phi : phis()) {
242                NodePredicate isAlive = u -> !isPhiAtMerge(u) || alive.contains(u);
243                if (phi.usages().filter(isAlive).isNotEmpty()) {
244                    alive.add(phi);
245                    for (PhiNode keptAlive : phi.values().filter(PhiNode.class).filter(isAlive.negate())) {
246                        alive.add(keptAlive);
247                    }
248                }
249            }
250            for (PhiNode phi : phis().filter(((NodePredicate) alive::contains).negate()).snapshot()) {
251                phi.replaceAtUsages(null);
252                phi.safeDelete();
253            }
254        }
255    }
256
257    private static final int NO_INCREMENT = Integer.MIN_VALUE;
258
259    /**
260     * Returns an array with one entry for each input of the phi, which is either
261     * {@link #NO_INCREMENT} or the increment, i.e., the value by which the phi is incremented in
262     * the corresponding branch.
263     */
264    private static int[] getSelfIncrements(PhiNode phi) {
265        int[] selfIncrement = new int[phi.valueCount()];
266        for (int i = 0; i < phi.valueCount(); i++) {
267            ValueNode input = phi.valueAt(i);
268            long increment = NO_INCREMENT;
269            if (input != null && input instanceof AddNode && input.stamp() instanceof IntegerStamp) {
270                AddNode add = (AddNode) input;
271                if (add.getX() == phi && add.getY().isConstant()) {
272                    increment = add.getY().asJavaConstant().asLong();
273                } else if (add.getY() == phi && add.getX().isConstant()) {
274                    increment = add.getX().asJavaConstant().asLong();
275                }
276            } else if (input == phi) {
277                increment = 0;
278            }
279            if (increment < Integer.MIN_VALUE || increment > Integer.MAX_VALUE || increment == NO_INCREMENT) {
280                increment = NO_INCREMENT;
281            }
282            selfIncrement[i] = (int) increment;
283        }
284        return selfIncrement;
285    }
286
287    /**
288     * Coalesces loop phis that represent the same value (which is not handled by normal Global
289     * Value Numbering).
290     */
291    public void canonicalizePhis(SimplifierTool tool) {
292        int phiCount = phis().count();
293        if (phiCount > 1) {
294            int phiInputCount = phiPredecessorCount();
295            int phiIndex = 0;
296            int[][] selfIncrement = new int[phiCount][];
297            PhiNode[] phis = this.phis().snapshot().toArray(new PhiNode[phiCount]);
298
299            for (phiIndex = 0; phiIndex < phiCount; phiIndex++) {
300                PhiNode phi = phis[phiIndex];
301                if (phi != null) {
302                    nextPhi: for (int otherPhiIndex = phiIndex + 1; otherPhiIndex < phiCount; otherPhiIndex++) {
303                        PhiNode otherPhi = phis[otherPhiIndex];
304                        if (otherPhi == null || phi.getNodeClass() != otherPhi.getNodeClass() || !phi.valueEquals(otherPhi)) {
305                            continue nextPhi;
306                        }
307                        if (selfIncrement[phiIndex] == null) {
308                            selfIncrement[phiIndex] = getSelfIncrements(phi);
309                        }
310                        if (selfIncrement[otherPhiIndex] == null) {
311                            selfIncrement[otherPhiIndex] = getSelfIncrements(otherPhi);
312                        }
313                        int[] phiIncrement = selfIncrement[phiIndex];
314                        int[] otherPhiIncrement = selfIncrement[otherPhiIndex];
315                        for (int inputIndex = 0; inputIndex < phiInputCount; inputIndex++) {
316                            if (phiIncrement[inputIndex] == NO_INCREMENT) {
317                                if (phi.valueAt(inputIndex) != otherPhi.valueAt(inputIndex)) {
318                                    continue nextPhi;
319                                }
320                            }
321                            if (phiIncrement[inputIndex] != otherPhiIncrement[inputIndex]) {
322                                continue nextPhi;
323                            }
324                        }
325                        if (tool != null) {
326                            tool.addToWorkList(otherPhi.usages());
327                        }
328                        otherPhi.replaceAtUsages(phi);
329                        GraphUtil.killWithUnusedFloatingInputs(otherPhi);
330                        phis[otherPhiIndex] = null;
331                    }
332                }
333            }
334        }
335    }
336}