001/*
002 * Copyright (c) 2015, 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 java.util.*;
026
027import jdk.internal.jvmci.code.*;
028import jdk.internal.jvmci.meta.*;
029
030import com.oracle.graal.graph.*;
031import com.oracle.graal.graph.spi.*;
032import com.oracle.graal.nodes.extended.*;
033import com.oracle.graal.nodes.spi.*;
034import com.oracle.graal.nodes.util.*;
035
036/**
037 * Graph decoder that simplifies nodes during decoding. The standard
038 * {@link Canonicalizable#canonical node canonicalization} interface is used to canonicalize nodes
039 * during decoding. Additionally, {@link IfNode branches} and {@link IntegerSwitchNode switches}
040 * with constant conditions are simplified.
041 */
042public class SimplifyingGraphDecoder extends GraphDecoder {
043
044    protected final MetaAccessProvider metaAccess;
045    protected final ConstantReflectionProvider constantReflection;
046    protected final StampProvider stampProvider;
047    protected final boolean canonicalizeReads;
048
049    protected class PECanonicalizerTool implements CanonicalizerTool {
050        @Override
051        public MetaAccessProvider getMetaAccess() {
052            return metaAccess;
053        }
054
055        @Override
056        public ConstantReflectionProvider getConstantReflection() {
057            return constantReflection;
058        }
059
060        @Override
061        public boolean canonicalizeReads() {
062            return canonicalizeReads;
063        }
064
065        @Override
066        public boolean allUsagesAvailable() {
067            return false;
068        }
069    }
070
071    public SimplifyingGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, boolean canonicalizeReads, Architecture architecture) {
072        super(architecture);
073        this.metaAccess = metaAccess;
074        this.constantReflection = constantReflection;
075        this.stampProvider = stampProvider;
076        this.canonicalizeReads = canonicalizeReads;
077    }
078
079    @Override
080    protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
081        GraphUtil.normalizeLoops(methodScope.graph);
082        super.cleanupGraph(methodScope, start);
083
084        for (Node node : methodScope.graph.getNewNodes(start)) {
085            if (node instanceof MergeNode) {
086                MergeNode mergeNode = (MergeNode) node;
087                if (mergeNode.forwardEndCount() == 1) {
088                    methodScope.graph.reduceTrivialMerge(mergeNode);
089                }
090            }
091        }
092
093        for (Node node : methodScope.graph.getNewNodes(start)) {
094            if (node instanceof BeginNode || node instanceof KillingBeginNode) {
095                if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
096                    GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
097                    node.safeDelete();
098                }
099            }
100        }
101
102        for (Node node : methodScope.graph.getNewNodes(start)) {
103            if (!(node instanceof FixedNode) && node.hasNoUsages()) {
104                GraphUtil.killCFG(node);
105            }
106        }
107    }
108
109    @Override
110    protected boolean allowLazyPhis() {
111        /*
112         * We do not need to exactly reproduce the encoded graph, so we want to avoid unnecessary
113         * phi functions.
114         */
115        return true;
116    }
117
118    @Override
119    protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
120        if (node instanceof IfNode) {
121            IfNode ifNode = (IfNode) node;
122            if (ifNode.condition() instanceof LogicNegationNode) {
123                ifNode.eliminateNegation();
124            }
125            if (ifNode.condition() instanceof LogicConstantNode) {
126                boolean condition = ((LogicConstantNode) ifNode.condition()).getValue();
127                AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition);
128                AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition);
129
130                methodScope.graph.removeSplit(ifNode, survivingSuccessor);
131                assert deadSuccessor.next() == null : "must not be parsed yet";
132                deadSuccessor.safeDelete();
133            }
134
135        } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) {
136            IntegerSwitchNode switchNode = (IntegerSwitchNode) node;
137            int value = switchNode.value().asJavaConstant().asInt();
138            AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value);
139            List<Node> allSuccessors = switchNode.successors().snapshot();
140
141            methodScope.graph.removeSplit(switchNode, survivingSuccessor);
142            for (Node successor : allSuccessors) {
143                if (successor != survivingSuccessor) {
144                    assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet";
145                    successor.safeDelete();
146                }
147            }
148
149        } else if (node instanceof Canonicalizable) {
150            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool());
151            if (canonical == null) {
152                /*
153                 * This is a possible return value of canonicalization. However, we might need to
154                 * add additional usages later on for which we need a node. Therefore, we just do
155                 * nothing and leave the node in place.
156                 */
157            } else if (canonical != node) {
158                if (!canonical.isAlive()) {
159                    assert !canonical.isDeleted();
160                    canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
161                    if (canonical instanceof FixedWithNextNode) {
162                        methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical);
163                    } else if (canonical instanceof ControlSinkNode) {
164                        FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor();
165                        predecessor.setNext((ControlSinkNode) canonical);
166                        node.safeDelete();
167                        for (Node successor : node.successors()) {
168                            successor.safeDelete();
169                        }
170
171                    } else {
172                        assert !(canonical instanceof FixedNode);
173                    }
174                }
175                if (!node.isDeleted()) {
176                    GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
177                    node.replaceAtUsages(canonical);
178                    node.safeDelete();
179                }
180                assert lookupNode(loopScope, nodeOrderId) == node;
181                registerNode(loopScope, nodeOrderId, canonical, true, false);
182            }
183        }
184    }
185
186    @Override
187    protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
188        if (node instanceof Canonicalizable) {
189            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool());
190            if (canonical == null) {
191                /*
192                 * This is a possible return value of canonicalization. However, we might need to
193                 * add additional usages later on for which we need a node. Therefore, we just do
194                 * nothing and leave the node in place.
195                 */
196            } else if (canonical != node) {
197                if (!canonical.isAlive()) {
198                    assert !canonical.isDeleted();
199                    canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
200                }
201                assert node.hasNoUsages();
202                // methodScope.graph.replaceFloating((FloatingNode) node, canonical);
203                return canonical;
204            }
205        }
206        return node;
207    }
208
209    @Override
210    protected Node addFloatingNode(MethodScope methodScope, Node node) {
211        /*
212         * In contrast to the base class implementation, we do not need to exactly reproduce the
213         * encoded graph. Since we do canonicalization, we also want nodes to be unique.
214         */
215        return methodScope.graph.addOrUnique(node);
216    }
217}