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