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