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