1 /*
   2  * Copyright (c) 2013, 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_1;
  28 
  29 import java.nio.ByteBuffer;
  30 import java.nio.ByteOrder;
  31 
  32 import org.graalvm.compiler.core.common.LIRKind;
  33 import org.graalvm.compiler.core.common.type.ArithmeticStamp;
  34 import org.graalvm.compiler.core.common.type.FloatStamp;
  35 import org.graalvm.compiler.core.common.type.IntegerStamp;
  36 import org.graalvm.compiler.core.common.type.Stamp;
  37 import org.graalvm.compiler.core.common.type.StampFactory;
  38 import org.graalvm.compiler.graph.NodeClass;
  39 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  40 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
  41 import org.graalvm.compiler.nodeinfo.NodeInfo;
  42 import org.graalvm.compiler.nodes.ConstantNode;
  43 import org.graalvm.compiler.nodes.NodeView;
  44 import org.graalvm.compiler.nodes.ValueNode;
  45 import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
  46 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  47 import org.graalvm.compiler.serviceprovider.BufferUtil;
  48 
  49 import jdk.vm.ci.code.CodeUtil;
  50 import jdk.vm.ci.meta.JavaKind;
  51 import jdk.vm.ci.meta.SerializableConstant;
  52 
  53 /**
  54  * The {@code ReinterpretNode} class represents a reinterpreting conversion that changes the stamp
  55  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  56  * the old stamp.
  57  */
  58 @NodeInfo(cycles = CYCLES_1)
  59 public final class ReinterpretNode extends UnaryNode implements ArithmeticLIRLowerable {
  60 
  61     public static final NodeClass<ReinterpretNode> TYPE = NodeClass.create(ReinterpretNode.class);
  62 
  63     protected ReinterpretNode(JavaKind to, ValueNode value) {
  64         this(StampFactory.forKind(to), value);
  65     }
  66 
  67     protected ReinterpretNode(Stamp to, ValueNode value) {
  68         super(TYPE, getReinterpretStamp(to, value.stamp(NodeView.DEFAULT)), value);
  69         assert to instanceof ArithmeticStamp;
  70     }
  71 
  72     public static ValueNode create(JavaKind to, ValueNode value, NodeView view) {
  73         return create(StampFactory.forKind(to), value, view);
  74     }
  75 
  76     public static ValueNode create(Stamp to, ValueNode value, NodeView view) {
  77         return canonical(null, to, value, view);
  78     }
  79 
  80     private static SerializableConstant evalConst(Stamp stamp, SerializableConstant c) {
  81         /*
  82          * We don't care about byte order here. Either would produce the correct result.
  83          */
  84         ByteBuffer buffer = ByteBuffer.wrap(new byte[c.getSerializedSize()]).order(ByteOrder.nativeOrder());
  85         c.serialize(buffer);
  86 
  87         BufferUtil.asBaseBuffer(buffer).rewind();
  88         SerializableConstant ret = ((ArithmeticStamp) stamp).deserialize(buffer);
  89 
  90         assert !buffer.hasRemaining();
  91         return ret;
  92     }
  93 
  94     @Override
  95     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
  96         NodeView view = NodeView.from(tool);
  97         return canonical(this, this.stamp(view), forValue, view);
  98     }
  99 
 100     public static ValueNode canonical(ReinterpretNode node, Stamp forStamp, ValueNode forValue, NodeView view) {
 101         if (forValue.isConstant()) {
 102             return ConstantNode.forConstant(forStamp, evalConst(forStamp, (SerializableConstant) forValue.asConstant()), null);
 103         }
 104         if (forStamp.isCompatible(forValue.stamp(view))) {
 105             return forValue;
 106         }
 107         if (forValue instanceof ReinterpretNode) {
 108             ReinterpretNode reinterpret = (ReinterpretNode) forValue;
 109             return new ReinterpretNode(forStamp, reinterpret.getValue());
 110         }
 111         return node != null ? node : new ReinterpretNode(forStamp, forValue);
 112     }
 113 
 114     /**
 115      * Compute the {@link IntegerStamp} from a {@link FloatStamp}, losing as little information as
 116      * possible.
 117      *
 118      * Sorting by their bit pattern reinterpreted as signed integers gives the following order of
 119      * floating point numbers:
 120      *
 121      * -0 | negative numbers | -Inf | NaNs | 0 | positive numbers | +Inf | NaNs
 122      *
 123      * So we can compute a better integer range if we know that the input is positive, negative,
 124      * finite, non-zero and/or not NaN.
 125      */
 126     private static IntegerStamp floatToInt(FloatStamp stamp) {
 127         int bits = stamp.getBits();
 128 
 129         long signBit = 1L << (bits - 1);
 130         long exponentMask;
 131         if (bits == 64) {
 132             exponentMask = Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
 133         } else {
 134             assert bits == 32;
 135             exponentMask = Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
 136         }
 137 
 138         long positiveInfinity = exponentMask;
 139         long negativeInfinity = CodeUtil.signExtend(signBit | positiveInfinity, bits);
 140         long negativeZero = CodeUtil.signExtend(signBit | 0, bits);
 141 
 142         if (stamp.isNaN()) {
 143             // special case: in addition to the range, we know NaN has all exponent bits set
 144             return IntegerStamp.create(bits, negativeInfinity + 1, CodeUtil.maxValue(bits), exponentMask, CodeUtil.mask(bits));
 145         }
 146 
 147         long upperBound;
 148         if (stamp.isNonNaN()) {
 149             if (stamp.upperBound() < 0.0) {
 150                 if (stamp.lowerBound() > Double.NEGATIVE_INFINITY) {
 151                     upperBound = negativeInfinity - 1;
 152                 } else {
 153                     upperBound = negativeInfinity;
 154                 }
 155             } else if (stamp.upperBound() == 0.0) {
 156                 upperBound = 0;
 157             } else if (stamp.upperBound() < Double.POSITIVE_INFINITY) {
 158                 upperBound = positiveInfinity - 1;
 159             } else {
 160                 upperBound = positiveInfinity;
 161             }
 162         } else {
 163             upperBound = CodeUtil.maxValue(bits);
 164         }
 165 
 166         long lowerBound;
 167         if (stamp.lowerBound() > 0.0) {
 168             if (stamp.isNonNaN()) {
 169                 lowerBound = 1;
 170             } else {
 171                 lowerBound = negativeInfinity + 1;
 172             }
 173         } else if (stamp.upperBound() == Double.NEGATIVE_INFINITY) {
 174             lowerBound = negativeInfinity;
 175         } else if (stamp.upperBound() < 0.0) {
 176             lowerBound = negativeZero + 1;
 177         } else {
 178             lowerBound = negativeZero;
 179         }
 180 
 181         return StampFactory.forInteger(bits, lowerBound, upperBound);
 182     }
 183 
 184     /**
 185      * Compute the {@link IntegerStamp} from a {@link FloatStamp}, losing as little information as
 186      * possible.
 187      *
 188      * Sorting by their bit pattern reinterpreted as signed integers gives the following order of
 189      * floating point numbers:
 190      *
 191      * -0 | negative numbers | -Inf | NaNs | 0 | positive numbers | +Inf | NaNs
 192      *
 193      * So from certain integer ranges we may be able to infer something about the sign, finiteness
 194      * or NaN-ness of the result.
 195      */
 196     private static FloatStamp intToFloat(IntegerStamp stamp) {
 197         int bits = stamp.getBits();
 198 
 199         double minPositive;
 200         double maxPositive;
 201 
 202         long signBit = 1L << (bits - 1);
 203         long exponentMask;
 204         if (bits == 64) {
 205             exponentMask = Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
 206             minPositive = Double.MIN_VALUE;
 207             maxPositive = Double.MAX_VALUE;
 208         } else {
 209             assert bits == 32;
 210             exponentMask = Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
 211             minPositive = Float.MIN_VALUE;
 212             maxPositive = Float.MAX_VALUE;
 213         }
 214 
 215         long significandMask = CodeUtil.mask(bits) & ~(signBit | exponentMask);
 216 
 217         long positiveInfinity = exponentMask;
 218         long negativeInfinity = CodeUtil.signExtend(signBit | positiveInfinity, bits);
 219         long negativeZero = CodeUtil.signExtend(signBit | 0, bits);
 220 
 221         if ((stamp.downMask() & exponentMask) == exponentMask && (stamp.downMask() & significandMask) != 0) {
 222             // if all exponent bits and at least one significand bit are set, the result is NaN
 223             return new FloatStamp(bits, Double.NaN, Double.NaN, false);
 224         }
 225 
 226         double upperBound;
 227         if (stamp.upperBound() < negativeInfinity) {
 228             if (stamp.lowerBound() > negativeZero) {
 229                 upperBound = -minPositive;
 230             } else {
 231                 upperBound = -0.0;
 232             }
 233         } else if (stamp.upperBound() < 0) {
 234             if (stamp.lowerBound() > negativeInfinity) {
 235                 return new FloatStamp(bits, Double.NaN, Double.NaN, false);
 236             } else if (stamp.lowerBound() == negativeInfinity) {
 237                 upperBound = Double.NEGATIVE_INFINITY;
 238             } else if (stamp.lowerBound() > negativeZero) {
 239                 upperBound = -minPositive;
 240             } else {
 241                 upperBound = -0.0;
 242             }
 243         } else if (stamp.upperBound() == 0) {
 244             upperBound = 0.0;
 245         } else if (stamp.upperBound() < positiveInfinity) {
 246             upperBound = maxPositive;
 247         } else {
 248             upperBound = Double.POSITIVE_INFINITY;
 249         }
 250 
 251         double lowerBound;
 252         if (stamp.lowerBound() > positiveInfinity) {
 253             return new FloatStamp(bits, Double.NaN, Double.NaN, false);
 254         } else if (stamp.lowerBound() == positiveInfinity) {
 255             lowerBound = Double.POSITIVE_INFINITY;
 256         } else if (stamp.lowerBound() > 0) {
 257             lowerBound = minPositive;
 258         } else if (stamp.lowerBound() > negativeInfinity) {
 259             lowerBound = 0.0;
 260         } else {
 261             lowerBound = Double.NEGATIVE_INFINITY;
 262         }
 263 
 264         boolean nonNaN;
 265         if ((stamp.upMask() & exponentMask) != exponentMask) {
 266             // NaN has all exponent bits set
 267             nonNaN = true;
 268         } else {
 269             boolean negativeNaNBlock = stamp.lowerBound() < 0 && stamp.upperBound() > negativeInfinity;
 270             boolean positiveNaNBlock = stamp.upperBound() > positiveInfinity;
 271             nonNaN = !negativeNaNBlock && !positiveNaNBlock;
 272         }
 273 
 274         return new FloatStamp(bits, lowerBound, upperBound, nonNaN);
 275     }
 276 
 277     private static Stamp getReinterpretStamp(Stamp toStamp, Stamp fromStamp) {
 278         if (toStamp instanceof IntegerStamp && fromStamp instanceof FloatStamp) {
 279             return floatToInt((FloatStamp) fromStamp);
 280         } else if (toStamp instanceof FloatStamp && fromStamp instanceof IntegerStamp) {
 281             return intToFloat((IntegerStamp) fromStamp);
 282         } else {
 283             return toStamp;
 284         }
 285     }
 286 
 287     @Override
 288     public boolean inferStamp() {
 289         return updateStamp(getReinterpretStamp(stamp(NodeView.DEFAULT), getValue().stamp(NodeView.DEFAULT)));
 290     }
 291 
 292     @Override
 293     public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
 294         LIRKind kind = builder.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT));
 295         builder.setResult(this, gen.emitReinterpret(kind, builder.operand(getValue())));
 296     }
 297 
 298     public static ValueNode reinterpret(JavaKind toKind, ValueNode value) {
 299         return value.graph().unique(new ReinterpretNode(toKind, value));
 300     }
 301 }