1 /* 2 * Copyright (c) 2012, 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.core.common.type; 24 25 import static org.graalvm.compiler.core.common.calc.FloatConvert.D2F; 26 import static org.graalvm.compiler.core.common.calc.FloatConvert.D2I; 27 import static org.graalvm.compiler.core.common.calc.FloatConvert.D2L; 28 import static org.graalvm.compiler.core.common.calc.FloatConvert.F2D; 29 import static org.graalvm.compiler.core.common.calc.FloatConvert.F2I; 30 import static org.graalvm.compiler.core.common.calc.FloatConvert.F2L; 31 32 import java.nio.ByteBuffer; 33 import java.util.function.DoubleBinaryOperator; 34 35 import org.graalvm.compiler.core.common.LIRKind; 36 import org.graalvm.compiler.core.common.spi.LIRKindTool; 37 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; 38 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp; 39 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp; 40 import org.graalvm.compiler.debug.GraalError; 41 42 import jdk.vm.ci.meta.Constant; 43 import jdk.vm.ci.meta.JavaConstant; 44 import jdk.vm.ci.meta.JavaKind; 45 import jdk.vm.ci.meta.MetaAccessProvider; 46 import jdk.vm.ci.meta.PrimitiveConstant; 47 import jdk.vm.ci.meta.ResolvedJavaType; 48 import jdk.vm.ci.meta.SerializableConstant; 49 50 public class FloatStamp extends PrimitiveStamp { 51 52 private final double lowerBound; 53 private final double upperBound; 54 private final boolean nonNaN; 55 56 protected FloatStamp(int bits) { 57 this(bits, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, false); 58 } 59 60 public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) { 61 super(bits, OPS); 62 assert bits == 64 || (bits == 32 && (Double.isNaN(lowerBound) || (float) lowerBound == lowerBound) && (Double.isNaN(upperBound) || (float) upperBound == upperBound)); 63 assert Double.isNaN(lowerBound) == Double.isNaN(upperBound); 64 this.lowerBound = lowerBound; 65 this.upperBound = upperBound; 66 this.nonNaN = nonNaN; 67 } 68 69 @Override 70 public Stamp unrestricted() { 71 return new FloatStamp(getBits()); 72 } 73 74 @Override 75 public Stamp empty() { 76 return new FloatStamp(getBits(), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, true); 77 } 78 79 @Override 80 public Stamp constant(Constant c, MetaAccessProvider meta) { 81 JavaConstant jc = (JavaConstant) c; 82 assert jc.getJavaKind().isNumericFloat() && jc.getJavaKind().getBitCount() == getBits(); 83 return StampFactory.forConstant(jc); 84 } 85 86 @Override 87 public SerializableConstant deserialize(ByteBuffer buffer) { 88 switch (getBits()) { 89 case 32: 90 return JavaConstant.forFloat(buffer.getFloat()); 91 case 64: 92 return JavaConstant.forDouble(buffer.getDouble()); 93 default: 94 throw GraalError.shouldNotReachHere(); 95 } 96 } 97 98 @Override 99 public boolean hasValues() { 100 return lowerBound <= upperBound || !nonNaN; 101 } 102 103 @Override 104 public JavaKind getStackKind() { 105 if (getBits() > 32) { 106 return JavaKind.Double; 107 } else { 108 return JavaKind.Float; 109 } 110 } 111 112 @Override 113 public LIRKind getLIRKind(LIRKindTool tool) { 114 return tool.getFloatingKind(getBits()); 115 } 116 117 @Override 118 public ResolvedJavaType javaType(MetaAccessProvider metaAccess) { 119 switch (getBits()) { 120 case 32: 121 return metaAccess.lookupJavaType(Float.TYPE); 122 case 64: 123 return metaAccess.lookupJavaType(Double.TYPE); 124 default: 125 throw GraalError.shouldNotReachHere(); 126 } 127 } 128 129 /** 130 * The (inclusive) lower bound on the value described by this stamp. 131 */ 132 public double lowerBound() { 133 return lowerBound; 134 } 135 136 /** 137 * The (inclusive) upper bound on the value described by this stamp. 138 */ 139 public double upperBound() { 140 return upperBound; 141 } 142 143 /** 144 * Returns true if NaN is non included in the value described by this stamp. 145 */ 146 public boolean isNonNaN() { 147 return nonNaN; 148 } 149 150 /** 151 * Returns true if this stamp represents the NaN value. 152 */ 153 public boolean isNaN() { 154 return Double.isNaN(lowerBound); 155 } 156 157 @Override 158 public boolean isUnrestricted() { 159 return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN; 160 } 161 162 public boolean contains(double value) { 163 if (Double.isNaN(value)) { 164 return !nonNaN; 165 } else { 166 /* 167 * Don't use Double.compare for checking the bounds as -0.0 isn't correctly tracked, so 168 * the presence of 0.0 means -0.0 might also exist in the range. 169 */ 170 return value >= lowerBound && value <= upperBound; 171 } 172 } 173 174 @Override 175 public String toString() { 176 StringBuilder str = new StringBuilder(); 177 str.append('f'); 178 str.append(getBits()); 179 str.append(nonNaN ? "!" : ""); 180 if (lowerBound == upperBound) { 181 str.append(" [").append(lowerBound).append(']'); 182 } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) { 183 str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']'); 184 } 185 return str.toString(); 186 } 187 188 private static double meetBounds(double a, double b, DoubleBinaryOperator op) { 189 if (Double.isNaN(a)) { 190 return b; 191 } else if (Double.isNaN(b)) { 192 return a; 193 } else { 194 return op.applyAsDouble(a, b); 195 } 196 } 197 198 @Override 199 public Stamp meet(Stamp otherStamp) { 200 if (otherStamp == this) { 201 return this; 202 } 203 FloatStamp other = (FloatStamp) otherStamp; 204 assert getBits() == other.getBits(); 205 double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max); 206 double meetLowerBound = meetBounds(lowerBound, other.lowerBound, Math::min); 207 boolean meetNonNaN = nonNaN && other.nonNaN; 208 if (Double.compare(meetLowerBound, lowerBound) == 0 && Double.compare(meetUpperBound, upperBound) == 0 && meetNonNaN == nonNaN) { 209 return this; 210 } else if (Double.compare(meetLowerBound, other.lowerBound) == 0 && Double.compare(meetUpperBound, other.upperBound) == 0 && meetNonNaN == other.nonNaN) { 211 return other; 212 } else { 213 return new FloatStamp(getBits(), meetLowerBound, meetUpperBound, meetNonNaN); 214 } 215 } 216 217 @Override 218 public Stamp join(Stamp otherStamp) { 219 if (otherStamp == this) { 220 return this; 221 } 222 FloatStamp other = (FloatStamp) otherStamp; 223 assert getBits() == other.getBits(); 224 double joinUpperBound = Math.min(upperBound, other.upperBound); 225 double joinLowerBound = Math.max(lowerBound, other.lowerBound); 226 boolean joinNonNaN = nonNaN || other.nonNaN; 227 if (Double.compare(joinLowerBound, lowerBound) == 0 && Double.compare(joinUpperBound, upperBound) == 0 && joinNonNaN == nonNaN) { 228 return this; 229 } else if (Double.compare(joinLowerBound, other.lowerBound) == 0 && Double.compare(joinUpperBound, other.upperBound) == 0 && joinNonNaN == other.nonNaN) { 230 return other; 231 } else { 232 return new FloatStamp(getBits(), joinLowerBound, joinUpperBound, joinNonNaN); 233 } 234 } 235 236 @Override 237 public int hashCode() { 238 final int prime = 31; 239 int result = 1; 240 long temp; 241 result = prime * result + super.hashCode(); 242 temp = Double.doubleToLongBits(lowerBound); 243 result = prime * result + (int) (temp ^ (temp >>> 32)); 244 result = prime * result + (nonNaN ? 1231 : 1237); 245 temp = Double.doubleToLongBits(upperBound); 246 result = prime * result + (int) (temp ^ (temp >>> 32)); 247 return result; 248 } 249 250 @Override 251 public boolean isCompatible(Stamp stamp) { 252 if (this == stamp) { 253 return true; 254 } 255 if (stamp instanceof FloatStamp) { 256 FloatStamp other = (FloatStamp) stamp; 257 return getBits() == other.getBits(); 258 } 259 return false; 260 } 261 262 @Override 263 public boolean isCompatible(Constant constant) { 264 if (constant instanceof PrimitiveConstant) { 265 PrimitiveConstant prim = (PrimitiveConstant) constant; 266 return prim.getJavaKind().isNumericFloat(); 267 } 268 return false; 269 } 270 271 @Override 272 public boolean equals(Object obj) { 273 if (this == obj) { 274 return true; 275 } 276 if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) { 277 return false; 278 } 279 FloatStamp other = (FloatStamp) obj; 280 if (Double.doubleToLongBits(lowerBound) != Double.doubleToLongBits(other.lowerBound)) { 281 return false; 282 } 283 if (Double.doubleToLongBits(upperBound) != Double.doubleToLongBits(other.upperBound)) { 284 return false; 285 } 286 if (nonNaN != other.nonNaN) { 287 return false; 288 } 289 return super.equals(other); 290 } 291 292 @Override 293 public JavaConstant asConstant() { 294 if (isConstant()) { 295 switch (getBits()) { 296 case 32: 297 return JavaConstant.forFloat((float) lowerBound); 298 case 64: 299 return JavaConstant.forDouble(lowerBound); 300 } 301 } 302 return null; 303 } 304 305 private boolean isConstant() { 306 /* 307 * There are many forms of NaNs and any operations on them can silently convert them into 308 * the canonical NaN. 309 */ 310 return (Double.compare(lowerBound, upperBound) == 0 && nonNaN); 311 } 312 313 private static FloatStamp stampForConstant(Constant constant) { 314 FloatStamp result; 315 PrimitiveConstant value = (PrimitiveConstant) constant; 316 switch (value.getJavaKind()) { 317 case Float: 318 if (Float.isNaN(value.asFloat())) { 319 result = new FloatStamp(32, Double.NaN, Double.NaN, false); 320 } else { 321 result = new FloatStamp(32, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); 322 } 323 break; 324 case Double: 325 if (Double.isNaN(value.asDouble())) { 326 result = new FloatStamp(64, Double.NaN, Double.NaN, false); 327 } else { 328 result = new FloatStamp(64, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble())); 329 } 330 break; 331 default: 332 throw GraalError.shouldNotReachHere(); 333 } 334 if (result.isConstant()) { 335 return result; 336 } 337 return null; 338 } 339 340 private static Stamp maybeFoldConstant(UnaryOp<?> op, FloatStamp stamp) { 341 if (stamp.isConstant()) { 342 JavaConstant constant = stamp.asConstant(); 343 Constant folded = op.foldConstant(constant); 344 if (folded != null) { 345 return FloatStamp.stampForConstant(folded); 346 } 347 } 348 return null; 349 } 350 351 private static Stamp maybeFoldConstant(BinaryOp<?> op, FloatStamp stamp1, FloatStamp stamp2) { 352 if (stamp1.isConstant() && stamp2.isConstant()) { 353 JavaConstant constant1 = stamp1.asConstant(); 354 JavaConstant constant2 = stamp2.asConstant(); 355 Constant folded = op.foldConstant(constant1, constant2); 356 if (folded != null) { 357 FloatStamp stamp = stampForConstant(folded); 358 if (stamp != null && stamp.isConstant()) { 359 assert stamp.asConstant().equals(folded); 360 return stamp; 361 } 362 } 363 } 364 return null; 365 } 366 367 public static final ArithmeticOpTable OPS = new ArithmeticOpTable( 368 369 new UnaryOp.Neg() { 370 371 @Override 372 public Constant foldConstant(Constant c) { 373 PrimitiveConstant value = (PrimitiveConstant) c; 374 switch (value.getJavaKind()) { 375 case Float: 376 return JavaConstant.forFloat(-value.asFloat()); 377 case Double: 378 return JavaConstant.forDouble(-value.asDouble()); 379 default: 380 throw GraalError.shouldNotReachHere(); 381 } 382 } 383 384 @Override 385 public Stamp foldStamp(Stamp s) { 386 FloatStamp stamp = (FloatStamp) s; 387 Stamp folded = maybeFoldConstant(this, stamp); 388 if (folded != null) { 389 return folded; 390 } 391 return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN()); 392 } 393 394 }, 395 396 new BinaryOp.Add(false, true) { 397 398 @Override 399 public Constant foldConstant(Constant const1, Constant const2) { 400 PrimitiveConstant a = (PrimitiveConstant) const1; 401 PrimitiveConstant b = (PrimitiveConstant) const2; 402 assert a.getJavaKind() == b.getJavaKind(); 403 switch (a.getJavaKind()) { 404 case Float: 405 return JavaConstant.forFloat(a.asFloat() + b.asFloat()); 406 case Double: 407 return JavaConstant.forDouble(a.asDouble() + b.asDouble()); 408 default: 409 throw GraalError.shouldNotReachHere(); 410 } 411 } 412 413 @Override 414 public Stamp foldStamp(Stamp s1, Stamp s2) { 415 FloatStamp stamp1 = (FloatStamp) s1; 416 FloatStamp stamp2 = (FloatStamp) s2; 417 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 418 if (folded != null) { 419 return folded; 420 } 421 return stamp1.unrestricted(); 422 } 423 424 @Override 425 public boolean isNeutral(Constant value) { 426 PrimitiveConstant n = (PrimitiveConstant) value; 427 switch (n.getJavaKind()) { 428 case Float: 429 return Float.compare(n.asFloat(), -0.0f) == 0; 430 case Double: 431 return Double.compare(n.asDouble(), -0.0) == 0; 432 default: 433 throw GraalError.shouldNotReachHere(); 434 } 435 } 436 }, 437 438 new BinaryOp.Sub(false, false) { 439 440 @Override 441 public Constant foldConstant(Constant const1, Constant const2) { 442 PrimitiveConstant a = (PrimitiveConstant) const1; 443 PrimitiveConstant b = (PrimitiveConstant) const2; 444 assert a.getJavaKind() == b.getJavaKind(); 445 switch (a.getJavaKind()) { 446 case Float: 447 return JavaConstant.forFloat(a.asFloat() - b.asFloat()); 448 case Double: 449 return JavaConstant.forDouble(a.asDouble() - b.asDouble()); 450 default: 451 throw GraalError.shouldNotReachHere(); 452 } 453 } 454 455 @Override 456 public Stamp foldStamp(Stamp s1, Stamp s2) { 457 FloatStamp stamp1 = (FloatStamp) s1; 458 FloatStamp stamp2 = (FloatStamp) s2; 459 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 460 if (folded != null) { 461 return folded; 462 } 463 return stamp1.unrestricted(); 464 } 465 466 @Override 467 public boolean isNeutral(Constant value) { 468 PrimitiveConstant n = (PrimitiveConstant) value; 469 switch (n.getJavaKind()) { 470 case Float: 471 return Float.compare(n.asFloat(), 0.0f) == 0; 472 case Double: 473 return Double.compare(n.asDouble(), 0.0) == 0; 474 default: 475 throw GraalError.shouldNotReachHere(); 476 } 477 } 478 }, 479 480 new BinaryOp.Mul(false, true) { 481 482 @Override 483 public Constant foldConstant(Constant const1, Constant const2) { 484 PrimitiveConstant a = (PrimitiveConstant) const1; 485 PrimitiveConstant b = (PrimitiveConstant) const2; 486 assert a.getJavaKind() == b.getJavaKind(); 487 switch (a.getJavaKind()) { 488 case Float: 489 return JavaConstant.forFloat(a.asFloat() * b.asFloat()); 490 case Double: 491 return JavaConstant.forDouble(a.asDouble() * b.asDouble()); 492 default: 493 throw GraalError.shouldNotReachHere(); 494 } 495 } 496 497 @Override 498 public Stamp foldStamp(Stamp s1, Stamp s2) { 499 FloatStamp stamp1 = (FloatStamp) s1; 500 FloatStamp stamp2 = (FloatStamp) s2; 501 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 502 if (folded != null) { 503 return folded; 504 } 505 return stamp1.unrestricted(); 506 } 507 508 @Override 509 public boolean isNeutral(Constant value) { 510 PrimitiveConstant n = (PrimitiveConstant) value; 511 switch (n.getJavaKind()) { 512 case Float: 513 return Float.compare(n.asFloat(), 1.0f) == 0; 514 case Double: 515 return Double.compare(n.asDouble(), 1.0) == 0; 516 default: 517 throw GraalError.shouldNotReachHere(); 518 } 519 } 520 }, 521 522 null, 523 524 null, 525 526 new BinaryOp.Div(false, false) { 527 528 @Override 529 public Constant foldConstant(Constant const1, Constant const2) { 530 PrimitiveConstant a = (PrimitiveConstant) const1; 531 PrimitiveConstant b = (PrimitiveConstant) const2; 532 assert a.getJavaKind() == b.getJavaKind(); 533 switch (a.getJavaKind()) { 534 case Float: 535 float floatDivisor = b.asFloat(); 536 return (floatDivisor == 0) ? null : JavaConstant.forFloat(a.asFloat() / floatDivisor); 537 case Double: 538 double doubleDivisor = b.asDouble(); 539 return (doubleDivisor == 0) ? null : JavaConstant.forDouble(a.asDouble() / doubleDivisor); 540 default: 541 throw GraalError.shouldNotReachHere(); 542 } 543 } 544 545 @Override 546 public Stamp foldStamp(Stamp s1, Stamp s2) { 547 FloatStamp stamp1 = (FloatStamp) s1; 548 FloatStamp stamp2 = (FloatStamp) s2; 549 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 550 if (folded != null) { 551 return folded; 552 } 553 return stamp1.unrestricted(); 554 } 555 556 @Override 557 public boolean isNeutral(Constant value) { 558 PrimitiveConstant n = (PrimitiveConstant) value; 559 switch (n.getJavaKind()) { 560 case Float: 561 return Float.compare(n.asFloat(), 1.0f) == 0; 562 case Double: 563 return Double.compare(n.asDouble(), 1.0) == 0; 564 default: 565 throw GraalError.shouldNotReachHere(); 566 } 567 } 568 }, 569 570 new BinaryOp.Rem(false, false) { 571 572 @Override 573 public Constant foldConstant(Constant const1, Constant const2) { 574 PrimitiveConstant a = (PrimitiveConstant) const1; 575 PrimitiveConstant b = (PrimitiveConstant) const2; 576 assert a.getJavaKind() == b.getJavaKind(); 577 switch (a.getJavaKind()) { 578 case Float: 579 return JavaConstant.forFloat(a.asFloat() % b.asFloat()); 580 case Double: 581 return JavaConstant.forDouble(a.asDouble() % b.asDouble()); 582 default: 583 throw GraalError.shouldNotReachHere(); 584 } 585 } 586 587 @Override 588 public Stamp foldStamp(Stamp s1, Stamp s2) { 589 FloatStamp stamp1 = (FloatStamp) s1; 590 FloatStamp stamp2 = (FloatStamp) s2; 591 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 592 if (folded != null) { 593 return folded; 594 } 595 return stamp1.unrestricted(); 596 } 597 }, 598 599 new UnaryOp.Not() { 600 601 @Override 602 public Constant foldConstant(Constant c) { 603 PrimitiveConstant value = (PrimitiveConstant) c; 604 switch (value.getJavaKind()) { 605 case Float: 606 int f = Float.floatToRawIntBits(value.asFloat()); 607 return JavaConstant.forFloat(Float.intBitsToFloat(~f)); 608 case Double: 609 long d = Double.doubleToRawLongBits(value.asDouble()); 610 return JavaConstant.forDouble(Double.longBitsToDouble(~d)); 611 default: 612 throw GraalError.shouldNotReachHere(); 613 } 614 } 615 616 @Override 617 public Stamp foldStamp(Stamp s) { 618 FloatStamp stamp = (FloatStamp) s; 619 JavaConstant constant = stamp.asConstant(); 620 if (constant != null) { 621 Constant folded = foldConstant(constant); 622 if (folded != null) { 623 FloatStamp result = stampForConstant(folded); 624 if (result != null && result.isConstant()) { 625 return result; 626 } 627 } 628 } 629 return s.unrestricted(); 630 } 631 }, 632 633 new BinaryOp.And(true, true) { 634 635 @Override 636 public Constant foldConstant(Constant const1, Constant const2) { 637 PrimitiveConstant a = (PrimitiveConstant) const1; 638 PrimitiveConstant b = (PrimitiveConstant) const2; 639 assert a.getJavaKind() == b.getJavaKind(); 640 switch (a.getJavaKind()) { 641 case Float: 642 int fa = Float.floatToRawIntBits(a.asFloat()); 643 int fb = Float.floatToRawIntBits(b.asFloat()); 644 return JavaConstant.forFloat(Float.intBitsToFloat(fa & fb)); 645 case Double: 646 long da = Double.doubleToRawLongBits(a.asDouble()); 647 long db = Double.doubleToRawLongBits(b.asDouble()); 648 return JavaConstant.forDouble(Double.longBitsToDouble(da & db)); 649 default: 650 throw GraalError.shouldNotReachHere(); 651 } 652 } 653 654 @Override 655 public Stamp foldStamp(Stamp s1, Stamp s2) { 656 FloatStamp stamp1 = (FloatStamp) s1; 657 FloatStamp stamp2 = (FloatStamp) s2; 658 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 659 if (folded != null) { 660 return folded; 661 } 662 return stamp1.unrestricted(); 663 } 664 665 @Override 666 public boolean isNeutral(Constant n) { 667 PrimitiveConstant value = (PrimitiveConstant) n; 668 switch (value.getJavaKind()) { 669 case Float: 670 return Float.floatToRawIntBits(value.asFloat()) == 0xFFFFFFFF; 671 case Double: 672 return Double.doubleToRawLongBits(value.asDouble()) == 0xFFFFFFFFFFFFFFFFL; 673 default: 674 throw GraalError.shouldNotReachHere(); 675 } 676 } 677 }, 678 679 new BinaryOp.Or(true, true) { 680 681 @Override 682 public Constant foldConstant(Constant const1, Constant const2) { 683 PrimitiveConstant a = (PrimitiveConstant) const1; 684 PrimitiveConstant b = (PrimitiveConstant) const2; 685 assert a.getJavaKind() == b.getJavaKind(); 686 switch (a.getJavaKind()) { 687 case Float: 688 int fa = Float.floatToRawIntBits(a.asFloat()); 689 int fb = Float.floatToRawIntBits(b.asFloat()); 690 float floatOr = Float.intBitsToFloat(fa | fb); 691 assert (fa | fb) == Float.floatToRawIntBits((floatOr)); 692 return JavaConstant.forFloat(floatOr); 693 case Double: 694 long da = Double.doubleToRawLongBits(a.asDouble()); 695 long db = Double.doubleToRawLongBits(b.asDouble()); 696 return JavaConstant.forDouble(Double.longBitsToDouble(da | db)); 697 default: 698 throw GraalError.shouldNotReachHere(); 699 } 700 } 701 702 @Override 703 public Stamp foldStamp(Stamp s1, Stamp s2) { 704 FloatStamp stamp1 = (FloatStamp) s1; 705 FloatStamp stamp2 = (FloatStamp) s2; 706 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 707 if (folded != null) { 708 return folded; 709 } 710 return stamp1.unrestricted(); 711 } 712 713 @Override 714 public boolean isNeutral(Constant n) { 715 PrimitiveConstant value = (PrimitiveConstant) n; 716 switch (value.getJavaKind()) { 717 case Float: 718 return Float.floatToRawIntBits(value.asFloat()) == 0; 719 case Double: 720 return Double.doubleToRawLongBits(value.asDouble()) == 0L; 721 default: 722 throw GraalError.shouldNotReachHere(); 723 } 724 } 725 }, 726 727 new BinaryOp.Xor(true, true) { 728 729 @Override 730 public Constant foldConstant(Constant const1, Constant const2) { 731 PrimitiveConstant a = (PrimitiveConstant) const1; 732 PrimitiveConstant b = (PrimitiveConstant) const2; 733 assert a.getJavaKind() == b.getJavaKind(); 734 switch (a.getJavaKind()) { 735 case Float: 736 int fa = Float.floatToRawIntBits(a.asFloat()); 737 int fb = Float.floatToRawIntBits(b.asFloat()); 738 return JavaConstant.forFloat(Float.intBitsToFloat(fa ^ fb)); 739 case Double: 740 long da = Double.doubleToRawLongBits(a.asDouble()); 741 long db = Double.doubleToRawLongBits(b.asDouble()); 742 return JavaConstant.forDouble(Double.longBitsToDouble(da ^ db)); 743 default: 744 throw GraalError.shouldNotReachHere(); 745 } 746 } 747 748 @Override 749 public Stamp foldStamp(Stamp s1, Stamp s2) { 750 FloatStamp stamp1 = (FloatStamp) s1; 751 FloatStamp stamp2 = (FloatStamp) s2; 752 Stamp folded = maybeFoldConstant(this, stamp1, stamp2); 753 if (folded != null) { 754 return folded; 755 } 756 return stamp1.unrestricted(); 757 } 758 759 @Override 760 public boolean isNeutral(Constant n) { 761 PrimitiveConstant value = (PrimitiveConstant) n; 762 switch (value.getJavaKind()) { 763 case Float: 764 return Float.floatToRawIntBits(value.asFloat()) == 0; 765 case Double: 766 return Double.doubleToRawLongBits(value.asDouble()) == 0L; 767 default: 768 throw GraalError.shouldNotReachHere(); 769 } 770 } 771 }, 772 773 null, null, null, 774 775 new UnaryOp.Abs() { 776 777 @Override 778 public Constant foldConstant(Constant c) { 779 PrimitiveConstant value = (PrimitiveConstant) c; 780 switch (value.getJavaKind()) { 781 case Float: 782 return JavaConstant.forFloat(Math.abs(value.asFloat())); 783 case Double: 784 return JavaConstant.forDouble(Math.abs(value.asDouble())); 785 default: 786 throw GraalError.shouldNotReachHere(); 787 } 788 } 789 790 @Override 791 public Stamp foldStamp(Stamp s) { 792 FloatStamp stamp = (FloatStamp) s; 793 Stamp folded = maybeFoldConstant(this, stamp); 794 if (folded != null) { 795 return folded; 796 } 797 if (stamp.isNaN()) { 798 return stamp; 799 } 800 return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN()); 801 } 802 }, 803 804 new UnaryOp.Sqrt() { 805 806 @Override 807 public Constant foldConstant(Constant c) { 808 PrimitiveConstant value = (PrimitiveConstant) c; 809 switch (value.getJavaKind()) { 810 case Float: 811 return JavaConstant.forFloat((float) Math.sqrt(value.asFloat())); 812 case Double: 813 return JavaConstant.forDouble(Math.sqrt(value.asDouble())); 814 default: 815 throw GraalError.shouldNotReachHere(); 816 } 817 } 818 819 @Override 820 public Stamp foldStamp(Stamp s) { 821 FloatStamp stamp = (FloatStamp) s; 822 Stamp folded = maybeFoldConstant(this, stamp); 823 if (folded != null) { 824 return folded; 825 } 826 return s.unrestricted(); 827 } 828 }, 829 830 null, null, null, 831 832 new FloatConvertOp(F2I) { 833 834 @Override 835 public Constant foldConstant(Constant c) { 836 PrimitiveConstant value = (PrimitiveConstant) c; 837 return JavaConstant.forInt((int) value.asFloat()); 838 } 839 840 @Override 841 public Stamp foldStamp(Stamp stamp) { 842 FloatStamp floatStamp = (FloatStamp) stamp; 843 assert floatStamp.getBits() == 32; 844 boolean mustHaveZero = !floatStamp.isNonNaN(); 845 int lowerBound = (int) floatStamp.lowerBound(); 846 int upperBound = (int) floatStamp.upperBound(); 847 if (mustHaveZero) { 848 if (lowerBound > 0) { 849 lowerBound = 0; 850 } else if (upperBound < 0) { 851 upperBound = 0; 852 } 853 } 854 return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound); 855 } 856 }, 857 858 new FloatConvertOp(F2L) { 859 860 @Override 861 public Constant foldConstant(Constant c) { 862 PrimitiveConstant value = (PrimitiveConstant) c; 863 return JavaConstant.forLong((long) value.asFloat()); 864 } 865 866 @Override 867 public Stamp foldStamp(Stamp stamp) { 868 FloatStamp floatStamp = (FloatStamp) stamp; 869 assert floatStamp.getBits() == 32; 870 boolean mustHaveZero = !floatStamp.isNonNaN(); 871 long lowerBound = (long) floatStamp.lowerBound(); 872 long upperBound = (long) floatStamp.upperBound(); 873 if (mustHaveZero) { 874 if (lowerBound > 0) { 875 lowerBound = 0; 876 } else if (upperBound < 0) { 877 upperBound = 0; 878 } 879 } 880 return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound); 881 } 882 }, 883 884 new FloatConvertOp(D2I) { 885 886 @Override 887 public Constant foldConstant(Constant c) { 888 PrimitiveConstant value = (PrimitiveConstant) c; 889 return JavaConstant.forInt((int) value.asDouble()); 890 } 891 892 @Override 893 public Stamp foldStamp(Stamp stamp) { 894 FloatStamp floatStamp = (FloatStamp) stamp; 895 assert floatStamp.getBits() == 64; 896 boolean mustHaveZero = !floatStamp.isNonNaN(); 897 int lowerBound = (int) floatStamp.lowerBound(); 898 int upperBound = (int) floatStamp.upperBound(); 899 if (mustHaveZero) { 900 if (lowerBound > 0) { 901 lowerBound = 0; 902 } else if (upperBound < 0) { 903 upperBound = 0; 904 } 905 } 906 return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound); 907 } 908 }, 909 910 new FloatConvertOp(D2L) { 911 912 @Override 913 public Constant foldConstant(Constant c) { 914 PrimitiveConstant value = (PrimitiveConstant) c; 915 return JavaConstant.forLong((long) value.asDouble()); 916 } 917 918 @Override 919 public Stamp foldStamp(Stamp stamp) { 920 FloatStamp floatStamp = (FloatStamp) stamp; 921 assert floatStamp.getBits() == 64; 922 boolean mustHaveZero = !floatStamp.isNonNaN(); 923 long lowerBound = (long) floatStamp.lowerBound(); 924 long upperBound = (long) floatStamp.upperBound(); 925 if (mustHaveZero) { 926 if (lowerBound > 0) { 927 lowerBound = 0; 928 } else if (upperBound < 0) { 929 upperBound = 0; 930 } 931 } 932 return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound); 933 } 934 }, 935 936 new FloatConvertOp(F2D) { 937 938 @Override 939 public Constant foldConstant(Constant c) { 940 PrimitiveConstant value = (PrimitiveConstant) c; 941 return JavaConstant.forDouble(value.asFloat()); 942 } 943 944 @Override 945 public Stamp foldStamp(Stamp stamp) { 946 FloatStamp floatStamp = (FloatStamp) stamp; 947 assert floatStamp.getBits() == 32; 948 return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN()); 949 } 950 }, 951 952 new FloatConvertOp(D2F) { 953 954 @Override 955 public Constant foldConstant(Constant c) { 956 PrimitiveConstant value = (PrimitiveConstant) c; 957 return JavaConstant.forFloat((float) value.asDouble()); 958 } 959 960 @Override 961 public Stamp foldStamp(Stamp stamp) { 962 FloatStamp floatStamp = (FloatStamp) stamp; 963 assert floatStamp.getBits() == 64; 964 return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN()); 965 } 966 }); 967 }