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.I2D;
  26 import static org.graalvm.compiler.core.common.calc.FloatConvert.I2F;
  27 import static org.graalvm.compiler.core.common.calc.FloatConvert.L2D;
  28 import static org.graalvm.compiler.core.common.calc.FloatConvert.L2F;
  29 
  30 import java.nio.ByteBuffer;
  31 import java.util.Formatter;
  32 
  33 import org.graalvm.compiler.core.common.LIRKind;
  34 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  35 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
  36 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
  37 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
  38 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp;
  39 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp;
  40 import org.graalvm.compiler.debug.GraalError;
  41 
  42 import jdk.vm.ci.code.CodeUtil;
  43 import jdk.vm.ci.meta.Constant;
  44 import jdk.vm.ci.meta.JavaConstant;
  45 import jdk.vm.ci.meta.JavaKind;
  46 import jdk.vm.ci.meta.MetaAccessProvider;
  47 import jdk.vm.ci.meta.PrimitiveConstant;
  48 import jdk.vm.ci.meta.ResolvedJavaType;
  49 import jdk.vm.ci.meta.SerializableConstant;
  50 
  51 /**
  52  * Describes the possible values of a node that produces an int or long result.
  53  *
  54  * The description consists of (inclusive) lower and upper bounds and up (may be set) and down
  55  * (always set) bit-masks.
  56  */
  57 public class IntegerStamp extends PrimitiveStamp {
  58 
  59     private final long lowerBound;
  60     private final long upperBound;
  61     private final long downMask;
  62     private final long upMask;
  63 
  64     public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
  65         super(bits, OPS);
  66         this.lowerBound = lowerBound;
  67         this.upperBound = upperBound;
  68         this.downMask = downMask;
  69         this.upMask = upMask;
  70         assert lowerBound >= CodeUtil.minValue(bits) : this;
  71         assert upperBound <= CodeUtil.maxValue(bits) : this;
  72         assert (downMask & CodeUtil.mask(bits)) == downMask : this;
  73         assert (upMask & CodeUtil.mask(bits)) == upMask : this;
  74     }
  75 
  76     public static IntegerStamp stampForMask(int bits, long downMask, long upMask) {
  77         long lowerBound;
  78         long upperBound;
  79         if (((upMask >>> (bits - 1)) & 1) == 0) {
  80             lowerBound = downMask;
  81             upperBound = upMask;
  82         } else if (((downMask >>> (bits - 1)) & 1) == 1) {
  83             lowerBound = downMask;
  84             upperBound = upMask;
  85         } else {
  86             lowerBound = downMask | (-1L << (bits - 1));
  87             upperBound = CodeUtil.maxValue(bits) & upMask;
  88         }
  89         lowerBound = CodeUtil.convert(lowerBound, bits, false);
  90         upperBound = CodeUtil.convert(upperBound, bits, false);
  91         return new IntegerStamp(bits, lowerBound, upperBound, downMask, upMask);
  92     }
  93 
  94     @Override
  95     public IntegerStamp unrestricted() {
  96         return new IntegerStamp(getBits(), CodeUtil.minValue(getBits()), CodeUtil.maxValue(getBits()), 0, CodeUtil.mask(getBits()));
  97     }
  98 
  99     @Override
 100     public Stamp empty() {
 101         return new IntegerStamp(getBits(), CodeUtil.maxValue(getBits()), CodeUtil.minValue(getBits()), CodeUtil.mask(getBits()), 0);
 102     }
 103 
 104     @Override
 105     public Stamp constant(Constant c, MetaAccessProvider meta) {
 106         if (c instanceof PrimitiveConstant) {
 107             long value = ((PrimitiveConstant) c).asLong();
 108             return StampFactory.forInteger(getBits(), value, value);
 109         }
 110         return this;
 111     }
 112 
 113     @Override
 114     public SerializableConstant deserialize(ByteBuffer buffer) {
 115         switch (getBits()) {
 116             case 1:
 117                 return JavaConstant.forBoolean(buffer.get() != 0);
 118             case 8:
 119                 return JavaConstant.forByte(buffer.get());
 120             case 16:
 121                 return JavaConstant.forShort(buffer.getShort());
 122             case 32:
 123                 return JavaConstant.forInt(buffer.getInt());
 124             case 64:
 125                 return JavaConstant.forLong(buffer.getLong());
 126             default:
 127                 throw GraalError.shouldNotReachHere();
 128         }
 129     }
 130 
 131     @Override
 132     public boolean hasValues() {
 133         return lowerBound <= upperBound;
 134     }
 135 
 136     @Override
 137     public JavaKind getStackKind() {
 138         if (getBits() > 32) {
 139             return JavaKind.Long;
 140         } else {
 141             return JavaKind.Int;
 142         }
 143     }
 144 
 145     @Override
 146     public LIRKind getLIRKind(LIRKindTool tool) {
 147         return tool.getIntegerKind(getBits());
 148     }
 149 
 150     @Override
 151     public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
 152         switch (getBits()) {
 153             case 1:
 154                 return metaAccess.lookupJavaType(Boolean.TYPE);
 155             case 8:
 156                 return metaAccess.lookupJavaType(Byte.TYPE);
 157             case 16:
 158                 return metaAccess.lookupJavaType(Short.TYPE);
 159             case 32:
 160                 return metaAccess.lookupJavaType(Integer.TYPE);
 161             case 64:
 162                 return metaAccess.lookupJavaType(Long.TYPE);
 163             default:
 164                 throw GraalError.shouldNotReachHere();
 165         }
 166     }
 167 
 168     /**
 169      * The signed inclusive lower bound on the value described by this stamp.
 170      */
 171     public long lowerBound() {
 172         return lowerBound;
 173     }
 174 
 175     /**
 176      * The signed inclusive upper bound on the value described by this stamp.
 177      */
 178     public long upperBound() {
 179         return upperBound;
 180     }
 181 
 182     /**
 183      * This bit-mask describes the bits that are always set in the value described by this stamp.
 184      */
 185     public long downMask() {
 186         return downMask;
 187     }
 188 
 189     /**
 190      * This bit-mask describes the bits that can be set in the value described by this stamp.
 191      */
 192     public long upMask() {
 193         return upMask;
 194     }
 195 
 196     public boolean isUnrestricted() {
 197         return lowerBound == CodeUtil.minValue(getBits()) && upperBound == CodeUtil.maxValue(getBits()) && downMask == 0 && upMask == CodeUtil.mask(getBits());
 198     }
 199 
 200     public boolean contains(long value) {
 201         return value >= lowerBound && value <= upperBound && (value & downMask) == downMask && (value & upMask) == (value & CodeUtil.mask(getBits()));
 202     }
 203 
 204     public boolean isPositive() {
 205         return lowerBound() >= 0;
 206     }
 207 
 208     public boolean isNegative() {
 209         return upperBound() <= 0;
 210     }
 211 
 212     public boolean isStrictlyPositive() {
 213         return lowerBound() > 0;
 214     }
 215 
 216     public boolean isStrictlyNegative() {
 217         return upperBound() < 0;
 218     }
 219 
 220     public boolean canBePositive() {
 221         return upperBound() > 0;
 222     }
 223 
 224     public boolean canBeNegative() {
 225         return lowerBound() < 0;
 226     }
 227 
 228     @Override
 229     public String toString() {
 230         StringBuilder str = new StringBuilder();
 231         str.append('i');
 232         str.append(getBits());
 233         if (lowerBound == upperBound) {
 234             str.append(" [").append(lowerBound).append(']');
 235         } else if (lowerBound != CodeUtil.minValue(getBits()) || upperBound != CodeUtil.maxValue(getBits())) {
 236             str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
 237         }
 238         if (downMask != 0) {
 239             str.append(" \u21ca");
 240             new Formatter(str).format("%016x", downMask);
 241         }
 242         if (upMask != CodeUtil.mask(getBits())) {
 243             str.append(" \u21c8");
 244             new Formatter(str).format("%016x", upMask);
 245         }
 246         return str.toString();
 247     }
 248 
 249     private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
 250         assert getBits() == other.getBits();
 251         if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0 || (newUpMask == 0 && (newLowerBound > 0 || newUpperBound < 0))) {
 252             return empty();
 253         } else if (newLowerBound == lowerBound && newUpperBound == upperBound && newDownMask == downMask && newUpMask == upMask) {
 254             return this;
 255         } else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) {
 256             return other;
 257         } else {
 258             return new IntegerStamp(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
 259         }
 260     }
 261 
 262     @Override
 263     public Stamp meet(Stamp otherStamp) {
 264         if (otherStamp == this) {
 265             return this;
 266         }
 267         IntegerStamp other = (IntegerStamp) otherStamp;
 268         return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
 269     }
 270 
 271     @Override
 272     public Stamp join(Stamp otherStamp) {
 273         if (otherStamp == this) {
 274             return this;
 275         }
 276         IntegerStamp other = (IntegerStamp) otherStamp;
 277         long newDownMask = downMask | other.downMask;
 278         long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask;
 279         long newUpperBound = Math.min(upperBound, other.upperBound);
 280         long newUpMask = upMask & other.upMask;
 281         IntegerStamp limit = StampFactory.forInteger(getBits(), newLowerBound, newUpperBound);
 282         return createStamp(other, newUpperBound, newLowerBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
 283     }
 284 
 285     @Override
 286     public boolean isCompatible(Stamp stamp) {
 287         if (this == stamp) {
 288             return true;
 289         }
 290         if (stamp instanceof IntegerStamp) {
 291             IntegerStamp other = (IntegerStamp) stamp;
 292             return getBits() == other.getBits();
 293         }
 294         return false;
 295     }
 296 
 297     @Override
 298     public boolean isCompatible(Constant constant) {
 299         if (constant instanceof PrimitiveConstant) {
 300             PrimitiveConstant prim = (PrimitiveConstant) constant;
 301             return prim.getJavaKind().isNumericInteger();
 302         }
 303         return false;
 304     }
 305 
 306     @Override
 307     public int hashCode() {
 308         final int prime = 31;
 309         int result = 1;
 310         result = prime * result + super.hashCode();
 311         result = prime * result + (int) (lowerBound ^ (lowerBound >>> 32));
 312         result = prime * result + (int) (upperBound ^ (upperBound >>> 32));
 313         result = prime * result + (int) (downMask ^ (downMask >>> 32));
 314         result = prime * result + (int) (upMask ^ (upMask >>> 32));
 315         return result;
 316     }
 317 
 318     @Override
 319     public boolean equals(Object obj) {
 320         if (this == obj) {
 321             return true;
 322         }
 323         if (obj == null || getClass() != obj.getClass() || !super.equals(obj)) {
 324             return false;
 325         }
 326         IntegerStamp other = (IntegerStamp) obj;
 327         if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask) {
 328             return false;
 329         }
 330         return super.equals(other);
 331     }
 332 
 333     public static long upMaskFor(int bits, long lowerBound, long upperBound) {
 334         long mask = lowerBound | upperBound;
 335         if (mask == 0) {
 336             return 0;
 337         } else {
 338             return ((-1L) >>> Long.numberOfLeadingZeros(mask)) & CodeUtil.mask(bits);
 339         }
 340     }
 341 
 342     /**
 343      * Checks if the 2 stamps represent values of the same sign. Returns true if the two stamps are
 344      * both positive of null or if they are both strictly negative
 345      *
 346      * @return true if the two stamps are both positive of null or if they are both strictly
 347      *         negative
 348      */
 349     public static boolean sameSign(IntegerStamp s1, IntegerStamp s2) {
 350         return s1.isPositive() && s2.isPositive() || s1.isStrictlyNegative() && s2.isStrictlyNegative();
 351     }
 352 
 353     @Override
 354     public JavaConstant asConstant() {
 355         if (lowerBound == upperBound) {
 356             switch (getBits()) {
 357                 case 1:
 358                     return JavaConstant.forBoolean(lowerBound != 0);
 359                 case 8:
 360                     return JavaConstant.forByte((byte) lowerBound);
 361                 case 16:
 362                     return JavaConstant.forShort((short) lowerBound);
 363                 case 32:
 364                     return JavaConstant.forInt((int) lowerBound);
 365                 case 64:
 366                     return JavaConstant.forLong(lowerBound);
 367             }
 368         }
 369         return null;
 370     }
 371 
 372     public static boolean addOverflowsPositively(long x, long y, int bits) {
 373         long result = x + y;
 374         if (bits == 64) {
 375             return (~x & ~y & result) < 0;
 376         } else {
 377             return result > CodeUtil.maxValue(bits);
 378         }
 379     }
 380 
 381     public static boolean addOverflowsNegatively(long x, long y, int bits) {
 382         long result = x + y;
 383         if (bits == 64) {
 384             return (x & y & ~result) < 0;
 385         } else {
 386             return result < CodeUtil.minValue(bits);
 387         }
 388     }
 389 
 390     public static long carryBits(long x, long y) {
 391         return (x + y) ^ x ^ y;
 392     }
 393 
 394     private static long saturate(long v, int bits) {
 395         if (bits < 64) {
 396             long max = CodeUtil.maxValue(bits);
 397             if (v > max) {
 398                 return max;
 399             }
 400             long min = CodeUtil.minValue(bits);
 401             if (v < min) {
 402                 return min;
 403             }
 404         }
 405         return v;
 406     }
 407 
 408     public static boolean multiplicationOverflows(long a, long b, int bits) {
 409         assert bits <= 64 && bits >= 0;
 410         long result = a * b;
 411         // result is positive if the sign is the same
 412         boolean positive = (a >= 0 && b >= 0) || (a < 0 && b < 0);
 413         if (bits == 64) {
 414             if (a > 0 && b > 0) {
 415                 return a > 0x7FFFFFFF_FFFFFFFFL / b;
 416             } else if (a > 0 && b <= 0) {
 417                 return b < 0x80000000_00000000L / a;
 418             } else if (a <= 0 && b > 0) {
 419                 return a < 0x80000000_00000000L / b;
 420             } else {
 421                 // a<=0 && b <=0
 422                 return a != 0 && b < 0x7FFFFFFF_FFFFFFFFL / a;
 423             }
 424         } else {
 425             if (positive) {
 426                 return result > CodeUtil.maxValue(bits);
 427             } else {
 428                 return result < CodeUtil.minValue(bits);
 429             }
 430         }
 431     }
 432 
 433     public static boolean subtractionCanOverflow(IntegerStamp x, IntegerStamp y) {
 434         assert x.getBits() == y.getBits();
 435         // Checkstyle: stop
 436         long x_l = x.lowerBound();
 437         long x_h = x.upperBound();
 438         long y_l = y.lowerBound();
 439         long y_h = y.upperBound();
 440         // Checkstyle: resume
 441         return subtractionOverflows(x_l, y_h, x.getBits()) || subtractionOverflows(x_h, y_l, x.getBits());
 442     }
 443 
 444     public static boolean subtractionOverflows(long x, long y, int bits) {
 445         long result = x - y;
 446         if (bits == 64) {
 447             return (((x ^ y) & (x ^ result)) < 0);
 448         }
 449         return result < CodeUtil.minValue(bits) || result > CodeUtil.maxValue(bits);
 450     }
 451 
 452     public static final ArithmeticOpTable OPS = new ArithmeticOpTable(
 453 
 454                     new UnaryOp.Neg() {
 455 
 456                         @Override
 457                         public Constant foldConstant(Constant value) {
 458                             PrimitiveConstant c = (PrimitiveConstant) value;
 459                             return JavaConstant.forIntegerKind(c.getJavaKind(), -c.asLong());
 460                         }
 461 
 462                         @Override
 463                         public Stamp foldStamp(Stamp s) {
 464                             IntegerStamp stamp = (IntegerStamp) s;
 465                             int bits = stamp.getBits();
 466                             if (stamp.lowerBound() != CodeUtil.minValue(bits)) {
 467                                 // TODO(ls) check if the mask calculation is correct...
 468                                 return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound());
 469                             } else {
 470                                 return stamp.unrestricted();
 471                             }
 472                         }
 473                     },
 474 
 475                     new BinaryOp.Add(true, true) {
 476 
 477                         @Override
 478                         public Constant foldConstant(Constant const1, Constant const2) {
 479                             PrimitiveConstant a = (PrimitiveConstant) const1;
 480                             PrimitiveConstant b = (PrimitiveConstant) const2;
 481                             assert a.getJavaKind() == b.getJavaKind();
 482                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() + b.asLong());
 483                         }
 484 
 485                         @Override
 486                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
 487                             IntegerStamp a = (IntegerStamp) stamp1;
 488                             IntegerStamp b = (IntegerStamp) stamp2;
 489 
 490                             int bits = a.getBits();
 491                             assert bits == b.getBits();
 492 
 493                             if (a.isUnrestricted()) {
 494                                 return a;
 495                             } else if (b.isUnrestricted()) {
 496                                 return b;
 497                             }
 498                             long defaultMask = CodeUtil.mask(bits);
 499                             long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
 500                             long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask()));
 501                             long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry;
 502                             long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry;
 503 
 504                             newDownMask &= defaultMask;
 505                             newUpMask &= defaultMask;
 506 
 507                             long newLowerBound;
 508                             long newUpperBound;
 509                             boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits);
 510                             boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits);
 511                             boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits);
 512                             boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits);
 513                             if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsPositively && upperOverflowsPositively)) {
 514                                 newLowerBound = CodeUtil.minValue(bits);
 515                                 newUpperBound = CodeUtil.maxValue(bits);
 516                             } else {
 517                                 newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits);
 518                                 newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
 519                             }
 520                             IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
 521                             newUpMask &= limit.upMask();
 522                             newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
 523                             newDownMask |= limit.downMask();
 524                             newLowerBound |= newDownMask;
 525                             return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
 526                         }
 527 
 528                         @Override
 529                         public boolean isNeutral(Constant value) {
 530                             PrimitiveConstant n = (PrimitiveConstant) value;
 531                             return n.asLong() == 0;
 532                         }
 533                     },
 534 
 535                     new BinaryOp.Sub(true, false) {
 536 
 537                         @Override
 538                         public Constant foldConstant(Constant const1, Constant const2) {
 539                             PrimitiveConstant a = (PrimitiveConstant) const1;
 540                             PrimitiveConstant b = (PrimitiveConstant) const2;
 541                             assert a.getJavaKind() == b.getJavaKind();
 542                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() - b.asLong());
 543                         }
 544 
 545                         @Override
 546                         public Stamp foldStamp(Stamp a, Stamp b) {
 547                             return OPS.getAdd().foldStamp(a, OPS.getNeg().foldStamp(b));
 548                         }
 549 
 550                         @Override
 551                         public boolean isNeutral(Constant value) {
 552                             PrimitiveConstant n = (PrimitiveConstant) value;
 553                             return n.asLong() == 0;
 554                         }
 555 
 556                         @Override
 557                         public Constant getZero(Stamp s) {
 558                             IntegerStamp stamp = (IntegerStamp) s;
 559                             return JavaConstant.forPrimitiveInt(stamp.getBits(), 0);
 560                         }
 561                     },
 562 
 563                     new BinaryOp.Mul(true, true) {
 564 
 565                         @Override
 566                         public Constant foldConstant(Constant const1, Constant const2) {
 567                             PrimitiveConstant a = (PrimitiveConstant) const1;
 568                             PrimitiveConstant b = (PrimitiveConstant) const2;
 569                             assert a.getJavaKind() == b.getJavaKind();
 570                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() * b.asLong());
 571                         }
 572 
 573                         @Override
 574                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
 575                             IntegerStamp a = (IntegerStamp) stamp1;
 576                             IntegerStamp b = (IntegerStamp) stamp2;
 577 
 578                             int bits = a.getBits();
 579                             assert bits == b.getBits();
 580                             // if a==0 or b==0 result of a*b is always 0
 581                             if (a.upMask() == 0) {
 582                                 return a;
 583                             } else if (b.upMask() == 0) {
 584                                 return b;
 585                             } else {
 586                                 // if a has the full range or b, the result will also have it
 587                                 if (a.isUnrestricted()) {
 588                                     return a;
 589                                 } else if (b.isUnrestricted()) {
 590                                     return b;
 591                                 }
 592                                 // a!=0 && b !=0 holds
 593                                 long newLowerBound = Long.MAX_VALUE;
 594                                 long newUpperBound = Long.MIN_VALUE;
 595                                 /*
 596                                  * Based on the signs of the incoming stamps lower and upper bound
 597                                  * of the result of the multiplication may be swapped. LowerBound
 598                                  * can become upper bound if both signs are negative, and so on. To
 599                                  * determine the new values for lower and upper bound we need to
 600                                  * look at the max and min of the cases blow:
 601                                  *
 602                                  * @formatter:off
 603                                  *
 604                                  * a.lowerBound * b.lowerBound
 605                                  * a.lowerBound * b.upperBound
 606                                  * a.upperBound * b.lowerBound
 607                                  * a.upperBound * b.upperBound
 608                                  *
 609                                  * @formatter:on
 610                                  *
 611                                  * We are only interested in those cases that are relevant due to
 612                                  * the sign of the involved stamps (whether a stamp includes
 613                                  * negative and / or positive values). Based on the signs, the maximum
 614                                  * or minimum of the above multiplications form the new lower and
 615                                  * upper bounds.
 616                                  *
 617                                  * The table below contains the interesting candidates for lower and
 618                                  * upper bound after multiplication.
 619                                  *
 620                                  * For example if we consider two stamps a & b that both contain
 621                                  * negative and positive values, the product of minN_a * minN_b
 622                                  * (both the smallest negative value for each stamp) can only be the
 623                                  * highest positive number. The other candidates can be computed in
 624                                  * a similar fashion. Some of them can never be a new minimum or
 625                                  * maximum and are therefore excluded.
 626                                  *
 627                                  *
 628                                  * @formatter:off
 629                                  *
 630                                  *          [x..........0..........y]
 631                                  *          -------------------------
 632                                  *          [minN   maxN minP   maxP]
 633                                  *               where maxN = min(0,y) && minP = max(0,x)
 634                                  *
 635                                  *
 636                                  *                |minN_a  maxN_a    minP_a  maxP_a
 637                                  *         _______|________________________________
 638                                  *         minN_b |MAX      /     :   /      MIN
 639                                  *         maxN_b | /      MIN    :  MAX      /
 640                                  *                |---------------+----------------
 641                                  *         minP_b | /      MAX    :  MIN      /
 642                                  *         maxP_b |MIN      /     :   /      MAX
 643                                  *
 644                                  * @formatter:on
 645                                  */
 646                                 // We materialize all factors here. If they are needed, the signs of
 647                                 // the stamp will ensure the correct value is used.
 648                                 // Checkstyle: stop
 649                                 long minN_a = a.lowerBound();
 650                                 long maxN_a = Math.min(0, a.upperBound());
 651                                 long minP_a = Math.max(0, a.lowerBound());
 652                                 long maxP_a = a.upperBound();
 653 
 654                                 long minN_b = b.lowerBound();
 655                                 long maxN_b = Math.min(0, b.upperBound());
 656                                 long minP_b = Math.max(0, b.lowerBound());
 657                                 long maxP_b = b.upperBound();
 658                                 // Checkstyle: resume
 659 
 660                                 // multiplication has shift semantics
 661                                 long newUpMask = ~CodeUtil.mask(Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask)) & CodeUtil.mask(bits);
 662 
 663                                 if (a.canBePositive()) {
 664                                     if (b.canBePositive()) {
 665                                         if (multiplicationOverflows(maxP_a, maxP_b, bits)) {
 666                                             return a.unrestricted();
 667                                         }
 668                                         long maxCandidate = maxP_a * maxP_b;
 669                                         if (multiplicationOverflows(minP_a, minP_b, bits)) {
 670                                             return a.unrestricted();
 671                                         }
 672                                         long minCandidate = minP_a * minP_b;
 673                                         newLowerBound = Math.min(newLowerBound, minCandidate);
 674                                         newUpperBound = Math.max(newUpperBound, maxCandidate);
 675                                     }
 676                                     if (b.canBeNegative()) {
 677                                         if (multiplicationOverflows(minP_a, maxN_b, bits)) {
 678                                             return a.unrestricted();
 679                                         }
 680                                         long maxCandidate = minP_a * maxN_b;
 681                                         if (multiplicationOverflows(maxP_a, minN_b, bits)) {
 682                                             return a.unrestricted();
 683                                         }
 684                                         long minCandidate = maxP_a * minN_b;
 685                                         newLowerBound = Math.min(newLowerBound, minCandidate);
 686                                         newUpperBound = Math.max(newUpperBound, maxCandidate);
 687                                     }
 688                                 }
 689                                 if (a.canBeNegative()) {
 690                                     if (b.canBePositive()) {
 691                                         if (multiplicationOverflows(maxN_a, minP_b, bits)) {
 692                                             return a.unrestricted();
 693                                         }
 694                                         long maxCandidate = maxN_a * minP_b;
 695                                         if (multiplicationOverflows(minN_a, maxP_b, bits)) {
 696                                             return a.unrestricted();
 697                                         }
 698                                         long minCandidate = minN_a * maxP_b;
 699                                         newLowerBound = Math.min(newLowerBound, minCandidate);
 700                                         newUpperBound = Math.max(newUpperBound, maxCandidate);
 701                                     }
 702                                     if (b.canBeNegative()) {
 703                                         if (multiplicationOverflows(minN_a, minN_b, bits)) {
 704                                             return a.unrestricted();
 705                                         }
 706                                         long maxCandidate = minN_a * minN_b;
 707                                         if (multiplicationOverflows(maxN_a, maxN_b, bits)) {
 708                                             return a.unrestricted();
 709                                         }
 710                                         long minCandidate = maxN_a * maxN_b;
 711                                         newLowerBound = Math.min(newLowerBound, minCandidate);
 712                                         newUpperBound = Math.max(newUpperBound, maxCandidate);
 713                                     }
 714                                 }
 715 
 716                                 assert newLowerBound <= newUpperBound;
 717                                 return StampFactory.forIntegerWithMask(bits, newLowerBound, newUpperBound, 0, newUpMask);
 718                             }
 719                         }
 720 
 721                         @Override
 722                         public boolean isNeutral(Constant value) {
 723                             PrimitiveConstant n = (PrimitiveConstant) value;
 724                             return n.asLong() == 1;
 725                         }
 726                     },
 727 
 728                     new BinaryOp.Div(true, false) {
 729 
 730                         @Override
 731                         public Constant foldConstant(Constant const1, Constant const2) {
 732                             PrimitiveConstant a = (PrimitiveConstant) const1;
 733                             PrimitiveConstant b = (PrimitiveConstant) const2;
 734                             assert a.getJavaKind() == b.getJavaKind();
 735                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() / b.asLong());
 736                         }
 737 
 738                         @Override
 739                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
 740                             IntegerStamp a = (IntegerStamp) stamp1;
 741                             IntegerStamp b = (IntegerStamp) stamp2;
 742                             assert a.getBits() == b.getBits();
 743                             if (b.isStrictlyPositive()) {
 744                                 long newLowerBound = a.lowerBound() / b.upperBound();
 745                                 long newUpperBound = a.upperBound() / b.lowerBound();
 746                                 return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
 747                             } else {
 748                                 return a.unrestricted();
 749                             }
 750                         }
 751 
 752                         @Override
 753                         public boolean isNeutral(Constant value) {
 754                             PrimitiveConstant n = (PrimitiveConstant) value;
 755                             return n.asLong() == 1;
 756                         }
 757                     },
 758 
 759                     new BinaryOp.Rem(false, false) {
 760 
 761                         @Override
 762                         public Constant foldConstant(Constant const1, Constant const2) {
 763                             PrimitiveConstant a = (PrimitiveConstant) const1;
 764                             PrimitiveConstant b = (PrimitiveConstant) const2;
 765                             assert a.getJavaKind() == b.getJavaKind();
 766                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() % b.asLong());
 767                         }
 768 
 769                         @Override
 770                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
 771                             IntegerStamp a = (IntegerStamp) stamp1;
 772                             IntegerStamp b = (IntegerStamp) stamp2;
 773                             assert a.getBits() == b.getBits();
 774                             // zero is always possible
 775                             long newLowerBound = Math.min(a.lowerBound(), 0);
 776                             long newUpperBound = Math.max(a.upperBound(), 0);
 777 
 778                             /* the maximum absolute value of the result, derived from b */
 779                             long magnitude;
 780                             if (b.lowerBound() == CodeUtil.minValue(b.getBits())) {
 781                                 // Math.abs(...) - 1 does not work in a case
 782                                 magnitude = CodeUtil.maxValue(b.getBits());
 783                             } else {
 784                                 magnitude = Math.max(Math.abs(b.lowerBound()), Math.abs(b.upperBound())) - 1;
 785                             }
 786                             newLowerBound = Math.max(newLowerBound, -magnitude);
 787                             newUpperBound = Math.min(newUpperBound, magnitude);
 788 
 789                             return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
 790                         }
 791                     },
 792 
 793                     new UnaryOp.Not() {
 794 
 795                         @Override
 796                         public Constant foldConstant(Constant c) {
 797                             PrimitiveConstant value = (PrimitiveConstant) c;
 798                             return JavaConstant.forIntegerKind(value.getJavaKind(), ~value.asLong());
 799                         }
 800 
 801                         @Override
 802                         public Stamp foldStamp(Stamp stamp) {
 803                             IntegerStamp integerStamp = (IntegerStamp) stamp;
 804                             int bits = integerStamp.getBits();
 805                             long defaultMask = CodeUtil.mask(bits);
 806                             return new IntegerStamp(bits, ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask);
 807                         }
 808                     },
 809 
 810                     new BinaryOp.And(true, true) {
 811 
 812                         @Override
 813                         public Constant foldConstant(Constant const1, Constant const2) {
 814                             PrimitiveConstant a = (PrimitiveConstant) const1;
 815                             PrimitiveConstant b = (PrimitiveConstant) const2;
 816                             assert a.getJavaKind() == b.getJavaKind();
 817                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() & b.asLong());
 818                         }
 819 
 820                         @Override
 821                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
 822                             IntegerStamp a = (IntegerStamp) stamp1;
 823                             IntegerStamp b = (IntegerStamp) stamp2;
 824                             assert a.getBits() == b.getBits();
 825                             return stampForMask(a.getBits(), a.downMask() & b.downMask(), a.upMask() & b.upMask());
 826                         }
 827 
 828                         @Override
 829                         public boolean isNeutral(Constant value) {
 830                             PrimitiveConstant n = (PrimitiveConstant) value;
 831                             int bits = n.getJavaKind().getBitCount();
 832                             long mask = CodeUtil.mask(bits);
 833                             return (n.asLong() & mask) == mask;
 834                         }
 835                     },
 836 
 837                     new BinaryOp.Or(true, true) {
 838 
 839                         @Override
 840                         public Constant foldConstant(Constant const1, Constant const2) {
 841                             PrimitiveConstant a = (PrimitiveConstant) const1;
 842                             PrimitiveConstant b = (PrimitiveConstant) const2;
 843                             assert a.getJavaKind() == b.getJavaKind();
 844                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() | b.asLong());
 845                         }
 846 
 847                         @Override
 848                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
 849                             IntegerStamp a = (IntegerStamp) stamp1;
 850                             IntegerStamp b = (IntegerStamp) stamp2;
 851                             assert a.getBits() == b.getBits();
 852                             return stampForMask(a.getBits(), a.downMask() | b.downMask(), a.upMask() | b.upMask());
 853                         }
 854 
 855                         @Override
 856                         public boolean isNeutral(Constant value) {
 857                             PrimitiveConstant n = (PrimitiveConstant) value;
 858                             return n.asLong() == 0;
 859                         }
 860                     },
 861 
 862                     new BinaryOp.Xor(true, true) {
 863 
 864                         @Override
 865                         public Constant foldConstant(Constant const1, Constant const2) {
 866                             PrimitiveConstant a = (PrimitiveConstant) const1;
 867                             PrimitiveConstant b = (PrimitiveConstant) const2;
 868                             assert a.getJavaKind() == b.getJavaKind();
 869                             return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() ^ b.asLong());
 870                         }
 871 
 872                         @Override
 873                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
 874                             IntegerStamp a = (IntegerStamp) stamp1;
 875                             IntegerStamp b = (IntegerStamp) stamp2;
 876                             assert a.getBits() == b.getBits();
 877 
 878                             long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
 879                             long newDownMask = (a.downMask() ^ b.downMask()) & ~variableBits;
 880                             long newUpMask = (a.downMask() ^ b.downMask()) | variableBits;
 881                             return stampForMask(a.getBits(), newDownMask, newUpMask);
 882                         }
 883 
 884                         @Override
 885                         public boolean isNeutral(Constant value) {
 886                             PrimitiveConstant n = (PrimitiveConstant) value;
 887                             return n.asLong() == 0;
 888                         }
 889 
 890                         @Override
 891                         public Constant getZero(Stamp s) {
 892                             IntegerStamp stamp = (IntegerStamp) s;
 893                             return JavaConstant.forPrimitiveInt(stamp.getBits(), 0);
 894                         }
 895                     },
 896 
 897                     new ShiftOp.Shl() {
 898 
 899                         @Override
 900                         public Constant foldConstant(Constant value, int amount) {
 901                             PrimitiveConstant c = (PrimitiveConstant) value;
 902                             switch (c.getJavaKind()) {
 903                                 case Int:
 904                                     return JavaConstant.forInt(c.asInt() << amount);
 905                                 case Long:
 906                                     return JavaConstant.forLong(c.asLong() << amount);
 907                                 default:
 908                                     throw GraalError.shouldNotReachHere();
 909                             }
 910                         }
 911 
 912                         @Override
 913                         public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
 914                             IntegerStamp value = (IntegerStamp) stamp;
 915                             int bits = value.getBits();
 916                             long defaultMask = CodeUtil.mask(bits);
 917                             if (value.upMask() == 0) {
 918                                 return value;
 919                             }
 920                             int shiftMask = getShiftAmountMask(stamp);
 921                             int shiftBits = Integer.bitCount(shiftMask);
 922                             if (shift.lowerBound() == shift.upperBound()) {
 923                                 int shiftAmount = (int) (shift.lowerBound() & shiftMask);
 924                                 if (shiftAmount == 0) {
 925                                     return value;
 926                                 }
 927                                 // the mask of bits that will be lost or shifted into the sign bit
 928                                 long removedBits = -1L << (bits - shiftAmount - 1);
 929                                 if ((value.lowerBound() & removedBits) == 0 && (value.upperBound() & removedBits) == 0) {
 930                                     /*
 931                                      * use a better stamp if neither lower nor upper bound can lose
 932                                      * bits
 933                                      */
 934                                     return new IntegerStamp(bits, value.lowerBound() << shiftAmount, value.upperBound() << shiftAmount, value.downMask() << shiftAmount, value.upMask() << shiftAmount);
 935                                 }
 936                             }
 937                             if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) {
 938                                 long downMask = defaultMask;
 939                                 long upMask = 0;
 940                                 for (long i = shift.lowerBound(); i <= shift.upperBound(); i++) {
 941                                     if (shift.contains(i)) {
 942                                         downMask &= value.downMask() << (i & shiftMask);
 943                                         upMask |= value.upMask() << (i & shiftMask);
 944                                     }
 945                                 }
 946                                 Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
 947                                 return result;
 948                             }
 949                             return value.unrestricted();
 950                         }
 951 
 952                         @Override
 953                         public int getShiftAmountMask(Stamp s) {
 954                             IntegerStamp stamp = (IntegerStamp) s;
 955                             assert CodeUtil.isPowerOf2(stamp.getBits());
 956                             return stamp.getBits() - 1;
 957                         }
 958                     },
 959 
 960                     new ShiftOp.Shr() {
 961 
 962                         @Override
 963                         public Constant foldConstant(Constant value, int amount) {
 964                             PrimitiveConstant c = (PrimitiveConstant) value;
 965                             switch (c.getJavaKind()) {
 966                                 case Int:
 967                                     return JavaConstant.forInt(c.asInt() >> amount);
 968                                 case Long:
 969                                     return JavaConstant.forLong(c.asLong() >> amount);
 970                                 default:
 971                                     throw GraalError.shouldNotReachHere();
 972                             }
 973                         }
 974 
 975                         @Override
 976                         public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
 977                             IntegerStamp value = (IntegerStamp) stamp;
 978                             int bits = value.getBits();
 979                             if (shift.lowerBound() == shift.upperBound()) {
 980                                 long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
 981                                 if (shiftCount == 0) {
 982                                     return stamp;
 983                                 }
 984 
 985                                 int extraBits = 64 - bits;
 986                                 long defaultMask = CodeUtil.mask(bits);
 987                                 // shifting back and forth performs sign extension
 988                                 long downMask = (value.downMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
 989                                 long upMask = (value.upMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
 990                                 return new IntegerStamp(bits, value.lowerBound() >> shiftCount, value.upperBound() >> shiftCount, downMask, upMask);
 991                             }
 992                             long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
 993                             return IntegerStamp.stampForMask(bits, 0, mask);
 994                         }
 995 
 996                         @Override
 997                         public int getShiftAmountMask(Stamp s) {
 998                             IntegerStamp stamp = (IntegerStamp) s;
 999                             assert CodeUtil.isPowerOf2(stamp.getBits());
1000                             return stamp.getBits() - 1;
1001                         }
1002                     },
1003 
1004                     new ShiftOp.UShr() {
1005 
1006                         @Override
1007                         public Constant foldConstant(Constant value, int amount) {
1008                             PrimitiveConstant c = (PrimitiveConstant) value;
1009                             switch (c.getJavaKind()) {
1010                                 case Int:
1011                                     return JavaConstant.forInt(c.asInt() >>> amount);
1012                                 case Long:
1013                                     return JavaConstant.forLong(c.asLong() >>> amount);
1014                                 default:
1015                                     throw GraalError.shouldNotReachHere();
1016                             }
1017                         }
1018 
1019                         @Override
1020                         public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
1021                             IntegerStamp value = (IntegerStamp) stamp;
1022                             int bits = value.getBits();
1023                             if (shift.lowerBound() == shift.upperBound()) {
1024                                 long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
1025                                 if (shiftCount == 0) {
1026                                     return stamp;
1027                                 }
1028 
1029                                 long downMask = value.downMask() >>> shiftCount;
1030                                 long upMask = value.upMask() >>> shiftCount;
1031                                 if (value.lowerBound() < 0) {
1032                                     return new IntegerStamp(bits, downMask, upMask, downMask, upMask);
1033                                 } else {
1034                                     return new IntegerStamp(bits, value.lowerBound() >>> shiftCount, value.upperBound() >>> shiftCount, downMask, upMask);
1035                                 }
1036                             }
1037                             long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
1038                             return IntegerStamp.stampForMask(bits, 0, mask);
1039                         }
1040 
1041                         @Override
1042                         public int getShiftAmountMask(Stamp s) {
1043                             IntegerStamp stamp = (IntegerStamp) s;
1044                             assert CodeUtil.isPowerOf2(stamp.getBits());
1045                             return stamp.getBits() - 1;
1046                         }
1047                     },
1048 
1049                     new UnaryOp.Abs() {
1050 
1051                         @Override
1052                         public Constant foldConstant(Constant value) {
1053                             PrimitiveConstant c = (PrimitiveConstant) value;
1054                             return JavaConstant.forIntegerKind(c.getJavaKind(), Math.abs(c.asLong()));
1055                         }
1056 
1057                         @Override
1058                         public Stamp foldStamp(Stamp input) {
1059                             IntegerStamp stamp = (IntegerStamp) input;
1060                             int bits = stamp.getBits();
1061                             if (stamp.lowerBound() == CodeUtil.minValue(bits)) {
1062                                 return input.unrestricted();
1063                             } else {
1064                                 long limit = Math.max(-stamp.lowerBound(), stamp.upperBound());
1065                                 return StampFactory.forInteger(bits, 0, limit);
1066                             }
1067                         }
1068                     },
1069 
1070                     null,
1071 
1072                     new IntegerConvertOp.ZeroExtend() {
1073 
1074                         @Override
1075                         public Constant foldConstant(int inputBits, int resultBits, Constant c) {
1076                             PrimitiveConstant value = (PrimitiveConstant) c;
1077                             return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.zeroExtend(value.asLong(), inputBits));
1078                         }
1079 
1080                         @Override
1081                         public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
1082                             IntegerStamp stamp = (IntegerStamp) input;
1083                             assert inputBits == stamp.getBits();
1084                             assert inputBits <= resultBits;
1085 
1086                             long downMask = CodeUtil.zeroExtend(stamp.downMask(), inputBits);
1087                             long upMask = CodeUtil.zeroExtend(stamp.upMask(), inputBits);
1088 
1089                             if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) {
1090                                 /* signed range including 0 and -1 */
1091                                 /*
1092                                  * after sign extension, the whole range from 0 to MAX_INT is
1093                                  * possible
1094                                  */
1095                                 return IntegerStamp.stampForMask(resultBits, downMask, upMask);
1096                             }
1097 
1098                             long lowerBound = CodeUtil.zeroExtend(stamp.lowerBound(), inputBits);
1099                             long upperBound = CodeUtil.zeroExtend(stamp.upperBound(), inputBits);
1100 
1101                             return new IntegerStamp(resultBits, lowerBound, upperBound, downMask, upMask);
1102                         }
1103                     },
1104 
1105                     new IntegerConvertOp.SignExtend() {
1106 
1107                         @Override
1108                         public Constant foldConstant(int inputBits, int resultBits, Constant c) {
1109                             PrimitiveConstant value = (PrimitiveConstant) c;
1110                             return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.signExtend(value.asLong(), inputBits));
1111                         }
1112 
1113                         @Override
1114                         public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
1115                             IntegerStamp stamp = (IntegerStamp) input;
1116                             assert inputBits == stamp.getBits();
1117                             assert inputBits <= resultBits;
1118 
1119                             long defaultMask = CodeUtil.mask(resultBits);
1120                             long downMask = CodeUtil.signExtend(stamp.downMask(), inputBits) & defaultMask;
1121                             long upMask = CodeUtil.signExtend(stamp.upMask(), inputBits) & defaultMask;
1122 
1123                             return new IntegerStamp(resultBits, stamp.lowerBound(), stamp.upperBound(), downMask, upMask);
1124                         }
1125                     },
1126 
1127                     new IntegerConvertOp.Narrow() {
1128 
1129                         @Override
1130                         public Constant foldConstant(int inputBits, int resultBits, Constant c) {
1131                             PrimitiveConstant value = (PrimitiveConstant) c;
1132                             return JavaConstant.forPrimitiveInt(resultBits, CodeUtil.narrow(value.asLong(), resultBits));
1133                         }
1134 
1135                         @Override
1136                         public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
1137                             IntegerStamp stamp = (IntegerStamp) input;
1138                             assert inputBits == stamp.getBits();
1139                             assert resultBits <= inputBits;
1140                             if (resultBits == inputBits) {
1141                                 return stamp;
1142                             }
1143 
1144                             final long upperBound;
1145                             if (stamp.lowerBound() < CodeUtil.minValue(resultBits)) {
1146                                 upperBound = CodeUtil.maxValue(resultBits);
1147                             } else {
1148                                 upperBound = saturate(stamp.upperBound(), resultBits);
1149                             }
1150                             final long lowerBound;
1151                             if (stamp.upperBound() > CodeUtil.maxValue(resultBits)) {
1152                                 lowerBound = CodeUtil.minValue(resultBits);
1153                             } else {
1154                                 lowerBound = saturate(stamp.lowerBound(), resultBits);
1155                             }
1156 
1157                             long defaultMask = CodeUtil.mask(resultBits);
1158                             long newDownMask = stamp.downMask() & defaultMask;
1159                             long newUpMask = stamp.upMask() & defaultMask;
1160                             long newLowerBound = CodeUtil.signExtend((lowerBound | newDownMask) & newUpMask, resultBits);
1161                             long newUpperBound = CodeUtil.signExtend((upperBound | newDownMask) & newUpMask, resultBits);
1162                             return new IntegerStamp(resultBits, newLowerBound, newUpperBound, newDownMask, newUpMask);
1163                         }
1164                     },
1165 
1166                     new FloatConvertOp(I2F) {
1167 
1168                         @Override
1169                         public Constant foldConstant(Constant c) {
1170                             PrimitiveConstant value = (PrimitiveConstant) c;
1171                             return JavaConstant.forFloat(value.asInt());
1172                         }
1173 
1174                         @Override
1175                         public Stamp foldStamp(Stamp input) {
1176                             IntegerStamp stamp = (IntegerStamp) input;
1177                             assert stamp.getBits() == 32;
1178                             float lowerBound = stamp.lowerBound();
1179                             float upperBound = stamp.upperBound();
1180                             return StampFactory.forFloat(JavaKind.Float, lowerBound, upperBound, true);
1181                         }
1182                     },
1183 
1184                     new FloatConvertOp(L2F) {
1185 
1186                         @Override
1187                         public Constant foldConstant(Constant c) {
1188                             PrimitiveConstant value = (PrimitiveConstant) c;
1189                             return JavaConstant.forFloat(value.asLong());
1190                         }
1191 
1192                         @Override
1193                         public Stamp foldStamp(Stamp input) {
1194                             IntegerStamp stamp = (IntegerStamp) input;
1195                             assert stamp.getBits() == 64;
1196                             float lowerBound = stamp.lowerBound();
1197                             float upperBound = stamp.upperBound();
1198                             return StampFactory.forFloat(JavaKind.Float, lowerBound, upperBound, true);
1199                         }
1200                     },
1201 
1202                     new FloatConvertOp(I2D) {
1203 
1204                         @Override
1205                         public Constant foldConstant(Constant c) {
1206                             PrimitiveConstant value = (PrimitiveConstant) c;
1207                             return JavaConstant.forDouble(value.asInt());
1208                         }
1209 
1210                         @Override
1211                         public Stamp foldStamp(Stamp input) {
1212                             IntegerStamp stamp = (IntegerStamp) input;
1213                             assert stamp.getBits() == 32;
1214                             double lowerBound = stamp.lowerBound();
1215                             double upperBound = stamp.upperBound();
1216                             return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, true);
1217                         }
1218                     },
1219 
1220                     new FloatConvertOp(L2D) {
1221 
1222                         @Override
1223                         public Constant foldConstant(Constant c) {
1224                             PrimitiveConstant value = (PrimitiveConstant) c;
1225                             return JavaConstant.forDouble(value.asLong());
1226                         }
1227 
1228                         @Override
1229                         public Stamp foldStamp(Stamp input) {
1230                             IntegerStamp stamp = (IntegerStamp) input;
1231                             assert stamp.getBits() == 64;
1232                             double lowerBound = stamp.lowerBound();
1233                             double upperBound = stamp.upperBound();
1234                             return StampFactory.forFloat(JavaKind.Double, lowerBound, upperBound, true);
1235                         }
1236                     });
1237 }