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 }