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 }