< prev index next >

src/jdk.incubator.vector/share/classes/jdk/incubator/vector/package-info.java

Print this page
rev 55595 : package-info added

*** 22,31 **** * or visit www.oracle.com if you need additional information or have any * questions. */ /** - * <h2>API for expressing Single Instruction Multiple Data computations</h2> * {@Incubating} * */ package jdk.incubator.vector; --- 22,301 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ /** * {@Incubating} + * <p> + * Classes to express vector computations that, given suitable hardware + * and runtime ability, are accelerated using vector hardware instructions. + * <p> + * Vector computations consist of a sequence of operations on vectors. + * A vector is a fixed sequence of scalar values; a scalar value is + * a single unit of value such as an int, a long, a float and so on. + * Operations on vectors typically perform the equivalent scalar operation on all + * scalar values of the participating vectors, usually generating a vector result. + * When run on a supporting platform, these operations can be + * executed in parallel by the hardware. + * This style of parallelism is called <em>Single Instruction Multiple Data</em> (SIMD) + * parallelism. * + * <p>The abstract class {@link jdk.incubator.vector.Vector} represents an ordered immutable sequence of + * values of the same element type 'e' that is one of the following primitive types - + * byte, short, int, long, float, or double. The type variable E corresponds to the + * boxed element type, specifically the class that wraps a value of e in an object + * (such as Integer class that wraps a value of int). + * + * <p>Vector declares a set of vector operations (methods) that are common to + * all element types (such as addition). Subclasses of Vector corresponding to + * a specific element type declare further operations that are specific to that element type + * (such as access to element values in lanes, logical operations on values of integral + * elements types, or transcendental operations on values of floating point element + * types). There are six abstract subclasses of {@link jdk.incubator.vector.Vector} corresponding to the supported set of + * element types: {@link jdk.incubator.vector.ByteVector}, {@link jdk.incubator.vector.ShortVector}, + * {@link jdk.incubator.vector.IntVector}, {@link jdk.incubator.vector.LongVector}, + * {@link jdk.incubator.vector.FloatVector}, and {@link jdk.incubator.vector.DoubleVector}. + * + * In addition to element type, vectors are parameterized by their <em>shape</em>, + * which is their length. The supported shapes are + * represented by the enum {@link jdk.incubator.vector.Vector.Shape}. + * The combination of element type and shape determines a <em>vector species</em>, + * represented by {@link jdk.incubator.vector.Vector.Species}. The various typed + * vector classes expose static constants corresponding to the supported species, + * and static methods on these types generally take a species as a parameter. + * For example, + * {@link jdk.incubator.vector.FloatVector#fromArray(Species<Float>, float[], int) FloatVector.fromArray()} + * creates and returns a float vector of the specified species, with elements + * loaded from the specified float array. + * + * <p> + * The species instance for a specific combination of element type and shape + * can be obtained by reading the appropriate static field, as follows: + * <p> + * {@code Vector.Species<Float> s = FloatVector.SPECIES_256; + * <p> + * + * Code that is agnostic to species can request the "preferred" species for a + * given element type, where the optimal size is selected for the current platform: + * <p> + * {@code Vector.Species<Float> s = FloatVector.SPECIES_PREFERRED; + * <p> + * + * <p> + * Here is an example of multiplying elements of two float arrays {@code a and b} using vector computation + * and storing result in array {@code c}. + * <pre>{@code + * static final Vector.Species<Float> SPECIES = FloatVector.SPECIES_512; + * + * void vectorMultiply(float[] a, float[] b, float[] c) { + * int i = 0; + * // It is assumed array arguments are of the same size + * for (; i < (a.length & ~(SPECIES.length() - 1)); + * i += SPECIES.length()) { + * FloatVector va = FloatVector.fromArray(SPECIES, a, i); + * FloatVector vb = FloatVector.fromArray(SPECIES, b, i); + * FloatVector vc = va.mul(vb) + * vc.intoArray(c, i); + * } + * + * for (; i < a.length; i++) { + * c[i] = a[i] * b[i]; + * } + * } + * }</pre> + * + * The scalar computation after the vector computation is required to process the tail of + * elements, the length of which is smaller than the species length. + * + * The example above uses vectors hardcoded to a concrete shape (512-bit). Instead, we could use preferred + * species as shown below, to make the code dynamically adapt to optimal shape for the platform on which it runs. + * + * <pre>{@code + * static final Vector.Species<Float> SPECIES = FloatVector.SPECIES_PREFERRED; + * }</pre> + * + * <h2>Vector operations</h2> + * We use the term <em>lanes</em> when defining operations on vectors. The number of lanes + * in a vector is the number of scalar elements it holds. For example, a vector of + * type {@code Float} and shape {@code Shape.S_256_BIT} has eight lanes. + * Vector operations can be grouped into various categories and their behavior + * generally specified as follows: + * <ul> + * <li> + * A vector unary operation operates on one input vector to produce a + * result vector. + * For each lane of the input vector the + * lane element is operated on using the specified scalar unary operation and + * the element result is placed into the vector result at the same lane. + * The following pseudocode expresses the behavior of this operation category, + * where {@code e} is the element type and {@code EVector} corresponds to the + * primitive Vector type: + * + * <pre>{@code + * EVector a = ...; + * e[] ar = new e[a.length()]; + * for (int i = 0; i < a.length(); i++) { + * ar[i] = scalar_unary_op(a.get(i)); + * } + * EVector r = EVector.fromArray(a.species(), ar, 0); + * }</pre> + * + * Unless otherwise specified the input and result vectors will have the same + * element type and shape. + * + * <li> + * A vector binary operation operates on two input + * vectors to produce a result vector. + * For each lane of the two input vectors, + * a and b say, the corresponding lane elements from a and b are operated on + * using the specified scalar binary operation and the element result is placed + * into the vector result at the same lane. + * The following pseudocode expresses the behavior of this operation category: + * + * <pre>{@code + * EVector a = ...; + * EVector b = ...; + * e[] ar = new e[a.length()]; + * for (int i = 0; i < a.length(); i++) { + * ar[i] = scalar_binary_op(a.get(i), b.get(i)); + * } + * EVector r = EVector.fromArray(a.species(), ar, 0); + * }</pre> + * + * Unless otherwise specified the two input and result vectors will have the + * same element type and shape. + * + * <li> + * Generalizing from unary and binary operations, a vector n-ary + * operation operates on n input vectors to produce a + * result vector. + * N lane elements from each input vector are operated on + * using the specified n-ary scalar operation and the element result is placed + * into the vector result at the same lane. + * + * Unless otherwise specified the n input and result vectors will have the same + * element type and shape. + * + * <li> + * A vector reduction operation operates on all the lane + * elements of an input vector, and applies an accumulation function to all the + * lane elements to produce a scalar result. + * If the reduction operation is associative then the result may be accumulated + * by operating on the lane elements in any order using a specified associative + * scalar binary operation and identity value. Otherwise, the reduction + * operation specifies the behavior of the accumulation function. + * The following pseudocode expresses the behavior of this operation category + * if it is associative: + * <pre>{@code + * EVector a = ...; + * e r = <identity value>; + * for (int i = 0; i < a.length(); i++) { + * r = assoc_scalar_binary_op(r, a.get(i)); + * } + * }</pre> + * + * Unless otherwise specified the scalar result type and element type will be + * the same. + * + * <li> + * A vector binary test operation operates on two input vectors to produce a + * result mask. For each lane of the two input vectors, a and b say, the + * the corresponding lane elements from a and b are operated on using the + * specified scalar binary test operation and the boolean result is placed + * into the mask at the same lane. + * The following pseudocode expresses the behavior of this operation category: + * <pre>{@code + * EVector a = ...; + * EVector b = ...; + * boolean[] ar = new boolean[a.length()]; + * for (int i = 0; i < a.length(); i++) { + * ar[i] = scalar_binary_test_op(a.get(i), b.get(i)); + * } + * Mask<E> r = EVector.maskFromArray(a.species(), ar, 0); + * }</pre> + * + * Unless otherwise specified the two input vectors and result mask will have + * the same element type and shape. + * + * <li> + * The prior categories of operation can be said to operate within the vector + * lanes, where lane access is uniformly applied to all vectors, specifically + * the scalar operation is applied to elements taken from input vectors at the + * same lane, and if appropriate applied to the result vector at the same lane. + * A further category of operation is a cross-lane vector operation where lane + * access is defined by the arguments to the operation. Cross-lane operations + * generally rearrange lane elements, for example by permutation (commonly + * controlled by a {@link jdk.incubator.vector.Vector.Shuffle}) or by blending (commonly controlled by a + * {@link jdk.incubator.vector.Vector.Mask}). Such an operation explicitly specifies how it rearranges lane + * elements. + * </ul> + * + * Some vector operations are specified as instance methods (such as adding + * one vector to another); others are specified as static methods (such as + * loading vector values from an array.) + * <p> + * If a vector operation does not belong to one of the above categories then + * the operation explicitly specifies how it processes the lane elements of + * input vectors, and where appropriate expresses the behavior using + * pseudocode. + * + * <p> + * Many vector operations provide an additional {@link jdk.incubator.vector.Vector.Mask mask}-accepting + * variant. + * The mask controls which lanes are selected for application of the scalar + * operation. Masks are a key component for the support of control flow in + * vector computations. + * <p> + * For certain operation categories the mask accepting variants can be specified + * in generic terms. If a lane of the mask is set then the scalar operation is + * applied to corresponding lane elements, otherwise if a lane of a mask is not + * set then a default scalar operation is applied and its result is placed into + * the vector result at the same lane. The default operation is specified for + * the following operation categories: + * <ul> + * <li> + * For a vector n-ary operation the default operation is a function that returns + * it's first argument, specifically a lane element of the first input vector. + * <li> + * For an associative vector reduction operation the default operation is a + * function that returns the identity value. + * <li> + * For vector binary test operation the default operation is a function that + * returns false. + *</ul> + * Otherwise, the mask accepting variant of the operation explicitly specifies + * how it processes the lane elements of input vectors, and where appropriate + * expresses the behavior using pseudocode. + * + * <p> + * For convenience, many vector operations of arity greater than one provide + * an additional scalar-accepting variant (such as adding a constant scalar + * value to all lanes of a vector). This variant accepts compatible + * scalar values instead of vectors for the second and subsequent input vectors, + * if any. + * Unless otherwise specified the scalar variant behaves as if each scalar value + * is transformed to a vector using the appropriate vector {@code broadcast} operation, and + * then the vector accepting vector operation is applied using the transformed + * values. + * + * <h2> Performance notes </h2> + * This package depends on the runtime's ability to dynamically compile vector operations + * into optimal vector hardware instructions. There is a default scalar implementation + * for each operation which is used if the operation cannot be compiled to vector instructions. + * + * <p>There are certain things users need to pay attention to for generating optimal vector machine code: + * + * <ul> + * <li>The shape of vectors used should be supported by the underlying platform. For example, + * code written using {@code IntVector} of Shape S_512_BIT will not be compiled to vector + * instructions on a platform which supports only 256 bit vectors. Instead, the default + * scalar implementation will be used. + * For this reason, it is recommended to use the preferred species as shown above to write + * generically sized vector computations. + * <li>Classes defined in this package should be treated as + * <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a> classes. + * Use of identity-sensitive operations (including reference equality + * ({@code ==}), identity hash code, or synchronization) will limit generation of + * optimal vector instructions. + * </ul> */ package jdk.incubator.vector;
< prev index next >