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;
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 }
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() {
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) &&
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 }
|
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.Or;
37 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem;
38 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub;
39 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor;
40 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
41 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
42 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
43 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shl;
44 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shr;
45 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.UShr;
46 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs;
47 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg;
48 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not;
49 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
50 import org.graalvm.util.CollectionsUtil;
51
52 import jdk.vm.ci.meta.Constant;
53 import jdk.vm.ci.meta.JavaKind;
54
55 /**
56 * Information about arithmetic operations.
57 */
58 public final class ArithmeticOpTable {
59
60 private final UnaryOp<Neg> neg;
61 private final BinaryOp<Add> add;
62 private final BinaryOp<Sub> sub;
63
64 private final BinaryOp<Mul> mul;
65 private final BinaryOp<Div> div;
66 private final BinaryOp<Rem> rem;
67
68 private final UnaryOp<Not> not;
69 private final BinaryOp<And> and;
70 private final BinaryOp<Or> or;
71 private final BinaryOp<Xor> xor;
72
73 private final ShiftOp<Shl> shl;
77 private final UnaryOp<Abs> abs;
78 private final UnaryOp<Sqrt> sqrt;
79
80 private final IntegerConvertOp<ZeroExtend> zeroExtend;
81 private final IntegerConvertOp<SignExtend> signExtend;
82 private final IntegerConvertOp<Narrow> narrow;
83
84 private final FloatConvertOp[] floatConvert;
85 private final int hash;
86
87 public static ArithmeticOpTable forStamp(Stamp s) {
88 if (s instanceof ArithmeticStamp) {
89 return ((ArithmeticStamp) s).getOps();
90 } else {
91 return EMPTY;
92 }
93 }
94
95 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);
96
97 public interface ArithmeticOpWrapper {
98
99 <OP> UnaryOp<OP> wrapUnaryOp(UnaryOp<OP> op);
100
101 <OP> BinaryOp<OP> wrapBinaryOp(BinaryOp<OP> op);
102
103 <OP> ShiftOp<OP> wrapShiftOp(ShiftOp<OP> op);
104
105 <OP> IntegerConvertOp<OP> wrapIntegerConvertOp(IntegerConvertOp<OP> op);
106
107 FloatConvertOp wrapFloatConvertOp(FloatConvertOp op);
108 }
109
110 private static <T> T wrapIfNonNull(Function<T, T> wrapper, T obj) {
111 if (obj == null) {
112 return null;
113 } else {
114 return wrapper.apply(obj);
115 }
116 }
123 BinaryOp<Mul> mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul());
124 BinaryOp<Div> div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv());
125 BinaryOp<Rem> rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem());
126
127 UnaryOp<Not> not = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNot());
128 BinaryOp<And> and = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAnd());
129 BinaryOp<Or> or = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getOr());
130 BinaryOp<Xor> xor = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getXor());
131
132 ShiftOp<Shl> shl = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShl());
133 ShiftOp<Shr> shr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShr());
134 ShiftOp<UShr> ushr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getUShr());
135
136 UnaryOp<Abs> abs = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getAbs());
137 UnaryOp<Sqrt> sqrt = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getSqrt());
138
139 IntegerConvertOp<ZeroExtend> zeroExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getZeroExtend());
140 IntegerConvertOp<SignExtend> signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend());
141 IntegerConvertOp<Narrow> narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow());
142
143 FloatConvertOp[] floatConvert = CollectionsUtil.filterAndMapToArray(inner.floatConvert, Objects::nonNull, wrapper::wrapFloatConvertOp, FloatConvertOp[]::new);
144 return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
145 }
146
147 protected 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,
148 BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
149 IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
150 this.neg = neg;
151 this.add = add;
152 this.sub = sub;
153 this.mul = mul;
154 this.div = div;
155 this.rem = rem;
156 this.not = not;
157 this.and = and;
158 this.or = or;
159 this.xor = xor;
160 this.shl = shl;
161 this.shr = shr;
162 this.ushr = ushr;
163 this.abs = abs;
164 this.sqrt = sqrt;
165 this.zeroExtend = zeroExtend;
166 this.signExtend = signExtend;
167 this.narrow = narrow;
168 this.floatConvert = new FloatConvertOp[FloatConvert.values().length];
169 for (FloatConvertOp op : floatConvert) {
170 this.floatConvert[op.getFloatConvert().ordinal()] = op;
171 }
172
173 this.hash = Objects.hash(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow);
174 }
175
176 @Override
177 public int hashCode() {
178 return hash;
179 }
180
181 /**
182 * Describes the unary negation operation.
183 */
184 public UnaryOp<Neg> getNeg() {
185 return neg;
186 }
187
188 /**
189 * Describes the addition operation.
190 */
191 public BinaryOp<Add> getAdd() {
295 */
296 public IntegerConvertOp<SignExtend> getSignExtend() {
297 return signExtend;
298 }
299
300 /**
301 * Describes the narrowing conversion.
302 */
303 public IntegerConvertOp<Narrow> getNarrow() {
304 return narrow;
305 }
306
307 /**
308 * Describes integer/float/double conversions.
309 */
310 public FloatConvertOp getFloatConvert(FloatConvert op) {
311 return floatConvert[op.ordinal()];
312 }
313
314 public static String toString(Op... ops) {
315 return CollectionsUtil.mapAndJoin(ops, o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}", ",");
316 }
317
318 private boolean opsEquals(ArithmeticOpTable that) {
319 // @formatter:off
320 return Objects.equals(neg, that.neg) &&
321 Objects.equals(add, that.add) &&
322 Objects.equals(sub, that.sub) &&
323 Objects.equals(mul, that.mul) &&
324 Objects.equals(div, that.div) &&
325 Objects.equals(rem, that.rem) &&
326 Objects.equals(not, that.not) &&
327 Objects.equals(and, that.and) &&
328 Objects.equals(or, that.or) &&
329 Objects.equals(xor, that.xor) &&
330 Objects.equals(shl, that.shl) &&
331 Objects.equals(shr, that.shr) &&
332 Objects.equals(ushr, that.ushr) &&
333 Objects.equals(abs, that.abs) &&
334 Objects.equals(sqrt, that.sqrt) &&
335 Objects.equals(zeroExtend, that.zeroExtend) &&
719
720 public abstract static class ZeroExtend extends IntegerConvertOp<ZeroExtend> {
721
722 protected ZeroExtend() {
723 super("ZeroExtend");
724 }
725 }
726
727 public abstract static class SignExtend extends IntegerConvertOp<SignExtend> {
728
729 protected SignExtend() {
730 super("SignExtend");
731 }
732 }
733
734 public abstract static class Narrow extends IntegerConvertOp<Narrow> {
735
736 protected Narrow() {
737 super("Narrow");
738 }
739
740 @Override
741 public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
742 return null;
743 }
744 }
745
746 protected IntegerConvertOp(String op) {
747 super(op);
748 }
749
750 public abstract Constant foldConstant(int inputBits, int resultBits, Constant value);
751
752 public abstract Stamp foldStamp(int inputBits, int resultBits, Stamp stamp);
753
754 public IntegerConvertOp<T> unwrap() {
755 return this;
756 }
757
758 /**
759 * Computes the stamp of the input for the given output stamp.
760 */
761 public abstract Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp);
762 }
763 }
|