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 }