1 /*
   2  * Copyright (c) 2014, 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 jdk.vm.ci.meta.MetaUtil.getSimpleName;
  26 
  27 import java.util.Arrays;
  28 import java.util.Objects;
  29 import java.util.function.Function;
  30 
  31 import org.graalvm.compiler.core.common.calc.FloatConvert;
  32 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
  33 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
  34 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div;
  35 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul;
  36 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.MulHigh;
  37 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
  38 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem;
  39 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub;
  40 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.UMulHigh;
  41 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor;
  42 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
  43 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
  44 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
  45 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shl;
  46 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shr;
  47 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.UShr;
  48 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs;
  49 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg;
  50 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not;
  51 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
  52 import org.graalvm.util.CollectionsUtil;
  53 
  54 import jdk.vm.ci.meta.Constant;
  55 import jdk.vm.ci.meta.JavaKind;
  56 
  57 /**
  58  * Information about arithmetic operations.
  59  */
  60 public final class ArithmeticOpTable {
  61 
  62     private final UnaryOp<Neg> neg;
  63     private final BinaryOp<Add> add;
  64     private final BinaryOp<Sub> sub;
  65 
  66     private final BinaryOp<Mul> mul;
  67     private final BinaryOp<MulHigh> mulHigh;
  68     private final BinaryOp<UMulHigh> umulHigh;
  69     private final BinaryOp<Div> div;
  70     private final BinaryOp<Rem> rem;
  71 
  72     private final UnaryOp<Not> not;
  73     private final BinaryOp<And> and;
  74     private final BinaryOp<Or> or;
  75     private final BinaryOp<Xor> xor;
  76 
  77     private final ShiftOp<Shl> shl;
  78     private final ShiftOp<Shr> shr;
  79     private final ShiftOp<UShr> ushr;
  80 
  81     private final UnaryOp<Abs> abs;
  82     private final UnaryOp<Sqrt> sqrt;
  83 
  84     private final IntegerConvertOp<ZeroExtend> zeroExtend;
  85     private final IntegerConvertOp<SignExtend> signExtend;
  86     private final IntegerConvertOp<Narrow> narrow;
  87 
  88     private final FloatConvertOp[] floatConvert;
  89     private final int hash;
  90 
  91     public static ArithmeticOpTable forStamp(Stamp s) {
  92         if (s instanceof ArithmeticStamp) {
  93             return ((ArithmeticStamp) s).getOps();
  94         } else {
  95             return EMPTY;
  96         }
  97     }
  98 
  99     public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
 100 
 101     public interface ArithmeticOpWrapper {
 102 
 103         <OP> UnaryOp<OP> wrapUnaryOp(UnaryOp<OP> op);
 104 
 105         <OP> BinaryOp<OP> wrapBinaryOp(BinaryOp<OP> op);
 106 
 107         <OP> ShiftOp<OP> wrapShiftOp(ShiftOp<OP> op);
 108 
 109         <OP> IntegerConvertOp<OP> wrapIntegerConvertOp(IntegerConvertOp<OP> op);
 110 
 111         FloatConvertOp wrapFloatConvertOp(FloatConvertOp op);
 112     }
 113 
 114     private static <T> T wrapIfNonNull(Function<T, T> wrapper, T obj) {
 115         if (obj == null) {
 116             return null;
 117         } else {
 118             return wrapper.apply(obj);
 119         }
 120     }
 121 
 122     public static ArithmeticOpTable wrap(ArithmeticOpWrapper wrapper, ArithmeticOpTable inner) {
 123         UnaryOp<Neg> neg = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNeg());
 124         BinaryOp<Add> add = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAdd());
 125         BinaryOp<Sub> sub = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getSub());
 126 
 127         BinaryOp<Mul> mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul());
 128         BinaryOp<MulHigh> mulHigh = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMulHigh());
 129         BinaryOp<UMulHigh> umulHigh = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getUMulHigh());
 130         BinaryOp<Div> div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv());
 131         BinaryOp<Rem> rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem());
 132 
 133         UnaryOp<Not> not = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNot());
 134         BinaryOp<And> and = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAnd());
 135         BinaryOp<Or> or = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getOr());
 136         BinaryOp<Xor> xor = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getXor());
 137 
 138         ShiftOp<Shl> shl = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShl());
 139         ShiftOp<Shr> shr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShr());
 140         ShiftOp<UShr> ushr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getUShr());
 141 
 142         UnaryOp<Abs> abs = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getAbs());
 143         UnaryOp<Sqrt> sqrt = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getSqrt());
 144 
 145         IntegerConvertOp<ZeroExtend> zeroExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getZeroExtend());
 146         IntegerConvertOp<SignExtend> signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend());
 147         IntegerConvertOp<Narrow> narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow());
 148 
 149         FloatConvertOp[] floatConvert = CollectionsUtil.filterAndMapToArray(inner.floatConvert, Objects::nonNull, wrapper::wrapFloatConvertOp, FloatConvertOp[]::new);
 150         return new ArithmeticOpTable(neg, add, sub, mul, mulHigh, umulHigh, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
 151     }
 152 
 153     protected ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<MulHigh> mulHigh, BinaryOp<UMulHigh> umulHigh, BinaryOp<Div> div, BinaryOp<Rem> rem,
 154                     UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or, BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt,
 155                     IntegerConvertOp<ZeroExtend> zeroExtend, IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
 156         this.neg = neg;
 157         this.add = add;
 158         this.sub = sub;
 159         this.mul = mul;
 160         this.mulHigh = mulHigh;
 161         this.umulHigh = umulHigh;
 162         this.div = div;
 163         this.rem = rem;
 164         this.not = not;
 165         this.and = and;
 166         this.or = or;
 167         this.xor = xor;
 168         this.shl = shl;
 169         this.shr = shr;
 170         this.ushr = ushr;
 171         this.abs = abs;
 172         this.sqrt = sqrt;
 173         this.zeroExtend = zeroExtend;
 174         this.signExtend = signExtend;
 175         this.narrow = narrow;
 176         this.floatConvert = new FloatConvertOp[FloatConvert.values().length];
 177         for (FloatConvertOp op : floatConvert) {
 178             this.floatConvert[op.getFloatConvert().ordinal()] = op;
 179         }
 180 
 181         this.hash = Objects.hash(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow);
 182     }
 183 
 184     @Override
 185     public int hashCode() {
 186         return hash;
 187     }
 188 
 189     /**
 190      * Describes the unary negation operation.
 191      */
 192     public UnaryOp<Neg> getNeg() {
 193         return neg;
 194     }
 195 
 196     /**
 197      * Describes the addition operation.
 198      */
 199     public BinaryOp<Add> getAdd() {
 200         return add;
 201     }
 202 
 203     /**
 204      * Describes the subtraction operation.
 205      */
 206     public BinaryOp<Sub> getSub() {
 207         return sub;
 208     }
 209 
 210     /**
 211      * Describes the multiplication operation.
 212      */
 213     public BinaryOp<Mul> getMul() {
 214         return mul;
 215     }
 216 
 217     /**
 218      * Describes a signed operation that multiples the upper 32-bits of two long values.
 219      */
 220     public BinaryOp<MulHigh> getMulHigh() {
 221         return mulHigh;
 222     }
 223 
 224     /**
 225      * Describes an unsigned operation that multiples the upper 32-bits of two long values.
 226      */
 227     public BinaryOp<UMulHigh> getUMulHigh() {
 228         return umulHigh;
 229     }
 230 
 231     /**
 232      * Describes the division operation.
 233      */
 234     public BinaryOp<Div> getDiv() {
 235         return div;
 236     }
 237 
 238     /**
 239      * Describes the remainder operation.
 240      */
 241     public BinaryOp<Rem> getRem() {
 242         return rem;
 243     }
 244 
 245     /**
 246      * Describes the bitwise not operation.
 247      */
 248     public UnaryOp<Not> getNot() {
 249         return not;
 250     }
 251 
 252     /**
 253      * Describes the bitwise and operation.
 254      */
 255     public BinaryOp<And> getAnd() {
 256         return and;
 257     }
 258 
 259     /**
 260      * Describes the bitwise or operation.
 261      */
 262     public BinaryOp<Or> getOr() {
 263         return or;
 264     }
 265 
 266     /**
 267      * Describes the bitwise xor operation.
 268      */
 269     public BinaryOp<Xor> getXor() {
 270         return xor;
 271     }
 272 
 273     /**
 274      * Describes the shift left operation.
 275      */
 276     public ShiftOp<Shl> getShl() {
 277         return shl;
 278     }
 279 
 280     /**
 281      * Describes the signed shift right operation.
 282      */
 283     public ShiftOp<Shr> getShr() {
 284         return shr;
 285     }
 286 
 287     /**
 288      * Describes the unsigned shift right operation.
 289      */
 290     public ShiftOp<UShr> getUShr() {
 291         return ushr;
 292     }
 293 
 294     /**
 295      * Describes the absolute value operation.
 296      */
 297     public UnaryOp<Abs> getAbs() {
 298         return abs;
 299     }
 300 
 301     /**
 302      * Describes the square root operation.
 303      */
 304     public UnaryOp<Sqrt> getSqrt() {
 305         return sqrt;
 306     }
 307 
 308     /**
 309      * Describes the zero extend conversion.
 310      */
 311     public IntegerConvertOp<ZeroExtend> getZeroExtend() {
 312         return zeroExtend;
 313     }
 314 
 315     /**
 316      * Describes the sign extend conversion.
 317      */
 318     public IntegerConvertOp<SignExtend> getSignExtend() {
 319         return signExtend;
 320     }
 321 
 322     /**
 323      * Describes the narrowing conversion.
 324      */
 325     public IntegerConvertOp<Narrow> getNarrow() {
 326         return narrow;
 327     }
 328 
 329     /**
 330      * Describes integer/float/double conversions.
 331      */
 332     public FloatConvertOp getFloatConvert(FloatConvert op) {
 333         return floatConvert[op.ordinal()];
 334     }
 335 
 336     public static String toString(Op... ops) {
 337         return CollectionsUtil.mapAndJoin(ops, o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}", ",");
 338     }
 339 
 340     private boolean opsEquals(ArithmeticOpTable that) {
 341         // @formatter:off
 342         return Objects.equals(neg, that.neg) &&
 343                Objects.equals(add, that.add) &&
 344                Objects.equals(sub, that.sub) &&
 345                Objects.equals(mul, that.mul) &&
 346                Objects.equals(mulHigh, that.mulHigh) &&
 347                Objects.equals(umulHigh, that.umulHigh) &&
 348                Objects.equals(div, that.div) &&
 349                Objects.equals(rem, that.rem) &&
 350                Objects.equals(not, that.not) &&
 351                Objects.equals(and, that.and) &&
 352                Objects.equals(or, that.or) &&
 353                Objects.equals(xor, that.xor) &&
 354                Objects.equals(shl, that.shl) &&
 355                Objects.equals(shr, that.shr) &&
 356                Objects.equals(ushr, that.ushr) &&
 357                Objects.equals(abs, that.abs) &&
 358                Objects.equals(sqrt, that.sqrt) &&
 359                Objects.equals(zeroExtend, that.zeroExtend) &&
 360                Objects.equals(signExtend, that.signExtend) &&
 361                Objects.equals(narrow, that.narrow);
 362         // @formatter:on
 363     }
 364 
 365     @Override
 366     public boolean equals(Object obj) {
 367         if (this == obj) {
 368             return true;
 369         }
 370         if (obj == null) {
 371             return false;
 372         }
 373         if (getClass() != obj.getClass()) {
 374             return false;
 375         }
 376         ArithmeticOpTable that = (ArithmeticOpTable) obj;
 377         if (opsEquals(that)) {
 378             if (Arrays.equals(this.floatConvert, that.floatConvert)) {
 379                 return true;
 380             }
 381         }
 382         return false;
 383     }
 384 
 385     @Override
 386     public String toString() {
 387         return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, mulHigh, umulHigh, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) +
 388                         ",floatConvert[" + toString(floatConvert) + "]]";
 389     }
 390 
 391     public abstract static class Op {
 392 
 393         private final String operator;
 394 
 395         protected Op(String operator) {
 396             this.operator = operator;
 397         }
 398 
 399         @Override
 400         public String toString() {
 401             return operator;
 402         }
 403 
 404         @Override
 405         public int hashCode() {
 406             return operator.hashCode();
 407         }
 408 
 409         @Override
 410         public boolean equals(Object obj) {
 411             if (this == obj) {
 412                 return true;
 413             }
 414             if (obj == null) {
 415                 return false;
 416             }
 417             if (getClass() != obj.getClass()) {
 418                 return false;
 419             }
 420             Op that = (Op) obj;
 421             if (operator.equals(that.operator)) {
 422                 return true;
 423             }
 424             return true;
 425         }
 426     }
 427 
 428     /**
 429      * Describes a unary arithmetic operation.
 430      */
 431     public abstract static class UnaryOp<T> extends Op {
 432 
 433         public abstract static class Neg extends UnaryOp<Neg> {
 434 
 435             protected Neg() {
 436                 super("-");
 437             }
 438         }
 439 
 440         public abstract static class Not extends UnaryOp<Not> {
 441 
 442             protected Not() {
 443                 super("~");
 444             }
 445         }
 446 
 447         public abstract static class Abs extends UnaryOp<Abs> {
 448 
 449             protected Abs() {
 450                 super("ABS");
 451             }
 452         }
 453 
 454         public abstract static class Sqrt extends UnaryOp<Sqrt> {
 455 
 456             protected Sqrt() {
 457                 super("SQRT");
 458             }
 459         }
 460 
 461         protected UnaryOp(String operation) {
 462             super(operation);
 463         }
 464 
 465         /**
 466          * Apply the operation to a {@link Constant}.
 467          */
 468         public abstract Constant foldConstant(Constant value);
 469 
 470         /**
 471          * Apply the operation to a {@link Stamp}.
 472          */
 473         public abstract Stamp foldStamp(Stamp stamp);
 474 
 475         public UnaryOp<T> unwrap() {
 476             return this;
 477         }
 478     }
 479 
 480     /**
 481      * Describes a binary arithmetic operation.
 482      */
 483     public abstract static class BinaryOp<T> extends Op {
 484 
 485         public abstract static class Add extends BinaryOp<Add> {
 486 
 487             protected Add(boolean associative, boolean commutative) {
 488                 super("+", associative, commutative);
 489             }
 490         }
 491 
 492         public abstract static class Sub extends BinaryOp<Sub> {
 493 
 494             protected Sub(boolean associative, boolean commutative) {
 495                 super("-", associative, commutative);
 496             }
 497         }
 498 
 499         public abstract static class Mul extends BinaryOp<Mul> {
 500 
 501             protected Mul(boolean associative, boolean commutative) {
 502                 super("*", associative, commutative);
 503             }
 504         }
 505 
 506         public abstract static class MulHigh extends BinaryOp<MulHigh> {
 507 
 508             protected MulHigh(boolean associative, boolean commutative) {
 509                 super("*H", associative, commutative);
 510             }
 511         }
 512 
 513         public abstract static class UMulHigh extends BinaryOp<UMulHigh> {
 514 
 515             protected UMulHigh(boolean associative, boolean commutative) {
 516                 super("|*H|", associative, commutative);
 517             }
 518         }
 519 
 520         public abstract static class Div extends BinaryOp<Div> {
 521 
 522             protected Div(boolean associative, boolean commutative) {
 523                 super("/", associative, commutative);
 524             }
 525         }
 526 
 527         public abstract static class Rem extends BinaryOp<Rem> {
 528 
 529             protected Rem(boolean associative, boolean commutative) {
 530                 super("%", associative, commutative);
 531             }
 532         }
 533 
 534         public abstract static class And extends BinaryOp<And> {
 535 
 536             protected And(boolean associative, boolean commutative) {
 537                 super("&", associative, commutative);
 538             }
 539         }
 540 
 541         public abstract static class Or extends BinaryOp<Or> {
 542 
 543             protected Or(boolean associative, boolean commutative) {
 544                 super("|", associative, commutative);
 545             }
 546         }
 547 
 548         public abstract static class Xor extends BinaryOp<Xor> {
 549 
 550             protected Xor(boolean associative, boolean commutative) {
 551                 super("^", associative, commutative);
 552             }
 553         }
 554 
 555         private final boolean associative;
 556         private final boolean commutative;
 557 
 558         protected BinaryOp(String operation, boolean associative, boolean commutative) {
 559             super(operation);
 560             this.associative = associative;
 561             this.commutative = commutative;
 562         }
 563 
 564         /**
 565          * Apply the operation to two {@linkplain Constant Constants}.
 566          */
 567         public abstract Constant foldConstant(Constant a, Constant b);
 568 
 569         /**
 570          * Apply the operation to two {@linkplain Stamp Stamps}.
 571          */
 572         public abstract Stamp foldStamp(Stamp a, Stamp b);
 573 
 574         /**
 575          * Checks whether this operation is associative. An operation is associative when
 576          * {@code (a . b) . c == a . (b . c)} for all a, b, c. Note that you still have to be
 577          * careful with inverses. For example the integer subtraction operation will report
 578          * {@code true} here, since you can still reassociate as long as the correct negations are
 579          * inserted.
 580          */
 581         public final boolean isAssociative() {
 582             return associative;
 583         }
 584 
 585         /**
 586          * Checks whether this operation is commutative. An operation is commutative when
 587          * {@code a . b == b . a} for all a, b.
 588          */
 589         public final boolean isCommutative() {
 590             return commutative;
 591         }
 592 
 593         /**
 594          * Check whether a {@link Constant} is a neutral element for this operation. A neutral
 595          * element is any element {@code n} where {@code a . n == a} for all a.
 596          *
 597          * @param n the {@link Constant} that should be tested
 598          * @return true iff for all {@code a}: {@code a . n == a}
 599          */
 600         public boolean isNeutral(Constant n) {
 601             return false;
 602         }
 603 
 604         /**
 605          * Check whether this operation has a zero {@code z == a . a} for each a. Examples of
 606          * operations having such an element are subtraction and exclusive-or. Note that this may be
 607          * different from the numbers tested by {@link #isNeutral}.
 608          *
 609          * @param stamp a {@link Stamp}
 610          * @return a unique {@code z} such that {@code z == a . a} for each {@code a} in
 611          *         {@code stamp} if it exists, otherwise {@code null}
 612          */
 613         public Constant getZero(Stamp stamp) {
 614             return null;
 615         }
 616 
 617         public BinaryOp<T> unwrap() {
 618             return this;
 619         }
 620 
 621         @Override
 622         public int hashCode() {
 623             final int prime = 31;
 624             int result = super.hashCode();
 625             result = prime * result + (associative ? 1231 : 1237);
 626             result = prime * result + (commutative ? 1231 : 1237);
 627             return result;
 628         }
 629 
 630         @Override
 631         public boolean equals(Object obj) {
 632             if (this == obj) {
 633                 return true;
 634             }
 635             if (!super.equals(obj)) {
 636                 return false;
 637             }
 638             if (getClass() != obj.getClass()) {
 639                 return false;
 640             }
 641             BinaryOp<?> that = (BinaryOp<?>) obj;
 642             if (associative != that.associative) {
 643                 return false;
 644             }
 645             if (commutative != that.commutative) {
 646                 return false;
 647             }
 648             return true;
 649         }
 650 
 651         @Override
 652         public String toString() {
 653             if (associative) {
 654                 if (commutative) {
 655                     return super.toString() + "[AC]";
 656                 } else {
 657                     return super.toString() + "[A]";
 658                 }
 659             } else if (commutative) {
 660                 return super.toString() + "[C]";
 661             }
 662             return super.toString();
 663         }
 664     }
 665 
 666     /**
 667      * Describes a shift operation. The right argument of a shift operation always has kind
 668      * {@link JavaKind#Int}.
 669      */
 670     public abstract static class ShiftOp<OP> extends Op {
 671 
 672         public abstract static class Shl extends ShiftOp<Shl> {
 673 
 674             public Shl() {
 675                 super("<<");
 676             }
 677         }
 678 
 679         public abstract static class Shr extends ShiftOp<Shr> {
 680 
 681             public Shr() {
 682                 super(">>");
 683             }
 684         }
 685 
 686         public abstract static class UShr extends ShiftOp<UShr> {
 687 
 688             public UShr() {
 689                 super(">>>");
 690             }
 691         }
 692 
 693         protected ShiftOp(String operation) {
 694             super(operation);
 695         }
 696 
 697         /**
 698          * Apply the shift to a constant.
 699          */
 700         public abstract Constant foldConstant(Constant c, int amount);
 701 
 702         /**
 703          * Apply the shift to a stamp.
 704          */
 705         public abstract Stamp foldStamp(Stamp s, IntegerStamp amount);
 706 
 707         /**
 708          * Get the shift amount mask for a given result stamp.
 709          */
 710         public abstract int getShiftAmountMask(Stamp s);
 711     }
 712 
 713     public abstract static class FloatConvertOp extends UnaryOp<FloatConvertOp> {
 714 
 715         private final FloatConvert op;
 716 
 717         protected FloatConvertOp(FloatConvert op) {
 718             super(op.name());
 719             this.op = op;
 720         }
 721 
 722         public FloatConvert getFloatConvert() {
 723             return op;
 724         }
 725 
 726         @Override
 727         public FloatConvertOp unwrap() {
 728             return this;
 729         }
 730 
 731         @Override
 732         public int hashCode() {
 733             final int prime = 31;
 734             return prime * super.hashCode() + op.hashCode();
 735         }
 736 
 737         @Override
 738         public boolean equals(Object obj) {
 739             if (this == obj) {
 740                 return true;
 741             }
 742             if (!super.equals(obj)) {
 743                 return false;
 744             }
 745             if (getClass() != obj.getClass()) {
 746                 return false;
 747             }
 748             FloatConvertOp that = (FloatConvertOp) obj;
 749             if (op != that.op) {
 750                 return false;
 751             }
 752             return true;
 753         }
 754     }
 755 
 756     public abstract static class IntegerConvertOp<T> extends Op {
 757 
 758         public abstract static class ZeroExtend extends IntegerConvertOp<ZeroExtend> {
 759 
 760             protected ZeroExtend() {
 761                 super("ZeroExtend");
 762             }
 763         }
 764 
 765         public abstract static class SignExtend extends IntegerConvertOp<SignExtend> {
 766 
 767             protected SignExtend() {
 768                 super("SignExtend");
 769             }
 770         }
 771 
 772         public abstract static class Narrow extends IntegerConvertOp<Narrow> {
 773 
 774             protected Narrow() {
 775                 super("Narrow");
 776             }
 777 
 778             @Override
 779             public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
 780                 return null;
 781             }
 782         }
 783 
 784         protected IntegerConvertOp(String op) {
 785             super(op);
 786         }
 787 
 788         public abstract Constant foldConstant(int inputBits, int resultBits, Constant value);
 789 
 790         public abstract Stamp foldStamp(int inputBits, int resultBits, Stamp stamp);
 791 
 792         public IntegerConvertOp<T> unwrap() {
 793             return this;
 794         }
 795 
 796         /**
 797          * Computes the stamp of the input for the given output stamp.
 798          */
 799         public abstract Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp);
 800     }
 801 }