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