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 new IntegerStamp(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 285 @NodeIntrinsic 286 public static native float reinterpret(@ConstantNodeParameter JavaKind kind, int value); 287 288 @NodeIntrinsic 289 public static native int reinterpret(@ConstantNodeParameter JavaKind kind, float value); 290 291 @NodeIntrinsic 292 public static native double reinterpret(@ConstantNodeParameter JavaKind kind, long value); 293 294 @NodeIntrinsic 295 public static native long reinterpret(@ConstantNodeParameter JavaKind kind, double value); 296 }