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