/* * 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 * questions. */ package jdk.incubator.vector; import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.function.IntUnaryOperator; import jdk.incubator.vector.*; /** * A {@code Vector} is designed for use in computations that can be transformed * by a runtime compiler, on supported hardware, to Single Instruction Multiple * Data (SIMD) computations leveraging vector hardware registers and vector * hardware instructions. Such SIMD computations exploit data parallelism to * perform the same operation on multiple data points simultaneously in a * faster time it would ordinarily take to perform the same operation * sequentially on each data point. *

* A Vector represents an ordered immutable sequence of values of the same * element type {@code e} that is one of the following primitive types * {@code byte}, {@code short}, {@code int}, {@code long}, {@code float}, or * {@code double}). The type variable {@code E} corresponds to the boxed * element type, specifically the class that wraps a value of {@code e} in an * object (such the {@code Integer} class that wraps a value of {@code int}}. * A Vector has a {@link #shape() shape} {@code S}, extending type * {@link Shape}, that governs the total {@link #bitSize() size} in bits * of the sequence of values. *

* The number of values in the sequence is referred to as the Vector * {@link #length() length}. The length also corresponds to the number of * Vector lanes. The lane element at lane index {@code N} (from {@code 0}, * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th value in * the sequence. * Note: this arrangement * of Vector bit size, Vector length, element bit size, and lane element index * has no bearing on how a Vector instance and its sequence of elements may be * arranged in memory or represented as a value in a vector hardware register. *

* Vector declares a set of vector operations (methods) that are common to all * element types (such as addition). Sub-classes of Vector with a concrete * boxed 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 sub-classes of Vector corresponding to the supported set * of element types, {@link ByteVector}, {@link ShortVector}, * {@link IntVector} {@link LongVector}, {@link FloatVector}, and * {@link DoubleVector}. *

* Vector values, instances of Vector, are created from a special kind of * factory called a {@link Species}. A Species has an * element type and shape and creates Vector values of the same element type * and shape. * A species can be {@link Species#of(Class, Shape)} obtained} given an element * type and shape, or a preferred species can be * {@link Species#ofPreferred(Class)} obtained} given just an element type where the most * optimal shape is selected for the current platform. It is recommended that * Species instances be held in {@code static final} fields for optimal creation * and usage of Vector values by the runtime compiler. *

* Vector operations can be grouped into various categories and their behaviour * generally specified as follows: *

* * If a vector operation is represented as an instance method then first input * vector corresponds to {@code this} vector and subsequent input vectors are * arguments of the method. Otherwise, if the an operation is represented as a * static method then all input vectors are arguments of the method. *

* 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 behaviour using * pseudocode. * *

* Many vector operations provide an additional {@link 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 for * the following operation categories: *

    *
  • * 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. *
  • * For an associative vector reduction operation the default operation is a * function that returns the identity value. *
  • * For vector binary test operation the default operation is a function that * returns false. *
* Otherwise, the mask accepting variant of the operation explicitly specifies * how it processes the lane elements of input vectors, and where appropriate * expresses the behaviour using pseudocode. * *

* For convenience many vector operations, of arity greater than one, provide * an additional scalar accepting variant. 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 vector Species * {@code broadcast} operation, and * then the vector accepting vector operation is applied using the transformed * values. * *

* This is a value-based * class; use of identity-sensitive operations (including reference equality * ({@code ==}), identity hash code, or synchronization) on instances of * {@code Vector} may have unpredictable results and should be avoided. * * @param the boxed element type of elements in this vector */ public abstract class Vector { Vector() {} /** * Returns the species of this vector. * * @return the species of this vector */ public abstract Species species(); /** * Returns the primitive element type of this vector. * * @return the primitive element type of this vector */ public Class elementType() { return species().elementType(); } /** * Returns the element size, in bits, of this vector. * * @return the element size, in bits */ public int elementSize() { return species().elementSize(); } /** * Returns the shape of this vector. * * @return the shape of this vector */ public Shape shape() { return species().shape(); } /** * Returns the number of vector lanes (the length). * * @return the number of vector lanes */ public int length() { return species().length(); } /** * Returns the total vector size, in bits. * * @return the total vector size, in bits */ public int bitSize() { return species().bitSize(); } //Arithmetic /** * Adds this vector to an input vector. *

* This is a vector binary operation where the primitive addition operation * ({@code +}) is applied to lane elements. * * @param v the input vector * @return the result of adding this vector to the input vector */ public abstract Vector add(Vector v); /** * Adds this vector to an input vector, selecting lane elements * controlled by a mask. *

* This is a vector binary operation where the primitive addition operation * ({@code +}) is applied to lane elements. * * @param v the input vector * @param m the mask controlling lane selection * @return the result of adding this vector to the given vector */ public abstract Vector add(Vector v, Mask m); /** * Subtracts an input vector from this vector. *

* This is a vector binary operation where the primitive subtraction * operation ({@code -}) is applied to lane elements. * * @param v the input vector * @return the result of subtracting the input vector from this vector */ public abstract Vector sub(Vector v); /** * Subtracts an input vector from this vector, selecting lane elements * controlled by a mask. *

* This is a vector binary operation where the primitive subtraction * operation ({@code -}) is applied to lane elements. * * @param v the input vector * @param m the mask controlling lane selection * @return the result of subtracting the input vector from this vector */ public abstract Vector sub(Vector v, Mask m); /** * Multiplies this vector with an input vector. *

* This is a vector binary operation where the primitive multiplication * operation ({@code *}) is applied to lane elements. * * @param v the input vector * @return the result of multiplying this vector with the input vector */ public abstract Vector mul(Vector v); /** * Multiplies this vector with an input vector, selecting lane elements * controlled by a mask. *

* This is a vector binary operation where the primitive multiplication * operation ({@code *}) is applied to lane elements. * * @param v the input vector * @param m the mask controlling lane selection * @return the result of multiplying this vector with the input vector */ public abstract Vector mul(Vector v, Mask m); /** * Negates this vector. *

* This is a vector unary operation where the primitive negation operation * ({@code -}) is applied to lane elements. * * @return the negation this vector */ public abstract Vector neg(); /** * Negates this vector, selecting lane elements controlled by a mask. *

* This is a vector unary operation where the primitive negation operation * ({@code -})is applied to lane elements. * * @param m the mask controlling lane selection * @return the negation this vector */ public abstract Vector neg(Mask m); // Maths from java.math /** * Returns the modulus of this vector. *

* This is a vector unary operation where the operation * {@code (a) -> (a < 0) ? -a : a} is applied to lane elements. * * @return the modulus this vector */ public abstract Vector abs(); /** * Returns the modulus of this vector, selecting lane elements controlled by * a mask. *

* This is a vector unary operation where the operation * {@code (a) -> (a < 0) ? -a : a} is applied to lane elements. * * @param m the mask controlling lane selection * @return the modulus this vector */ public abstract Vector abs(Mask m); /** * Returns the minimum of this vector and an input vector. *

* This is a vector binary operation where the operation * {@code (a, b) -> a < b ? a : b} is applied to lane elements. * * @param v the input vector * @return the minimum of this vector and the input vector */ public abstract Vector min(Vector v); /** * Returns the minimum of this vector and an input vector, * selecting lane elements controlled by a mask. *

* This is a vector binary operation where the operation * {@code (a, b) -> a < b ? a : b} is applied to lane elements. * * @param v the input vector * @param m the mask controlling lane selection * @return the minimum of this vector and the input vector */ public abstract Vector min(Vector v, Mask m); /** * Returns the maximum of this vector and an input vector. *

* This is a vector binary operation where the operation * {@code (a, b) -> a > b ? a : b} is applied to lane elements. * * @param v the input vector * @return the maximum of this vector and the input vector */ public abstract Vector max(Vector v); /** * Returns the maximum of this vector and an input vector, * selecting lane elements controlled by a mask. *

* This is a vector binary operation where the operation * {@code (a, b) -> a > b ? a : b} is applied to lane elements. * * @param v the input vector * @param m the mask controlling lane selection * @return the maximum of this vector and the input vector */ public abstract Vector max(Vector v, Mask m); // Comparisons /** * Tests if this vector is equal to an input vector. *

* This is a vector binary test operation where the primitive equals * operation ({@code ==}) is applied to lane elements. * * @param v the input vector * @return the result mask of testing if this vector is equal to the input * vector */ public abstract Mask equal(Vector v); /** * Tests if this vector is not equal to an input vector. *

* This is a vector binary test operation where the primitive not equals * operation ({@code !=}) is applied to lane elements. * * @param v the input vector * @return the result mask of testing if this vector is not equal to the * input vector */ public abstract Mask notEqual(Vector v); /** * Tests if this vector is less than an input vector. *

* This is a vector binary test operation where the primitive less than * operation ({@code <}) is applied to lane elements. * * @param v the input vector * @return the mask result of testing if this vector is less than the input * vector */ public abstract Mask lessThan(Vector v); /** * Tests if this vector is less or equal to an input vector. *

* This is a vector binary test operation where the primitive less than * or equal to operation ({@code <=}) is applied to lane elements. * * @param v the input vector * @return the mask result of testing if this vector is less than or equal * to the input vector */ public abstract Mask lessThanEq(Vector v); /** * Tests if this vector is greater than an input vector. *

* This is a vector binary test operation where the primitive greater than * operation ({@code >}) is applied to lane elements. * * @param v the input vector * @return the mask result of testing if this vector is greater than the * input vector */ public abstract Mask greaterThan(Vector v); /** * Tests if this vector is greater than or equal to an input vector. *

* This is a vector binary test operation where the primitive greater than * or equal to operation ({@code >=}) is applied to lane elements. * * @param v the input vector * @return the mask result of testing if this vector is greater than or * equal to the given vector */ public abstract Mask greaterThanEq(Vector v); // Elemental shifting /** * Rotates left the lane elements of this vector by the given number of * lanes, {@code i}, modulus the vector length. *

* This is a cross-lane operation that permutes the lane elements of this * vector. * For each lane of the input vector, at lane index {@code N}, the lane * element is placed into to the result vector at lane index * {@code (i + N) % this.length()}. * * @param i the number of lanes to rotate left * @return the result of rotating left lane elements of this vector by the * given number of lanes */ public abstract Vector rotateEL(int i); /** * Rotates right the lane elements of this vector by the given number of * lanes, {@code i}, modulus the vector length. *

* This is a cross-lane operation that permutes the lane elements of this * vector and behaves as if rotating left the lane elements by * {@code this.length() - (i % this.length())} lanes. * * @param i the number of lanes to rotate left * @return the result of rotating right lane elements of this vector by the * given number of lanes */ public abstract Vector rotateER(int i); /** * Shift left the lane elements of this vector by the given number of * lanes, {@code i}, modulus the vector length. *

* This is a cross-lane operation that permutes the lane elements of this * vector and behaves as if rotating left the lane elements by {@code i}, * and then the zero value is placed into the result vector at lane indexes * less than {@code i % this.length()}. * * @param i the number of lanes to shift left * @return the result of shifting left lane elements of this vector by the * given number of lanes * @throws IllegalArgumentException if {@code i} is {@code < 0}. */ public abstract Vector shiftEL(int i); /** * Shift right the lane elements of this vector by the given number of * lanes, {@code i}, modulus the vector length. *

* This is a cross-lane operation that permutes the lane elements of this * vector and behaves as if rotating right the lane elements by {@code i}, * and then the zero value is placed into the result vector at lane indexes * greater or equal to {@code this.length() - (i % this.length())}. * * @param i the number of lanes to shift left * @return the result of shifting left lane elements of this vector by the * given number of lanes * @throws IllegalArgumentException if {@code i} is {@code < 0}. */ public abstract Vector shiftER(int i); /** * Blends the lane elements of this vector with those of an input vector, * selecting lanes controlled by a mask. *

* For each lane of the mask, at lane index {@code N}, if the mask lane * is set then the lane element at {@code N} from the input vector is * selected and placed into the resulting vector at {@code N}, * otherwise the the lane element at {@code N} from this input vector is * selected and placed into the resulting vector at {@code N}. * * @param v the input vector * @param m the mask controlling lane selection * @return the result of blending the lane elements of this vector with * those of an input vector */ public abstract Vector blend(Vector v, Mask m); /** * Rearranges the lane elements of this vector and those of an input vector, * selecting lane indexes controlled by shuffles and a mask. *

* This is a cross-lane operation that rearranges the lane elements of this * vector and the input vector. This method behaves as if it rearranges * each vector with the corresponding shuffle and then blends the two * results with the mask: *

{@code
     * return this.rearrange(s1).blend(v.rearrange(s2), m);
     * }
* * @param v the input vector * @param s the shuffle controlling lane index selection of the input vector * if corresponding mask lanes are set, otherwise controlling lane * index selection of this vector * @param m the mask controlling shuffled lane selection * @return the rearrangement of lane elements of this vector and * those of an input vector */ @ForceInline // rearrange public abstract Vector rearrange(Vector v, Shuffle s, Mask m); /** * Rearranges the lane elements of this vector selecting lane indexes * controlled by a shuffle. *

* This is a cross-lane operation that rearranges the lane elements of this * vector. * For each lane of the shuffle, at lane index {@code N} with lane * element {@code I}, the lane element at {@code I} from this vector is * selected and placed into the resulting vector at {@code N}. * * @param s the shuffle controlling lane index selection * @return the rearrangement of the lane elements of this vector */ // rearrange public abstract Vector rearrange(Shuffle s); // Conversions /** * Converts this vector into a shuffle, creating a shuffle from vector * lane elements cast to {@code int} then logically AND'ed with the * shuffle length minus one. *

* This methods behaves as if it returns the result of creating a shuffle * given an array of the vector lane elements, as follows: *

{@code
     * $type$[] a = this.toArray();
     * int[] sa = new int[a.length];
     * for (int i = 0; i < a.length; i++) {
     *     sa[i] = (int) a[i];
     * }
     * return this.species().shuffleFromValues(sa);
     * }
* * @return a shuffle representation of this vector */ public abstract Shuffle toShuffle(); // Bitwise preserving /** * Transforms this vector to a vector of the given species of element type {@code F}. *

* The underlying bits of this vector are copied to the resulting * vector without modification, but those bits, before copying, may be * truncated if the this vector's bit size is greater than desired vector's bit * size, or appended to with zero bits if this vector's bit size is less * than desired vector's bit size. *

* The method behaves as if this vector is stored into a byte buffer * and then the desired vector is loaded from the byte buffer using * native byte ordering. The implication is that ByteBuffer reads bytes * and then composes them based on the byte ordering so the result * depends on this composition. *

* For example, on a system with ByteOrder.LITTLE_ENDIAN, loading from * byte array with values {0,1,2,3} and reshaping to int, leads to bytes * being composed in order 0x3 0x2 0x1 0x0 which is decimal value 50462976. * On a system with ByteOrder.BIG_ENDIAN, the value is instead 66051 because * bytes are composed in order 0x0 0x1 0x2 0x3. *

* The following pseudocode expresses the behaviour: *

{@code
     * int blen = Math.max(this.bitSize(), s.bitSize()) / Byte.SIZE;
     * ByteBuffer bb = ByteBuffer.allocate(blen).order(ByteOrder.nativeOrder());
     * this.intoByteBuffer(bb, 0);
     * return s.fromByteBuffer(bb, 0);
     * }
* * @param s species of desired vector * @param the boxed element type of the species * @return a vector transformed, by shape and element type, from this vector */ @ForceInline public abstract Vector reinterpret(Species s); @ForceInline @SuppressWarnings("unchecked") Vector defaultReinterpret(Species s) { int blen = Math.max(s.bitSize(), this.species().bitSize()) / Byte.SIZE; ByteBuffer bb = ByteBuffer.allocate(blen).order(ByteOrder.nativeOrder()); this.intoByteBuffer(bb, 0); Class stype = s.elementType(); if (stype == byte.class) { return (Vector) ByteVector.fromByteBuffer((ByteVector.ByteSpecies)s, bb, 0); } else if (stype == short.class) { return (Vector) ShortVector.fromByteBuffer((ShortVector.ShortSpecies)s, bb, 0); } else if (stype == int.class) { return (Vector) IntVector.fromByteBuffer((IntVector.IntSpecies)s, bb, 0); } else if (stype == long.class) { return (Vector) LongVector.fromByteBuffer((LongVector.LongSpecies)s, bb, 0); } else if (stype == float.class) { return (Vector) FloatVector.fromByteBuffer((FloatVector.FloatSpecies)s, bb, 0); } else if (stype == double.class) { return (Vector) DoubleVector.fromByteBuffer((DoubleVector.DoubleSpecies)s, bb, 0); } else { throw new UnsupportedOperationException("Bad lane type for reinterpret."); } } /** * Transforms this vector to a vector of same element type but different shape identified by species. *

* The lane elements of this vector are copied without * modification to the resulting vector, but those lane elements, before * copying, may be truncated if this vector's length is greater than the desired * vector's length, or appended to with default element values if this * vector's length is less than desired vector's length. *

* The method behaves as if this vector is stored into a byte array * and then the returned vector is loaded from the byte array. * The following pseudocode expresses the behaviour: *

{@code
     * int alen = Math.max(this.bitSize(), s.bitSize()) / Byte.SIZE;
     * byte[] a = new byte[alen];
     * this.intoByteArray(a, 0);
     * return s.fromByteArray(a, 0);
     * }
* * @param s species of the desired vector * @return a vector transformed, by shape, from this vector */ public abstract Vector reshape(Species s); // Cast /** * Converts this vector to a vector of the given species element type {@code F}. *

* For each vector lane up to the length of this vector or * desired vector, which ever is the minimum, and where {@code N} is the * vector lane index, the element at index {@code N} of primitive type * {@code E} is converted, according to primitive conversion rules * specified by the Java Language Specification, to a value of primitive * type {@code F} and placed into the resulting vector at lane index * {@code N}. If desired vector's length is greater than this * vector's length then the default primitive value is placed into * subsequent lanes of the resulting vector. * * @param s species of the desired vector * @param the boxed element type of the species * @return a vector converted by shape and element type from this vector */ public abstract Vector cast(Species s); //Array stores /** * Stores this vector into a byte array starting at an offset. *

* Bytes are extracted from primitive lane elements according to the * native byte order of the underlying platform. *

* This method behaves as it calls the * byte buffer, offset, and mask accepting * {@link #intoByteBuffer(ByteBuffer, int, Mask) method} as follows: *

{@code
     * return this.intoByteBuffer(ByteBuffer.wrap(a), i, this.maskAllTrue());
     * }
* * @param a the byte array * @param i the offset into the array * @return a vector loaded from a byte array * @throws IndexOutOfBoundsException if {@code i < 0} or * {@code i > a.length - (this.length() * this.elementSize() / Byte.SIZE)} */ public abstract void intoByteArray(byte[] a, int i); /** * Stores this vector into a byte array starting at an offset and using a mask. *

* Bytes are extracted from primitive lane elements according to the * native byte order of the underlying platform. *

* This method behaves as it calls the * byte buffer, offset, and mask accepting * {@link #intoByteBuffer(ByteBuffer, int, Mask) method} as follows: *

{@code
     * return this.intoByteBuffer(ByteBuffer.wrap(a), i, m);
     * }
* * @param a the byte array * @param i the offset into the array * @param m the mask controlling lane selection * @throws IndexOutOfBoundsException if the offset is {@code < 0}, * or {@code > a.length}, * for any vector lane index {@code N} where the mask at lane {@code N} * is set * {@code i >= a.length - (N * this.elementSize() / Byte.SIZE)} */ public abstract void intoByteArray(byte[] a, int i, Mask m); /** * Stores this vector into a {@link ByteBuffer byte buffer} starting at an * offset into the byte buffer. *

* Bytes are extracted from primitive lane elements according to the * native byte order of the underlying platform. *

* This method behaves as if it calls the byte buffer, offset, and mask * accepting * {@link #intoByteBuffer(ByteBuffer, int, Mask)} method} as follows: *

{@code
     *   this.intoByteBuffer(b, i, this.maskAllTrue())
     * }
* * @param b the byte buffer * @param i the offset into the byte buffer * @throws IndexOutOfBoundsException if the offset is {@code < 0}, * or {@code > b.limit()}, * or if there are fewer than * {@code this.length() * this.elementSize() / Byte.SIZE} bytes * remaining in the byte buffer from the given offset */ public abstract void intoByteBuffer(ByteBuffer b, int i); /** * Stores this vector into a {@link ByteBuffer byte buffer} starting at an * offset into the byte buffer and using a mask. *

* This method behaves as if the byte buffer is viewed as a primitive * {@link java.nio.Buffer buffer} for the primitive element type, * according to the native byte order of the underlying platform, and * the lane elements of this vector are put into the buffer if the * corresponding mask lane is set. * The following pseudocode expresses the behaviour, where * {@coce EBuffer} is the primitive buffer type, {@code e} is the * primitive element type, and {@code EVector} is the primitive * vector type for this vector: *

{@code
     * EBuffer eb = b.duplicate().
     *     order(ByteOrder.nativeOrder()).position(i).
     *     asEBuffer();
     * e[] es = ((EVector)this).toArray();
     * for (int n = 0; n < t.length; n++) {
     *     if (m.isSet(n)) {
     *         eb.put(n, es[n]);
     *     }
     * }
     * }
* * @param b the byte buffer * @param i the offset into the byte buffer * @param m the mask * @throws IndexOutOfBoundsException if the offset is {@code < 0}, * or {@code > b.limit()}, * for any vector lane index {@code N} where the mask at lane {@code N} * is set * {@code i >= b.limit() - (N * this.elementSize() / Byte.SIZE)} bytes */ public abstract void intoByteBuffer(ByteBuffer b, int i, Mask m); /** * A {@code Shape} governs the total size, in bits, of a * {@link Vector}, {@link Mask}, or {@link Shuffle}. The shape in * combination with the element type together govern the number of lanes. */ public enum Shape { /** Shape of length 64 bits */ S_64_BIT(64), /** Shape of length 128 bits */ S_128_BIT(128), /** Shape of length 256 bits */ S_256_BIT(256), /** Shape of length 512 bits */ S_512_BIT(512), /** Shape of maximum length supported on the platform */ S_Max_BIT(Unsafe.getUnsafe().getMaxVectorSize(byte.class) * 8); @Stable final int bitSize; Shape(int bitSize) { this.bitSize = bitSize; } /** * Returns the size, in bits, of this shape. * * @return the size, in bits, of this shape. */ public int bitSize() { return bitSize; } /** * Return the number of lanes of a vector of this shape and whose element * type is of the provided species * * @param s the species describing the element type * @return the number of lanes */ int length(Species s) { return bitSize() / s.elementSize(); } /** * Finds appropriate shape depending on bitsize. * * @param bitSize the size in bits * @return the shape corresponding to bitsize * @see #bitSize */ public static Shape forBitSize(int bitSize) { switch (bitSize) { case 64: return Shape.S_64_BIT; case 128: return Shape.S_128_BIT; case 256: return Shape.S_256_BIT; case 512: return Shape.S_512_BIT; default: if ((bitSize > 0) && (bitSize <= 2048) && (bitSize % 128 == 0)) { return Shape.S_Max_BIT; } else { throw new IllegalArgumentException("Bad vector bit size: " + bitSize); } } } } /** * Class representing vectors of same element type, {@code E} and {@link Vector.Shape Shape}. * * @param the boxed element type of this species */ public static abstract class Species { Species() {} /** * Returns the primitive element type of vectors produced by this * species. * * @return the primitive element type */ public abstract Class elementType(); /** * Returns the vector box type for this species * * @return the box type */ abstract Class boxType(); /** * Returns the vector mask type for this species * * @return the box type */ abstract Class maskType(); /** * Returns the element size, in bits, of vectors produced by this * species. * * @return the element size, in bits */ public abstract int elementSize(); /** * Returns the shape of masks, shuffles, and vectors produced by this * species. * * @return the primitive element type */ public abstract Shape shape(); /** * Returns the shape of the corresponding index species * @return the shape */ @ForceInline public abstract Shape indexShape(); /** * Returns the mask, shuffe, or vector lanes produced by this species. * * @return the the number of lanes */ public int length() { return shape().length(this); } /** * Returns the total vector size, in bits, of vectors produced by this * species. * * @return the total vector size, in bits */ public int bitSize() { return shape().bitSize(); } // Factory /** * Finds a species for an element type and shape. * * @param c the element type * @param s the shape * @param the boxed element type * @return a species for an element type and shape * @throws IllegalArgumentException if no such species exists for the * element type and/or shape */ @SuppressWarnings("unchecked") public static Vector.Species of(Class c, Shape s) { if (c == float.class) { return (Vector.Species) FloatVector.species(s); } else if (c == double.class) { return (Vector.Species) DoubleVector.species(s); } else if (c == byte.class) { return (Vector.Species) ByteVector.species(s); } else if (c == short.class) { return (Vector.Species) ShortVector.species(s); } else if (c == int.class) { return (Vector.Species) IntVector.species(s); } else if (c == long.class) { return (Vector.Species) LongVector.species(s); } else { throw new IllegalArgumentException("Bad vector element type: " + c.getName()); } } /** * Finds a preferred species for an element type. *

* A preferred species is a species chosen by the platform that has a * shape of maximal bit size. A preferred species for different element * types will have the same shape, and therefore vectors created from * such species will be shape compatible. * * @param c the element type * @param the boxed element type * @return a preferred species for an element type * @throws IllegalArgumentException if no such species exists for the * element type */ public static Vector.Species ofPreferred(Class c) { Unsafe u = Unsafe.getUnsafe(); int vectorLength = u.getMaxVectorSize(c); int vectorBitSize = bitSizeForVectorLength(c, vectorLength); Shape s = Shape.forBitSize(vectorBitSize); return Species.of(c, s); } } abstract static class AbstractSpecies extends Vector.Species { @Stable protected final Vector.Shape shape; @Stable protected final Class elementType; @Stable protected final int elementSize; @Stable protected final Class boxType; @Stable protected final Class maskType; @Stable protected final Shape indexShape; AbstractSpecies(Vector.Shape shape, Class elementType, int elementSize, Class boxType, Class maskType) { this.shape = shape; this.elementType = elementType; this.elementSize = elementSize; this.boxType = boxType; this.maskType = maskType; if (boxType == Long64Vector.class || boxType == Double64Vector.class) { indexShape = Vector.Shape.S_64_BIT; } else { int bitSize = Vector.bitSizeForVectorLength(int.class, shape.bitSize() / elementSize); indexShape = Vector.Shape.forBitSize(bitSize); } } @Override @ForceInline public int bitSize() { return shape.bitSize(); } @Override @ForceInline public int length() { return shape.bitSize() / elementSize; } @Override @ForceInline public Class elementType() { return elementType; } @Override @ForceInline public Class boxType() { return boxType; } @Override @ForceInline public Class maskType() { return maskType; } @Override @ForceInline public int elementSize() { return elementSize; } @Override @ForceInline public Vector.Shape shape() { return shape; } @Override @ForceInline public Vector.Shape indexShape() { return indexShape; } @Override public String toString() { return new StringBuilder("Shape[") .append(bitSize()).append(" bits, ") .append(length()).append(" ").append(elementType.getSimpleName()).append("s x ") .append(elementSize()).append(" bits") .append("]") .toString(); } } /** * A {@code Mask} represents an ordered immutable sequence of {@code boolean} * values. A Mask can be used with a mask accepting vector operation to * control the selection and operation of lane elements of input vectors. *

* The number of values in the sequence is referred to as the Mask * {@link #length() length}. The length also corresponds to the number of * Mask lanes. The lane element at lane index {@code N} (from {@code 0}, * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th * value in the sequence. * A Mask and Vector of the same element type and shape have the same number * of lanes. *

* A lane is said to be set if the lane element is {@code true}, * otherwise a lane is said to be unset if the lane element is * {@code false}. *

* Mask declares a limited set of unary, binary and reductive mask * operations. *

    *
  • * A mask unary operation (1-ary) operates on one input mask to produce a * result mask. * For each lane of the input mask the * lane element is operated on using the specified scalar unary operation and * the boolean result is placed into the mask result at the same lane. * The following pseudocode expresses the behaviour of this operation category: * *
    {@code
         * Mask a = ...;
         * boolean[] ar = new boolean[a.length()];
         * for (int i = 0; i < a.length(); i++) {
         *     ar[i] = boolean_unary_op(a.isSet(i));
         * }
         * Mask r = a.species().maskFromArray(ar, 0);
         * }
    * *
  • * A mask binary operation (2-ary) operates on two input * masks to produce a result mask. * For each lane of the two input masks, * a and b say, the corresponding lane elements from a and b are operated on * using the specified scalar binary operation and the boolean result is placed * into the mask result at the same lane. * The following pseudocode expresses the behaviour of this operation category: * *
    {@code
         * Mask a = ...;
         * Mask b = ...;
         * boolean[] ar = new boolean[a.length()];
         * for (int i = 0; i < a.length(); i++) {
         *     ar[i] = scalar_binary_op(a.isSet(i), b.isSet(i));
         * }
         * Mask r = a.species().maskFromArray(ar, 0);
         * }
    * *
* @param the boxed element type of this mask */ public static abstract class Mask { Mask() {} /** * Returns the species of this mask. * * @return the species of this mask */ public abstract Species species(); /** * Returns the number of mask lanes (the length). * * @return the number of mask lanes */ public int length() { return species().length(); } /** * Converts this mask to a mask of the given species shape of element type {@code F}. *

* For each mask lane, where {@code N} is the lane index, if the * mask lane at index {@code N} is set, then the mask lane at index * {@code N} of the resulting mask is set, otherwise that mask lane is * not set. * * @param s the species of the desired mask * @param the boxed element type of the species * @return a mask converted by shape and element type * @throws IllegalArgumentException if this mask length and the species * length differ */ public abstract Mask cast(Species s); /** * Returns the lane elements of this mask packed into a {@code long} * value for at most the first 64 lane elements. *

* The lane elements are packed in the order of least significant bit * to most significant bit. * For each mask lane where {@code N} is the mask lane index, if the * mask lane is set then the {@code N}'th bit is set to one in the * resulting {@code long} value, otherwise the {@code N}'th bit is set * to zero. * * @return the lane elements of this mask packed into a {@code long} * value. */ public abstract long toLong(); /** * Returns an {@code boolean} array containing the lane elements of this * mask. *

* This method behaves as if it {@link #intoArray(boolean[], int)} stores} * this mask into an allocated array and returns that array as * follows: *

{@code
         * boolean[] a = new boolean[this.length()];
         * this.intoArray(a, 0);
         * return a;
         * }
* * @return an array containing the the lane elements of this vector */ public abstract boolean[] toArray(); /** * Stores this mask into a {@code boolean} array starting at offset. *

* For each mask lane, where {@code N} is the mask lane index, * the lane element at index {@code N} is stored into the array at index * {@code i + N}. * * @param a the array * @param i the offset into the array * @throws IndexOutOfBoundsException if {@code i < 0}, or * {@code i > a.length - this.length()} */ public abstract void intoArray(boolean[] a, int i); /** * Returns {@code true} if any of the mask lanes are set. * * @return {@code true} if any of the mask lanes are set, otherwise * {@code false}. */ public abstract boolean anyTrue(); /** * Returns {@code true} if all of the mask lanes are set. * * @return {@code true} if all of the mask lanes are set, otherwise * {@code false}. */ public abstract boolean allTrue(); /** * Returns the number of mask lanes that are set. * * @return the number of mask lanes that are set. */ public abstract int trueCount(); /** * Logically ands this mask with an input mask. *

* This is a mask binary operation where the logical and operation * ({@code &&} is applied to lane elements. * * @param o the input mask * @return the result of logically and'ing this mask with an input mask */ public abstract Mask and(Mask o); /** * Logically ors this mask with an input mask. *

* This is a mask binary operation where the logical or operation * ({@code ||} is applied to lane elements. * * @param o the input mask * @return the result of logically or'ing this mask with an input mask */ public abstract Mask or(Mask o); /** * Logically negates this mask. *

* This is a mask unary operation where the logical not operation * ({@code !} is applied to lane elements. * * @return the result of logically negating this mask. */ public abstract Mask not(); /** * Returns a vector representation of this mask. *

* For each mask lane, where {@code N} is the mask lane index, * if the mask lane is set then an element value whose most significant * bit is set is placed into the resulting vector at lane index * {@code N}, otherwise the default element value is placed into the * resulting vector at lane index {@code N}. * * @return a vector representation of this mask. */ public abstract Vector toVector(); /** * Tests if the lane at index {@code i} is set * @param i the lane index * * @return true if the lane at index {@code i} is set, otherwise false */ public abstract boolean getElement(int i); /** * Tests if the lane at index {@code i} is set * @param i the lane index * @return true if the lane at index {@code i} is set, otherwise false * @see #getElement */ public boolean isSet(int i) { return getElement(i); } } /** * A {@code Shuffle} represents an ordered immutable sequence of * {@code int} values. A Shuffle can be used with a shuffle accepting * vector operation to control the rearrangement of lane elements of input * vectors *

* The number of values in the sequence is referred to as the Shuffle * {@link #length() length}. The length also corresponds to the number of * Shuffle lanes. The lane element at lane index {@code N} (from {@code 0}, * inclusive, to length, exclusive) corresponds to the {@code N + 1}'th * value in the sequence. * A Shuffle and Vector of the same element type and shape have the same * number of lanes. *

* A Shuffle describes how a lane element of a vector may cross lanes from * its lane index, {@code i} say, to another lane index whose value is the * Shuffle's lane element at lane index {@code i}. Shuffle lane elements * will be in the range of {@code 0} (inclusive) to the shuffle length * (exclusive), and therefore cannot induce out of bounds errors when * used with vectors operations and vectors of the same length. * * @param the boxed element type of this mask */ public static abstract class Shuffle { Shuffle() {} /** * Returns the species of this shuffle. * * @return the species of this shuffle */ public abstract Species species(); /** * Returns the number of shuffle lanes (the length). * * @return the number of shuffle lanes */ public int length() { return species().length(); } /** * Converts this shuffle to a shuffle of the given species of element type {@code F}. *

* For each shuffle lane, where {@code N} is the lane index, the * shuffle element at index {@code N} is placed, unmodified, into the * resulting shuffle at index {@code N}. * * @param species species of desired shuffle * @param the boxed element type of the species * @return a shuffle converted by shape and element type * @throws IllegalArgumentException if this shuffle length and the * species length differ */ public abstract Shuffle cast(Species species); /** * Returns an {@code int} array containing the lane elements of this * shuffle. *

* This method behaves as if it {@link #intoArray(int[], int)} stores} * this shuffle into an allocated array and returns that array as * follows: *

{@code
         *   int[] a = new int[this.length()];
         *   this.intoArray(a, 0);
         *   return a;
         * }
* * @return an array containing the the lane elements of this vector */ public abstract int[] toArray(); /** * Stores this shuffle into an {@code int} array starting at offset. *

* For each shuffle lane, where {@code N} is the shuffle lane index, * the lane element at index {@code N} is stored into the array at index * {@code i + N}. * * @param a the array * @param i the offset into the array * @throws IndexOutOfBoundsException if {@code i < 0}, or * {@code i > a.length - this.length()} */ public abstract void intoArray(int[] a, int i); /** * Converts this shuffle into a vector, creating a vector from shuffle * lane elements (int values) cast to the vector element type. *

* This method behaves as if it returns the result of creating a * vector given an {@code int} array obtained from this shuffle's * lane elements, as follows: *

{@code
         *   int[] sa = this.toArray();
         *   $type$[] va = new $type$[a.length];
         *   for (int i = 0; i < a.length; i++) {
         *       va[i] = ($type$) sa[i];
         *   }
         *   return this.species().fromArray(va, 0);
         * }
* * @return a vector representation of this shuffle */ public abstract Vector toVector(); /** * Gets the {@code int} lane element at lane index {@code i} * * @param i the lane index * @return the {@code int} lane element at lane index {@code i} */ public int getElement(int i) { return toArray()[i]; } /** * Rearranges the lane elements of this shuffle selecting lane indexes * controlled by another shuffle. *

* For each lane of the shuffle, at lane index {@code N} with lane * element {@code I}, the lane element at {@code I} from this shuffle is * selected and placed into the resulting shuffle at {@code N}. * * @param s the shuffle controlling lane index selection * @return the rearrangement of the lane elements of this shuffle */ public abstract Shuffle rearrange(Shuffle s); } /** * Find bit size based on element type and number of elements. * * @param c the element type * @param numElem number of lanes in the vector * @return size in bits for vector */ public static int bitSizeForVectorLength(Class c, int numElem) { if (c == float.class) { return Float.SIZE * numElem; } else if (c == double.class) { return Double.SIZE * numElem; } else if (c == byte.class) { return Byte.SIZE * numElem; } else if (c == short.class) { return Short.SIZE * numElem; } else if (c == int.class) { return Integer.SIZE * numElem; } else if (c == long.class) { return Long.SIZE * numElem; } else { throw new IllegalArgumentException("Bad vector type: " + c.getName()); } } }