1 /* 2 * Copyright (c) 2011, 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 */ 23 package org.graalvm.compiler.nodes.calc; 24 25 import org.graalvm.compiler.core.common.calc.Condition; 26 import org.graalvm.compiler.core.common.type.AbstractPointerStamp; 27 import org.graalvm.compiler.core.common.type.FloatStamp; 28 import org.graalvm.compiler.core.common.type.IntegerStamp; 29 import org.graalvm.compiler.core.common.type.Stamp; 30 import org.graalvm.compiler.debug.GraalError; 31 import org.graalvm.compiler.graph.NodeClass; 32 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative; 33 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 34 import org.graalvm.compiler.nodeinfo.NodeInfo; 35 import org.graalvm.compiler.nodes.ConstantNode; 36 import org.graalvm.compiler.nodes.LogicConstantNode; 37 import org.graalvm.compiler.nodes.LogicNegationNode; 38 import org.graalvm.compiler.nodes.LogicNode; 39 import org.graalvm.compiler.nodes.ValueNode; 40 import org.graalvm.compiler.nodes.util.GraphUtil; 41 42 import jdk.vm.ci.meta.Constant; 43 import jdk.vm.ci.meta.ConstantReflectionProvider; 44 import jdk.vm.ci.meta.JavaKind; 45 import jdk.vm.ci.meta.PrimitiveConstant; 46 import jdk.vm.ci.meta.TriState; 47 48 @NodeInfo(shortName = "==") 49 public final class IntegerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> { 50 public static final NodeClass<IntegerEqualsNode> TYPE = NodeClass.create(IntegerEqualsNode.class); 51 52 public IntegerEqualsNode(ValueNode x, ValueNode y) { 53 super(TYPE, Condition.EQ, false, x, y); 54 assert !x.getStackKind().isNumericFloat() && x.getStackKind() != JavaKind.Object; 55 assert !y.getStackKind().isNumericFloat() && y.getStackKind() != JavaKind.Object; 56 } 57 58 public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { 59 LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false); 60 if (result != null) { 61 return result; 62 } else { 63 if (x instanceof ConditionalNode) { 64 ConditionalNode conditionalNode = (ConditionalNode) x; 65 if (conditionalNode.trueValue() == y) { 66 return conditionalNode.condition(); 67 } 68 if (conditionalNode.falseValue() == y) { 69 return LogicNegationNode.create(conditionalNode.condition()); 70 } 71 } else if (y instanceof ConditionalNode) { 72 ConditionalNode conditionalNode = (ConditionalNode) y; 73 if (conditionalNode.trueValue() == x) { 74 return conditionalNode.condition(); 75 } 76 if (conditionalNode.falseValue() == x) { 77 return LogicNegationNode.create(conditionalNode.condition()); 78 } 79 } 80 81 return new IntegerEqualsNode(x, y).maybeCommuteInputs(); 82 } 83 } 84 85 @Override 86 protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { 87 PrimitiveConstant primitive = (PrimitiveConstant) constant; 88 if (primitive.getJavaKind() == JavaKind.Int && primitive.asInt() == 0) { 89 ValueNode a = mirrored ? normalizeNode.getY() : normalizeNode.getX(); 90 ValueNode b = mirrored ? normalizeNode.getX() : normalizeNode.getY(); 91 92 if (normalizeNode.getX().getStackKind() == JavaKind.Double || normalizeNode.getX().getStackKind() == JavaKind.Float) { 93 return new FloatEqualsNode(a, b); 94 } else { 95 return new IntegerEqualsNode(a, b); 96 } 97 } 98 return this; 99 } 100 101 @Override 102 protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) { 103 if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) { 104 return new FloatEqualsNode(newX, newY); 105 } else if (newX.stamp() instanceof IntegerStamp && newY.stamp() instanceof IntegerStamp) { 106 return new IntegerEqualsNode(newX, newY); 107 } else if (newX.stamp() instanceof AbstractPointerStamp && newY.stamp() instanceof AbstractPointerStamp) { 108 return new IntegerEqualsNode(newX, newY); 109 } 110 throw GraalError.shouldNotReachHere(); 111 } 112 113 @Override 114 public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { 115 if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { 116 return LogicConstantNode.tautology(); 117 } else if (forX.stamp().alwaysDistinct(forY.stamp())) { 118 return LogicConstantNode.contradiction(); 119 } 120 return super.canonical(tool, forX, forY); 121 } 122 123 @Override 124 protected ValueNode canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) { 125 if (constant instanceof PrimitiveConstant) { 126 PrimitiveConstant primitiveConstant = (PrimitiveConstant) constant; 127 IntegerStamp nonConstantStamp = ((IntegerStamp) nonConstant.stamp()); 128 if ((primitiveConstant.asLong() == 1 && nonConstantStamp.upperBound() == 1 && nonConstantStamp.lowerBound() == 0) || 129 (primitiveConstant.asLong() == -1 && nonConstantStamp.upperBound() == 0 && nonConstantStamp.lowerBound() == -1)) { 130 // nonConstant can only be 0 or 1 (respective -1), test against 0 instead of 1 131 // (respective -1) for a more canonical graph and also to allow for faster execution 132 // on specific platforms. 133 return LogicNegationNode.create(IntegerEqualsNode.create(nonConstant, ConstantNode.forIntegerKind(nonConstant.getStackKind(), 0), null)); 134 } else if (primitiveConstant.asLong() == 0) { 135 if (nonConstant instanceof AndNode) { 136 AndNode andNode = (AndNode) nonConstant; 137 return new IntegerTestNode(andNode.getX(), andNode.getY()); 138 } else if (nonConstant instanceof SubNode) { 139 SubNode subNode = (SubNode) nonConstant; 140 return IntegerEqualsNode.create(subNode.getX(), subNode.getY(), tool.getConstantReflection()); 141 } else if (nonConstant instanceof ShiftNode && nonConstant.stamp() instanceof IntegerStamp) { 142 if (nonConstant instanceof LeftShiftNode) { 143 LeftShiftNode shift = (LeftShiftNode) nonConstant; 144 if (shift.getY().isConstant()) { 145 int mask = shift.getShiftAmountMask(); 146 int amount = shift.getY().asJavaConstant().asInt() & mask; 147 if (shift.getX().getStackKind() == JavaKind.Int) { 148 return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 >>> amount)); 149 } else { 150 assert shift.getX().getStackKind() == JavaKind.Long; 151 return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L >>> amount)); 152 } 153 } 154 } else if (nonConstant instanceof RightShiftNode) { 155 RightShiftNode shift = (RightShiftNode) nonConstant; 156 if (shift.getY().isConstant() && ((IntegerStamp) shift.getX().stamp()).isPositive()) { 157 int mask = shift.getShiftAmountMask(); 158 int amount = shift.getY().asJavaConstant().asInt() & mask; 159 if (shift.getX().getStackKind() == JavaKind.Int) { 160 return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount)); 161 } else { 162 assert shift.getX().getStackKind() == JavaKind.Long; 163 return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount)); 164 } 165 } 166 } else if (nonConstant instanceof UnsignedRightShiftNode) { 167 UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant; 168 if (shift.getY().isConstant()) { 169 int mask = shift.getShiftAmountMask(); 170 int amount = shift.getY().asJavaConstant().asInt() & mask; 171 if (shift.getX().getStackKind() == JavaKind.Int) { 172 return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount)); 173 } else { 174 assert shift.getX().getStackKind() == JavaKind.Long; 175 return new IntegerTestNode(shift.getX(), ConstantNode.forLong(-1L << amount)); 176 } 177 } 178 } 179 } 180 } 181 if (nonConstant instanceof AddNode) { 182 AddNode addNode = (AddNode) nonConstant; 183 if (addNode.getY().isJavaConstant()) { 184 return new IntegerEqualsNode(addNode.getX(), ConstantNode.forIntegerStamp(nonConstantStamp, primitiveConstant.asLong() - addNode.getY().asJavaConstant().asLong())); 185 } 186 } 187 if (nonConstant instanceof AndNode) { 188 /* 189 * a & c == c is the same as a & c != 0, if c is a single bit. 190 */ 191 AndNode andNode = (AndNode) nonConstant; 192 if (Long.bitCount(((PrimitiveConstant) constant).asLong()) == 1 && andNode.getY().isConstant() && andNode.getY().asJavaConstant().equals(constant)) { 193 return new LogicNegationNode(new IntegerTestNode(andNode.getX(), andNode.getY())); 194 } 195 } 196 } 197 return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored); 198 } 199 200 @Override 201 public Stamp getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp) { 202 if (!negated) { 203 return xStamp.join(yStamp); 204 } 205 return null; 206 } 207 208 @Override 209 public Stamp getSucceedingStampForY(boolean negated, Stamp xStamp, Stamp yStamp) { 210 if (!negated) { 211 return xStamp.join(yStamp); 212 } 213 return null; 214 } 215 216 @Override 217 public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) { 218 if (xStampGeneric instanceof IntegerStamp && yStampGeneric instanceof IntegerStamp) { 219 IntegerStamp xStamp = (IntegerStamp) xStampGeneric; 220 IntegerStamp yStamp = (IntegerStamp) yStampGeneric; 221 if (xStamp.alwaysDistinct(yStamp)) { 222 return TriState.FALSE; 223 } else if (xStamp.neverDistinct(yStamp)) { 224 return TriState.TRUE; 225 } 226 } 227 return TriState.UNKNOWN; 228 } 229 }