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 */ 23package org.graalvm.compiler.core.common.type; 24 25import static org.graalvm.compiler.core.common.calc.FloatConvert.D2F; 26import static org.graalvm.compiler.core.common.calc.FloatConvert.D2I; 27import static org.graalvm.compiler.core.common.calc.FloatConvert.D2L; 28import static org.graalvm.compiler.core.common.calc.FloatConvert.F2D; 29import static org.graalvm.compiler.core.common.calc.FloatConvert.F2I; 30import static org.graalvm.compiler.core.common.calc.FloatConvert.F2L; 31 32import java.nio.ByteBuffer; 33import java.util.function.DoubleBinaryOperator; 34 35import org.graalvm.compiler.core.common.LIRKind; 36import org.graalvm.compiler.core.common.spi.LIRKindTool; 37import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; 38import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp; 39import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp; 40import org.graalvm.compiler.debug.GraalError; 41 42import jdk.vm.ci.meta.Constant; 43import jdk.vm.ci.meta.JavaConstant; 44import jdk.vm.ci.meta.JavaKind; 45import jdk.vm.ci.meta.MetaAccessProvider; 46import jdk.vm.ci.meta.PrimitiveConstant; 47import jdk.vm.ci.meta.ResolvedJavaType; 48import jdk.vm.ci.meta.SerializableConstant; 49 50public 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 (nonNaN && Double.compare(lowerBound, upperBound) == 0) { 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 public static final ArithmeticOpTable OPS = new ArithmeticOpTable( 306 307 new UnaryOp.Neg() { 308 309 @Override 310 public Constant foldConstant(Constant c) { 311 PrimitiveConstant value = (PrimitiveConstant) c; 312 switch (value.getJavaKind()) { 313 case Float: 314 return JavaConstant.forFloat(-value.asFloat()); 315 case Double: 316 return JavaConstant.forDouble(-value.asDouble()); 317 default: 318 throw GraalError.shouldNotReachHere(); 319 } 320 } 321 322 @Override 323 public Stamp foldStamp(Stamp s) { 324 FloatStamp stamp = (FloatStamp) s; 325 return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN()); 326 } 327 }, 328 329 new BinaryOp.Add(false, true) { 330 331 @Override 332 public Constant foldConstant(Constant const1, Constant const2) { 333 PrimitiveConstant a = (PrimitiveConstant) const1; 334 PrimitiveConstant b = (PrimitiveConstant) const2; 335 assert a.getJavaKind() == b.getJavaKind(); 336 switch (a.getJavaKind()) { 337 case Float: 338 return JavaConstant.forFloat(a.asFloat() + b.asFloat()); 339 case Double: 340 return JavaConstant.forDouble(a.asDouble() + b.asDouble()); 341 default: 342 throw GraalError.shouldNotReachHere(); 343 } 344 } 345 346 @Override 347 public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 348 // TODO 349 return stamp1.unrestricted(); 350 } 351 352 @Override 353 public boolean isNeutral(Constant value) { 354 PrimitiveConstant n = (PrimitiveConstant) value; 355 switch (n.getJavaKind()) { 356 case Float: 357 return Float.compare(n.asFloat(), -0.0f) == 0; 358 case Double: 359 return Double.compare(n.asDouble(), -0.0) == 0; 360 default: 361 throw GraalError.shouldNotReachHere(); 362 } 363 } 364 }, 365 366 new BinaryOp.Sub(false, false) { 367 368 @Override 369 public Constant foldConstant(Constant const1, Constant const2) { 370 PrimitiveConstant a = (PrimitiveConstant) const1; 371 PrimitiveConstant b = (PrimitiveConstant) const2; 372 assert a.getJavaKind() == b.getJavaKind(); 373 switch (a.getJavaKind()) { 374 case Float: 375 return JavaConstant.forFloat(a.asFloat() - b.asFloat()); 376 case Double: 377 return JavaConstant.forDouble(a.asDouble() - b.asDouble()); 378 default: 379 throw GraalError.shouldNotReachHere(); 380 } 381 } 382 383 @Override 384 public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 385 // TODO 386 return stamp1.unrestricted(); 387 } 388 389 @Override 390 public boolean isNeutral(Constant value) { 391 PrimitiveConstant n = (PrimitiveConstant) value; 392 switch (n.getJavaKind()) { 393 case Float: 394 return Float.compare(n.asFloat(), 0.0f) == 0; 395 case Double: 396 return Double.compare(n.asDouble(), 0.0) == 0; 397 default: 398 throw GraalError.shouldNotReachHere(); 399 } 400 } 401 }, 402 403 new BinaryOp.Mul(false, true) { 404 405 @Override 406 public Constant foldConstant(Constant const1, Constant const2) { 407 PrimitiveConstant a = (PrimitiveConstant) const1; 408 PrimitiveConstant b = (PrimitiveConstant) const2; 409 assert a.getJavaKind() == b.getJavaKind(); 410 switch (a.getJavaKind()) { 411 case Float: 412 return JavaConstant.forFloat(a.asFloat() * b.asFloat()); 413 case Double: 414 return JavaConstant.forDouble(a.asDouble() * b.asDouble()); 415 default: 416 throw GraalError.shouldNotReachHere(); 417 } 418 } 419 420 @Override 421 public Stamp foldStamp(Stamp a, Stamp b) { 422 // TODO 423 return a.unrestricted(); 424 } 425 426 @Override 427 public boolean isNeutral(Constant value) { 428 PrimitiveConstant n = (PrimitiveConstant) value; 429 switch (n.getJavaKind()) { 430 case Float: 431 return Float.compare(n.asFloat(), 1.0f) == 0; 432 case Double: 433 return Double.compare(n.asDouble(), 1.0) == 0; 434 default: 435 throw GraalError.shouldNotReachHere(); 436 } 437 } 438 }, 439 440 null, 441 442 null, 443 444 new BinaryOp.Div(false, false) { 445 446 @Override 447 public Constant foldConstant(Constant const1, Constant const2) { 448 PrimitiveConstant a = (PrimitiveConstant) const1; 449 PrimitiveConstant b = (PrimitiveConstant) const2; 450 assert a.getJavaKind() == b.getJavaKind(); 451 switch (a.getJavaKind()) { 452 case Float: 453 return JavaConstant.forFloat(a.asFloat() / b.asFloat()); 454 case Double: 455 return JavaConstant.forDouble(a.asDouble() / b.asDouble()); 456 default: 457 throw GraalError.shouldNotReachHere(); 458 } 459 } 460 461 @Override 462 public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 463 // TODO 464 return stamp1.unrestricted(); 465 } 466 467 @Override 468 public boolean isNeutral(Constant value) { 469 PrimitiveConstant n = (PrimitiveConstant) value; 470 switch (n.getJavaKind()) { 471 case Float: 472 return Float.compare(n.asFloat(), 1.0f) == 0; 473 case Double: 474 return Double.compare(n.asDouble(), 1.0) == 0; 475 default: 476 throw GraalError.shouldNotReachHere(); 477 } 478 } 479 }, 480 481 new BinaryOp.Rem(false, false) { 482 483 @Override 484 public Constant foldConstant(Constant const1, Constant const2) { 485 PrimitiveConstant a = (PrimitiveConstant) const1; 486 PrimitiveConstant b = (PrimitiveConstant) const2; 487 assert a.getJavaKind() == b.getJavaKind(); 488 switch (a.getJavaKind()) { 489 case Float: 490 return JavaConstant.forFloat(a.asFloat() % b.asFloat()); 491 case Double: 492 return JavaConstant.forDouble(a.asDouble() % b.asDouble()); 493 default: 494 throw GraalError.shouldNotReachHere(); 495 } 496 } 497 498 @Override 499 public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 500 // TODO 501 return stamp1.unrestricted(); 502 } 503 }, 504 505 new UnaryOp.Not() { 506 507 @Override 508 public Constant foldConstant(Constant c) { 509 PrimitiveConstant value = (PrimitiveConstant) c; 510 switch (value.getJavaKind()) { 511 case Float: 512 int f = Float.floatToRawIntBits(value.asFloat()); 513 return JavaConstant.forFloat(Float.intBitsToFloat(~f)); 514 case Double: 515 long d = Double.doubleToRawLongBits(value.asDouble()); 516 return JavaConstant.forDouble(Double.longBitsToDouble(~d)); 517 default: 518 throw GraalError.shouldNotReachHere(); 519 } 520 } 521 522 @Override 523 public Stamp foldStamp(Stamp s) { 524 return s.unrestricted(); 525 } 526 }, 527 528 new BinaryOp.And(true, true) { 529 530 @Override 531 public Constant foldConstant(Constant const1, Constant const2) { 532 PrimitiveConstant a = (PrimitiveConstant) const1; 533 PrimitiveConstant b = (PrimitiveConstant) const2; 534 assert a.getJavaKind() == b.getJavaKind(); 535 switch (a.getJavaKind()) { 536 case Float: 537 int fa = Float.floatToRawIntBits(a.asFloat()); 538 int fb = Float.floatToRawIntBits(b.asFloat()); 539 return JavaConstant.forFloat(Float.intBitsToFloat(fa & fb)); 540 case Double: 541 long da = Double.doubleToRawLongBits(a.asDouble()); 542 long db = Double.doubleToRawLongBits(b.asDouble()); 543 return JavaConstant.forDouble(Double.longBitsToDouble(da & db)); 544 default: 545 throw GraalError.shouldNotReachHere(); 546 } 547 } 548 549 @Override 550 public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 551 return stamp1.unrestricted(); 552 } 553 554 @Override 555 public boolean isNeutral(Constant n) { 556 PrimitiveConstant value = (PrimitiveConstant) n; 557 switch (value.getJavaKind()) { 558 case Float: 559 return Float.floatToRawIntBits(value.asFloat()) == 0xFFFFFFFF; 560 case Double: 561 return Double.doubleToRawLongBits(value.asDouble()) == 0xFFFFFFFFFFFFFFFFL; 562 default: 563 throw GraalError.shouldNotReachHere(); 564 } 565 } 566 }, 567 568 new BinaryOp.Or(true, true) { 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 int fa = Float.floatToRawIntBits(a.asFloat()); 578 int fb = Float.floatToRawIntBits(b.asFloat()); 579 return JavaConstant.forFloat(Float.intBitsToFloat(fa | fb)); 580 case Double: 581 long da = Double.doubleToRawLongBits(a.asDouble()); 582 long db = Double.doubleToRawLongBits(b.asDouble()); 583 return JavaConstant.forDouble(Double.longBitsToDouble(da | db)); 584 default: 585 throw GraalError.shouldNotReachHere(); 586 } 587 } 588 589 @Override 590 public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 591 return stamp1.unrestricted(); 592 } 593 594 @Override 595 public boolean isNeutral(Constant n) { 596 PrimitiveConstant value = (PrimitiveConstant) n; 597 switch (value.getJavaKind()) { 598 case Float: 599 return Float.floatToRawIntBits(value.asFloat()) == 0; 600 case Double: 601 return Double.doubleToRawLongBits(value.asDouble()) == 0L; 602 default: 603 throw GraalError.shouldNotReachHere(); 604 } 605 } 606 }, 607 608 new BinaryOp.Xor(true, true) { 609 610 @Override 611 public Constant foldConstant(Constant const1, Constant const2) { 612 PrimitiveConstant a = (PrimitiveConstant) const1; 613 PrimitiveConstant b = (PrimitiveConstant) const2; 614 assert a.getJavaKind() == b.getJavaKind(); 615 switch (a.getJavaKind()) { 616 case Float: 617 int fa = Float.floatToRawIntBits(a.asFloat()); 618 int fb = Float.floatToRawIntBits(b.asFloat()); 619 return JavaConstant.forFloat(Float.intBitsToFloat(fa ^ fb)); 620 case Double: 621 long da = Double.doubleToRawLongBits(a.asDouble()); 622 long db = Double.doubleToRawLongBits(b.asDouble()); 623 return JavaConstant.forDouble(Double.longBitsToDouble(da ^ db)); 624 default: 625 throw GraalError.shouldNotReachHere(); 626 } 627 } 628 629 @Override 630 public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 631 return stamp1.unrestricted(); 632 } 633 634 @Override 635 public boolean isNeutral(Constant n) { 636 PrimitiveConstant value = (PrimitiveConstant) n; 637 switch (value.getJavaKind()) { 638 case Float: 639 return Float.floatToRawIntBits(value.asFloat()) == 0; 640 case Double: 641 return Double.doubleToRawLongBits(value.asDouble()) == 0L; 642 default: 643 throw GraalError.shouldNotReachHere(); 644 } 645 } 646 }, 647 648 null, null, null, 649 650 new UnaryOp.Abs() { 651 652 @Override 653 public Constant foldConstant(Constant c) { 654 PrimitiveConstant value = (PrimitiveConstant) c; 655 switch (value.getJavaKind()) { 656 case Float: 657 return JavaConstant.forFloat(Math.abs(value.asFloat())); 658 case Double: 659 return JavaConstant.forDouble(Math.abs(value.asDouble())); 660 default: 661 throw GraalError.shouldNotReachHere(); 662 } 663 } 664 665 @Override 666 public Stamp foldStamp(Stamp s) { 667 FloatStamp stamp = (FloatStamp) s; 668 if (stamp.isNaN()) { 669 return stamp; 670 } 671 return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN()); 672 } 673 }, 674 675 new UnaryOp.Sqrt() { 676 677 @Override 678 public Constant foldConstant(Constant c) { 679 PrimitiveConstant value = (PrimitiveConstant) c; 680 switch (value.getJavaKind()) { 681 case Float: 682 return JavaConstant.forFloat((float) Math.sqrt(value.asFloat())); 683 case Double: 684 return JavaConstant.forDouble(Math.sqrt(value.asDouble())); 685 default: 686 throw GraalError.shouldNotReachHere(); 687 } 688 } 689 690 @Override 691 public Stamp foldStamp(Stamp s) { 692 return s.unrestricted(); 693 } 694 }, 695 696 null, null, null, 697 698 new FloatConvertOp(F2I) { 699 700 @Override 701 public Constant foldConstant(Constant c) { 702 PrimitiveConstant value = (PrimitiveConstant) c; 703 return JavaConstant.forInt((int) value.asFloat()); 704 } 705 706 @Override 707 public Stamp foldStamp(Stamp stamp) { 708 FloatStamp floatStamp = (FloatStamp) stamp; 709 assert floatStamp.getBits() == 32; 710 boolean mustHaveZero = !floatStamp.isNonNaN(); 711 int lowerBound = (int) floatStamp.lowerBound(); 712 int upperBound = (int) floatStamp.upperBound(); 713 if (mustHaveZero) { 714 if (lowerBound > 0) { 715 lowerBound = 0; 716 } else if (upperBound < 0) { 717 upperBound = 0; 718 } 719 } 720 return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound); 721 } 722 }, 723 724 new FloatConvertOp(F2L) { 725 726 @Override 727 public Constant foldConstant(Constant c) { 728 PrimitiveConstant value = (PrimitiveConstant) c; 729 return JavaConstant.forLong((long) value.asFloat()); 730 } 731 732 @Override 733 public Stamp foldStamp(Stamp stamp) { 734 FloatStamp floatStamp = (FloatStamp) stamp; 735 assert floatStamp.getBits() == 32; 736 boolean mustHaveZero = !floatStamp.isNonNaN(); 737 long lowerBound = (long) floatStamp.lowerBound(); 738 long upperBound = (long) floatStamp.upperBound(); 739 if (mustHaveZero) { 740 if (lowerBound > 0) { 741 lowerBound = 0; 742 } else if (upperBound < 0) { 743 upperBound = 0; 744 } 745 } 746 return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound); 747 } 748 }, 749 750 new FloatConvertOp(D2I) { 751 752 @Override 753 public Constant foldConstant(Constant c) { 754 PrimitiveConstant value = (PrimitiveConstant) c; 755 return JavaConstant.forInt((int) value.asDouble()); 756 } 757 758 @Override 759 public Stamp foldStamp(Stamp stamp) { 760 FloatStamp floatStamp = (FloatStamp) stamp; 761 assert floatStamp.getBits() == 64; 762 boolean mustHaveZero = !floatStamp.isNonNaN(); 763 int lowerBound = (int) floatStamp.lowerBound(); 764 int upperBound = (int) floatStamp.upperBound(); 765 if (mustHaveZero) { 766 if (lowerBound > 0) { 767 lowerBound = 0; 768 } else if (upperBound < 0) { 769 upperBound = 0; 770 } 771 } 772 return StampFactory.forInteger(JavaKind.Int, lowerBound, upperBound); 773 } 774 }, 775 776 new FloatConvertOp(D2L) { 777 778 @Override 779 public Constant foldConstant(Constant c) { 780 PrimitiveConstant value = (PrimitiveConstant) c; 781 return JavaConstant.forLong((long) value.asDouble()); 782 } 783 784 @Override 785 public Stamp foldStamp(Stamp stamp) { 786 FloatStamp floatStamp = (FloatStamp) stamp; 787 assert floatStamp.getBits() == 64; 788 boolean mustHaveZero = !floatStamp.isNonNaN(); 789 long lowerBound = (long) floatStamp.lowerBound(); 790 long upperBound = (long) floatStamp.upperBound(); 791 if (mustHaveZero) { 792 if (lowerBound > 0) { 793 lowerBound = 0; 794 } else if (upperBound < 0) { 795 upperBound = 0; 796 } 797 } 798 return StampFactory.forInteger(JavaKind.Long, lowerBound, upperBound); 799 } 800 }, 801 802 new FloatConvertOp(F2D) { 803 804 @Override 805 public Constant foldConstant(Constant c) { 806 PrimitiveConstant value = (PrimitiveConstant) c; 807 return JavaConstant.forDouble(value.asFloat()); 808 } 809 810 @Override 811 public Stamp foldStamp(Stamp stamp) { 812 FloatStamp floatStamp = (FloatStamp) stamp; 813 assert floatStamp.getBits() == 32; 814 return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN()); 815 } 816 }, 817 818 new FloatConvertOp(D2F) { 819 820 @Override 821 public Constant foldConstant(Constant c) { 822 PrimitiveConstant value = (PrimitiveConstant) c; 823 return JavaConstant.forFloat((float) value.asDouble()); 824 } 825 826 @Override 827 public Stamp foldStamp(Stamp stamp) { 828 FloatStamp floatStamp = (FloatStamp) stamp; 829 assert floatStamp.getBits() == 64; 830 return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN()); 831 } 832 }); 833} 834