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