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