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