/* * Copyright (c) 2017, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ /** * {@Incubating} *
* Classes to express vector computations that, given suitable hardware * and runtime ability, are accelerated using vector hardware instructions. *
* 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 Single Instruction Multiple Data (SIMD) * parallelism. * *
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). * *
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 shape, * 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 vector species, * 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(Vector.Species, float[], int) FloatVector.fromArray()} * creates and returns a float vector of the specified species, with elements * loaded from the specified float array. * *
* The species instance for a specific combination of element type and shape * can be obtained by reading the appropriate static field, as follows: *
* {@code Vector.Species
*
* 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:
*
* {@code Vector.Species
*
*
* 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}.
*
* 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.
*
*
* 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.
*
* 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 as follows:
*
* 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.
*
* There are certain things users need to pay attention to for generating optimal vector machine code:
*
* {@code
* static final Vector.Species
*
* 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.
*
* {@code
* static final Vector.Species
*
* Vector operations
* We use the term lanes 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:
*
*
*
* {@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);
* }
*
* Unless otherwise specified the input and result vectors will have the same
* element type and shape.
*
* {@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);
* }
*
* Unless otherwise specified the two input and result vectors will have the
* same element type and shape.
*
* {@code
* EVector a = ...;
* e r =
*
* Unless otherwise specified the scalar result type and element type will be
* the same.
*
* {@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
*
* Unless otherwise specified the two input vectors and result mask will have
* the same element type and shape.
*
*
*
* 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.
*
* Performance notes
* 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.
*
*
*
*/
package jdk.incubator.vector;