SwitchNode.java revision 12651:6ef01bd40ce2
198184Sgordon/*
298184Sgordon * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
398184Sgordon * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
498184Sgordon *
598184Sgordon * This code is free software; you can redistribute it and/or modify it
698184Sgordon * under the terms of the GNU General Public License version 2 only, as
798184Sgordon * published by the Free Software Foundation.
8180564Sdougb *
998184Sgordon * This code is distributed in the hope that it will be useful, but WITHOUT
1098184Sgordon * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1198184Sgordon * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1298184Sgordon * version 2 for more details (a copy is included in the LICENSE file that
1398184Sgordon * accompanied this code).
14231667Sdougb *
15231667Sdougb * You should have received a copy of the GNU General Public License version
16231667Sdougb * 2 along with this work; if not, write to the Free Software Foundation,
1798184Sgordon * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1898184Sgordon *
1998184Sgordon * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2098184Sgordon * or visit www.oracle.com if you need additional information or have any
2198184Sgordon * questions.
22165664Syar */
23165664Syarpackage org.graalvm.compiler.nodes.extended;
24231667Sdougb
25231667Sdougbimport static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
26101851Sgordonimport static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
27104980Sschweikh
28104980Sschweikhimport java.util.Arrays;
29117346Smtm
30104980Sschweikhimport org.graalvm.compiler.core.common.type.AbstractPointerStamp;
31104980Sschweikhimport org.graalvm.compiler.core.common.type.StampFactory;
3298184Sgordonimport org.graalvm.compiler.debug.GraalError;
3398184Sgordonimport org.graalvm.compiler.graph.Node;
3498184Sgordonimport org.graalvm.compiler.graph.NodeClass;
35import org.graalvm.compiler.graph.NodeSuccessorList;
36import org.graalvm.compiler.graph.spi.SimplifierTool;
37import org.graalvm.compiler.nodeinfo.NodeInfo;
38import org.graalvm.compiler.nodes.AbstractBeginNode;
39import org.graalvm.compiler.nodes.ControlSplitNode;
40import org.graalvm.compiler.nodes.ValueNode;
41
42import jdk.vm.ci.meta.Constant;
43
44/**
45 * The {@code SwitchNode} class is the base of both lookup and table switches.
46 */
47// @formatter:off
48@NodeInfo(cycles = CYCLES_UNKNOWN,
49          cyclesRationale = "We cannot estimate the runtime cost of a switch statement without knowing the number" +
50                            "of case statements and the involved keys.",
51          size = SIZE_UNKNOWN,
52          sizeRationale = "We cannot estimate the code size of a switch statement without knowing the number" +
53                          "of case statements.")
54// @formatter:on
55public abstract class SwitchNode extends ControlSplitNode {
56
57    public static final NodeClass<SwitchNode> TYPE = NodeClass.create(SwitchNode.class);
58    @Successor protected NodeSuccessorList<AbstractBeginNode> successors;
59    @Input protected ValueNode value;
60
61    // do not change the contents of these arrays:
62    protected final double[] keyProbabilities;
63    protected final int[] keySuccessors;
64
65    /**
66     * Constructs a new Switch.
67     *
68     * @param value the instruction that provides the value to be switched over
69     * @param successors the list of successors of this switch
70     */
71    protected SwitchNode(NodeClass<? extends SwitchNode> c, ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
72        super(c, StampFactory.forVoid());
73        assert value.stamp().getStackKind().isNumericInteger() || value.stamp() instanceof AbstractPointerStamp : value.stamp() + " key not supported by SwitchNode";
74        assert keySuccessors.length == keyProbabilities.length;
75        this.successors = new NodeSuccessorList<>(this, successors);
76        this.value = value;
77        this.keySuccessors = keySuccessors;
78        this.keyProbabilities = keyProbabilities;
79        assert assertProbabilities();
80    }
81
82    private boolean assertProbabilities() {
83        double total = 0;
84        for (double d : keyProbabilities) {
85            total += d;
86            assert d >= 0.0 : "Cannot have negative probabilities in switch node: " + d;
87        }
88        assert total > 0.999 && total < 1.001 : "Total " + total;
89        return true;
90    }
91
92    @Override
93    public double probability(AbstractBeginNode successor) {
94        double sum = 0;
95        for (int i = 0; i < keySuccessors.length; i++) {
96            if (successors.get(keySuccessors[i]) == successor) {
97                sum += keyProbabilities[i];
98            }
99        }
100        return sum;
101    }
102
103    public ValueNode value() {
104        return value;
105    }
106
107    public abstract boolean isSorted();
108
109    /**
110     * The number of distinct keys in this switch.
111     */
112    public abstract int keyCount();
113
114    /**
115     * The key at the specified position, encoded in a Constant.
116     */
117    public abstract Constant keyAt(int i);
118
119    public boolean structureEquals(SwitchNode switchNode) {
120        return Arrays.equals(keySuccessors, switchNode.keySuccessors) && equalKeys(switchNode);
121    }
122
123    /**
124     * Returns true if the switch has the same keys in the same order as this switch.
125     */
126    public abstract boolean equalKeys(SwitchNode switchNode);
127
128    /**
129     * Returns the index of the successor belonging to the key at the specified index.
130     */
131    public int keySuccessorIndex(int i) {
132        return keySuccessors[i];
133    }
134
135    /**
136     * Returns the successor for the key at the given index.
137     */
138    public AbstractBeginNode keySuccessor(int i) {
139        return successors.get(keySuccessors[i]);
140    }
141
142    /**
143     * Returns the probability of the key at the given index.
144     */
145    public double keyProbability(int i) {
146        return keyProbabilities[i];
147    }
148
149    /**
150     * Returns the index of the default (fall through) successor of this switch.
151     */
152    public int defaultSuccessorIndex() {
153        return keySuccessors[keySuccessors.length - 1];
154    }
155
156    public AbstractBeginNode blockSuccessor(int i) {
157        return successors.get(i);
158    }
159
160    public void setBlockSuccessor(int i, AbstractBeginNode s) {
161        successors.set(i, s);
162    }
163
164    public int blockSuccessorCount() {
165        return successors.count();
166    }
167
168    /**
169     * Gets the successor corresponding to the default (fall through) case.
170     *
171     * @return the default successor
172     */
173    public AbstractBeginNode defaultSuccessor() {
174        if (defaultSuccessorIndex() == -1) {
175            throw new GraalError("unexpected");
176        }
177        return successors.get(defaultSuccessorIndex());
178    }
179
180    @Override
181    public AbstractBeginNode getPrimarySuccessor() {
182        return this.defaultSuccessor();
183    }
184
185    /**
186     * Delete all other successors except for the one reached by {@code survivingEdge}.
187     *
188     * @param tool
189     * @param survivingEdge index of the edge in the {@link SwitchNode#successors} list
190     */
191    protected void killOtherSuccessors(SimplifierTool tool, int survivingEdge) {
192        for (Node successor : successors()) {
193            /*
194             * Deleting a branch change change the successors so reload the surviving successor each
195             * time.
196             */
197            if (successor != blockSuccessor(survivingEdge)) {
198                tool.deleteBranch(successor);
199            }
200        }
201        tool.addToWorkList(blockSuccessor(survivingEdge));
202        graph().removeSplit(this, blockSuccessor(survivingEdge));
203    }
204}
205