diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java index 33eba66cd8c9a..2ad4b235f388d 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java @@ -33,6 +33,27 @@ * additional functionality for code generation. These types with their extended * functionality can be used with many other code generation facilities in the * library, such as generating random {@code Expression}s. + * + *

This module distinguishes scalar Java types and + * Vector API lane-element types: + *

+ * Vector generators (e.g. {@code Operations.VECTOR_OPERATIONS}) consume the + * vector-lane lists; scalar generators (e.g. + * {@code Operations.PRIMITIVE_OPERATIONS}) consume the scalar lists. */ public interface CodeGenerationDataNameType extends DataName.Type { @@ -101,9 +122,19 @@ public interface CodeGenerationDataNameType extends DataName.Type { static PrimitiveType booleans() { return PrimitiveType.BOOLEANS; } /** - * The Float16 type. + * The {@code Float16Vector} lane-element type. This is a + * {@link VectorElementType}, not a Java + * {@link PrimitiveType}; it appears in vector-lane lists but never in the + * scalar {@code PRIMITIVE_TYPES}/{@code FLOATING_TYPES} lists. * - * @return The Float16 type. + * @return The {@code Float16Vector} {@link VectorElementType}. + */ + static Float16VectorType float16s() { return Float16VectorType.FLOAT16; } + + /** + * The {@code Float16} scalar (logical) type. + * + * @return The scalar {@code Float16} type. */ static CodeGenerationDataNameType float16() { return Float16Type.FLOAT16; } @@ -185,6 +216,75 @@ public interface CodeGenerationDataNameType extends DataName.Type { float16() ); + // -------------------------------------------------------------------- + // Vector API lane-element type lists. + // + // These are typed as List and may include + // Float16VectorType.FLOAT16 in addition to the Java primitive lane + // carriers. They are the source of truth for vector lane iteration in + // vector generators (e.g. Operations.VECTOR_OPS). + // -------------------------------------------------------------------- + + /** + * All Vector API lane-element types: every Java numeric primitive lane + * carrier plus {@link Float16VectorType#FLOAT16}. + */ + List VECTOR_ELEMENT_TYPES = List.of( + bytes(), + shorts(), + float16s(), + ints(), + longs(), + floats(), + doubles() + ); + + /** + * Integral Vector API lane-element types (byte, short, int, long). + */ + List INTEGRAL_VECTOR_ELEMENT_TYPES = List.of( + bytes(), + shorts(), + ints(), + longs() + ); + + /** + * Floating Vector API lane-element types (float16, float, double). + */ + List FLOATING_VECTOR_ELEMENT_TYPES = List.of( + float16s(), + floats(), + doubles() + ); + + /** + * Integral-and-floating Vector API lane-element types: every lane type + * except booleans/chars (which have no Vector API counterparts). + */ + List INTEGRAL_AND_FLOATING_VECTOR_ELEMENT_TYPES = List.of( + bytes(), + shorts(), + float16s(), + ints(), + longs(), + floats(), + doubles() + ); + + /** + * Vector API lane-element types whose lanes are 32/64 bits and integral + * (int, long). + */ + List INT_LONG_VECTOR_ELEMENT_TYPES = List.of( + ints(), + longs() + ); + + // -------------------------------------------------------------------- + // Concrete VectorType lists (typed as the concrete Vector subclasses). + // -------------------------------------------------------------------- + List VECTOR_BYTE_VECTOR_TYPES = List.of( VectorType.BYTE_64, VectorType.BYTE_128, @@ -199,6 +299,13 @@ public interface CodeGenerationDataNameType extends DataName.Type { VectorType.SHORT_512 ); + List VECTOR_FLOAT16_VECTOR_TYPES = List.of( + VectorType.FLOAT16_64, + VectorType.FLOAT16_128, + VectorType.FLOAT16_256, + VectorType.FLOAT16_512 + ); + List VECTOR_INT_VECTOR_TYPES = List.of( VectorType.INT_64, VectorType.INT_128, @@ -230,6 +337,7 @@ public interface CodeGenerationDataNameType extends DataName.Type { List VECTOR_VECTOR_TYPES = Utils.concat( VECTOR_BYTE_VECTOR_TYPES, VECTOR_SHORT_VECTOR_TYPES, + VECTOR_FLOAT16_VECTOR_TYPES, VECTOR_INT_VECTOR_TYPES, VECTOR_LONG_VECTOR_TYPES, VECTOR_FLOAT_VECTOR_TYPES, diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/Float16VectorType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/Float16VectorType.java new file mode 100644 index 0000000000000..900f8432ebaee --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/Float16VectorType.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.template_framework.library; + +import compiler.lib.generators.Generators; +import compiler.lib.generators.Generator; + +import compiler.lib.template_framework.DataName; + +/** + * The {@link Float16VectorType} is the {@link VectorElementType} that describes + * the lane type of a {@code Float16Vector}. + * + *

Float16 is not a Java primitive type and therefore does + * not appear in any of the scalar {@link PrimitiveType} lists. As a + * {@link VectorElementType} it appears in vector-lane-typed lists such as + * {@link CodeGenerationDataNameType#VECTOR_ELEMENT_TYPES} and + * {@link CodeGenerationDataNameType#FLOATING_VECTOR_ELEMENT_TYPES}, which are + * consumed by vector-only generators (e.g. {@code Operations.VECTOR_OPERATIONS}). + * + *

The carrier type for a {@code Float16Vector} lane is {@code short}; the + * element type token used in {@code VectorOperators.Conversion.of*} expressions + * and {@code Float16Vector.SPECIES_*} is {@code Float16}. + * + *

NaN handling note: there are multiple bit representations for NaN within + * {@code short}/{@code Float16}. Consumers comparing {@code short[]} carrier + * arrays should canonicalize via {@code Float.float16ToFloat} (which returns a + * canonical NaN) before structural comparison. + */ +public final class Float16VectorType implements VectorElementType { + private static final Generator GEN_FLOAT16 = Generators.G.float16s(); + + /** The singleton instance. */ + public static final Float16VectorType FLOAT16 = new Float16VectorType(); + + private Float16VectorType() {} + + @Override + public boolean isSubtypeOf(DataName.Type other) { + return other instanceof Float16VectorType; + } + + @Override + public String name() { + return "Float16"; + } + + @Override + public String carrierTypeName() { + return "short"; + } + + @Override + public String boxedTypeName() { + return "Float16"; + } + + @Override + public int byteSize() { + return 2; + } + + @Override + public boolean isFloating() { + return true; + } + + @Override + public String toString() { + // Used by Template `let(...)` hashtag substitution as a Java scalar + // type for a single lane. Float16 has no Java keyword, so we return + // the carrier ("short"), which is what Float16Vector.lane(int) returns + // and what Float16Vector.broadcast(SPECIES, ...) accepts. + return carrierTypeName(); + } + + @Override + public Object con() { + return "(short)" + GEN_FLOAT16.next(); + } + + @Override + public Object callLibraryRNG() { + return "LibraryRNG.nextFloat16()"; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java index becda83a02975..29c0d98aacc83 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java @@ -40,6 +40,10 @@ import static compiler.lib.template_framework.library.CodeGenerationDataNameType.INTEGRAL_TYPES; import static compiler.lib.template_framework.library.CodeGenerationDataNameType.FLOATING_TYPES; import static compiler.lib.template_framework.library.CodeGenerationDataNameType.INT_LONG_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.VECTOR_ELEMENT_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.INTEGRAL_VECTOR_ELEMENT_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.FLOATING_VECTOR_ELEMENT_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.INT_LONG_VECTOR_ELEMENT_TYPES; /** * This class provides various lists of {@link Expression}s, that represent Java operators or library @@ -322,8 +326,11 @@ private enum VOPType { INTEGRAL_ASSOCIATIVE, // Binary - but only safe for integral reductions TERNARY } - private record VOP(String name, VOPType type, List elementTypes, boolean isDeterministic) { - VOP(String name, VOPType type, List elementTypes) { + // VOP element type pools are typed as VectorElementType so they can include + // Float16VectorType.FLOAT16 (the Float16Vector lane type) alongside the + // primitive lane types. + private record VOP(String name, VOPType type, List elementTypes, boolean isDeterministic) { + VOP(String name, VOPType type, List elementTypes) { this(name, type, elementTypes, true); } } @@ -333,81 +340,81 @@ private record VOP(String name, VOPType type, List elementTypes, // But if a test is just interested in determinism, they are still // non-deterministic. private static final List VECTOR_OPS = List.of( - new VOP("ABS", VOPType.UNARY, PRIMITIVE_TYPES), - new VOP("ACOS", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("ADD", VOPType.INTEGRAL_ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("AND", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("AND_NOT", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("ASHR", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("ASIN", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("ATAN", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("ATAN2", VOPType.BINARY, FLOATING_TYPES, false), // 2 ulp - new VOP("BIT_COUNT", VOPType.UNARY, INTEGRAL_TYPES), - new VOP("BITWISE_BLEND", VOPType.TERNARY, INTEGRAL_TYPES), - new VOP("CBRT", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("COMPRESS_BITS", VOPType.BINARY, INT_LONG_TYPES), - new VOP("COS", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("COSH", VOPType.UNARY, FLOATING_TYPES, false), // 2.5 ulp - new VOP("DIV", VOPType.BINARY, FLOATING_TYPES), - new VOP("EXP", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("EXPAND_BITS", VOPType.BINARY, INT_LONG_TYPES), - new VOP("EXPM1", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("FIRST_NONZERO", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("FMA", VOPType.TERNARY, FLOATING_TYPES), - new VOP("HYPOT", VOPType.BINARY, FLOATING_TYPES, false), // 1.5 ulp - new VOP("LEADING_ZEROS_COUNT", VOPType.UNARY, INTEGRAL_TYPES), - new VOP("LOG", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("LOG10", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("LOG1P", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("LSHL", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("LSHR", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("MIN", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("MAX", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("MUL", VOPType.INTEGRAL_ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("NEG", VOPType.UNARY, PRIMITIVE_TYPES), - new VOP("NOT", VOPType.UNARY, INTEGRAL_TYPES), - new VOP("OR", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("POW", VOPType.BINARY, FLOATING_TYPES, false), // 1 ulp - new VOP("REVERSE", VOPType.UNARY, INTEGRAL_TYPES), - new VOP("REVERSE_BYTES", VOPType.UNARY, INTEGRAL_TYPES), - new VOP("ROL", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("ROR", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("SADD", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("SIN", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp - new VOP("SINH", VOPType.UNARY, FLOATING_TYPES, false), // 2.5 ulp - new VOP("SQRT", VOPType.UNARY, FLOATING_TYPES), - new VOP("SSUB", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("SUADD", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("SUB", VOPType.BINARY, PRIMITIVE_TYPES), - new VOP("SUSUB", VOPType.BINARY, INTEGRAL_TYPES), - new VOP("TAN", VOPType.UNARY, FLOATING_TYPES, false), // 1.25 ulp - new VOP("TANH", VOPType.UNARY, FLOATING_TYPES, false), // 2.5 ulp - new VOP("TRAILING_ZEROS_COUNT", VOPType.UNARY, INTEGRAL_TYPES), - new VOP("UMAX", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("UMIN", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("XOR", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("ZOMO", VOPType.UNARY, INTEGRAL_TYPES) + new VOP("ABS", VOPType.UNARY, VECTOR_ELEMENT_TYPES), + new VOP("ACOS", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("ADD", VOPType.INTEGRAL_ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("AND", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("AND_NOT", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("ASHR", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("ASIN", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("ATAN", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("ATAN2", VOPType.BINARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 2 ulp + new VOP("BIT_COUNT", VOPType.UNARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("BITWISE_BLEND", VOPType.TERNARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("CBRT", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("COMPRESS_BITS", VOPType.BINARY, INT_LONG_VECTOR_ELEMENT_TYPES), + new VOP("COS", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("COSH", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 2.5 ulp + new VOP("DIV", VOPType.BINARY, FLOATING_VECTOR_ELEMENT_TYPES), + new VOP("EXP", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("EXPAND_BITS", VOPType.BINARY, INT_LONG_VECTOR_ELEMENT_TYPES), + new VOP("EXPM1", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("FIRST_NONZERO", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("FMA", VOPType.TERNARY, FLOATING_VECTOR_ELEMENT_TYPES), + new VOP("HYPOT", VOPType.BINARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1.5 ulp + new VOP("LEADING_ZEROS_COUNT", VOPType.UNARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("LOG", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("LOG10", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("LOG1P", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("LSHL", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("LSHR", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("MIN", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("MAX", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("MUL", VOPType.INTEGRAL_ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("NEG", VOPType.UNARY, VECTOR_ELEMENT_TYPES), + new VOP("NOT", VOPType.UNARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("OR", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("POW", VOPType.BINARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("REVERSE", VOPType.UNARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("REVERSE_BYTES", VOPType.UNARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("ROL", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("ROR", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("SADD", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("SIN", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1 ulp + new VOP("SINH", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 2.5 ulp + new VOP("SQRT", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES), + new VOP("SSUB", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("SUADD", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("SUB", VOPType.BINARY, VECTOR_ELEMENT_TYPES), + new VOP("SUSUB", VOPType.BINARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("TAN", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 1.25 ulp + new VOP("TANH", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES, false), // 2.5 ulp + new VOP("TRAILING_ZEROS_COUNT", VOPType.UNARY, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("UMAX", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("UMIN", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("XOR", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("ZOMO", VOPType.UNARY, INTEGRAL_VECTOR_ELEMENT_TYPES) ); private static final List VECTOR_CMP = List.of( - new VOP("EQ", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("GE", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("GT", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("LE", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("LT", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("NE", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), - new VOP("UGE", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("UGT", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("ULE", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), - new VOP("ULT", VOPType.ASSOCIATIVE, INTEGRAL_TYPES) + new VOP("EQ", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("GE", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("GT", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("LE", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("LT", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("NE", VOPType.ASSOCIATIVE, VECTOR_ELEMENT_TYPES), + new VOP("UGE", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("UGT", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("ULE", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES), + new VOP("ULT", VOPType.ASSOCIATIVE, INTEGRAL_VECTOR_ELEMENT_TYPES) ); private static final List VECTOR_TEST = List.of( - new VOP("IS_DEFAULT", VOPType.UNARY, PRIMITIVE_TYPES), - new VOP("IS_NEGATIVE", VOPType.UNARY, PRIMITIVE_TYPES), - new VOP("IS_FINITE", VOPType.UNARY, FLOATING_TYPES), - new VOP("IS_NAN", VOPType.UNARY, FLOATING_TYPES), - new VOP("IS_INFINITE", VOPType.UNARY, FLOATING_TYPES) + new VOP("IS_DEFAULT", VOPType.UNARY, VECTOR_ELEMENT_TYPES), + new VOP("IS_NEGATIVE", VOPType.UNARY, VECTOR_ELEMENT_TYPES), + new VOP("IS_FINITE", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES), + new VOP("IS_NAN", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES), + new VOP("IS_INFINITE", VOPType.UNARY, FLOATING_VECTOR_ELEMENT_TYPES) ); // TODO: Conversion VectorOperators -> convertShape @@ -519,6 +526,9 @@ private static List generateVectorOperations() { if (type.elementType == FLOATS) { ops.add(Expression.make(type, "", type2, ".reinterpretAsFloats()", reinterpretInfo)); } + if (type.elementType instanceof Float16VectorType) { + ops.add(Expression.make(type, "", type2, ".reinterpretAsFloat16s()", reinterpretInfo)); + } if (type.elementType == DOUBLES) { ops.add(Expression.make(type, "", type2, ".reinterpretAsDoubles()", reinterpretInfo)); } @@ -834,8 +844,18 @@ private static List ternaryOps(Operations.VOP vop, VectorType.Vector FLOAT16_OPERATIONS ); + /** + * Provides a list of Vector API operations. Iterates over all + * {@link CodeGenerationDataNameType#VECTOR_VECTOR_TYPES}, including + * {@code Float16Vector_*}, whose lanes are described by + * {@link Float16VectorType#FLOAT16}. + */ public static final List VECTOR_OPERATIONS = generateVectorOperations(); + /** + * Provides a list of all operations: every scalar operation and every + * Vector API operation. + */ public static final List ALL_OPERATIONS = Utils.concat( SCALAR_NUMERIC_OPERATIONS, VECTOR_OPERATIONS diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java index cd796fd0d3144..ddce36ddfa04c 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java @@ -40,8 +40,19 @@ * The {@link PrimitiveType} models Java's primitive types, and provides a set * of useful methods for code generation, such as the {@link #byteSize} and * {@link #boxedTypeName}. + * + *

{@link PrimitiveType} is a Java scalar type and additionally + * doubles as a {@link VectorElementType} for those Vector API lane types whose + * lane carrier is itself a Java primitive (e.g. {@code IntVector}'s lane + * carrier is {@code int}). For these primitive lane types + * {@link #carrierTypeName} coincides with {@link #name}. + * + *

Non-primitive lane types, such as the {@code Float16Vector} lane, are + * modeled by separate {@link VectorElementType} implementations (see + * {@link Float16VectorType}). They do not appear in any of + * the scalar {@code PRIMITIVE_TYPES}/{@code FLOATING_TYPES} lists. */ -public final class PrimitiveType implements CodeGenerationDataNameType { +public final class PrimitiveType implements VectorElementType { private static final Random RANDOM = Utils.getRandomInstance(); private static final RestrictableGenerator GEN_BYTE = Generators.G.safeRestrict(Generators.G.ints(), Byte.MIN_VALUE, Byte.MAX_VALUE); private static final RestrictableGenerator GEN_CHAR = Generators.G.safeRestrict(Generators.G.ints(), Character.MIN_VALUE, Character.MAX_VALUE); @@ -107,6 +118,11 @@ public String name() { }; } + @Override + public String carrierTypeName() { + return name(); + } + @Override public String toString() { return name(); @@ -132,6 +148,7 @@ public Object con() { * @return Size of the type in bytes. * @throws UnsupportedOperationException for boolean which has no defined size. */ + @Override public int byteSize() { return switch (kind) { case BYTE -> 1; @@ -147,6 +164,7 @@ public int byteSize() { * * @return the name of the boxed type. */ + @Override public String boxedTypeName() { return switch (kind) { case BYTE -> "Byte"; @@ -194,6 +212,7 @@ public String abbrev() { * * @return true iff the type is a floating point type. */ + @Override public boolean isFloating() { return switch (kind) { case BYTE, SHORT, CHAR, INT, LONG, BOOLEAN -> false; @@ -213,6 +232,7 @@ public boolean isFloating() { * @return the token representing the method call to obtain a * random value for the given type at runtime. */ + @Override public Object callLibraryRNG() { return switch (kind) { case BYTE -> "LibraryRNG.nextByte()"; @@ -231,6 +251,12 @@ public Object callLibraryRNG() { * random number generators available, wrapping {@link Generators}. This * is supposed to be used in tandem with {@link #callLibraryRNG}. * + *

In addition to the Java primitive generators, this also emits + * helpers for {@code Float16Vector}'s {@code short} carrier + * ({@code nextFloat16()} / {@code fill_float16(short[])}) so that + * {@link Float16VectorType#callLibraryRNG()} can be used with vector + * fuzzers without depending on this class importing Float16Vector itself. + * * Note: you must ensure that all required imports are performed: * {@code java.util.Random} * {@code jdk.test.lib.Utils} @@ -250,6 +276,7 @@ public static class LibraryRNG { private static final RestrictableGenerator GEN_LONG = Generators.G.longs(); private static final Generator GEN_DOUBLE = Generators.G.doubles(); private static final Generator GEN_FLOAT = Generators.G.floats(); + private static final Generator GEN_FLOAT16 = Generators.G.float16s(); public static byte nextByte() { return GEN_BYTE.next().byteValue(); @@ -283,6 +310,17 @@ public static boolean nextBoolean() { return RANDOM.nextBoolean(); } + // Float16Vector lane helpers. Float16 lanes are carried in short[]. + public static short nextFloat16() { + return GEN_FLOAT16.next(); + } + + public static void fill_float16(short[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = nextFloat16(); + } + } + """, CodeGenerationDataNameType.PRIMITIVE_TYPES.stream().map(type -> scope( let("type", type), diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorElementType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorElementType.java new file mode 100644 index 0000000000000..289d68e5d1cc9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorElementType.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.template_framework.library; + +/** + * A {@link VectorElementType} describes a single lane-element of a Vector API + * vector ({@link VectorType.Vector}). It abstracts over: + *

    + *
  • {@link PrimitiveType} - the standard Java primitive lane types + * (byte, short, int, long, float, double, and char/boolean where + * applicable). For these {@link #name()} is the primitive keyword + * (e.g. {@code "int"}) and {@code name() + ".class"} yields the + * primitive {@code Class} literal ({@code int.class}).
  • + *
  • {@link Float16VectorType} - the {@code Float16Vector} lane type. Float16 + * has no Java primitive keyword; its lanes are stored in a {@code short[]} + * carrier and {@link #name()} returns {@code "Float16"} so that + * {@code name() + ".class"} ({@code Float16.class}) is the token expected + * by {@code VectorOperators.Conversion.ofCast}/{@code ofReinterpret}.
  • + *
+ * + *

This interface intentionally lives outside the scalar + * {@link PrimitiveType} type lists (e.g. {@code PRIMITIVE_TYPES}, + * {@code FLOATING_TYPES}). Those lists model Java scalar types and are consumed + * by scalar fuzzers. Vector-lane lists (e.g. {@code VECTOR_ELEMENT_TYPES}, + * {@code FLOATING_VECTOR_ELEMENT_TYPES}) are typed as {@code List} + * and may include {@link Float16VectorType#FLOAT16}. + */ +public interface VectorElementType extends CodeGenerationDataNameType { + + /** + * @return The element type of the Java carrier array used to hold these + * lanes when calling {@code fromArray}/{@code intoArray}. For most + * lane types this is the same as {@link #name()}; for + * {@code Float16} it is {@code "short"}. + */ + String carrierTypeName(); + + /** + * @return The boxed type name used to parameterize generic types such as + * {@code VectorMask} and {@code VectorShuffle} + * (e.g. {@code "Integer"}, {@code "Float16"}). + */ + String boxedTypeName(); + + /** + * @return Size of the lane type in bytes. + */ + int byteSize(); + + /** + * @return {@code true} iff the lane type is a floating point type. + */ + boolean isFloating(); + + /** + * @return A token representing a call to the corresponding pseudo random + * number generator from {@link PrimitiveType#generateLibraryRNG()}. + */ + Object callLibraryRNG(); +} diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java index 7eabd42a723f0..710186df8c5c9 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java @@ -39,6 +39,11 @@ /** * The {@link VectorType} models the Vector API types. + * + *

A {@code VectorType.Vector} is parameterized by a {@link VectorElementType} + * (its lane element type) and a lane count. The lane element type may be a + * Java primitive lane ({@link PrimitiveType}) or {@link Float16VectorType} for + * {@code Float16Vector}. */ public abstract class VectorType implements CodeGenerationDataNameType { private static final Random RANDOM = Utils.getRandomInstance(); @@ -73,6 +78,11 @@ public abstract class VectorType implements CodeGenerationDataNameType { public static final VectorType.Vector DOUBLE_256 = new VectorType.Vector(DOUBLES, 4); public static final VectorType.Vector DOUBLE_512 = new VectorType.Vector(DOUBLES, 8); + public static final VectorType.Vector FLOAT16_64 = new VectorType.Vector(Float16VectorType.FLOAT16, 4); + public static final VectorType.Vector FLOAT16_128 = new VectorType.Vector(Float16VectorType.FLOAT16, 8); + public static final VectorType.Vector FLOAT16_256 = new VectorType.Vector(Float16VectorType.FLOAT16, 16); + public static final VectorType.Vector FLOAT16_512 = new VectorType.Vector(Float16VectorType.FLOAT16, 32); + private final String vectorTypeName; private VectorType(String vectorTypeName) { @@ -95,7 +105,7 @@ public boolean isSubtypeOf(DataName.Type other) { return this == other; } - private static final String vectorTypeName(PrimitiveType elementType) { + private static final String vectorTypeName(VectorElementType elementType) { return switch(elementType.name()) { case "byte" -> "ByteVector"; case "short" -> "ShortVector"; @@ -104,19 +114,20 @@ private static final String vectorTypeName(PrimitiveType elementType) { case "long" -> "LongVector"; case "float" -> "FloatVector"; case "double" -> "DoubleVector"; + case "Float16" -> "Float16Vector"; default -> throw new UnsupportedOperationException("Not supported: " + elementType.name()); }; } public static final class Vector extends VectorType { - public final PrimitiveType elementType; + public final VectorElementType elementType; public final int length; // lane count public final String speciesName; public final Mask maskType; public final Shuffle shuffleType; - private Vector(PrimitiveType elementType, int length) { + private Vector(VectorElementType elementType, int length) { super(vectorTypeName(elementType)); this.elementType = elementType; this.length = length; @@ -132,7 +143,7 @@ public final Object con() { return List.of(name(), ".zero(", speciesName, ")"); } else if (r <= 8) { return List.of( - name(), ".fromArray(", speciesName, ", new ", elementType.name(), "[] {", + name(), ".fromArray(", speciesName, ", new ", elementType.carrierTypeName(), "[] {", elementType.con(), Stream.generate(() -> List.of(", ", elementType.con()) diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java b/test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java index cb5b95109f572..f34fef80209d9 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java @@ -66,6 +66,8 @@ import compiler.lib.template_framework.library.Operations; import compiler.lib.template_framework.library.TestFrameworkClass; import compiler.lib.template_framework.library.PrimitiveType; +import compiler.lib.template_framework.library.Float16VectorType; +import compiler.lib.template_framework.library.VectorElementType; import compiler.lib.template_framework.library.VectorType; /** @@ -162,23 +164,38 @@ public static String generate(CompileFramework comp) { // - We check correctness with a reference method that does the same but runs in the interpreter. // - Input values are delivered via fields or array loads. // - The final vector is written into an array, and that array is returned. - var template2Body = Template.make("expression", "arguments", (Expression expression, List arguments) -> scope( - let("elementType", ((VectorType.Vector)expression.returnType).elementType), - """ - try { - #elementType[] out = new #elementType[1000]; - """, - expression.asToken(arguments), ".intoArray(out, 0);\n", - "return out;\n", - expression.info.exceptions.stream().map(exception -> - "} catch (" + exception + " e) { return e;\n" - ).toList(), - """ - } finally { - // Just javac is happy if there are no exceptions to catch. - } - """ - )); + // + // NaN canonicalization (Float16Vector only): the {@code short} carrier of Float16Vector lanes + // distinguishes multiple NaN bit patterns, so a structural comparison between two distinct NaN + // bit patterns would spuriously fail. We widen the {@code short[]} carrier to {@code float[]} + // via {@link Float#float16ToFloat}, which returns a canonical NaN for any NaN input. + var template2Body = Template.make("expression", "arguments", (Expression expression, List arguments) -> { + VectorType.Vector retType = (VectorType.Vector) expression.returnType; + boolean float16Result = retType.elementType instanceof Float16VectorType; + return scope( + let("carrierType", retType.elementType.carrierTypeName()), + """ + try { + #carrierType[] out = new #carrierType[1000]; + """, + expression.asToken(arguments), ".intoArray(out, 0);\n", + float16Result + ? List.of( + "// Float16Vector NaN canonicalization: widen short carrier to float for compare.\n", + "float[] outF = new float[out.length];\n", + "for (int i = 0; i < out.length; i++) { outF[i] = Float.float16ToFloat(out[i]); }\n", + "return outF;\n") + : "return out;\n", + expression.info.exceptions.stream().map(exception -> + "} catch (" + exception + " e) { return e;\n" + ).toList(), + """ + } finally { + // Just javac is happy if there are no exceptions to catch. + } + """ + ); + }); var template2 = Template.make("type", (VectorType.Vector type) -> { // The depth determines roughly how many operations are going to be used in the expression. @@ -202,32 +219,36 @@ public static String generate(CompileFramework comp) { } case 1 -> { // Create the constant outside, and pass it. + String typeName = (argumentType instanceof VectorElementType vet) + ? vet.carrierTypeName() + : argumentType.name(); arguments.add(new TestArgument( - List.of(argumentType.name(), " ", name, " = ", argumentType.con(), ";\n"), + List.of(typeName, " ", name, " = ", argumentType.con(), ";\n"), name, - List.of(argumentType.name(), " ", name), + List.of(typeName, " ", name), name )); } default -> { - if (argumentType instanceof PrimitiveType t) { + if (argumentType instanceof VectorElementType vet) { // We can use the LibraryRGN to create a new value for the primitive in each // invocation. We have to make sure to call the LibraryRNG in the "defineAndFill", // so we get the same value for both test and reference. If we called LibraryRNG // for "use", we would get separate values, which is not helpful. arguments.add(new TestArgument( - List.of(t.name(), " ", name, " = ", t.callLibraryRNG(), ";\n"), + List.of(vet.carrierTypeName(), " ", name, " = ", vet.callLibraryRNG(), ";\n"), name, - List.of(t.name(), " ", name), + List.of(vet.carrierTypeName(), " ", name), name )); } else if (argumentType instanceof VectorType.Vector t) { - PrimitiveType et = t.elementType; + VectorElementType et = t.elementType; + String fillMethod = (et instanceof Float16VectorType) ? "fill_float16" : "fill"; arguments.add(new TestArgument( - List.of(et.name(), "[] ", name, " = new ", et.name(), "[1000];\n", - "LibraryRNG.fill(", name,");\n"), + List.of(et.carrierTypeName(), "[] ", name, " = new ", et.carrierTypeName(), "[1000];\n", + "LibraryRNG.", fillMethod, "(", name,");\n"), name, - List.of(et.name(), "[] ", name), + List.of(et.carrierTypeName(), "[] ", name), List.of(t.name(), ".fromArray(", t.speciesName, ", ", name, ", 0)") )); } else if (argumentType instanceof VectorType.Mask t) {