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