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 }