1 /* 2 * Copyright (c) 2011, 2019, 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 24 25 package org.graalvm.compiler.nodes.calc; 26 27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; 28 29 import org.graalvm.compiler.core.common.calc.CanonicalCondition; 30 import org.graalvm.compiler.core.common.type.FloatStamp; 31 import org.graalvm.compiler.core.common.type.IntegerStamp; 32 import org.graalvm.compiler.core.common.type.Stamp; 33 import org.graalvm.compiler.debug.GraalError; 34 import org.graalvm.compiler.graph.Node; 35 import org.graalvm.compiler.graph.NodeClass; 36 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative; 37 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 38 import org.graalvm.compiler.nodeinfo.NodeInfo; 39 import org.graalvm.compiler.nodes.LogicConstantNode; 40 import org.graalvm.compiler.nodes.LogicNode; 41 import org.graalvm.compiler.nodes.NodeView; 42 import org.graalvm.compiler.nodes.ValueNode; 43 import org.graalvm.compiler.nodes.util.GraphUtil; 44 import org.graalvm.compiler.options.OptionValues; 45 46 import jdk.vm.ci.meta.ConstantReflectionProvider; 47 import jdk.vm.ci.meta.JavaKind; 48 import jdk.vm.ci.meta.MetaAccessProvider; 49 import jdk.vm.ci.meta.TriState; 50 51 @NodeInfo(shortName = "==", cycles = CYCLES_2) 52 public final class FloatEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> { 53 public static final NodeClass<FloatEqualsNode> TYPE = NodeClass.create(FloatEqualsNode.class); 54 private static final FloatEqualsOp OP = new FloatEqualsOp(); 55 FloatEqualsNode(ValueNode x, ValueNode y)56 public FloatEqualsNode(ValueNode x, ValueNode y) { 57 super(TYPE, CanonicalCondition.EQ, false, x, y); 58 assert !x.getStackKind().isNumericInteger() && x.getStackKind() != JavaKind.Object; 59 assert !y.getStackKind().isNumericInteger() && y.getStackKind() != JavaKind.Object; 60 assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT)); 61 } 62 create(ValueNode x, ValueNode y, NodeView view)63 public static LogicNode create(ValueNode x, ValueNode y, NodeView view) { 64 LogicNode result = CompareNode.tryConstantFoldPrimitive(CanonicalCondition.EQ, x, y, false, view); 65 if (result != null) { 66 return result; 67 } else { 68 return new FloatEqualsNode(x, y).maybeCommuteInputs(); 69 } 70 } 71 create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, ValueNode x, ValueNode y, NodeView view)72 public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, 73 ValueNode x, ValueNode y, NodeView view) { 74 LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, CanonicalCondition.EQ, false, x, y, view); 75 if (value != null) { 76 return value; 77 } 78 return create(x, y, view); 79 } 80 81 @Override isIdentityComparison()82 public boolean isIdentityComparison() { 83 Stamp xStamp = x.stamp(NodeView.DEFAULT); 84 Stamp yStamp = y.stamp(NodeView.DEFAULT); 85 if (xStamp instanceof FloatStamp && yStamp instanceof FloatStamp) { 86 /* 87 * If both stamps have at most one 0.0 and it's the same 0.0 then this is an identity 88 * comparison. FloatStamp isn't careful about tracking the presence of -0.0 so assume 89 * that anything that includes 0.0 might include -0.0. So if either one is non-zero then 90 * it's an identity comparison. 91 */ 92 return (!((FloatStamp) xStamp).contains(0.0) || !((FloatStamp) yStamp).contains(0.0)); 93 } else { 94 return false; 95 } 96 } 97 98 @Override canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY)99 public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { 100 NodeView view = NodeView.from(tool); 101 ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, unorderedIsTrue, forX, forY, view); 102 if (value != null) { 103 return value; 104 } 105 return this; 106 } 107 108 public static class FloatEqualsOp extends CompareOp { 109 110 @Override canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view)111 public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, 112 boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { 113 LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view); 114 if (result != null) { 115 return result; 116 } 117 Stamp xStampGeneric = forX.stamp(view); 118 Stamp yStampGeneric = forY.stamp(view); 119 if (xStampGeneric instanceof FloatStamp && yStampGeneric instanceof FloatStamp) { 120 FloatStamp xStamp = (FloatStamp) xStampGeneric; 121 FloatStamp yStamp = (FloatStamp) yStampGeneric; 122 if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY) && xStamp.isNonNaN() && yStamp.isNonNaN()) { 123 return LogicConstantNode.tautology(); 124 } else if (xStamp.alwaysDistinct(yStamp)) { 125 return LogicConstantNode.contradiction(); 126 } 127 } 128 return null; 129 } 130 131 @Override duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue, NodeView view)132 protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue, NodeView view) { 133 if (newX.stamp(view) instanceof FloatStamp && newY.stamp(view) instanceof FloatStamp) { 134 return new FloatEqualsNode(newX, newY); 135 } else if (newX.stamp(view) instanceof IntegerStamp && newY.stamp(view) instanceof IntegerStamp) { 136 return new IntegerEqualsNode(newX, newY); 137 } 138 throw GraalError.shouldNotReachHere(); 139 } 140 } 141 142 @Override getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp)143 public Stamp getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp) { 144 if (!negated) { 145 return xStamp.join(yStamp); 146 } 147 return null; 148 } 149 150 @Override getSucceedingStampForY(boolean negated, Stamp xStamp, Stamp yStamp)151 public Stamp getSucceedingStampForY(boolean negated, Stamp xStamp, Stamp yStamp) { 152 if (!negated) { 153 return xStamp.join(yStamp); 154 } 155 return null; 156 } 157 158 @Override tryFold(Stamp xStampGeneric, Stamp yStampGeneric)159 public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) { 160 if (xStampGeneric instanceof FloatStamp && yStampGeneric instanceof FloatStamp) { 161 FloatStamp xStamp = (FloatStamp) xStampGeneric; 162 FloatStamp yStamp = (FloatStamp) yStampGeneric; 163 if (xStamp.alwaysDistinct(yStamp)) { 164 return TriState.FALSE; 165 } else if (xStamp.neverDistinct(yStamp)) { 166 return TriState.TRUE; 167 } 168 } 169 return TriState.UNKNOWN; 170 } 171 } 172