/* * Copyright (c) 2017, 2019, 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 java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; import java.util.function.BinaryOperator; import java.util.function.IntUnaryOperator; import java.util.function.Function; import java.util.function.UnaryOperator; import java.util.concurrent.ThreadLocalRandom; import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; import static jdk.incubator.vector.VectorIntrinsics.*; import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // /** * A specialized {@link Vector} representing an ordered immutable sequence of * {@code byte} values. */ @SuppressWarnings("cast") // warning: redundant cast public abstract class ByteVector extends AbstractVector { ByteVector() {} static final int FORBID_OPCODE_KIND = VO_ONLYFP; @ForceInline static int opCode(Operator op) { return VectorOperators.opCode(op, VO_OPCODE_VALID, FORBID_OPCODE_KIND); } @ForceInline static int opCode(Operator op, int requireKind) { requireKind |= VO_OPCODE_VALID; return VectorOperators.opCode(op, requireKind, FORBID_OPCODE_KIND); } @ForceInline static boolean opKind(Operator op, int bit) { return VectorOperators.opKind(op, bit); } // Virtualized factories and operators, // coded with portable definitions. // These are all @ForceInline in case // they need to be used performantly. // The various shape-specific subclasses // also specialize them by wrapping // them in a call like this: // return (Byte128Vector) // super.bOp((Byte128Vector) o); // The purpose of that is to forcibly inline // the generic definition from this file // into a sharply type- and size-specific // wrapper in the subclass file, so that // the JIT can specialize the code. // The code is only inlined and expanded // if it gets hot. Think of it as a cheap // and lazy version of C++ templates. // Virtualized getter /*package-private*/ abstract byte[] vec(); // Virtualized constructors /** * Build a vector directly using my own constructor. * It is an error if the array is aliased elsewhere. */ /*package-private*/ abstract ByteVector vectorFactory(byte[] vec); /** * Build a mask directly using my species. * It is an error if the array is aliased elsewhere. */ /*package-private*/ @ForceInline final AbstractMask maskFactory(boolean[] bits) { return vspecies().maskFactory(bits); } // Constant loader (takes dummy as vector arg) interface FVOp { byte apply(int i); } /*package-private*/ @ForceInline final ByteVector vOp(FVOp f) { byte[] res = new byte[length()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(i); } return vectorFactory(res); } @ForceInline final ByteVector vOp(VectorMask m, FVOp f) { byte[] res = new byte[length()]; boolean[] mbits = ((AbstractMask)m).getBits(); for (int i = 0; i < res.length; i++) { if (mbits[i]) { res[i] = f.apply(i); } } return vectorFactory(res); } // Unary operator /*package-private*/ interface FUnOp { byte apply(int i, byte a); } /*package-private*/ abstract ByteVector uOp(FUnOp f); @ForceInline final ByteVector uOpTemplate(FUnOp f) { byte[] vec = vec(); byte[] res = new byte[length()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, vec[i]); } return vectorFactory(res); } /*package-private*/ abstract ByteVector uOp(VectorMask m, FUnOp f); @ForceInline final ByteVector uOpTemplate(VectorMask m, FUnOp f) { byte[] vec = vec(); byte[] res = new byte[length()]; boolean[] mbits = ((AbstractMask)m).getBits(); for (int i = 0; i < res.length; i++) { res[i] = mbits[i] ? f.apply(i, vec[i]) : vec[i]; } return vectorFactory(res); } // Binary operator /*package-private*/ interface FBinOp { byte apply(int i, byte a, byte b); } /*package-private*/ abstract ByteVector bOp(Vector o, FBinOp f); @ForceInline final ByteVector bOpTemplate(Vector o, FBinOp f) { byte[] res = new byte[length()]; byte[] vec1 = this.vec(); byte[] vec2 = ((ByteVector)o).vec(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, vec1[i], vec2[i]); } return vectorFactory(res); } /*package-private*/ abstract ByteVector bOp(Vector o, VectorMask m, FBinOp f); @ForceInline final ByteVector bOpTemplate(Vector o, VectorMask m, FBinOp f) { byte[] res = new byte[length()]; byte[] vec1 = this.vec(); byte[] vec2 = ((ByteVector)o).vec(); boolean[] mbits = ((AbstractMask)m).getBits(); for (int i = 0; i < res.length; i++) { res[i] = mbits[i] ? f.apply(i, vec1[i], vec2[i]) : vec1[i]; } return vectorFactory(res); } // Ternary operator /*package-private*/ interface FTriOp { byte apply(int i, byte a, byte b, byte c); } /*package-private*/ abstract ByteVector tOp(Vector o1, Vector o2, FTriOp f); @ForceInline final ByteVector tOpTemplate(Vector o1, Vector o2, FTriOp f) { byte[] res = new byte[length()]; byte[] vec1 = this.vec(); byte[] vec2 = ((ByteVector)o1).vec(); byte[] vec3 = ((ByteVector)o2).vec(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, vec1[i], vec2[i], vec3[i]); } return vectorFactory(res); } /*package-private*/ abstract ByteVector tOp(Vector o1, Vector o2, VectorMask m, FTriOp f); @ForceInline final ByteVector tOpTemplate(Vector o1, Vector o2, VectorMask m, FTriOp f) { byte[] res = new byte[length()]; byte[] vec1 = this.vec(); byte[] vec2 = ((ByteVector)o1).vec(); byte[] vec3 = ((ByteVector)o2).vec(); boolean[] mbits = ((AbstractMask)m).getBits(); for (int i = 0; i < res.length; i++) { res[i] = mbits[i] ? f.apply(i, vec1[i], vec2[i], vec3[i]) : vec1[i]; } return vectorFactory(res); } // Reduction operator /*package-private*/ abstract byte rOp(byte v, FBinOp f); @ForceInline final byte rOpTemplate(byte v, FBinOp f) { byte[] vec = vec(); for (int i = 0; i < vec.length; i++) { v = f.apply(i, v, vec[i]); } return v; } // Memory reference /*package-private*/ interface FLdOp { byte apply(M memory, int offset, int i); } /*package-private*/ @ForceInline final ByteVector ldOp(M memory, int offset, FLdOp f) { //dummy; no vec = vec(); byte[] res = new byte[length()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(memory, offset, i); } return vectorFactory(res); } /*package-private*/ @ForceInline final ByteVector ldOp(M memory, int offset, VectorMask m, FLdOp f) { //byte[] vec = vec(); byte[] res = new byte[length()]; boolean[] mbits = ((AbstractMask)m).getBits(); for (int i = 0; i < res.length; i++) { if (mbits[i]) { res[i] = f.apply(memory, offset, i); } } return vectorFactory(res); } interface FStOp { void apply(M memory, int offset, int i, byte a); } /*package-private*/ @ForceInline final void stOp(M memory, int offset, FStOp f) { byte[] vec = vec(); for (int i = 0; i < vec.length; i++) { f.apply(memory, offset, i, vec[i]); } } /*package-private*/ @ForceInline final void stOp(M memory, int offset, VectorMask m, FStOp f) { byte[] vec = vec(); boolean[] mbits = ((AbstractMask)m).getBits(); for (int i = 0; i < vec.length; i++) { if (mbits[i]) { f.apply(memory, offset, i, vec[i]); } } } // Binary test /*package-private*/ interface FBinTest { boolean apply(int cond, int i, byte a, byte b); } /*package-private*/ @ForceInline final AbstractMask bTest(int cond, Vector o, FBinTest f) { byte[] vec1 = vec(); byte[] vec2 = ((ByteVector)o).vec(); boolean[] bits = new boolean[length()]; for (int i = 0; i < length(); i++){ bits[i] = f.apply(cond, i, vec1[i], vec2[i]); } return maskFactory(bits); } /*package-private*/ @ForceInline static boolean doBinTest(int cond, byte a, byte b) { switch (cond) { case BT_eq: return a == b; case BT_ne: return a != b; case BT_lt: return a < b; case BT_le: return a <= b; case BT_gt: return a > b; case BT_ge: return a >= b; } throw new AssertionError(Integer.toHexString(cond)); } /*package-private*/ @Override abstract ByteSpecies vspecies(); /*package-private*/ @ForceInline static long toBits(byte e) { return e; } /*package-private*/ @ForceInline static byte fromBits(long bits) { return ((byte)bits); } // Static factories (other than memory operations) // Note: A surprising behavior in javadoc // sometimes makes a lone /** {@inheritDoc} */ // comment drop the method altogether, // apparently if the method mentions an // parameter or return type of Vector // instead of Vector as originally specified. // Adding an empty HTML fragment appears to // nudge javadoc into providing the desired // inherited documentation. We use the HTML // comment for this. /** * {@inheritDoc} */ @ForceInline public static ByteVector zero(VectorSpecies species) { ByteSpecies vsp = (ByteSpecies) species; return VectorIntrinsics.broadcastCoerced(vsp.vectorType(), byte.class, species.length(), 0, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); } /** * Returns a vector of the same species as this one * where all lane elements are set to * the primitive value {@code e}. * * The contents of the current vector are discarded; * only the species is relevant to this operation. * *

This method returns the value of this expression: * {@code ByteVector.broadcast(this.species(), e)}. * * @apiNote * Unlike the similar method named {@code broadcast()} * in the supertype {@code Vector}, this method does not * need to validate its argument, and cannot throw * {@code IllegalArgumentException}. This method is * therefore preferable to the supertype method. * * @param e the value to broadcast * @return a vector where all lane elements are set to * the primitive value {@code e} * @see #broadcast(VectorSpecies,long) * @see Vector#broadcast(long) * @see VectorSpecies#broadcast(long) */ public abstract ByteVector broadcast(byte e); /** * Returns a vector of the given species * where all lane elements are set to * the primitive value {@code e}. * * @param species species of the desired vector * @param e the value to broadcast * @return a vector where all lane elements are set to * the primitive value {@code e} * @see #broadcast(long) * @see Vector#broadcast(long) * @see VectorSpecies#broadcast(long) */ public static ByteVector broadcast(VectorSpecies species, byte e) { ByteSpecies vsp = (ByteSpecies) species; return vsp.broadcast(e); } /*package-private*/ @ForceInline final ByteVector broadcastTemplate(byte e) { ByteSpecies vsp = vspecies(); return vsp.broadcast(e); } /** * {@inheritDoc} * @apiNote * When working with vector subtypes like {@code ByteVector}, * {@linkplain #broadcast(byte) the more strongly typed method} * is typically selected. It can be explicitly selected * using a cast: {@code v.broadcast((byte)e)}. * The two expressions will produce numerically identical results. */ @Override public abstract ByteVector broadcast(long e); /** * Returns a vector of the given species * where all lane elements are set to * the primitive value {@code e}. * * The {@code long} value must be accurately representable * by the {@code ETYPE} of the vector species, so that * {@code e==(long)(ETYPE)e}. * * @param species species of the desired vector * @param e the value to broadcast * @return a vector where all lane elements are set to * the primitive value {@code e} * @throws IllegalArgumentException * if the given {@code long} value cannot * be represented by the vector's {@code ETYPE} * @see #broadcast(VectorSpecies,byte) * @see VectorSpecies#checkValue(long) */ public static ByteVector broadcast(VectorSpecies species, long e) { ByteSpecies vsp = (ByteSpecies) species; return vsp.broadcast(e); } /*package-private*/ @ForceInline final ByteVector broadcastTemplate(long e) { return vspecies().broadcast(e); } /** * Returns a vector where each lane element is set to given * primitive values. *

* For each vector lane, where {@code N} is the vector lane index, the * the primitive value at index {@code N} is placed into the resulting * vector at lane index {@code N}. * * @param species species of the desired vector * @param es the given primitive values * @return a vector where each lane element is set to given primitive * values * @throws IllegalArgumentException * if {@code es.length != species.length()} */ @ForceInline @SuppressWarnings("unchecked") public static ByteVector fromValues(VectorSpecies species, byte... es) { ByteSpecies vsp = (ByteSpecies) species; int vlength = vsp.laneCount(); VectorIntrinsics.requireLength(es.length, vlength); // Get an unaliased copy and use it directly: return vsp.vectorFactory(Arrays.copyOf(es, vlength)); } /** * Returns a vector where the first lane element is set to the primtive * value {@code e}, all other lane elements are set to the default * value(zero). * * @param species species of the desired vector * @param e the value * @return a vector where the first lane element is set to the primitive * value {@code e} */ // FIXME: Does this carry its weight? @ForceInline public static ByteVector single(VectorSpecies species, byte e) { return zero(species).withLane(0, e); } /** * Returns a vector where each lane element is set to a randomly * generated primitive value. * * The semantics are equivalent to calling * {@code (byte)}{@link ThreadLocalRandom#nextInt()} * for each lane, from first to last. * * @param species species of the desired vector * @return a vector where each lane elements is set to a randomly * generated primitive value */ public static ByteVector random(VectorSpecies species) { ByteSpecies vsp = (ByteSpecies) species; ThreadLocalRandom r = ThreadLocalRandom.current(); return vsp.vOp(i -> nextRandom(r)); } private static byte nextRandom(ThreadLocalRandom r) { return (byte) r.nextInt(); } // Unary lanewise support /** * {@inheritDoc} */ public abstract ByteVector lanewise(VectorOperators.Unary op); @ForceInline final ByteVector lanewiseTemplate(VectorOperators.Unary op) { if (opKind(op, VO_SPECIAL)) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } if (op == NEG) { // FIXME: Support this in the JIT. return broadcast(0).lanewiseTemplate(SUB, this); } } int opc = opCode(op); return VectorIntrinsics.unaryOp( opc, getClass(), byte.class, length(), this, UN_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_NEG: return v0 -> v0.uOp((i, a) -> (byte) -a); case VECTOR_OP_ABS: return v0 -> v0.uOp((i, a) -> (byte) Math.abs(a)); case VECTOR_OP_NOT: return v0 -> v0.uOp((i, a) -> (byte) ~a); default: return null; }})); } private static final ImplCache> UN_IMPL = new ImplCache<>(Unary.class, ByteVector.class); /** * {@inheritDoc} */ @ForceInline public final ByteVector lanewise(VectorOperators.Unary op, VectorMask m) { return blend(lanewise(op), m); } // Binary lanewise support /** * {@inheritDoc} * @see #lanewise(VectorOperators.Binary,byte) * @see #lanewise(VectorOperators.Binary,byte,VectorMask) */ @Override public abstract ByteVector lanewise(VectorOperators.Binary op, Vector v); @ForceInline final ByteVector lanewiseTemplate(VectorOperators.Binary op, Vector v) { ByteVector that = (ByteVector) v; that.check(this); if (opKind(op, VO_SPECIAL | VO_SHIFT)) { if (op == FIRST_NONZERO) { // FIXME: Support this in the JIT. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (byte) 0); that = that.blend((byte) 0, thisNZ.cast(vspecies())); op = OR_UNCHECKED; } if (opKind(op, VO_SHIFT)) { // As per shift specification for Java, mask the shift count. // This allows the JIT to ignore some ISA details. that = that.lanewise(AND, SHIFT_MASK); } if (op == ROR || op == ROL) { // FIXME: JIT should do this ByteVector neg = that.lanewise(NEG); ByteVector hi = this.lanewise(LSHL, (op == ROR) ? neg : that); ByteVector lo = this.lanewise(LSHR, (op == ROR) ? that : neg); return hi.lanewise(OR, lo); } else if (op == AND_NOT) { // FIXME: Support this in the JIT. that = that.lanewise(NOT); op = AND; } else if (op == DIV) { VectorMask eqz = that.eq((byte)0); if (eqz.anyTrue()) { throw that.divZeroException(); } } } int opc = opCode(op); return VectorIntrinsics.binaryOp( opc, getClass(), byte.class, length(), this, that, BIN_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_ADD: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a + b)); case VECTOR_OP_SUB: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a - b)); case VECTOR_OP_MUL: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a * b)); case VECTOR_OP_DIV: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a / b)); case VECTOR_OP_MAX: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)Math.max(a, b)); case VECTOR_OP_MIN: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)Math.min(a, b)); case VECTOR_OP_FIRST_NONZERO: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> toBits(a) != 0 ? a : b); case VECTOR_OP_AND: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a & b)); case VECTOR_OP_OR: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a | b)); case VECTOR_OP_AND_NOT: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a & ~b)); case VECTOR_OP_XOR: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> (byte)(a ^ b)); case VECTOR_OP_LSHIFT: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> (byte)(a << n)); case VECTOR_OP_RSHIFT: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> (byte)(a >> n)); case VECTOR_OP_URSHIFT: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> (byte)((a & LSHR_SETUP_MASK) >>> n)); case VECTOR_OP_LROTATE: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> (byte)((a << n)|(a >> -n))); case VECTOR_OP_RROTATE: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> (byte)((a >> n)|(a << -n))); default: return null; }})); } private static final ImplCache> BIN_IMPL = new ImplCache<>(Binary.class, ByteVector.class); /** * {@inheritDoc} * @see #lanewise(VectorOperators.Binary,byte,VectorMask) */ @ForceInline public final ByteVector lanewise(VectorOperators.Binary op, Vector v, VectorMask m) { ByteVector that = (ByteVector) v; if (op == DIV) { // suppress div/0 exceptions in unset lanes that = that.lanewise(NOT, that.eq((byte)0)); return blend(lanewise(DIV, that), m); } return blend(lanewise(op, v), m); } // FIXME: Maybe all of the public final methods in this file (the // simple ones that just call lanewise) should be pushed down to // the X-VectorBits template. They can't optimize properly at // this level, and must rely on inlining. Does it work? // (If it works, of course keep the code here.) /** * Combines the lane values of this vector * with the value of a broadcast scalar. * * This is a lane-wise binary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, this.broadcast(e))}. * * @param op the operation used to process lane values * @param e the input scalar * @return the result of applying the operation lane-wise * to the two input vectors * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte,VectorMask) */ @ForceInline public final ByteVector lanewise(VectorOperators.Binary op, byte e) { int opc = opCode(op); if (opKind(op, VO_SHIFT) && (byte)(int)e == e) { return lanewiseShift(op, (int) e); } if (op == AND_NOT) { op = AND; e = (byte) ~e; } return lanewise(op, broadcast(e)); } /** * Combines the lane values of this vector * with the value of a broadcast scalar, * with selection of lane elements controlled by a mask. * * This is a masked lane-wise binary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, this.broadcast(e), m)}. * * @param op the operation used to process lane values * @param e the input scalar * @param m the mask controlling lane selection * @return the result of applying the operation lane-wise * to the input vector and the scalar * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector lanewise(VectorOperators.Binary op, byte e, VectorMask m) { return blend(lanewise(op, e), m); } /** * {@inheritDoc} * @apiNote * When working with vector subtypes like {@code ByteVector}, * {@linkplain #lanewise(VectorOperators.Binary,byte) * the more strongly typed method} * is typically selected. It can be explicitly selected * using a cast: {@code v.lanewise(op,(byte)e)}. * The two expressions will produce numerically identical results. */ @ForceInline public final ByteVector lanewise(VectorOperators.Binary op, long e) { byte e1 = (byte) e; if ((long)e1 != e // allow shift ops to clip down their int parameters && !(opKind(op, VO_SHIFT) && (int)e1 == e) ) { vspecies().checkValue(e); // for exception } return lanewise(op, e1); } /** * {@inheritDoc} * @apiNote * When working with vector subtypes like {@code ByteVector}, * {@linkplain #lanewise(VectorOperators.Binary,byte,VectorMask) * the more strongly typed method} * is typically selected. It can be explicitly selected * using a cast: {@code v.lanewise(op,(byte)e,m)}. * The two expressions will produce numerically identical results. */ @ForceInline public final ByteVector lanewise(VectorOperators.Binary op, long e, VectorMask m) { return blend(lanewise(op, e), m); } /*package-private*/ abstract ByteVector lanewiseShift(VectorOperators.Binary op, int e); /*package-private*/ @ForceInline final ByteVector lanewiseShiftTemplate(VectorOperators.Binary op, int e) { // Special handling for these. FIXME: Refactor? int opc = opCode(op); assert(opKind(op, VO_SHIFT)); // As per shift specification for Java, mask the shift count. e &= SHIFT_MASK; if (op == ROR || op == ROL) { // FIXME: JIT should do this ByteVector hi = this.lanewise(LSHL, (op == ROR) ? -e : e); ByteVector lo = this.lanewise(LSHR, (op == ROR) ? e : -e); return hi.lanewise(OR, lo); } return VectorIntrinsics.broadcastInt( opc, getClass(), byte.class, length(), this, e, BIN_INT_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_LSHIFT: return (v, n) -> v.uOp((i, a) -> (byte)(a << n)); case VECTOR_OP_RSHIFT: return (v, n) -> v.uOp((i, a) -> (byte)(a >> n)); case VECTOR_OP_URSHIFT: return (v, n) -> v.uOp((i, a) -> (byte)((a & LSHR_SETUP_MASK) >>> n)); case VECTOR_OP_LROTATE: return (v, n) -> v.uOp((i, a) -> (byte)((a << n)|(a >> -n))); case VECTOR_OP_RROTATE: return (v, n) -> v.uOp((i, a) -> (byte)((a >> n)|(a << -n))); default: return null; }})); } private static final ImplCache> BIN_INT_IMPL = new ImplCache<>(Binary.class, ByteVector.class); // As per shift specification for Java, mask the shift count. // We mask 0X3F (long), 0X1F (int), 0x0F (short), 0x7 (byte). // The latter two maskings go beyond the JLS, but seem reasonable // since our lane types are first-class types, not just dressed // up ints. private static final int SHIFT_MASK = (Byte.SIZE - 1); // Also simulate >>> on sub-word variables with a mask. private static final int LSHR_SETUP_MASK = ((1 << Byte.SIZE) - 1); // Ternary lanewise support // Ternary operators come in eight variations: // lanewise(op, [broadcast(e1)|v1], [broadcast(e2)|v2]) // lanewise(op, [broadcast(e1)|v1], [broadcast(e2)|v2], mask) // It is annoying to support all of these variations of masking // and broadcast, but it would be more surprising not to continue // the obvious pattern started by unary and binary. /** * {@inheritDoc} * @see #lanewise(VectorOperators.Ternary,byte,byte,VectorMask) * @see #lanewise(VectorOperators.Ternary,Vector,byte,VectorMask) * @see #lanewise(VectorOperators.Ternary,byte,Vector,VectorMask) * @see #lanewise(VectorOperators.Ternary,byte,byte) * @see #lanewise(VectorOperators.Ternary,Vector,byte) * @see #lanewise(VectorOperators.Ternary,byte,Vector) */ @Override public abstract ByteVector lanewise(VectorOperators.Ternary op, Vector v1, Vector v2); @ForceInline final ByteVector lanewiseTemplate(VectorOperators.Ternary op, Vector v1, Vector v2) { ByteVector that = (ByteVector) v1; ByteVector tother = (ByteVector) v2; // It's a word: https://www.dictionary.com/browse/tother // See also Chapter 11 of Dickens, Our Mutual Friend: // "Totherest Governor," replied Mr Riderhood... that.check(this); tother.check(this); if (op == BITWISE_BLEND) { // FIXME: Support this in the JIT. that = this.lanewise(XOR, that).lanewise(AND, tother); return this.lanewise(XOR, that); } int opc = opCode(op); return VectorIntrinsics.ternaryOp( opc, getClass(), byte.class, length(), this, that, tother, TERN_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_BITWISE_BLEND: return (v0, v1_, v2_) -> v0.tOp(v1_, v2_, (i, a, b, c) -> (byte)(a^((a^b)&c))); default: return null; }})); } private static final ImplCache> TERN_IMPL = new ImplCache<>(Ternary.class, ByteVector.class); /** * {@inheritDoc} * @see #lanewise(VectorOperators.Ternary,byte,byte,VectorMask) * @see #lanewise(VectorOperators.Ternary,Vector,byte,VectorMask) * @see #lanewise(VectorOperators.Ternary,byte,Vector,VectorMask) */ @ForceInline public final ByteVector lanewise(VectorOperators.Ternary op, Vector v1, Vector v2, VectorMask m) { return blend(lanewise(op, v1, v2), m); } /** * Combines the lane values of this vector * with the values of two broadcast scalars. * * This is a lane-wise ternary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, this.broadcast(e1), this.broadcast(e2))}. * * @param op the operation used to combine lane values * @param e1 the first input scalar * @param e2 the second input scalar * @return the result of applying the operation lane-wise * to the input vector and the scalars * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Ternary,Vector,Vector) * @see #lanewise(VectorOperators.Ternary,byte,byte,VectorMask) */ @ForceInline public final ByteVector lanewise(VectorOperators.Ternary op, //(op,e1,e2) byte e1, byte e2) { return lanewise(op, broadcast(e1), broadcast(e2)); } /** * Combines the lane values of this vector * with the values of two broadcast scalars, * with selection of lane elements controlled by a mask. * * This is a masked lane-wise ternary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, this.broadcast(e1), this.broadcast(e2), m)}. * * @param op the operation used to combine lane values * @param e1 the first input scalar * @param e2 the second input scalar * @param m the mask controlling lane selection * @return the result of applying the operation lane-wise * to the input vector and the scalars * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Ternary,Vector,Vector,VectorMask) * @see #lanewise(VectorOperators.Ternary,byte,byte) */ @ForceInline public final ByteVector lanewise(VectorOperators.Ternary op, //(op,e1,e2,m) byte e1, byte e2, VectorMask m) { return blend(lanewise(op, e1, e2), m); } /** * Combines the lane values of this vector * with the values of another vector and a broadcast scalar. * * This is a lane-wise ternary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, v1, this.broadcast(e2))}. * * @param op the operation used to combine lane values * @param v1 the other input vector * @param e2 the input scalar * @return the result of applying the operation lane-wise * to the input vectors and the scalar * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Ternary,byte,byte) * @see #lanewise(VectorOperators.Ternary,Vector,byte,VectorMask) */ @ForceInline public final ByteVector lanewise(VectorOperators.Ternary op, //(op,v1,e2) Vector v1, byte e2) { return lanewise(op, v1, broadcast(e2)); } /** * Combines the lane values of this vector * with the values of another vector and a broadcast scalar, * with selection of lane elements controlled by a mask. * * This is a masked lane-wise ternary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, v1, this.broadcast(e2), m)}. * * @param op the operation used to combine lane values * @param v1 the other input vector * @param e2 the input scalar * @param m the mask controlling lane selection * @return the result of applying the operation lane-wise * to the input vectors and the scalar * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Ternary,Vector,Vector) * @see #lanewise(VectorOperators.Ternary,byte,byte,VectorMask) * @see #lanewise(VectorOperators.Ternary,Vector,byte) */ @ForceInline public final ByteVector lanewise(VectorOperators.Ternary op, //(op,v1,e2,m) Vector v1, byte e2, VectorMask m) { return blend(lanewise(op, v1, e2), m); } /** * Combines the lane values of this vector * with the values of another vector and a broadcast scalar. * * This is a lane-wise ternary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, this.broadcast(e1), v2)}. * * @param op the operation used to combine lane values * @param e1 the input scalar * @param v2 the other input vector * @return the result of applying the operation lane-wise * to the input vectors and the scalar * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Ternary,Vector,Vector) * @see #lanewise(VectorOperators.Ternary,byte,Vector,VectorMask) */ @ForceInline public final ByteVector lanewise(VectorOperators.Ternary op, //(op,e1,v2) byte e1, Vector v2) { return lanewise(op, broadcast(e1), v2); } /** * Combines the lane values of this vector * with the values of another vector and a broadcast scalar, * with selection of lane elements controlled by a mask. * * This is a masked lane-wise ternary operation which applies * the selected operation to each lane. * The return value will be equal to this expression: * {@code this.lanewise(op, this.broadcast(e1), v2, m)}. * * @param op the operation used to combine lane values * @param e1 the input scalar * @param v2 the other input vector * @param m the mask controlling lane selection * @return the result of applying the operation lane-wise * to the input vectors and the scalar * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #lanewise(VectorOperators.Ternary,Vector,Vector,VectorMask) * @see #lanewise(VectorOperators.Ternary,byte,Vector) */ @ForceInline public final ByteVector lanewise(VectorOperators.Ternary op, //(op,e1,v2,m) byte e1, Vector v2, VectorMask m) { return blend(lanewise(op, e1, v2), m); } // (Thus endeth the Great and Mighty Ternary Ogdoad.) // https://en.wikipedia.org/wiki/Ogdoad /// FULL-SERVICE BINARY METHODS: ADD, SUB, MUL, DIV // // These include masked and non-masked versions. // This subclass adds broadcast (masked or not). /** * {@inheritDoc} * @see #add(byte) */ @Override @ForceInline public final ByteVector add(Vector v) { return lanewise(ADD, v); } /** * Adds this vector to the broadcast of an input scalar. * * This is a lane-wise binary operation which applies * the primitive addition operation ({@code +}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte) * lanewise}{@code (}{@link VectorOperators#ADD * ADD}{@code , e)}. * * @param e the input scalar * @return the result of adding each lane of this vector to the scalar * @see #add(Vector) * @see #broadcast(byte) * @see #add(byte,VectorMask) * @see VectorOperators#ADD * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector add(byte e) { return lanewise(ADD, e); } /** * {@inheritDoc} * @see #add(byte,VectorMask) */ @Override @ForceInline public final ByteVector add(Vector v, VectorMask m) { return lanewise(ADD, v, m); } /** * Adds this vector to the broadcast of an input scalar, * selecting lane elements controlled by a mask. * * This is a masked lane-wise binary operation which applies * the primitive addition operation ({@code +}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte,VectorMask) * lanewise}{@code (}{@link VectorOperators#ADD * ADD}{@code , s, m)}. * * @param e the input scalar * @param m the mask controlling lane selection * @return the result of adding each lane of this vector to the scalar * @see #add(Vector,VectorMask) * @see #broadcast(byte) * @see #add(byte) * @see VectorOperators#ADD * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector add(byte e, VectorMask m) { return lanewise(ADD, e, m); } /** * {@inheritDoc} * @see #sub(byte) */ @Override @ForceInline public final ByteVector sub(Vector v) { return lanewise(SUB, v); } /** * Subtracts an input scalar from this vector. * * This is a masked lane-wise binary operation which applies * the primitive subtraction operation ({@code -}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte) * lanewise}{@code (}{@link VectorOperators#SUB * SUB}{@code , e)}. * * @param e the input scalar * @return the result of subtracting the scalar from each lane of this vector * @see #sub(Vector) * @see #broadcast(byte) * @see #sub(byte,VectorMask) * @see VectorOperators#SUB * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector sub(byte e) { return lanewise(SUB, e); } /** * {@inheritDoc} * @see #sub(byte,VectorMask) */ @Override @ForceInline public final ByteVector sub(Vector v, VectorMask m) { return lanewise(SUB, v, m); } /** * Subtracts an input scalar from this vector * under the control of a mask. * * This is a masked lane-wise binary operation which applies * the primitive subtraction operation ({@code -}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte,VectorMask) * lanewise}{@code (}{@link VectorOperators#SUB * SUB}{@code , s, m)}. * * @param e the input scalar * @param m the mask controlling lane selection * @return the result of subtracting the scalar from each lane of this vector * @see #sub(Vector,VectorMask) * @see #broadcast(byte) * @see #sub(byte) * @see VectorOperators#SUB * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector sub(byte e, VectorMask m) { return lanewise(SUB, e, m); } /** * {@inheritDoc} * @see #mul(byte) */ @Override @ForceInline public final ByteVector mul(Vector v) { return lanewise(MUL, v); } /** * Multiplies this vector by the broadcast of an input scalar. * * This is a lane-wise binary operation which applies * the primitive multiplication operation ({@code *}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte) * lanewise}{@code (}{@link VectorOperators#MUL * MUL}{@code , e)}. * * @param e the input scalar * @return the result of multiplying this vector by the given scalar * @see #mul(Vector) * @see #broadcast(byte) * @see #mul(byte,VectorMask) * @see VectorOperators#MUL * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector mul(byte e) { return lanewise(MUL, e); } /** * {@inheritDoc} * @see #mul(byte,VectorMask) */ @Override @ForceInline public final ByteVector mul(Vector v, VectorMask m) { return lanewise(MUL, v, m); } /** * Multiplies this vector by the broadcast of an input scalar, * selecting lane elements controlled by a mask. * * This is a masked lane-wise binary operation which applies * the primitive multiplication operation ({@code *}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte,VectorMask) * lanewise}{@code (}{@link VectorOperators#MUL * MUL}{@code , s, m)}. * * @param e the input scalar * @param m the mask controlling lane selection * @return the result of muling each lane of this vector to the scalar * @see #mul(Vector,VectorMask) * @see #broadcast(byte) * @see #mul(byte) * @see VectorOperators#MUL * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector mul(byte e, VectorMask m) { return lanewise(MUL, e, m); } /** * {@inheritDoc} * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. * @see #div(byte) */ @Override @ForceInline public final ByteVector div(Vector v) { return lanewise(DIV, v); } /** * Divides this vector by the broadcast of an input scalar. * * This is a lane-wise binary operation which applies * the primitive division operation ({@code /}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte) * lanewise}{@code (}{@link VectorOperators#DIV * DIV}{@code , e)}. * * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. * @see #div(byte) * * @param e the input scalar * @return the result of dividing each lane of this vector by the scalar * @see #div(Vector) * @see #broadcast(byte) * @see #div(byte,VectorMask) * @see VectorOperators#DIV * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector div(byte e) { return lanewise(DIV, e); } /** * {@inheritDoc} * @see #div(byte,VectorMask) * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. */ @Override @ForceInline public final ByteVector div(Vector v, VectorMask m) { return lanewise(DIV, v, m); } /** * Divides this vector by the broadcast of an input scalar, * selecting lane elements controlled by a mask. * * This is a masked lane-wise binary operation which applies * the primitive division operation ({@code /}) to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte,VectorMask) * lanewise}{@code (}{@link VectorOperators#DIV * DIV}{@code , s, m)}. * * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. * * @param e the input scalar * @param m the mask controlling lane selection * @return the result of dividing each lane of this vector by the scalar * @see #div(Vector,VectorMask) * @see #broadcast(byte) * @see #div(byte) * @see VectorOperators#DIV * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,byte) */ @ForceInline public final ByteVector div(byte e, VectorMask m) { return lanewise(DIV, e, m); } /// END OF FULL-SERVICE BINARY METHODS /// SECOND-TIER BINARY METHODS // // There are no masked versions. /** * {@inheritDoc} */ @Override @ForceInline public final ByteVector min(Vector v) { return lanewise(MIN, v); } // FIXME: "broadcast of an input scalar" is really wordy. Reduce? /** * Computes the smaller of this vector and the broadcast of an input scalar. * * This is a lane-wise binary operation which applies the * operation {@code Math.min()} to each pair of * corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte) * lanewise}{@code (}{@link VectorOperators#MIN * MIN}{@code , e)}. * * @param e the input scalar * @return the result of multiplying this vector by the given scalar * @see #min(Vector) * @see #broadcast(byte) * @see VectorOperators#MIN * @see #lanewise(VectorOperators.Binary,byte,VectorMask) */ @ForceInline public final ByteVector min(byte e) { return lanewise(MIN, e); } /** * {@inheritDoc} */ @Override @ForceInline public final ByteVector max(Vector v) { return lanewise(MAX, v); } /** * Computes the larger of this vector and the broadcast of an input scalar. * * This is a lane-wise binary operation which applies the * operation {@code Math.max()} to each pair of * corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,byte) * lanewise}{@code (}{@link VectorOperators#MAX * MAX}{@code , e)}. * * @param e the input scalar * @return the result of multiplying this vector by the given scalar * @see #max(Vector) * @see #broadcast(byte) * @see VectorOperators#MAX * @see #lanewise(VectorOperators.Binary,byte,VectorMask) */ @ForceInline public final ByteVector max(byte e) { return lanewise(MAX, e); } // common bitwise operators: and, or, not (with scalar versions) /** * Computes the bitwise logical conjunction ({@code &}) * of this vector and a second input vector. * * This is a lane-wise binary operation which applies the * the primitive bitwise "and" operation ({@code &}) * to each pair of corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,Vector) * lanewise}{@code (}{@link VectorOperators#AND * AND}{@code , v)}. * *

* This is not a full-service named operation like * {@link #add(Vector) add}. A masked version of * version of this operation is not directly available * but may be obtained via the masked version of * {@code lanewise}. * * @param v a second input vector * @return the bitwise {@code &} of this vector and the second input vector * @see #and(byte) * @see #or(Vector) * @see #not() * @see VectorOperators#AND * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) */ @ForceInline public final ByteVector and(Vector v) { return lanewise(AND, v); } /** * Computes the bitwise logical conjunction ({@code &}) * of this vector and a scalar. * * This is a lane-wise binary operation which applies the * the primitive bitwise "and" operation ({@code &}) * to each pair of corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,Vector) * lanewise}{@code (}{@link VectorOperators#AND * AND}{@code , e)}. * * @param e an input scalar * @return the bitwise {@code &} of this vector and scalar * @see #and(Vector) * @see VectorOperators#AND * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) */ @ForceInline public final ByteVector and(byte e) { return lanewise(AND, e); } /** * Computes the bitwise logical disjunction ({@code |}) * of this vector and a second input vector. * * This is a lane-wise binary operation which applies the * the primitive bitwise "or" operation ({@code |}) * to each pair of corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,Vector) * lanewise}{@code (}{@link VectorOperators#OR * AND}{@code , v)}. * *

* This is not a full-service named operation like * {@link #add(Vector) add}. A masked version of * version of this operation is not directly available * but may be obtained via the masked version of * {@code lanewise}. * * @param v a second input vector * @return the bitwise {@code |} of this vector and the second input vector * @see #or(byte) * @see #and(Vector) * @see #not() * @see VectorOperators#OR * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) */ @ForceInline public final ByteVector or(Vector v) { return lanewise(OR, v); } /** * Computes the bitwise logical disjunction ({@code |}) * of this vector and a scalar. * * This is a lane-wise binary operation which applies the * the primitive bitwise "or" operation ({@code |}) * to each pair of corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,Vector) * lanewise}{@code (}{@link VectorOperators#OR * OR}{@code , e)}. * * @param e an input scalar * @return the bitwise {@code |} of this vector and scalar * @see #or(Vector) * @see VectorOperators#OR * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) */ @ForceInline public final ByteVector or(byte e) { return lanewise(OR, e); } /// UNARY METHODS /** * {@inheritDoc} */ @Override @ForceInline public final ByteVector neg() { return lanewise(NEG); } /** * {@inheritDoc} */ @Override @ForceInline public final ByteVector abs() { return lanewise(ABS); } // not (~) /** * Computes the bitwise logical complement ({@code ~}) * of this vector. * * This is a lane-wise binary operation which applies the * the primitive bitwise "not" operation ({@code ~}) * to each lane value. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Unary) * lanewise}{@code (}{@link VectorOperators#NOT * NOT}{@code )}. * *

* This is not a full-service named operation like * {@link #add(Vector) add}. A masked version of * version of this operation is not directly available * but may be obtained via the masked version of * {@code lanewise}. * * @return the bitwise complement {@code ~} of this vector * @see #and(Vector) * @see VectorOperators#NOT * @see #lanewise(VectorOperators.Unary,VectorMask) */ @ForceInline public final ByteVector not() { return lanewise(NOT); } /// COMPARISONS /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask eq(Vector v) { return compare(EQ, v); } /** * Tests if this vector is equal to an input scalar. * * This is a lane-wise binary test operation which applies * the primitive equals operation ({@code ==}) to each lane. * The result is the same as {@code compare(VectorOperators.Comparison.EQ, e)}. * * @param e the input scalar * @return the result mask of testing if this vector * is equal to {@code e} * @see #compare(VectorOperators.Comparison,byte) */ @ForceInline public final VectorMask eq(byte e) { return compare(EQ, e); } /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask lt(Vector v) { return compare(LT, v); } /** * Tests if this vector is less than an input scalar. * * This is a lane-wise binary test operation which applies * the primitive less than operation ({@code <}) to each lane. * The result is the same as {@code compare(VectorOperators.LT, e)}. * * @param e the input scalar * @return the mask result of testing if this vector * is less than the input scalar * @see #compare(VectorOperators.Comparison,byte) */ @ForceInline public final VectorMask lt(byte e) { return compare(LT, e); } /** * {@inheritDoc} */ @Override public abstract VectorMask test(VectorOperators.Test op); /*package-private*/ @ForceInline final > M testTemplate(Class maskType, Test op) { ByteSpecies vsp = vspecies(); if (opKind(op, VO_SPECIAL)) { ByteVector bits = this.viewAsIntegralLanes(); VectorMask m; if (op == IS_DEFAULT) { m = bits.compare(EQ, (byte) 0); } else if (op == IS_NEGATIVE) { m = bits.compare(LT, (byte) 0); } else { throw new AssertionError(op); } return maskType.cast(m); } int opc = opCode(op); throw new AssertionError(op); } /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask test(VectorOperators.Test op, VectorMask m) { return test(op).and(m); } /** * {@inheritDoc} */ @Override public abstract VectorMask compare(VectorOperators.Comparison op, Vector v); /*package-private*/ @ForceInline final > M compareTemplate(Class maskType, Comparison op, Vector v) { Objects.requireNonNull(v); ByteSpecies vsp = vspecies(); ByteVector that = (ByteVector) v; that.check(this); int opc = opCode(op); return VectorIntrinsics.compare( opc, getClass(), maskType, byte.class, length(), this, that, (cond, v0, v1) -> { AbstractMask m = v0.bTest(cond, v1, (cond_, i, a, b) -> compareWithOp(cond, a, b)); @SuppressWarnings("unchecked") M m2 = (M) m; return m2; }); } @ForceInline private static boolean compareWithOp(int cond, byte a, byte b) { switch (cond) { case VectorIntrinsics.BT_eq: return a == b; case VectorIntrinsics.BT_ne: return a != b; case VectorIntrinsics.BT_lt: return a < b; case VectorIntrinsics.BT_le: return a <= b; case VectorIntrinsics.BT_gt: return a > b; case VectorIntrinsics.BT_ge: return a >= b; } throw new AssertionError(); } /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask compare(VectorOperators.Comparison op, Vector v, VectorMask m) { return compare(op, v).and(m); } /** * Tests this vector by comparing it with an input scalar, * according to the given comparison operation. * * This is a lane-wise binary test operation which applies * the comparison operation to each lane. *

* The result is the same as * {@code compare(op, broadcast(species(), e))}. * That is, the scalar may be regarded as broadcast to * a vector of the same species, and then compared * against the original vector, using the selected * comparison operation. * * @param op the operation used to compare lane values * @param e the input scalar * @return the mask result of testing lane-wise if this vector * compares to the input, according to the selected * comparison operator * @see ByteVector#compare(VectorOperators.Comparison,Vector) * @see #eq(byte) * @see #lt(byte) */ public abstract VectorMask compare(Comparison op, byte e); /*package-private*/ @ForceInline final > M compareTemplate(Class maskType, Comparison op, byte e) { return compareTemplate(maskType, op, broadcast(e)); } /** * Tests this vector by comparing it with an input scalar, * according to the given comparison operation, * in lanes selected by a mask. * * This is a masked lane-wise binary test operation which applies * to each pair of corresponding lane values. * * The returned result is equal to the expression * {@code compare(op,s).and(m)}. * * @param op the operation used to compare lane values * @param e the input scalar * @param m the mask controlling lane selection * @return the mask result of testing lane-wise if this vector * compares to the input, according to the selected * comparison operator, * and only in the lanes selected by the mask * @see ByteVector#compare(VectorOperators.Comparison,Vector,VectorMask) */ @ForceInline public final VectorMask compare(VectorOperators.Comparison op, byte e, VectorMask m) { return compare(op, e).and(m); } /** * {@inheritDoc} */ @Override public abstract VectorMask compare(Comparison op, long e); /*package-private*/ @ForceInline final > M compareTemplate(Class maskType, Comparison op, long e) { return compareTemplate(maskType, op, broadcast(e)); } /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask compare(Comparison op, long e, VectorMask m) { return compare(op, broadcast(e), m); } /** * {@inheritDoc} */ @Override public abstract ByteVector blend(Vector v, VectorMask m); /*package-private*/ @ForceInline final > ByteVector blendTemplate(Class maskType, ByteVector v, M m) { v.check(this); return VectorIntrinsics.blend( getClass(), maskType, byte.class, length(), this, v, m, (v0, v1, m_) -> v0.bOp(v1, m_, (i, a, b) -> b)); } /** * {@inheritDoc} */ @Override public abstract ByteVector addIndex(int scale); /*package-private*/ @ForceInline final ByteVector addIndexTemplate(int scale) { ByteSpecies vsp = vspecies(); // make sure VLENGTH*scale doesn't overflow: vsp.checkScale(scale); return VectorIntrinsics.indexVector( getClass(), byte.class, length(), this, scale, vsp, (v, scale_, s) -> { // If the platform doesn't support an INDEX // instruction directly, load IOTA from memory // and multiply. ByteVector iota = s.iota(); byte sc = (byte) scale_; return v.add(sc == 1 ? iota : iota.mul(sc)); }); } /** * Replaces selected lanes of this vector with * a scalar value * under the control of a mask. * * This is a masked lane-wise binary operation which * selects each lane value from one or the other input. * * The returned result is equal to the expression * {@code blend(broadcast(e),m)}. * * @param e the input scalar, containing the replacement lane value * @param m the mask controlling lane selection of the scalar * @return the result of blending the lane elements of this vector with * the scalar value */ @ForceInline public final ByteVector blend(byte e, VectorMask m) { return blend(broadcast(e), m); } /** * Replaces selected lanes of this vector with * a scalar value * under the control of a mask. * * This is a masked lane-wise binary operation which * selects each lane value from one or the other input. * * The returned result is equal to the expression * {@code blend(broadcast(e),m)}. * * @param e the input scalar, containing the replacement lane value * @param m the mask controlling lane selection of the scalar * @return the result of blending the lane elements of this vector with * the scalar value */ @ForceInline public final ByteVector blend(long e, VectorMask m) { return blend(broadcast(e), m); } /** * {@inheritDoc} */ @Override public abstract ByteVector slice(int origin, Vector v1); /*package-private*/ final @ForceInline ByteVector sliceTemplate(int origin, Vector v1) { ByteVector that = (ByteVector) v1; that.check(this); byte[] a0 = this.vec(); byte[] a1 = that.vec(); byte[] res = new byte[a0.length]; int vlen = res.length; int firstPart = vlen - origin; System.arraycopy(a0, origin, res, 0, firstPart); System.arraycopy(a1, 0, res, firstPart, origin); return vectorFactory(res); } /** * {@inheritDoc} */ @Override @ForceInline public final ByteVector slice(int origin, Vector w, VectorMask m) { return broadcast(0).blend(slice(origin, w), m); } /** * {@inheritDoc} */ @Override public abstract ByteVector slice(int origin); /** * {@inheritDoc} */ @Override public abstract ByteVector unslice(int origin, Vector w, int part); /*package-private*/ final @ForceInline ByteVector unsliceTemplate(int origin, Vector w, int part) { ByteVector that = (ByteVector) w; that.check(this); byte[] slice = this.vec(); byte[] res = that.vec().clone(); int vlen = res.length; int firstPart = vlen - origin; switch (part) { case 0: System.arraycopy(slice, 0, res, origin, firstPart); break; case 1: System.arraycopy(slice, firstPart, res, 0, origin); break; default: throw wrongPartForSlice(part); } return vectorFactory(res); } /*package-private*/ final @ForceInline > ByteVector unsliceTemplate(Class maskType, int origin, Vector w, int part, M m) { ByteVector that = (ByteVector) w; that.check(this); ByteVector slice = that.sliceTemplate(origin, that); slice = slice.blendTemplate(maskType, this, m); return slice.unsliceTemplate(origin, w, part); } /** * {@inheritDoc} */ @Override public abstract ByteVector unslice(int origin, Vector w, int part, VectorMask m); /** * {@inheritDoc} */ @Override public abstract ByteVector unslice(int origin); private ArrayIndexOutOfBoundsException wrongPartForSlice(int part) { String msg = String.format("bad part number %d for slice operation", part); return new ArrayIndexOutOfBoundsException(msg); } /** * {@inheritDoc} */ @Override public abstract ByteVector rearrange(VectorShuffle m); /*package-private*/ @ForceInline final > ByteVector rearrangeTemplate(Class shuffletype, S shuffle) { shuffle.checkIndexes(); return VectorIntrinsics.rearrangeOp( getClass(), shuffletype, byte.class, length(), this, shuffle, (v1, s_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); })); } /** * {@inheritDoc} */ @Override public abstract ByteVector rearrange(VectorShuffle s, VectorMask m); /*package-private*/ @ForceInline final > ByteVector rearrangeTemplate(Class shuffletype, S shuffle, VectorMask m) { ByteVector unmasked = VectorIntrinsics.rearrangeOp( getClass(), shuffletype, byte.class, length(), this, shuffle, (v1, s_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return ei < 0 ? 0 : v1.lane(ei); })); VectorMask valid = shuffle.laneIsValid(); if (m.andNot(valid).anyTrue()) { shuffle.checkIndexes(); throw new AssertionError(); } return broadcast((byte)0).blend(unmasked, valid); } /** * {@inheritDoc} */ @Override public abstract ByteVector rearrange(VectorShuffle s, Vector v); /*package-private*/ @ForceInline final > ByteVector rearrangeTemplate(Class shuffletype, S shuffle, ByteVector v) { VectorMask valid = shuffle.laneIsValid(); S ws = shuffletype.cast(shuffle.wrapIndexes()); ByteVector r0 = VectorIntrinsics.rearrangeOp( getClass(), shuffletype, byte.class, length(), this, ws, (v0, s_) -> v0.uOp((i, a) -> { int ei = s_.laneSource(i); return v0.lane(ei); })); ByteVector r1 = VectorIntrinsics.rearrangeOp( getClass(), shuffletype, byte.class, length(), v, ws, (v1, s_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); })); return r1.blend(r0, valid); } /** * {@inheritDoc} */ @Override public abstract ByteVector selectFrom(Vector v); /*package-private*/ @ForceInline final ByteVector selectFromTemplate(ByteVector v) { return v.rearrange(this.toShuffle()); } /** * {@inheritDoc} */ @Override public abstract ByteVector selectFrom(Vector s, VectorMask m); /*package-private*/ @ForceInline final ByteVector selectFromTemplate(ByteVector v, AbstractMask m) { return v.rearrange(this.toShuffle(), m); } /// Ternary operations /** * Blends together the bits of two vectors under * the control of a third, which supplies mask bits. * * * This is a lane-wise ternary operation which performs * a bitwise blending operation {@code (a&~c)|(b&c)} * to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Ternary,Vector,Vector) * lanewise}{@code (}{@link VectorOperators#BITWISE_BLEND * BITWISE_BLEND}{@code , bits, mask)}. * * @param bits input bits to blend into the current vector * @param mask a bitwise mask to enable blending of the input bits * @return the bitwise blend of the given bits into the current vector, * under control of the bitwise mask * @see #bitwiseBlend(byte,byte) * @see #bitwiseBlend(byte,Vector) * @see #bitwiseBlend(Vector,byte) * @see VectorOperators#BITWISE_BLEND * @see #lanewise(VectorOperators.Ternary,Vector,Vector,VectorMask) */ @ForceInline public final ByteVector bitwiseBlend(Vector bits, Vector mask) { return lanewise(BITWISE_BLEND, bits, mask); } /** * Blends together the bits of a vector and a scalar under * the control of another scalar, which supplies mask bits. * * * This is a lane-wise ternary operation which performs * a bitwise blending operation {@code (a&~c)|(b&c)} * to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Ternary,Vector,Vector) * lanewise}{@code (}{@link VectorOperators#BITWISE_BLEND * BITWISE_BLEND}{@code , bits, mask)}. * * @param bits input bits to blend into the current vector * @param mask a bitwise mask to enable blending of the input bits * @return the bitwise blend of the given bits into the current vector, * under control of the bitwise mask * @see #bitwiseBlend(Vector,Vector) * @see VectorOperators#BITWISE_BLEND * @see #lanewise(VectorOperators.Ternary,byte,byte,VectorMask) */ @ForceInline public final ByteVector bitwiseBlend(byte bits, byte mask) { return lanewise(BITWISE_BLEND, bits, mask); } /** * Blends together the bits of a vector and a scalar under * the control of another vector, which supplies mask bits. * * * This is a lane-wise ternary operation which performs * a bitwise blending operation {@code (a&~c)|(b&c)} * to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Ternary,Vector,Vector) * lanewise}{@code (}{@link VectorOperators#BITWISE_BLEND * BITWISE_BLEND}{@code , bits, mask)}. * * @param bits input bits to blend into the current vector * @param mask a bitwise mask to enable blending of the input bits * @return the bitwise blend of the given bits into the current vector, * under control of the bitwise mask * @see #bitwiseBlend(Vector,Vector) * @see VectorOperators#BITWISE_BLEND * @see #lanewise(VectorOperators.Ternary,byte,Vector,VectorMask) */ @ForceInline public final ByteVector bitwiseBlend(byte bits, Vector mask) { return lanewise(BITWISE_BLEND, bits, mask); } /** * Blends together the bits of two vectors under * the control of a scalar, which supplies mask bits. * * * This is a lane-wise ternary operation which performs * a bitwise blending operation {@code (a&~c)|(b&c)} * to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Ternary,Vector,Vector) * lanewise}{@code (}{@link VectorOperators#BITWISE_BLEND * BITWISE_BLEND}{@code , bits, mask)}. * * @param bits input bits to blend into the current vector * @param mask a bitwise mask to enable blending of the input bits * @return the bitwise blend of the given bits into the current vector, * under control of the bitwise mask * @see #bitwiseBlend(Vector,Vector) * @see VectorOperators#BITWISE_BLEND * @see #lanewise(VectorOperators.Ternary,Vector,byte,VectorMask) */ @ForceInline public final ByteVector bitwiseBlend(Vector bits, byte mask) { return lanewise(BITWISE_BLEND, bits, mask); } // Type specific horizontal reductions /** * Returns a value accumulated from all the lanes of this vector. * * This is an associative cross-lane reduction operation which * applies the specified operation to all the lane elements. * *

* A few reduction operations do not support arbitrary reordering * of their operands, yet are included here because of their * usefulness. * *

    *
  • * In the case of {@code FIRST_NONZERO}, the reduction returns * the value from the lowest-numbered non-zero lane. * * *
  • * In the case of floating point addition and multiplication, the * precise result will reflect the choice of an arbitrary order * of operations, which may even vary over time. * *
  • * All other reduction operations are fully commutative and * associative. The implementation can choose any order of * processing, yet it will always produce the same result. * *
* * * @param op the operation used to combine lane values * @return the accumulated result * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #reduceLanes(VectorOperators.Associative,VectorMask) * @see #add(Vector) * @see #mul(Vector) * @see #min(Vector) * @see #max(Vector) * @see #and(Vector) * @see #or(Vector) * @see VectorOperators#XOR * @see VectorOperators#FIRST_NONZERO */ public abstract byte reduceLanes(VectorOperators.Associative op); /** * Returns a value accumulated from selected lanes of this vector, * controlled by a mask. * * This is an associative cross-lane reduction operation which * applies the specified operation to the selected lane elements. *

* If no elements are selected, an operation-specific identity * value is returned. *

    *
  • * If the operation is * {@code ADD}, {@code XOR}, {@code OR}, * or {@code FIRST_NONZERO}, * then the identity value is zero, the default {@code byte} value. *
  • * If the operation is {@code MUL}, * then the identity value is one. *
  • * If the operation is {@code AND}, * then the identity value is minus one (all bits set). *
  • * If the operation is {@code MAX}, * then the identity value is {@code Byte.MIN_VALUE}. *
  • * If the operation is {@code MIN}, * then the identity value is {@code Byte.MAX_VALUE}. *
* * @param op the operation used to combine lane values * @param m the mask controlling lane selection * @return the reduced result accumulated from the selected lane values * @throws UnsupportedOperationException if this vector does * not support the requested operation * @see #reduceLanes(VectorOperators.Associative) */ public abstract byte reduceLanes(VectorOperators.Associative op, VectorMask m); /*package-private*/ @ForceInline final byte reduceLanesTemplate(VectorOperators.Associative op, VectorMask m) { ByteVector v = reduceIdentityVector(op).blend(this, m); return v.reduceLanesTemplate(op); } /*package-private*/ @ForceInline final byte reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { // FIXME: The JIT should handle this, and other scan ops alos. VectorMask thisNZ = this.viewAsIntegralLanes().compare(NE, (byte) 0); return this.lane(thisNZ.firstTrue()); } int opc = opCode(op); return fromBits(VectorIntrinsics.reductionCoerced( opc, getClass(), byte.class, length(), this, REDUCE_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_ADD: return v -> toBits(v.rOp((byte)0, (i, a, b) -> (byte)(a + b))); case VECTOR_OP_MUL: return v -> toBits(v.rOp((byte)1, (i, a, b) -> (byte)(a * b))); case VECTOR_OP_MIN: return v -> toBits(v.rOp(MAX_OR_INF, (i, a, b) -> (byte) Math.min(a, b))); case VECTOR_OP_MAX: return v -> toBits(v.rOp(MIN_OR_INF, (i, a, b) -> (byte) Math.max(a, b))); case VECTOR_OP_FIRST_NONZERO: return v -> toBits(v.rOp((byte)0, (i, a, b) -> toBits(a) != 0 ? a : b)); case VECTOR_OP_AND: return v -> toBits(v.rOp((byte)-1, (i, a, b) -> (byte)(a & b))); case VECTOR_OP_OR: return v -> toBits(v.rOp((byte)0, (i, a, b) -> (byte)(a | b))); case VECTOR_OP_XOR: return v -> toBits(v.rOp((byte)0, (i, a, b) -> (byte)(a ^ b))); default: return null; }}))); } private static final ImplCache> REDUCE_IMPL = new ImplCache<>(Associative.class, ByteVector.class); private @ForceInline ByteVector reduceIdentityVector(VectorOperators.Associative op) { int opc = opCode(op); UnaryOperator fn = REDUCE_ID_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_ADD: case VECTOR_OP_OR: case VECTOR_OP_XOR: case VECTOR_OP_FIRST_NONZERO: return v -> v.broadcast(0); case VECTOR_OP_MUL: return v -> v.broadcast(1); case VECTOR_OP_AND: return v -> v.broadcast(-1); case VECTOR_OP_MIN: return v -> v.broadcast(MAX_OR_INF); case VECTOR_OP_MAX: return v -> v.broadcast(MIN_OR_INF); default: return null; } }); return fn.apply(this); } private static final ImplCache> REDUCE_ID_IMPL = new ImplCache<>(Associative.class, ByteVector.class); private static final byte MIN_OR_INF = Byte.MIN_VALUE; private static final byte MAX_OR_INF = Byte.MAX_VALUE; public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, VectorMask m); // Type specific accessors /** * Gets the lane element at lane index {@code i} * * @param i the lane index * @return the lane element at lane index {@code i} * @throws IllegalArgumentException if the index is is out of range * ({@code < 0 || >= length()}) */ public abstract byte lane(int i); /** * Replaces the lane element of this vector at lane index {@code i} with * value {@code e}. * * This is a cross-lane operation and behaves as if it returns the result * of blending this vector with an input vector that is the result of * broadcasting {@code e} and a mask that has only one lane set at lane * index {@code i}. * * @param i the lane index of the lane element to be replaced * @param e the value to be placed * @return the result of replacing the lane element of this vector at lane * index {@code i} with value {@code e}. * @throws IllegalArgumentException if the index is is out of range * ({@code < 0 || >= length()}) */ public abstract ByteVector withLane(int i, byte e); // Memory load operations /** * Returns an array of type {@code byte[]} * containing all the lane values. * The array length is the same as the vector length. * The array elements are stored in lane order. *

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

{@code
     *   byte[] a = new byte[this.length()];
     *   this.intoArray(a, 0);
     *   return a;
     * }
* * @return an array containing the lane values of this vector */ @ForceInline @Override public final byte[] toArray() { byte[] a = new byte[vspecies().laneCount()]; intoArray(a, 0); return a; } /** {@inheritDoc} * @implNote * When this method is used on used on vectors * of type {@code ByteVector}, * there will be no loss of precision or range, * and so no {@code IllegalArgumentException} will * be thrown. */ @ForceInline @Override public final int[] toIntArray() { byte[] a = toArray(); int[] res = new int[a.length]; for (int i = 0; i < a.length; i++) { byte e = a[i]; res[i] = (int) ByteSpecies.toIntegralChecked(e, true); } return res; } /** {@inheritDoc} * @implNote * When this method is used on used on vectors * of type {@code ByteVector}, * there will be no loss of precision or range, * and so no {@code IllegalArgumentException} will * be thrown. */ @ForceInline @Override public final long[] toLongArray() { byte[] a = toArray(); long[] res = new long[a.length]; for (int i = 0; i < a.length; i++) { byte e = a[i]; res[i] = ByteSpecies.toIntegralChecked(e, false); } return res; } /** {@inheritDoc} * @implNote * When this method is used on used on vectors * of type {@code ByteVector}, * there will be no loss of precision. */ @ForceInline @Override public final double[] toDoubleArray() { byte[] a = toArray(); double[] res = new double[a.length]; for (int i = 0; i < a.length; i++) { res[i] = (double) a[i]; } return res; } /** * Loads a vector from a byte array starting at an offset. * Bytes are composed into primitive lane elements according * to {@linkplain ByteOrder#LITTLE_ENDIAN little endian} ordering. * The vector is arranged into lanes according to * memory ordering. *

* This method behaves as if it returns the result of calling * {@link #fromByteBuffer(VectorSpecies,ByteBuffer,int,ByteOrder,VectorMask) * fromByteBuffer()} as follows: *

{@code
     * var bb = ByteBuffer.wrap(a);
     * var bo = ByteOrder.LITTLE_ENDIAN;
     * var m = species.maskAll(true);
     * return fromByteBuffer(species, bb, offset, m, bo);
     * }
* * @param species species of desired vector * @param a the byte array * @param offset the offset into the array * @return a vector loaded from a byte array * @throws IndexOutOfBoundsException * if {@code offset+N*ESIZE < 0} * or {@code offset+(N+1)*ESIZE > a.length} * for any lane {@code N} in the vector */ @ForceInline public static ByteVector fromByteArray(VectorSpecies species, byte[] a, int offset) { return fromByteArray(species, a, offset, ByteOrder.LITTLE_ENDIAN); } /** * Loads a vector from a byte array starting at an offset. * Bytes are composed into primitive lane elements according * to the specified byte order. * The vector is arranged into lanes according to * memory ordering. *

* This method behaves as if it returns the result of calling * {@link #fromByteBuffer(VectorSpecies,ByteBuffer,int,ByteOrder,VectorMask) * fromByteBuffer()} as follows: *

{@code
     * var bb = ByteBuffer.wrap(a);
     * var m = species.maskAll(true);
     * return fromByteBuffer(species, bb, offset, m, bo);
     * }
* * @param species species of desired vector * @param a the byte array * @param offset the offset into the array * @param bo the intended byte order * @return a vector loaded from a byte array * @throws IndexOutOfBoundsException * if {@code offset+N*ESIZE < 0} * or {@code offset+(N+1)*ESIZE > a.length} * for any lane {@code N} in the vector */ @ForceInline public static ByteVector fromByteArray(VectorSpecies species, byte[] a, int offset, ByteOrder bo) { ByteSpecies vsp = (ByteSpecies) species; offset = checkFromIndexSize(offset, vsp.vectorBitSize() / Byte.SIZE, a.length); return vsp.dummyVector() .fromByteArray0(a, offset).maybeSwap(bo); } /** * Loads a vector from a byte array starting at an offset * and using a mask. * Lanes where the mask is unset are filled with the default * value of {@code byte} (zero). * Bytes are composed into primitive lane elements according * to {@linkplain ByteOrder#LITTLE_ENDIAN little endian} ordering. * The vector is arranged into lanes according to * memory ordering. *

* This method behaves as if it returns the result of calling * {@link #fromByteBuffer(VectorSpecies,ByteBuffer,int,ByteOrder,VectorMask) * fromByteBuffer()} as follows: *

{@code
     * var bb = ByteBuffer.wrap(a);
     * var bo = ByteOrder.LITTLE_ENDIAN;
     * return fromByteBuffer(species, bb, offset, bo, m);
     * }
* * @param species species of desired vector * @param a the byte array * @param offset the offset into the array * @param m the mask controlling lane selection * @return a vector loaded from a byte array * @throws IndexOutOfBoundsException * if {@code offset+N*ESIZE < 0} * or {@code offset+(N+1)*ESIZE > a.length} * for any lane {@code N} in the vector where * the mask is set */ @ForceInline public static ByteVector fromByteArray(VectorSpecies species, byte[] a, int offset, VectorMask m) { return fromByteArray(species, a, offset, ByteOrder.LITTLE_ENDIAN, m); } /** * Loads a vector from a byte array starting at an offset * and using a mask. * Lanes where the mask is unset are filled with the default * value of {@code byte} (zero). * Bytes are composed into primitive lane elements according * to {@linkplain ByteOrder#LITTLE_ENDIAN little endian} ordering. * The vector is arranged into lanes according to * memory ordering. *

* This method behaves as if it returns the result of calling * {@link #fromByteBuffer(VectorSpecies,ByteBuffer,int,ByteOrder,VectorMask) * fromByteBuffer()} as follows: *

{@code
     * var bb = ByteBuffer.wrap(a);
     * return fromByteBuffer(species, bb, offset, m, bo);
     * }
* * @param species species of desired vector * @param a the byte array * @param offset the offset into the array * @param bo the intended byte order * @param m the mask controlling lane selection * @return a vector loaded from a byte array * @throws IndexOutOfBoundsException * if {@code offset+N*ESIZE < 0} * or {@code offset+(N+1)*ESIZE > a.length} * for any lane {@code N} in the vector * where the mask is set */ @ForceInline public static ByteVector fromByteArray(VectorSpecies species, byte[] a, int offset, ByteOrder bo, VectorMask m) { ByteSpecies vsp = (ByteSpecies) species; ByteVector zero = vsp.zero(); if (offset >= 0 && offset <= (a.length - vsp.length() * 1)) { ByteVector v = zero.fromByteArray0(a, offset); return zero.blend(v.maybeSwap(bo), m); } ByteVector iota = zero.addIndex(1); ((AbstractMask)m) .checkIndexByLane(offset, a.length, iota, 1); ByteBuffer tb = wrapper(a, offset, bo); return vsp.ldOp(tb, 0, (AbstractMask)m, (tb_, __, i) -> tb_.get(i)); } /** * Loads a vector from an array of type {@code byte[]} * starting at an offset. * For each vector lane, where {@code N} is the vector lane index, the * array element at index {@code offset + N} is placed into the * resulting vector at lane index {@code N}. * * @param species species of desired vector * @param a the array * @param offset the offset into the array * @return the vector loaded from an array * @throws IndexOutOfBoundsException * if {@code offset+N < 0} or {@code offset+N >= a.length} * for any lane {@code N} in the vector */ @ForceInline public static ByteVector fromArray(VectorSpecies species, byte[] a, int offset) { ByteSpecies vsp = (ByteSpecies) species; offset = checkFromIndexSize(offset, vsp.laneCount(), a.length); return vsp.dummyVector().fromArray0(a, offset); } /** * Loads a vector from an array of type {@code byte[]} * starting at an offset and using a mask. * Lanes where the mask is unset are filled with the default * value of {@code byte} (zero). * For each vector lane, where {@code N} is the vector lane index, * if the mask lane at index {@code N} is set then the array element at * index {@code offset + N} 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}. * * @param species species of desired vector * @param a the array * @param offset the offset into the array * @param m the mask controlling lane selection * @return the vector loaded from an array * @throws IndexOutOfBoundsException * if {@code offset+N < 0} or {@code offset+N >= a.length} * for any lane {@code N} in the vector * where the mask is set */ @ForceInline public static ByteVector fromArray(VectorSpecies species, byte[] a, int offset, VectorMask m) { ByteSpecies vsp = (ByteSpecies) species; if (offset >= 0 && offset <= (a.length - species.length())) { ByteVector zero = vsp.zero(); return zero.blend(zero.fromArray0(a, offset), m); } ByteVector iota = vsp.iota(); ((AbstractMask)m) .checkIndexByLane(offset, a.length, iota, 1); return vsp.vOp(m, i -> a[offset + i]); } /** * Gathers a new vector composed of elements from an array of type * {@code byte[]}, * using indexes obtained by adding a fixed {@code offset} to a * series of secondary offsets from an index map. * The index map is a contiguous sequence of {@code VLENGTH} * elements in a second array of {@code int}s, starting at a given * {@code mapOffset}. *

* For each vector lane, where {@code N} is the vector lane index, * the lane is loaded from the array * element {@code a[f(N)]}, where {@code f(N)} is the * index mapping expression * {@code offset + indexMap[mapOffset + N]]}. * * @param species species of desired vector * @param a the array * @param offset the offset into the array, may be negative if relative * indexes in the index map compensate to produce a value within the * array bounds * @param indexMap the index map * @param mapOffset the offset into the index map * @return the vector loaded from the indexed elements of the array * @throws IndexOutOfBoundsException * if {@code mapOffset+N < 0} * or if {@code mapOffset+N >= indexMap.length}, * or if {@code f(N)=offset+indexMap[mapOffset+N]} * is an invalid index into {@code a}, * for any lane {@code N} in the vector * @see ByteVector#toIntArray() */ @ForceInline public static ByteVector fromArray(VectorSpecies species, byte[] a, int offset, int[] indexMap, int mapOffset) { ByteSpecies vsp = (ByteSpecies) species; return vsp.vOp(n -> a[offset + indexMap[mapOffset + n]]); } /** * Gathers a new vector composed of elements from an array of type * {@code byte[]}, * under the control of a mask, and * using indexes obtained by adding a fixed {@code offset} to a * series of secondary offsets from an index map. * The index map is a contiguous sequence of {@code VLENGTH} * elements in a second array of {@code int}s, starting at a given * {@code mapOffset}. *

* For each vector lane, where {@code N} is the vector lane index, * if the lane is set in the mask, * the lane is loaded from the array * element {@code a[f(N)]}, where {@code f(N)} is the * index mapping expression * {@code offset + indexMap[mapOffset + N]]}. * Unset lanes in the resulting vector are set to zero. * * @param species species of desired vector * @param a the array * @param offset the offset into the array, may be negative if relative * indexes in the index map compensate to produce a value within the * array bounds * @param indexMap the index map * @param mapOffset the offset into the index map * @param m the mask controlling lane selection * @return the vector loaded from the indexed elements of the array * @throws IndexOutOfBoundsException * if {@code mapOffset+N < 0} * or if {@code mapOffset+N >= indexMap.length}, * or if {@code f(N)=offset+indexMap[mapOffset+N]} * is an invalid index into {@code a}, * for any lane {@code N} in the vector * where the mask is set * @see ByteVector#toIntArray() */ @ForceInline public static ByteVector fromArray(VectorSpecies species, byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { ByteSpecies vsp = (ByteSpecies) species; // Do it the slow way. return vsp.vOp(m, n -> a[offset + indexMap[mapOffset + n]]); } /** * Loads a vector from a {@linkplain ByteBuffer byte buffer} * starting at an offset into the byte buffer. *

* This method behaves as if it returns the result of calling * {@link #fromByteBuffer(VectorSpecies,ByteBuffer,int,ByteOrder,VectorMask) * fromByteBuffer()} as follows: *

{@code
     * var bb = ByteBuffer.wrap(a);
     * var bo = ByteOrder.LITTLE_ENDIAN;
     * var m = species.maskAll(true);
     * return fromByteBuffer(species, bb, offset, m, bo);
     * }
* * @param species species of desired vector * @param bb the byte buffer * @param offset the offset into the byte buffer * @param bo the intended byte order * @return a vector loaded from a byte buffer * @throws IndexOutOfBoundsException * if {@code offset+N*1 < 0} * or {@code offset+N*1 >= bb.limit()} * for any lane {@code N} in the vector */ @ForceInline public static ByteVector fromByteBuffer(VectorSpecies species, ByteBuffer bb, int offset, ByteOrder bo) { ByteSpecies vsp = (ByteSpecies) species; offset = checkFromIndexSize(offset, vsp.laneCount(), bb.limit()); return vsp.dummyVector() .fromByteBuffer0(bb, offset).maybeSwap(bo); } /** * Loads a vector from a {@linkplain ByteBuffer byte buffer} * starting at an offset into the byte buffer * and using a mask. *

* This method behaves as if it returns the result of calling * {@link #fromByteBuffer(VectorSpecies,ByteBuffer,int,ByteOrder,VectorMask) * fromByteBuffer()} as follows: *

{@code
     * var bb = ByteBuffer.wrap(a);
     * var bo = ByteOrder.LITTLE_ENDIAN;
     * var m = species.maskAll(true);
     * return fromByteBuffer(species, bb, offset, m, bo);
     * }
* * @param species species of desired vector * @param bb the byte buffer * @param offset the offset into the byte buffer * @param bo the intended byte order * @param m the mask controlling lane selection * @return a vector loaded from a byte buffer * @throws IndexOutOfBoundsException * if {@code offset+N*1 < 0} * or {@code offset+N*1 >= bb.limit()} * for any lane {@code N} in the vector * where the mask is set */ @ForceInline public static ByteVector fromByteBuffer(VectorSpecies species, ByteBuffer bb, int offset, ByteOrder bo, VectorMask m) { if (m.allTrue()) { return fromByteBuffer(species, bb, offset, bo); } ByteSpecies vsp = (ByteSpecies) species; checkMaskFromIndexSize(offset, vsp, m, 1, bb.limit()); ByteVector zero = zero(vsp); ByteVector v = zero.fromByteBuffer0(bb, offset); return zero.blend(v.maybeSwap(bo), m); } // Memory store operations /** * Stores this vector into an array of type {@code byte[]} * starting at an offset. *

* For each vector lane, where {@code N} is the vector lane index, * the lane element at index {@code N} is stored into the array * element {@code a[offset+N]}. * * @param a the array, of type {@code byte[]} * @param offset the offset into the array * @throws IndexOutOfBoundsException * if {@code offset+N < 0} or {@code offset+N >= a.length} * for any lane {@code N} in the vector */ @ForceInline public final void intoArray(byte[] a, int offset) { ByteSpecies vsp = vspecies(); offset = checkFromIndexSize(offset, vsp.laneCount(), a.length); VectorIntrinsics.store( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), a, arrayAddress(a, offset), this, a, offset, (arr, off, v) -> v.stOp(arr, off, (arr_, off_, i, e) -> arr_[off_ + i] = e)); } /** * Stores this vector into an array of {@code byte} * starting at offset and using a mask. *

* For each vector lane, where {@code N} is the vector lane index, * the lane element at index {@code N} is stored into the array * element {@code a[offset+N]}. * If the mask lane at {@code N} is unset then the corresponding * array element {@code a[offset+N]} is left unchanged. *

* Array range checking is done for lanes where the mask is set. * Lanes where the mask is unset are not stored and do not need * to correspond to legitimate elements of {@code a}. * That is, unset lanes may correspond to array indexes less than * zero or beyond the end of the array. * * @param a the array, of type {@code byte[]} * @param offset the offset into the array * @param m the mask controlling lane storage * @throws IndexOutOfBoundsException * if {@code offset+N < 0} or {@code offset+N >= a.length} * for any lane {@code N} in the vector * where the mask is set */ @ForceInline public final void intoArray(byte[] a, int offset, VectorMask m) { if (m.allTrue()) { intoArray(a, offset); } else { // FIXME: Cannot vectorize yet, if there's a mask. stOp(a, offset, m, (arr, off, i, v) -> arr[off+i] = v); } } /** * Scatters this vector into an array of type {@code byte[]} * using indexes obtained by adding a fixed {@code offset} to a * series of secondary offsets from an index map. * The index map is a contiguous sequence of {@code VLENGTH} * elements in a second array of {@code int}s, starting at a given * {@code mapOffset}. *

* For each vector lane, where {@code N} is the vector lane index, * the lane element at index {@code N} is stored into the array * element {@code a[f(N)]}, where {@code f(N)} is the * index mapping expression * {@code offset + indexMap[mapOffset + N]]}. * * @param a the array * @param offset an offset to combine with the index map offsets * @param indexMap the index map * @param mapOffset the offset into the index map * @returns a vector of the values {@code a[f(N)]}, where * {@code f(N) = offset + indexMap[mapOffset + N]]}. * @throws IndexOutOfBoundsException * if {@code mapOffset+N < 0} * or if {@code mapOffset+N >= indexMap.length}, * or if {@code f(N)=offset+indexMap[mapOffset+N]} * is an invalid index into {@code a}, * for any lane {@code N} in the vector * @see ByteVector#toIntArray() */ @ForceInline public final void intoArray(byte[] a, int offset, int[] indexMap, int mapOffset) { ByteSpecies vsp = vspecies(); if (length() == 1) { intoArray(a, offset + indexMap[mapOffset]); return; } IntVector.IntSpecies isp = (IntVector.IntSpecies) vsp.indexSpecies(); if (isp.laneCount() != vsp.laneCount()) { stOp(a, offset, (arr, off, i, e) -> { int j = indexMap[mapOffset + i]; arr[off + j] = e; }); return; } // Index vector: vix[0:n] = i -> offset + indexMap[mo + i] IntVector vix = IntVector .fromArray(isp, indexMap, mapOffset) .add(offset); vix = VectorIntrinsics.checkIndex(vix, a.length); VectorIntrinsics.storeWithMap( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), isp.vectorType(), a, arrayAddress(a, 0), vix, this, a, offset, indexMap, mapOffset, (arr, off, v, map, mo) -> v.stOp(arr, off, (arr_, off_, i, e) -> { int j = map[mo + i]; arr[off + j] = e; })); } /** * Scatters this vector into an array of type {@code byte[]}, * under the control of a mask, and * using indexes obtained by adding a fixed {@code offset} to a * series of secondary offsets from an index map. * The index map is a contiguous sequence of {@code VLENGTH} * elements in a second array of {@code int}s, starting at a given * {@code mapOffset}. *

* For each vector lane, where {@code N} is the vector lane index, * if the mask lane at index {@code N} is set then * the lane element at index {@code N} is stored into the array * element {@code a[f(N)]}, where {@code f(N)} is the * index mapping expression * {@code offset + indexMap[mapOffset + N]]}. * * @param a the array * @param offset an offset to combine with the index map offsets * @param indexMap the index map * @param mapOffset the offset into the index map * @param m the mask * @returns a vector of the values {@code m ? a[f(N)] : 0}, * {@code f(N) = offset + indexMap[mapOffset + N]]}. * @throws IndexOutOfBoundsException * if {@code mapOffset+N < 0} * or if {@code mapOffset+N >= indexMap.length}, * or if {@code f(N)=offset+indexMap[mapOffset+N]} * is an invalid index into {@code a}, * for any lane {@code N} in the vector * where the mask is set * @see ByteVector#toIntArray() */ @ForceInline public final void intoArray(byte[] a, int offset, int[] indexMap, int mapOffset, VectorMask m) { ByteSpecies vsp = vspecies(); if (m.allTrue()) { intoArray(a, offset, indexMap, mapOffset); return; } throw new AssertionError("fixme"); } /** * {@inheritDoc} */ @Override @ForceInline public final void intoByteArray(byte[] a, int offset) { offset = checkFromIndexSize(offset, bitSize() / Byte.SIZE, a.length); this.maybeSwap(ByteOrder.LITTLE_ENDIAN) .intoByteArray0(a, offset); } /** * {@inheritDoc} */ @Override @ForceInline public final void intoByteArray(byte[] a, int offset, VectorMask m) { if (m.allTrue()) { intoByteArray(a, offset); return; } ByteSpecies vsp = vspecies(); if (offset >= 0 && offset <= (a.length - vsp.length() * 1)) { var oldVal = fromByteArray0(a, offset); var newVal = oldVal.blend(this, m); newVal.intoByteArray0(a, offset); } else { checkMaskFromIndexSize(offset, vsp, m, 1, a.length); ByteBuffer tb = wrapper(a, offset, NATIVE_ENDIAN); this.stOp(tb, 0, m, (tb_, __, i, e) -> tb_.put(i, e)); } } /** * {@inheritDoc} */ @Override @ForceInline public final void intoByteArray(byte[] a, int offset, ByteOrder bo, VectorMask m) { maybeSwap(bo).intoByteArray(a, offset, m); } /** * {@inheritDoc} */ @Override @ForceInline public final void intoByteBuffer(ByteBuffer bb, int offset, ByteOrder bo) { maybeSwap(bo).intoByteBuffer0(bb, offset); } /** * {@inheritDoc} */ @Override @ForceInline public final void intoByteBuffer(ByteBuffer bb, int offset, ByteOrder bo, VectorMask m) { if (m.allTrue()) { intoByteBuffer(bb, offset, bo); return; } ByteSpecies vsp = vspecies(); checkMaskFromIndexSize(offset, vsp, m, 1, bb.limit()); conditionalStoreNYI(offset, vsp, m, 1, bb.limit()); var oldVal = fromByteBuffer0(bb, offset); var newVal = oldVal.blend(this.maybeSwap(bo), m); newVal.intoByteBuffer0(bb, offset); } // ================================================ // Low-level memory operations. // // Note that all of these operations *must* inline into a context // where the exact species of the involved vector is a // compile-time constant. Otherwise, the intrinsic generation // will fail and performance will suffer. // // In many cases this is achieved by re-deriving a version of the // method in each concrete subclass (per species). The re-derived // method simply calls one of these generic methods, with exact // parameters for the controlling metadata, which is either a // typed vector or constant species instance. // Unchecked loading operations in native byte order. // Caller is reponsible for applying index checks, masking, and // byte swapping. /*package-private*/ abstract ByteVector fromArray0(byte[] a, int offset); @ForceInline final ByteVector fromArray0Template(byte[] a, int offset) { ByteSpecies vsp = vspecies(); return VectorIntrinsics.load( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), a, arrayAddress(a, offset), a, offset, vsp, (arr, off, s) -> s.ldOp(arr, off, (arr_, off_, i) -> arr_[off_ + i])); } @Override abstract ByteVector fromByteArray0(byte[] a, int offset); @ForceInline final ByteVector fromByteArray0Template(byte[] a, int offset) { ByteSpecies vsp = vspecies(); return VectorIntrinsics.load( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), a, byteArrayAddress(a, offset), a, offset, vsp, (arr, off, s) -> { ByteBuffer tb = wrapper(arr, off, NATIVE_ENDIAN); return s.ldOp(tb, 0, (tb_, __, i) -> tb_.get(i)); }); } abstract ByteVector fromByteBuffer0(ByteBuffer bb, int offset); @ForceInline final ByteVector fromByteBuffer0Template(ByteBuffer bb, int offset) { ByteSpecies vsp = vspecies(); return VectorIntrinsics.load( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), bufferBase(bb), bufferAddress(bb, offset), bb, offset, vsp, (buf, off, s) -> { ByteBuffer tb = wrapper(buf, off, NATIVE_ENDIAN); return s.ldOp(tb, 0, (tb_, __, i) -> tb_.get(i)); }); } // Unchecked storing operations in native byte order. // Caller is reponsible for applying index checks, masking, and // byte swapping. abstract void intoArray0(byte[] a, int offset); @ForceInline final void intoArray0Template(byte[] a, int offset) { ByteSpecies vsp = vspecies(); VectorIntrinsics.store( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), a, arrayAddress(a, offset), this, a, offset, (arr, off, v) -> v.stOp(arr, off, (arr_, off_, i, e) -> arr_[off_+i] = e)); } abstract void intoByteArray0(byte[] a, int offset); @ForceInline final void intoByteArray0Template(byte[] a, int offset) { ByteSpecies vsp = vspecies(); VectorIntrinsics.store( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), a, byteArrayAddress(a, offset), this, a, offset, (arr, off, v) -> { ByteBuffer tb = wrapper(arr, off, NATIVE_ENDIAN); v.stOp(tb, 0, (tb_, __, i, e) -> tb_.put(i, e)); }); } @ForceInline final void intoByteBuffer0(ByteBuffer bb, int offset) { ByteSpecies vsp = vspecies(); VectorIntrinsics.store( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), bufferBase(bb), bufferAddress(bb, offset), this, bb, offset, (buf, off, v) -> { ByteBuffer tb = wrapper(buf, off, NATIVE_ENDIAN); v.stOp(tb, 0, (tb_, __, i, e) -> tb_.put(i, e)); }); } // End of low-level memory operations. private static void checkMaskFromIndexSize(int offset, ByteSpecies vsp, VectorMask m, int scale, int limit) { ((AbstractMask)m) .checkIndexByLane(offset, limit, vsp.iota(), scale); } @ForceInline private void conditionalStoreNYI(int offset, ByteSpecies vsp, VectorMask m, int scale, int limit) { if (offset < 0 || offset + vsp.laneCount() * scale > limit) { String msg = String.format("unimplemented: store @%d in [0..%d), %s in %s", offset, limit, m, vsp); throw new AssertionError(msg); } } /*package-private*/ @Override @ForceInline final ByteVector maybeSwap(ByteOrder bo) { return this; } static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_BYTE_INDEX_SCALE); static final long ARRAY_BASE = Unsafe.ARRAY_BYTE_BASE_OFFSET; @ForceInline static long arrayAddress(byte[] a, int index) { return ARRAY_BASE + (((long)index) << ARRAY_SHIFT); } @ForceInline static long byteArrayAddress(byte[] a, int index) { return Unsafe.ARRAY_BYTE_BASE_OFFSET + index; } // Byte buffer wrappers. private static ByteBuffer wrapper(ByteBuffer bb, int offset, ByteOrder bo) { return bb.duplicate().position(offset).slice() .order(bo); } private static ByteBuffer wrapper(byte[] a, int offset, ByteOrder bo) { return ByteBuffer.wrap(a, offset, a.length - offset) .order(bo); } // ================================================ /// Reinterpreting view methods: // lanewise reinterpret: viewAsXVector() // keep shape, redraw lanes: reinterpretAsEs() /** * {@inheritDoc} */ @ForceInline @Override public final ByteVector reinterpretAsBytes() { return this; } /** * {@inheritDoc} */ @ForceInline @Override public final ByteVector viewAsIntegralLanes() { return this; } /** * {@inheritDoc} * * @implNote This method always throws * {@code IllegalArgumentException}, because there is no floating * point type of the same size as {@code byte}. The return type * of this method is arbitrarily designated as * {@code Vector}. Future versions of this API may change the return * type if additional floating point types become available. */ @ForceInline @Override public final Vector viewAsFloatingLanes() { LaneType flt = LaneType.BYTE.asFloating(); throw new AssertionError(); // should already throw IAE } // ================================================ /// Object methods: toString, equals, hashCode // // Object methods are defined as if via Arrays.toString, etc., // is applied to the array of elements. Two equal vectors // are required to have equal species and equal lane values. /** * Returns a string representation of this vector, of the form * {@code "[0,1,2...]"}, reporting the lane values of this vector, * in lane order. * * The string is produced as if by a call to {@link * java.util.Arrays#toString(byte[]) Arrays.toString()}, * as appropriate to the {@code byte} array returned by * {@link #toArray this.toArray()}. * * @return a string of the form {@code "[0,1,2...]"} * reporting the lane values of this vector */ @Override @ForceInline public final String toString() { // now that toArray is strongly typed, we can define this return Arrays.toString(toArray()); } /** * {@inheritDoc} */ @Override @ForceInline public final boolean equals(Object obj) { if (obj instanceof Vector) { Vector that = (Vector) obj; if (this.species().equals(that.species())) { return this.eq(that.check(this.species())).allTrue(); } } return false; } /** * {@inheritDoc} */ @Override @ForceInline public final int hashCode() { // now that toArray is strongly typed, we can define this return Objects.hash(species(), Arrays.hashCode(toArray())); } // ================================================ // Species /** * Class representing {@link ByteVector}'s of the same {@link VectorShape VectorShape}. */ /*package-private*/ static final class ByteSpecies extends AbstractSpecies { private ByteSpecies(VectorShape shape, Class vectorType, Class> maskType, Function vectorFactory) { super(shape, LaneType.of(byte.class), vectorType, maskType, vectorFactory); assert(this.elementSize() == Byte.SIZE); } // Specializing overrides: @Override @ForceInline public final Class elementType() { return byte.class; } @Override @ForceInline public final Class genericElementType() { return Byte.class; } @Override @ForceInline public final Class arrayType() { return byte[].class; } @SuppressWarnings("unchecked") @Override @ForceInline public final Class vectorType() { return (Class) vectorType; } @Override @ForceInline public final long checkValue(long e) { longToElementBits(e); // only for exception return e; } /*package-private*/ @Override @ForceInline final ByteVector broadcastBits(long bits) { return (ByteVector) VectorIntrinsics.broadcastCoerced( vectorType, byte.class, laneCount, bits, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } /*package-private*/ @ForceInline final ByteVector broadcast(byte e) { return broadcastBits(toBits(e)); } @Override @ForceInline public final ByteVector broadcast(long e) { return broadcastBits(longToElementBits(e)); } /*package-private*/ final @Override @ForceInline long longToElementBits(long value) { // Do the conversion, and then test it for failure. byte e = (byte) value; if ((long) e != value) { throw badElementBits(value, e); } return toBits(e); } /*package-private*/ @ForceInline static long toIntegralChecked(byte e, boolean convertToInt) { long value = convertToInt ? (int) e : (long) e; if ((byte) value != e) { throw badArrayBits(e, convertToInt, value); } return value; } @Override @ForceInline public final ByteVector fromValues(long... values) { VectorIntrinsics.requireLength(values.length, laneCount); byte[] va = new byte[laneCount()]; for (int i = 0; i < va.length; i++) { long lv = values[i]; byte v = (byte) lv; va[i] = v; if ((long)v != lv) { throw badElementBits(lv, v); } } return dummyVector().fromArray0(va, 0); } /* this non-public one is for internal conversions */ @Override @ForceInline final ByteVector fromIntValues(int[] values) { VectorIntrinsics.requireLength(values.length, laneCount); byte[] va = new byte[laneCount()]; for (int i = 0; i < va.length; i++) { int lv = values[i]; byte v = (byte) lv; va[i] = v; if ((int)v != lv) { throw badElementBits(lv, v); } } return dummyVector().fromArray0(va, 0); } // Virtual constructors @ForceInline @Override final public ByteVector fromArray(Object a, int offset) { // User entry point: Be careful with inputs. return ByteVector .fromArray(this, (byte[]) a, offset); } @Override final ByteVector dummyVector() { return (ByteVector) super.dummyVector(); } final ByteVector vectorFactory(byte[] vec) { // Species delegates all factory requests to its dummy // vector. The dummy knows all about it. return dummyVector().vectorFactory(vec); } /*package-private*/ final @Override @ForceInline ByteVector rvOp(RVOp f) { byte[] res = new byte[laneCount()]; for (int i = 0; i < res.length; i++) { byte bits = (byte) f.apply(i); res[i] = fromBits(bits); } return dummyVector().vectorFactory(res); } ByteVector vOp(FVOp f) { byte[] res = new byte[laneCount()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(i); } return dummyVector().vectorFactory(res); } ByteVector vOp(VectorMask m, FVOp f) { byte[] res = new byte[laneCount()]; boolean[] mbits = ((AbstractMask)m).getBits(); for (int i = 0; i < res.length; i++) { if (mbits[i]) { res[i] = f.apply(i); } } return dummyVector().vectorFactory(res); } /*package-private*/ @ForceInline ByteVector ldOp(M memory, int offset, FLdOp f) { return dummyVector().ldOp(memory, offset, f); } /*package-private*/ @ForceInline ByteVector ldOp(M memory, int offset, AbstractMask m, FLdOp f) { return dummyVector().ldOp(memory, offset, m, f); } /*package-private*/ @ForceInline void stOp(M memory, int offset, FStOp f) { dummyVector().stOp(memory, offset, f); } /*package-private*/ @ForceInline void stOp(M memory, int offset, AbstractMask m, FStOp f) { dummyVector().stOp(memory, offset, m, f); } // N.B. Make sure these constant vectors and // masks load up correctly into registers. // // Also, see if we can avoid all that switching. // Could we cache both vectors and both masks in // this species object? // Zero and iota vector access @Override @ForceInline public final ByteVector zero() { if ((Class) vectorType() == ByteMaxVector.class) return ByteMaxVector.ZERO; switch (vectorBitSize()) { case 64: return Byte64Vector.ZERO; case 128: return Byte128Vector.ZERO; case 256: return Byte256Vector.ZERO; case 512: return Byte512Vector.ZERO; } throw new AssertionError(); } @Override @ForceInline public final ByteVector iota() { if ((Class) vectorType() == ByteMaxVector.class) return ByteMaxVector.IOTA; switch (vectorBitSize()) { case 64: return Byte64Vector.IOTA; case 128: return Byte128Vector.IOTA; case 256: return Byte256Vector.IOTA; case 512: return Byte512Vector.IOTA; } throw new AssertionError(); } // Mask access @Override @ForceInline public final VectorMask maskAll(boolean bit) { if ((Class) vectorType() == ByteMaxVector.class) return ByteMaxVector.ByteMaxMask.maskAll(bit); switch (vectorBitSize()) { case 64: return Byte64Vector.Byte64Mask.maskAll(bit); case 128: return Byte128Vector.Byte128Mask.maskAll(bit); case 256: return Byte256Vector.Byte256Mask.maskAll(bit); case 512: return Byte512Vector.Byte512Mask.maskAll(bit); } throw new AssertionError(); } } /** * Finds a species for an element type of {@code byte} and shape. * * @param s the shape * @return a species for an element type of {@code byte} and shape * @throws IllegalArgumentException if no such species exists for the shape */ static ByteSpecies species(VectorShape s) { Objects.requireNonNull(s); switch (s) { case S_64_BIT: return (ByteSpecies) SPECIES_64; case S_128_BIT: return (ByteSpecies) SPECIES_128; case S_256_BIT: return (ByteSpecies) SPECIES_256; case S_512_BIT: return (ByteSpecies) SPECIES_512; case S_Max_BIT: return (ByteSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } /** Species representing {@link ByteVector}s of {@link VectorShape#S_64_BIT VectorShape.S_64_BIT}. */ public static final VectorSpecies SPECIES_64 = new ByteSpecies(VectorShape.S_64_BIT, Byte64Vector.class, Byte64Vector.Byte64Mask.class, Byte64Vector::new); /** Species representing {@link ByteVector}s of {@link VectorShape#S_128_BIT VectorShape.S_128_BIT}. */ public static final VectorSpecies SPECIES_128 = new ByteSpecies(VectorShape.S_128_BIT, Byte128Vector.class, Byte128Vector.Byte128Mask.class, Byte128Vector::new); /** Species representing {@link ByteVector}s of {@link VectorShape#S_256_BIT VectorShape.S_256_BIT}. */ public static final VectorSpecies SPECIES_256 = new ByteSpecies(VectorShape.S_256_BIT, Byte256Vector.class, Byte256Vector.Byte256Mask.class, Byte256Vector::new); /** Species representing {@link ByteVector}s of {@link VectorShape#S_512_BIT VectorShape.S_512_BIT}. */ public static final VectorSpecies SPECIES_512 = new ByteSpecies(VectorShape.S_512_BIT, Byte512Vector.class, Byte512Vector.Byte512Mask.class, Byte512Vector::new); /** Species representing {@link ByteVector}s of {@link VectorShape#S_Max_BIT VectorShape.S_Max_BIT}. */ public static final VectorSpecies SPECIES_MAX = new ByteSpecies(VectorShape.S_Max_BIT, ByteMaxVector.class, ByteMaxVector.ByteMaxMask.class, ByteMaxVector::new); /** * Preferred species for {@link ByteVector}s. * A preferred species is a species of maximal bit-size for the platform. */ public static final VectorSpecies SPECIES_PREFERRED = (ByteSpecies) VectorSpecies.ofPreferred(byte.class); }