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