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