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}