1/*
2 * Copyright (c) 2012, 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.InputType.Association;
26import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
27import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
28
29import org.graalvm.compiler.graph.IterableNodeType;
30import org.graalvm.compiler.graph.Node;
31import org.graalvm.compiler.graph.NodeClass;
32import org.graalvm.compiler.graph.iterators.NodeIterable;
33import org.graalvm.compiler.graph.spi.Simplifiable;
34import org.graalvm.compiler.graph.spi.SimplifierTool;
35import org.graalvm.compiler.nodeinfo.NodeInfo;
36
37@NodeInfo(allowedUsageTypes = {Association}, cycles = CYCLES_0, size = SIZE_0)
38public final class LoopExitNode extends BeginStateSplitNode implements IterableNodeType, Simplifiable {
39
40    public static final NodeClass<LoopExitNode> TYPE = NodeClass.create(LoopExitNode.class);
41
42    /*
43     * The declared type of the field cannot be LoopBeginNode, because loop explosion during partial
44     * evaluation can temporarily assign a non-loop begin. This node will then be deleted shortly
45     * after - but we still must not have type system violations for that short amount of time.
46     */
47    @Input(Association) AbstractBeginNode loopBegin;
48
49    public LoopExitNode(LoopBeginNode loop) {
50        super(TYPE);
51        assert loop != null;
52        loopBegin = loop;
53    }
54
55    public LoopBeginNode loopBegin() {
56        return (LoopBeginNode) loopBegin;
57    }
58
59    @Override
60    public NodeIterable<Node> anchored() {
61        return super.anchored().filter(n -> {
62            if (n instanceof ProxyNode) {
63                ProxyNode proxyNode = (ProxyNode) n;
64                return proxyNode.proxyPoint() != this;
65            }
66            return true;
67        });
68    }
69
70    @Override
71    public void prepareDelete(FixedNode evacuateFrom) {
72        removeProxies();
73        super.prepareDelete(evacuateFrom);
74    }
75
76    public void removeProxies() {
77        if (this.hasUsages()) {
78            outer: while (true) {
79                for (ProxyNode vpn : proxies().snapshot()) {
80                    ValueNode value = vpn.value();
81                    vpn.replaceAtUsagesAndDelete(value);
82                    if (value == this) {
83                        // Guard proxy could have this input as value.
84                        continue outer;
85                    }
86                }
87                break;
88            }
89        }
90    }
91
92    @SuppressWarnings({"unchecked", "rawtypes"})
93    public NodeIterable<ProxyNode> proxies() {
94        return (NodeIterable) usages().filter(n -> {
95            if (n instanceof ProxyNode) {
96                ProxyNode proxyNode = (ProxyNode) n;
97                return proxyNode.proxyPoint() == this;
98            }
99            return false;
100        });
101    }
102
103    @Override
104    public void simplify(SimplifierTool tool) {
105        Node prev = this.predecessor();
106        while (tool.allUsagesAvailable() && prev instanceof BeginNode && prev.hasNoUsages()) {
107            AbstractBeginNode begin = (AbstractBeginNode) prev;
108            prev = prev.predecessor();
109            graph().removeFixed(begin);
110        }
111    }
112}
113