Skip to content

Commit 0496806

Browse files
committed
8359412: Template-Framework Library: Operations and Expressions
Reviewed-by: chagedorn, mhaessig, galder
1 parent d47e6b7 commit 0496806

File tree

7 files changed

+1611
-0
lines changed

7 files changed

+1611
-0
lines changed

test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java

Lines changed: 349 additions & 0 deletions
Large diffs are not rendered by default.

test/hotspot/jtreg/compiler/lib/template_framework/library/Expression.java

Lines changed: 474 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package compiler.lib.template_framework.library;
25+
26+
import java.util.List;
27+
import java.util.ArrayList;
28+
import java.util.Set;
29+
30+
import static compiler.lib.template_framework.library.PrimitiveType.BYTES;
31+
import static compiler.lib.template_framework.library.PrimitiveType.SHORTS;
32+
import static compiler.lib.template_framework.library.PrimitiveType.CHARS;
33+
import static compiler.lib.template_framework.library.PrimitiveType.INTS;
34+
import static compiler.lib.template_framework.library.PrimitiveType.LONGS;
35+
import static compiler.lib.template_framework.library.PrimitiveType.FLOATS;
36+
import static compiler.lib.template_framework.library.PrimitiveType.DOUBLES;
37+
import static compiler.lib.template_framework.library.PrimitiveType.BOOLEANS;
38+
39+
/**
40+
* This class provides various lists of {@link Expression}s, that represent Java operators or library
41+
* methods. For example, we represent arithmetic operations on primitive types.
42+
*/
43+
public final class Operations {
44+
45+
// private constructor to avoid instantiation.
46+
private Operations() {}
47+
48+
/**
49+
* Provides a lits of operations on {@link PrimitiveType}s, such as arithmetic, logical,
50+
* and cast operations.
51+
*/
52+
public static final List<Expression> PRIMITIVE_OPERATIONS = generatePrimitiveOperations();
53+
54+
private static List<Expression> generatePrimitiveOperations() {
55+
List<Expression> ops = new ArrayList<>();
56+
57+
Expression.Info withArithmeticException = new Expression.Info().withExceptions(Set.of("ArithmeticException"));
58+
Expression.Info withNondeterministicResult = new Expression.Info().withNondeterministicResult();
59+
60+
// Cast between all primitive types. Except for Boolean, we cannot cast from and to.
61+
CodeGenerationDataNameType.INTEGRAL_AND_FLOATING_TYPES.stream().forEach(src -> {
62+
CodeGenerationDataNameType.INTEGRAL_AND_FLOATING_TYPES.stream().forEach(dst -> {
63+
ops.add(Expression.make(dst, "(" + dst.name() + ")(", src, ")"));
64+
});
65+
});
66+
67+
// Ternary operator.
68+
CodeGenerationDataNameType.INTEGRAL_AND_FLOATING_TYPES.stream().forEach(type -> {
69+
ops.add(Expression.make(type, "(", BOOLEANS, "?", type, ":", type, ")"));
70+
});
71+
72+
List.of(INTS, LONGS).stream().forEach(type -> {
73+
// Arithmetic operators
74+
ops.add(Expression.make(type, "(-(", type, "))"));
75+
ops.add(Expression.make(type, "(", type, " + ", type, ")"));
76+
ops.add(Expression.make(type, "(", type, " - ", type, ")"));
77+
ops.add(Expression.make(type, "(", type, " * ", type, ")"));
78+
ops.add(Expression.make(type, "(", type, " / ", type, ")", withArithmeticException));
79+
ops.add(Expression.make(type, "(", type, " % ", type, ")", withArithmeticException));
80+
81+
// Bitwise Operators (non short-circuit)
82+
ops.add(Expression.make(type, "(~(", type, "))"));
83+
ops.add(Expression.make(type, "(", type, " & ", type, ")"));
84+
ops.add(Expression.make(type, "(", type, " | ", type, ")"));
85+
ops.add(Expression.make(type, "(", type, " ^ ", type, ")"));
86+
ops.add(Expression.make(type, "(", type, " << ", type, ")"));
87+
ops.add(Expression.make(type, "(", type, " >> ", type, ")"));
88+
ops.add(Expression.make(type, "(", type, " >>> ", type, ")"));
89+
90+
// Relational / Comparison Operators
91+
ops.add(Expression.make(BOOLEANS, "(", type, " == ", type, ")"));
92+
ops.add(Expression.make(BOOLEANS, "(", type, " != ", type, ")"));
93+
ops.add(Expression.make(BOOLEANS, "(", type, " > ", type, ")"));
94+
ops.add(Expression.make(BOOLEANS, "(", type, " < ", type, ")"));
95+
ops.add(Expression.make(BOOLEANS, "(", type, " >= ", type, ")"));
96+
ops.add(Expression.make(BOOLEANS, "(", type, " <= ", type, ")"));
97+
});
98+
99+
CodeGenerationDataNameType.FLOATING_TYPES.stream().forEach(type -> {
100+
// Arithmetic operators
101+
ops.add(Expression.make(type, "(-(", type, "))"));
102+
ops.add(Expression.make(type, "(", type, " + ", type, ")"));
103+
ops.add(Expression.make(type, "(", type, " - ", type, ")"));
104+
ops.add(Expression.make(type, "(", type, " * ", type, ")"));
105+
ops.add(Expression.make(type, "(", type, " / ", type, ")"));
106+
ops.add(Expression.make(type, "(", type, " % ", type, ")"));
107+
108+
// Relational / Comparison Operators
109+
ops.add(Expression.make(BOOLEANS, "(", type, " == ", type, ")"));
110+
ops.add(Expression.make(BOOLEANS, "(", type, " != ", type, ")"));
111+
ops.add(Expression.make(BOOLEANS, "(", type, " > ", type, ")"));
112+
ops.add(Expression.make(BOOLEANS, "(", type, " < ", type, ")"));
113+
ops.add(Expression.make(BOOLEANS, "(", type, " >= ", type, ")"));
114+
ops.add(Expression.make(BOOLEANS, "(", type, " <= ", type, ")"));
115+
});
116+
117+
// ------------ byte -------------
118+
// Cast and ternary operator handled above.
119+
// Arithmetic operations are not performed in byte, but rather promoted to int.
120+
121+
// ------------ Byte -------------
122+
ops.add(Expression.make(INTS, "Byte.compare(", BYTES, ", ", BYTES, ")"));
123+
ops.add(Expression.make(INTS, "Byte.compareUnsigned(", BYTES, ", ", BYTES, ")"));
124+
ops.add(Expression.make(INTS, "Byte.toUnsignedInt(", BYTES, ")"));
125+
ops.add(Expression.make(LONGS, "Byte.toUnsignedLong(", BYTES, ")"));
126+
127+
// ------------ char -------------
128+
// Cast and ternary operator handled above.
129+
// Arithmetic operations are not performned in char, but rather promoted to int.
130+
131+
// ------------ Character -------------
132+
ops.add(Expression.make(INTS, "Character.compare(", CHARS, ", ", CHARS, ")"));
133+
ops.add(Expression.make(CHARS, "Character.reverseBytes(", CHARS, ")"));
134+
135+
// ------------ short -------------
136+
// Cast and ternary operator handled above.
137+
// Arithmetic operations are not performned in short, but rather promoted to int.
138+
139+
// ------------ Short -------------
140+
ops.add(Expression.make(INTS, "Short.compare(", SHORTS, ", ", SHORTS, ")"));
141+
ops.add(Expression.make(INTS, "Short.compareUnsigned(", SHORTS, ", ", SHORTS, ")"));
142+
ops.add(Expression.make(SHORTS, "Short.reverseBytes(", SHORTS, ")"));
143+
ops.add(Expression.make(INTS, "Short.toUnsignedInt(", SHORTS, ")"));
144+
ops.add(Expression.make(LONGS, "Short.toUnsignedLong(", SHORTS, ")"));
145+
146+
// ------------ int -------------
147+
// Cast and ternary operator handled above.
148+
// Arithmetic, Bitwise, Relational / Comparison handled above.
149+
150+
// ------------ Integer -------------
151+
ops.add(Expression.make(INTS, "Integer.bitCount(", INTS, ")"));
152+
ops.add(Expression.make(INTS, "Integer.compare(", INTS, ", ", INTS, ")"));
153+
ops.add(Expression.make(INTS, "Integer.compareUnsigned(", INTS, ", ", INTS, ")"));
154+
ops.add(Expression.make(INTS, "Integer.compress(", INTS, ", ", INTS, ")"));
155+
ops.add(Expression.make(INTS, "Integer.divideUnsigned(", INTS, ", ", INTS, ")", withArithmeticException));
156+
ops.add(Expression.make(INTS, "Integer.expand(", INTS, ", ", INTS, ")"));
157+
ops.add(Expression.make(INTS, "Integer.highestOneBit(", INTS, ")"));
158+
ops.add(Expression.make(INTS, "Integer.lowestOneBit(", INTS, ")"));
159+
ops.add(Expression.make(INTS, "Integer.max(", INTS, ", ", INTS, ")"));
160+
ops.add(Expression.make(INTS, "Integer.min(", INTS, ", ", INTS, ")"));
161+
ops.add(Expression.make(INTS, "Integer.numberOfLeadingZeros(", INTS, ")"));
162+
ops.add(Expression.make(INTS, "Integer.numberOfTrailingZeros(", INTS, ")"));
163+
ops.add(Expression.make(INTS, "Integer.remainderUnsigned(", INTS, ", ", INTS, ")", withArithmeticException));
164+
ops.add(Expression.make(INTS, "Integer.reverse(", INTS, ")"));
165+
ops.add(Expression.make(INTS, "Integer.reverseBytes(", INTS, ")"));
166+
ops.add(Expression.make(INTS, "Integer.rotateLeft(", INTS, ", ", INTS, ")"));
167+
ops.add(Expression.make(INTS, "Integer.rotateRight(", INTS, ", ", INTS, ")"));
168+
ops.add(Expression.make(INTS, "Integer.signum(", INTS, ")"));
169+
ops.add(Expression.make(INTS, "Integer.sum(", INTS, ", ", INTS, ")"));
170+
ops.add(Expression.make(LONGS, "Integer.toUnsignedLong(", INTS, ")"));
171+
172+
// ------------ long -------------
173+
// Cast and ternary operator handled above.
174+
// Arithmetic, Bitwise, Relational / Comparison handled above.
175+
176+
// ------------ Long -------------
177+
ops.add(Expression.make(INTS, "Long.bitCount(", LONGS, ")"));
178+
ops.add(Expression.make(INTS, "Long.compare(", LONGS, ", ", LONGS, ")"));
179+
ops.add(Expression.make(INTS, "Long.compareUnsigned(", LONGS, ", ", LONGS, ")"));
180+
ops.add(Expression.make(LONGS, "Long.compress(", LONGS, ", ", LONGS, ")"));
181+
ops.add(Expression.make(LONGS, "Long.divideUnsigned(", LONGS, ", ", LONGS, ")", withArithmeticException));
182+
ops.add(Expression.make(LONGS, "Long.expand(", LONGS, ", ", LONGS, ")"));
183+
ops.add(Expression.make(LONGS, "Long.highestOneBit(", LONGS, ")"));
184+
ops.add(Expression.make(LONGS, "Long.lowestOneBit(", LONGS, ")"));
185+
ops.add(Expression.make(LONGS, "Long.max(", LONGS, ", ", LONGS, ")"));
186+
ops.add(Expression.make(LONGS, "Long.min(", LONGS, ", ", LONGS, ")"));
187+
ops.add(Expression.make(INTS, "Long.numberOfLeadingZeros(", LONGS, ")"));
188+
ops.add(Expression.make(INTS, "Long.numberOfTrailingZeros(", LONGS, ")"));
189+
ops.add(Expression.make(LONGS, "Long.remainderUnsigned(", LONGS, ", ", LONGS, ")", withArithmeticException));
190+
ops.add(Expression.make(LONGS, "Long.reverse(", LONGS, ")"));
191+
ops.add(Expression.make(LONGS, "Long.reverseBytes(", LONGS, ")"));
192+
ops.add(Expression.make(LONGS, "Long.rotateLeft(", LONGS, ", ", INTS, ")"));
193+
ops.add(Expression.make(LONGS, "Long.rotateRight(", LONGS, ", ", INTS, ")"));
194+
ops.add(Expression.make(INTS, "Long.signum(", LONGS, ")"));
195+
ops.add(Expression.make(LONGS, "Long.sum(", LONGS, ", ", LONGS, ")"));
196+
197+
// ------------ float -------------
198+
// Cast and ternary operator handled above.
199+
// Arithmetic and Relational / Comparison handled above.
200+
201+
// ------------ Float -------------
202+
ops.add(Expression.make(INTS, "Float.compare(", FLOATS, ", ", FLOATS, ")"));
203+
ops.add(Expression.make(INTS, "Float.floatToIntBits(", FLOATS, ")"));
204+
ops.add(Expression.make(INTS, "Float.floatToRawIntBits(", FLOATS, ")", withNondeterministicResult));
205+
// Note: there are multiple NaN values with different bit representations.
206+
ops.add(Expression.make(FLOATS, "Float.float16ToFloat(", SHORTS, ")"));
207+
ops.add(Expression.make(FLOATS, "Float.intBitsToFloat(", INTS, ")"));
208+
ops.add(Expression.make(BOOLEANS, "Float.isFinite(", FLOATS, ")"));
209+
ops.add(Expression.make(BOOLEANS, "Float.isInfinite(", FLOATS, ")"));
210+
ops.add(Expression.make(BOOLEANS, "Float.isNaN(", FLOATS, ")"));
211+
ops.add(Expression.make(FLOATS, "Float.max(", FLOATS, ", ", FLOATS, ")"));
212+
ops.add(Expression.make(FLOATS, "Float.min(", FLOATS, ", ", FLOATS, ")"));
213+
ops.add(Expression.make(FLOATS, "Float.sum(", FLOATS, ", ", FLOATS, ")"));
214+
215+
// ------------ double -------------
216+
// Cast and ternary operator handled above.
217+
// Arithmetic and Relational / Comparison handled above.
218+
219+
// ------------ Double -------------
220+
ops.add(Expression.make(INTS, "Double.compare(", DOUBLES, ", ", DOUBLES, ")"));
221+
ops.add(Expression.make(LONGS, "Double.doubleToLongBits(", DOUBLES, ")"));
222+
// Note: there are multiple NaN values with different bit representations.
223+
ops.add(Expression.make(LONGS, "Double.doubleToRawLongBits(", DOUBLES, ")", withNondeterministicResult));
224+
ops.add(Expression.make(DOUBLES, "Double.longBitsToDouble(", LONGS, ")"));
225+
ops.add(Expression.make(BOOLEANS, "Double.isFinite(", DOUBLES, ")"));
226+
ops.add(Expression.make(BOOLEANS, "Double.isInfinite(", DOUBLES, ")"));
227+
ops.add(Expression.make(BOOLEANS, "Double.isNaN(", DOUBLES, ")"));
228+
ops.add(Expression.make(DOUBLES, "Double.max(", DOUBLES, ", ", DOUBLES, ")"));
229+
ops.add(Expression.make(DOUBLES, "Double.min(", DOUBLES, ", ", DOUBLES, ")"));
230+
ops.add(Expression.make(DOUBLES, "Double.sum(", DOUBLES, ", ", DOUBLES, ")"));
231+
232+
// ------------ boolean -------------
233+
// Cast and ternary operator handled above.
234+
// There are no boolean arithmetic operators
235+
236+
// Logical operators
237+
ops.add(Expression.make(BOOLEANS, "(!(", BOOLEANS, "))"));
238+
ops.add(Expression.make(BOOLEANS, "(", BOOLEANS, " || ", BOOLEANS, ")"));
239+
ops.add(Expression.make(BOOLEANS, "(", BOOLEANS, " && ", BOOLEANS, ")"));
240+
ops.add(Expression.make(BOOLEANS, "(", BOOLEANS, " ^ ", BOOLEANS, ")"));
241+
242+
// ------------ Boolean -------------
243+
ops.add(Expression.make(INTS, "Boolean.compare(", BOOLEANS, ", ", BOOLEANS, ")"));
244+
ops.add(Expression.make(BOOLEANS, "Boolean.logicalAnd(", BOOLEANS, ", ", BOOLEANS, ")"));
245+
ops.add(Expression.make(BOOLEANS, "Boolean.logicalOr(", BOOLEANS, ", ", BOOLEANS, ")"));
246+
ops.add(Expression.make(BOOLEANS, "Boolean.logicalXor(", BOOLEANS, ", ", BOOLEANS, ")"));
247+
248+
// TODO: Math and other classes.
249+
250+
// Make sure the list is not modifiable.
251+
return List.copyOf(ops);
252+
}
253+
}

test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
import compiler.lib.generators.RestrictableGenerator;
3232

3333
import compiler.lib.template_framework.DataName;
34+
import compiler.lib.template_framework.Template;
35+
import compiler.lib.template_framework.TemplateToken;
36+
import static compiler.lib.template_framework.Template.body;
3437

3538
/**
3639
* The {@link PrimitiveType} models Java's primitive types, and provides a set
@@ -148,4 +151,91 @@ public boolean isFloating() {
148151
case FLOAT, DOUBLE -> true;
149152
};
150153
}
154+
155+
/**
156+
* Calls the corresponding pseudo random number generator from
157+
* {@link #generateLibraryRNG}, for the given type. Accordingly,
158+
* one must generate {@link #generateLibraryRNG} into the same
159+
* test if one wants to use this method.
160+
*
161+
* Note: if you simply need a compile time constant, then please
162+
* use {@link #con} instead.
163+
*
164+
* @return the token representing the method call to obtain a
165+
* random value for the given type at runtime.
166+
*/
167+
public Object callLibraryRNG() {
168+
return switch (kind) {
169+
case BYTE -> "LibraryRNG.nextByte()";
170+
case SHORT -> "LibraryRNG.nextShort()";
171+
case CHAR -> "LibraryRNG.nextChar()";
172+
case INT -> "LibraryRNG.nextInt()";
173+
case LONG -> "LibraryRNG.nextLong()";
174+
case FLOAT -> "LibraryRNG.nextFloat()";
175+
case DOUBLE -> "LibraryRNG.nextDouble()";
176+
case BOOLEAN -> "LibraryRNG.nextBoolean()";
177+
};
178+
}
179+
180+
/**
181+
* Generates the {@code LibraryRNG} class, which makes a set of pseudo
182+
* random number generators available, wrapping {@link Generators}. This
183+
* is supposed to be used in tandem with {@link #callLibraryRNG}.
184+
*
185+
* Note: you must ensure that all required imports are performed:
186+
* {@code java.util.Random}
187+
* {@code jdk.test.lib.Utils}
188+
* {@code compiler.lib.generators.*}
189+
*
190+
* @return a TemplateToken that holds all the {@code LibraryRNG} class.
191+
*/
192+
public static TemplateToken generateLibraryRNG() {
193+
var template = Template.make(() -> body(
194+
"""
195+
public static class LibraryRNG {
196+
private static final Random RANDOM = Utils.getRandomInstance();
197+
private static final RestrictableGenerator<Integer> GEN_BYTE = Generators.G.safeRestrict(Generators.G.ints(), Byte.MIN_VALUE, Byte.MAX_VALUE);
198+
private static final RestrictableGenerator<Integer> GEN_CHAR = Generators.G.safeRestrict(Generators.G.ints(), Character.MIN_VALUE, Character.MAX_VALUE);
199+
private static final RestrictableGenerator<Integer> GEN_SHORT = Generators.G.safeRestrict(Generators.G.ints(), Short.MIN_VALUE, Short.MAX_VALUE);
200+
private static final RestrictableGenerator<Integer> GEN_INT = Generators.G.ints();
201+
private static final RestrictableGenerator<Long> GEN_LONG = Generators.G.longs();
202+
private static final Generator<Double> GEN_DOUBLE = Generators.G.doubles();
203+
private static final Generator<Float> GEN_FLOAT = Generators.G.floats();
204+
205+
public static byte nextByte() {
206+
return GEN_BYTE.next().byteValue();
207+
}
208+
209+
public static short nextShort() {
210+
return GEN_SHORT.next().shortValue();
211+
}
212+
213+
public static char nextChar() {
214+
return (char)GEN_CHAR.next().intValue();
215+
}
216+
217+
public static int nextInt() {
218+
return GEN_INT.next();
219+
}
220+
221+
public static long nextLong() {
222+
return GEN_LONG.next();
223+
}
224+
225+
public static float nextFloat() {
226+
return GEN_FLOAT.next();
227+
}
228+
229+
public static double nextDouble() {
230+
return GEN_DOUBLE.next();
231+
}
232+
233+
public static boolean nextBoolean() {
234+
return RANDOM.nextBoolean();
235+
}
236+
}
237+
"""
238+
));
239+
return template.asToken();
240+
};
151241
}

0 commit comments

Comments
 (0)