/* * 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; #if[!byte] import java.nio.$Type$Buffer; #end[!byte] 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.*; #warn This file is preprocessed before being compiled /** * A specialized {@link Vector} representing an ordered immutable sequence of * {@code $type$} values. */ @SuppressWarnings("cast") // warning: redundant cast public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { $abstractvectortype$() {} #if[FP] static final int FORBID_OPCODE_KIND = VO_NOFP; #else[FP] static final int FORBID_OPCODE_KIND = VO_ONLYFP; #end[FP] @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 $type$[] vec(); // Virtualized constructors /** * Build a vector directly using my own constructor. * It is an error if the array is aliased elsewhere. */ /*package-private*/ abstract $abstractvectortype$ vectorFactory($type$[] vec); /** * Build a mask directly using my species. * It is an error if the array is aliased elsewhere. */ /*package-private*/ @ForceInline final AbstractMask<$Boxtype$> maskFactory(boolean[] bits) { return vspecies().maskFactory(bits); } // Constant loader (takes dummy as vector arg) interface FVOp { $type$ apply(int i); } /*package-private*/ @ForceInline final $abstractvectortype$ vOp(FVOp f) { $type$[] res = new $type$[length()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(i); } return vectorFactory(res); } @ForceInline final $abstractvectortype$ vOp(VectorMask<$Boxtype$> m, FVOp f) { $type$[] res = new $type$[length()]; boolean[] mbits = ((AbstractMask<$Boxtype$>)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 { $type$ apply(int i, $type$ a); } /*package-private*/ abstract $abstractvectortype$ uOp(FUnOp f); @ForceInline final $abstractvectortype$ uOpTemplate(FUnOp f) { $type$[] vec = vec(); $type$[] res = new $type$[length()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, vec[i]); } return vectorFactory(res); } /*package-private*/ abstract $abstractvectortype$ uOp(VectorMask<$Boxtype$> m, FUnOp f); @ForceInline final $abstractvectortype$ uOpTemplate(VectorMask<$Boxtype$> m, FUnOp f) { $type$[] vec = vec(); $type$[] res = new $type$[length()]; boolean[] mbits = ((AbstractMask<$Boxtype$>)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 { $type$ apply(int i, $type$ a, $type$ b); } /*package-private*/ abstract $abstractvectortype$ bOp(Vector<$Boxtype$> o, FBinOp f); @ForceInline final $abstractvectortype$ bOpTemplate(Vector<$Boxtype$> o, FBinOp f) { $type$[] res = new $type$[length()]; $type$[] vec1 = this.vec(); $type$[] vec2 = (($abstractvectortype$)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 $abstractvectortype$ bOp(Vector<$Boxtype$> o, VectorMask<$Boxtype$> m, FBinOp f); @ForceInline final $abstractvectortype$ bOpTemplate(Vector<$Boxtype$> o, VectorMask<$Boxtype$> m, FBinOp f) { $type$[] res = new $type$[length()]; $type$[] vec1 = this.vec(); $type$[] vec2 = (($abstractvectortype$)o).vec(); boolean[] mbits = ((AbstractMask<$Boxtype$>)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 { $type$ apply(int i, $type$ a, $type$ b, $type$ c); } /*package-private*/ abstract $abstractvectortype$ tOp(Vector<$Boxtype$> o1, Vector<$Boxtype$> o2, FTriOp f); @ForceInline final $abstractvectortype$ tOpTemplate(Vector<$Boxtype$> o1, Vector<$Boxtype$> o2, FTriOp f) { $type$[] res = new $type$[length()]; $type$[] vec1 = this.vec(); $type$[] vec2 = (($abstractvectortype$)o1).vec(); $type$[] vec3 = (($abstractvectortype$)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 $abstractvectortype$ tOp(Vector<$Boxtype$> o1, Vector<$Boxtype$> o2, VectorMask<$Boxtype$> m, FTriOp f); @ForceInline final $abstractvectortype$ tOpTemplate(Vector<$Boxtype$> o1, Vector<$Boxtype$> o2, VectorMask<$Boxtype$> m, FTriOp f) { $type$[] res = new $type$[length()]; $type$[] vec1 = this.vec(); $type$[] vec2 = (($abstractvectortype$)o1).vec(); $type$[] vec3 = (($abstractvectortype$)o2).vec(); boolean[] mbits = ((AbstractMask<$Boxtype$>)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 $type$ rOp($type$ v, FBinOp f); @ForceInline final $type$ rOpTemplate($type$ v, FBinOp f) { $type$[] 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 { $type$ apply(M memory, int offset, int i); } /*package-private*/ @ForceInline final $abstractvectortype$ ldOp(M memory, int offset, FLdOp f) { //dummy; no vec = vec(); $type$[] res = new $type$[length()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(memory, offset, i); } return vectorFactory(res); } /*package-private*/ @ForceInline final $abstractvectortype$ ldOp(M memory, int offset, VectorMask<$Boxtype$> m, FLdOp f) { //$type$[] vec = vec(); $type$[] res = new $type$[length()]; boolean[] mbits = ((AbstractMask<$Boxtype$>)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, $type$ a); } /*package-private*/ @ForceInline final void stOp(M memory, int offset, FStOp f) { $type$[] 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<$Boxtype$> m, FStOp f) { $type$[] vec = vec(); boolean[] mbits = ((AbstractMask<$Boxtype$>)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, $type$ a, $type$ b); } /*package-private*/ @ForceInline final AbstractMask<$Boxtype$> bTest(int cond, Vector<$Boxtype$> o, FBinTest f) { $type$[] vec1 = vec(); $type$[] vec2 = (($abstractvectortype$)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, $type$ a, $type$ 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 $Type$Species vspecies(); /*package-private*/ @ForceInline static long toBits($type$ e) { return {#if[FP]? $Type$.$type$To$Bitstype$Bits(e): e}; } /*package-private*/ @ForceInline static $type$ fromBits(long bits) { return {#if[FP]?$Type$.$bitstype$BitsTo$Type$}(($bitstype$)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<$Boxtype$> // 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 $abstractvectortype$ zero(VectorSpecies<$Boxtype$> species) { $Type$Species vsp = ($Type$Species) species; #if[FP] return VectorIntrinsics.broadcastCoerced(vsp.vectorType(), $type$.class, species.length(), toBits(0.0f), vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); #else[FP] return VectorIntrinsics.broadcastCoerced(vsp.vectorType(), $type$.class, species.length(), 0, vsp, ((bits_, s_) -> s_.rvOp(i -> bits_))); #end[FP] } /** * 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 $abstractvectortype$.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 $abstractvectortype$ broadcast($type$ 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 $abstractvectortype$ broadcast(VectorSpecies<$Boxtype$> species, $type$ e) { $Type$Species vsp = ($Type$Species) species; return vsp.broadcast(e); } /*package-private*/ @ForceInline final $abstractvectortype$ broadcastTemplate($type$ e) { $Type$Species vsp = vspecies(); return vsp.broadcast(e); } #if[!long] /** * {@inheritDoc} * @apiNote * When working with vector subtypes like {@code $abstractvectortype$}, * {@linkplain #broadcast($type$) the more strongly typed method} * is typically selected. It can be explicitly selected * using a cast: {@code v.broadcast(($type$)e)}. * The two expressions will produce numerically identical results. */ @Override public abstract $abstractvectortype$ 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,$type$) * @see VectorSpecies#checkValue(long) */ public static $abstractvectortype$ broadcast(VectorSpecies<$Boxtype$> species, long e) { $Type$Species vsp = ($Type$Species) species; return vsp.broadcast(e); } /*package-private*/ @ForceInline final $abstractvectortype$ broadcastTemplate(long e) { return vspecies().broadcast(e); } #end[!long] /** * 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 $abstractvectortype$ fromValues(VectorSpecies<$Boxtype$> species, $type$... es) { $Type$Species vsp = ($Type$Species) 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({#if[FP]?positive }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 $abstractvectortype$ single(VectorSpecies<$Boxtype$> species, $type$ 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 #if[byteOrShort] * {@code ($type$)}{@link ThreadLocalRandom#nextInt()} #else[byteOrShort] * {@link ThreadLocalRandom#next$Type$()} #end[byteOrShort] * 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 $abstractvectortype$ random(VectorSpecies<$Boxtype$> species) { $Type$Species vsp = ($Type$Species) species; ThreadLocalRandom r = ThreadLocalRandom.current(); return vsp.vOp(i -> nextRandom(r)); } private static $type$ nextRandom(ThreadLocalRandom r) { #if[byteOrShort] return ($type$) r.nextInt(); #else[byteOrShort] return r.next$Type$(); #end[byteOrShort] } // Unary lanewise support /** * {@inheritDoc} */ public abstract $abstractvectortype$ lanewise(VectorOperators.Unary op); @ForceInline final $abstractvectortype$ lanewiseTemplate(VectorOperators.Unary op) { if (opKind(op, VO_SPECIAL)) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } #if[BITWISE] if (op == NEG) { // FIXME: Support this in the JIT. return broadcast(0).lanewiseTemplate(SUB, this); } #end[BITWISE] } int opc = opCode(op); return VectorIntrinsics.unaryOp( opc, getClass(), $type$.class, length(), this, UN_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_NEG: return v0 -> v0.uOp((i, a) -> ($type$) -a); case VECTOR_OP_ABS: return v0 -> v0.uOp((i, a) -> ($type$) Math.abs(a)); #if[BITWISE] case VECTOR_OP_NOT: return v0 -> v0.uOp((i, a) -> ($type$) ~a); #end[BITWISE] #if[FP] case VECTOR_OP_SIN: return v0 -> v0.uOp((i, a) -> ($type$) Math.sin(a)); case VECTOR_OP_COS: return v0 -> v0.uOp((i, a) -> ($type$) Math.cos(a)); case VECTOR_OP_TAN: return v0 -> v0.uOp((i, a) -> ($type$) Math.tan(a)); case VECTOR_OP_ASIN: return v0 -> v0.uOp((i, a) -> ($type$) Math.asin(a)); case VECTOR_OP_ACOS: return v0 -> v0.uOp((i, a) -> ($type$) Math.acos(a)); case VECTOR_OP_ATAN: return v0 -> v0.uOp((i, a) -> ($type$) Math.atan(a)); case VECTOR_OP_EXP: return v0 -> v0.uOp((i, a) -> ($type$) Math.exp(a)); case VECTOR_OP_LOG: return v0 -> v0.uOp((i, a) -> ($type$) Math.log(a)); case VECTOR_OP_LOG10: return v0 -> v0.uOp((i, a) -> ($type$) Math.log10(a)); case VECTOR_OP_SQRT: return v0 -> v0.uOp((i, a) -> ($type$) Math.sqrt(a)); case VECTOR_OP_CBRT: return v0 -> v0.uOp((i, a) -> ($type$) Math.cbrt(a)); case VECTOR_OP_SINH: return v0 -> v0.uOp((i, a) -> ($type$) Math.sinh(a)); case VECTOR_OP_COSH: return v0 -> v0.uOp((i, a) -> ($type$) Math.cosh(a)); case VECTOR_OP_TANH: return v0 -> v0.uOp((i, a) -> ($type$) Math.tanh(a)); case VECTOR_OP_EXPM1: return v0 -> v0.uOp((i, a) -> ($type$) Math.expm1(a)); case VECTOR_OP_LOG1P: return v0 -> v0.uOp((i, a) -> ($type$) Math.log1p(a)); #end[FP] default: return null; }})); } private static final ImplCache> UN_IMPL = new ImplCache<>(Unary.class, $Type$Vector.class); /** * {@inheritDoc} */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Unary op, VectorMask<$Boxtype$> m) { return blend(lanewise(op), m); } // Binary lanewise support /** * {@inheritDoc} * @see #lanewise(VectorOperators.Binary,$type$) * @see #lanewise(VectorOperators.Binary,$type$,VectorMask) */ @Override public abstract $abstractvectortype$ lanewise(VectorOperators.Binary op, Vector<$Boxtype$> v); @ForceInline final $abstractvectortype$ lanewiseTemplate(VectorOperators.Binary op, Vector<$Boxtype$> v) { $abstractvectortype$ that = ($abstractvectortype$) v; that.check(this); if (opKind(op, VO_SPECIAL {#if[!FP]? | VO_SHIFT})) { if (op == FIRST_NONZERO) { // FIXME: Support this in the JIT. VectorMask<$Boxbitstype$> thisNZ = this.viewAsIntegralLanes().compare(NE, ($bitstype$) 0); that = that.blend(($type$) 0, thisNZ.cast(vspecies())); op = OR_UNCHECKED; #if[FP] // FIXME: Support OR_UNCHECKED on float/double also! return this.viewAsIntegralLanes() .lanewise(op, that.viewAsIntegralLanes()) .viewAsFloatingLanes(); #end[FP] } #if[BITWISE] #if[!FP] 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); } #end[!FP] if (op == ROR || op == ROL) { // FIXME: JIT should do this $abstractvectortype$ neg = that.lanewise(NEG); $abstractvectortype$ hi = this.lanewise(LSHL, (op == ROR) ? neg : that); $abstractvectortype$ 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<$Boxtype$> eqz = that.eq(($type$)0); if (eqz.anyTrue()) { throw that.divZeroException(); } } #end[BITWISE] } int opc = opCode(op); return VectorIntrinsics.binaryOp( opc, getClass(), $type$.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) -> ($type$)(a + b)); case VECTOR_OP_SUB: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)(a - b)); case VECTOR_OP_MUL: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)(a * b)); case VECTOR_OP_DIV: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)(a / b)); case VECTOR_OP_MAX: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)Math.max(a, b)); case VECTOR_OP_MIN: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)Math.min(a, b)); case VECTOR_OP_FIRST_NONZERO: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> toBits(a) != 0 ? a : b); #if[BITWISE] case VECTOR_OP_AND: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)(a & b)); case VECTOR_OP_OR: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)(a | b)); case VECTOR_OP_AND_NOT: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)(a & ~b)); case VECTOR_OP_XOR: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$)(a ^ b)); case VECTOR_OP_LSHIFT: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> ($type$)(a << n)); case VECTOR_OP_RSHIFT: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> ($type$)(a >> n)); case VECTOR_OP_URSHIFT: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> ($type$)((a & LSHR_SETUP_MASK) >>> n)); case VECTOR_OP_LROTATE: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> ($type$)((a << n)|(a >> -n))); case VECTOR_OP_RROTATE: return (v0, v1) -> v0.bOp(v1, (i, a, n) -> ($type$)((a >> n)|(a << -n))); #end[BITWISE] #if[FP] case VECTOR_OP_OR: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> fromBits(toBits(a) | toBits(b))); case VECTOR_OP_ATAN2: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$) Math.atan2(a, b)); case VECTOR_OP_POW: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$) Math.pow(a, b)); case VECTOR_OP_HYPOT: return (v0, v1) -> v0.bOp(v1, (i, a, b) -> ($type$) Math.hypot(a, b)); #end[FP] default: return null; }})); } private static final ImplCache> BIN_IMPL = new ImplCache<>(Binary.class, $Type$Vector.class); /** * {@inheritDoc} * @see #lanewise(VectorOperators.Binary,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Binary op, Vector<$Boxtype$> v, VectorMask<$Boxtype$> m) { #if[BITWISE] $abstractvectortype$ that = ($abstractvectortype$) v; if (op == DIV) { // suppress div/0 exceptions in unset lanes that = that.lanewise(NOT, that.eq(($type$)0)); return blend(lanewise(DIV, that), m); } #end[BITWISE] 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,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Binary op, $type$ e) { int opc = opCode(op); #if[BITWISE] if (opKind(op, VO_SHIFT) && ($type$)(int)e == e) { return lanewiseShift(op, (int) e); } if (op == AND_NOT) { op = AND; e = ($type$) ~e; } #end[BITWISE] 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,$type$) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Binary op, $type$ e, VectorMask<$Boxtype$> m) { return blend(lanewise(op, e), m); } #if[!long] /** * {@inheritDoc} * @apiNote * When working with vector subtypes like {@code $abstractvectortype$}, * {@linkplain #lanewise(VectorOperators.Binary,$type$) * the more strongly typed method} * is typically selected. It can be explicitly selected * using a cast: {@code v.lanewise(op,($type$)e)}. * The two expressions will produce numerically identical results. */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Binary op, long e) { $type$ e1 = ($type$) e; if ((long)e1 != e #if[BITWISE] // allow shift ops to clip down their int parameters && !(opKind(op, VO_SHIFT) && (int)e1 == e) #end[BITWISE] ) { vspecies().checkValue(e); // for exception } return lanewise(op, e1); } /** * {@inheritDoc} * @apiNote * When working with vector subtypes like {@code $abstractvectortype$}, * {@linkplain #lanewise(VectorOperators.Binary,$type$,VectorMask) * the more strongly typed method} * is typically selected. It can be explicitly selected * using a cast: {@code v.lanewise(op,($type$)e,m)}. * The two expressions will produce numerically identical results. */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Binary op, long e, VectorMask<$Boxtype$> m) { return blend(lanewise(op, e), m); } #end[!long] #if[BITWISE] /*package-private*/ abstract $abstractvectortype$ lanewiseShift(VectorOperators.Binary op, int e); /*package-private*/ @ForceInline final $abstractvectortype$ 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 $abstractvectortype$ hi = this.lanewise(LSHL, (op == ROR) ? -e : e); $abstractvectortype$ lo = this.lanewise(LSHR, (op == ROR) ? e : -e); return hi.lanewise(OR, lo); } return VectorIntrinsics.broadcastInt( opc, getClass(), $type$.class, length(), this, e, BIN_INT_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_LSHIFT: return (v, n) -> v.uOp((i, a) -> ($type$)(a << n)); case VECTOR_OP_RSHIFT: return (v, n) -> v.uOp((i, a) -> ($type$)(a >> n)); case VECTOR_OP_URSHIFT: return (v, n) -> v.uOp((i, a) -> ($type$)((a & LSHR_SETUP_MASK) >>> n)); case VECTOR_OP_LROTATE: return (v, n) -> v.uOp((i, a) -> ($type$)((a << n)|(a >> -n))); case VECTOR_OP_RROTATE: return (v, n) -> v.uOp((i, a) -> ($type$)((a >> n)|(a << -n))); default: return null; }})); } private static final ImplCache> BIN_INT_IMPL = new ImplCache<>(Binary.class, $Type$Vector.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 = ($Boxtype$.SIZE - 1); #if[byteOrShort] // Also simulate >>> on sub-word variables with a mask. private static final int LSHR_SETUP_MASK = ((1 << $Boxtype$.SIZE) - 1); #else[byteOrShort] private static final $type$ LSHR_SETUP_MASK = -1; #end[byteOrShort] #end[BITWISE] // 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,$type$,$type$,VectorMask) * @see #lanewise(VectorOperators.Ternary,Vector,$type$,VectorMask) * @see #lanewise(VectorOperators.Ternary,$type$,Vector,VectorMask) * @see #lanewise(VectorOperators.Ternary,$type$,$type$) * @see #lanewise(VectorOperators.Ternary,Vector,$type$) * @see #lanewise(VectorOperators.Ternary,$type$,Vector) */ @Override public abstract $abstractvectortype$ lanewise(VectorOperators.Ternary op, Vector<$Boxtype$> v1, Vector<$Boxtype$> v2); @ForceInline final $abstractvectortype$ lanewiseTemplate(VectorOperators.Ternary op, Vector<$Boxtype$> v1, Vector<$Boxtype$> v2) { $abstractvectortype$ that = ($abstractvectortype$) v1; $abstractvectortype$ tother = ($abstractvectortype$) 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[BITWISE] if (op == BITWISE_BLEND) { // FIXME: Support this in the JIT. that = this.lanewise(XOR, that).lanewise(AND, tother); return this.lanewise(XOR, that); } #end[BITWISE] int opc = opCode(op); return VectorIntrinsics.ternaryOp( opc, getClass(), $type$.class, length(), this, that, tother, TERN_IMPL.find(op, opc, (opc_) -> { switch (opc_) { #if[BITWISE] case VECTOR_OP_BITWISE_BLEND: return (v0, v1_, v2_) -> v0.tOp(v1_, v2_, (i, a, b, c) -> ($type$)(a^((a^b)&c))); #end[BITWISE] #if[FP] case VECTOR_OP_FMA: return (v0, v1_, v2_) -> v0.tOp(v1_, v2_, (i, a, b, c) -> Math.fma(a, b, c)); #end[FP] default: return null; }})); } private static final ImplCache> TERN_IMPL = new ImplCache<>(Ternary.class, $Type$Vector.class); /** * {@inheritDoc} * @see #lanewise(VectorOperators.Ternary,$type$,$type$,VectorMask) * @see #lanewise(VectorOperators.Ternary,Vector,$type$,VectorMask) * @see #lanewise(VectorOperators.Ternary,$type$,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Ternary op, Vector<$Boxtype$> v1, Vector<$Boxtype$> v2, VectorMask<$Boxtype$> 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,$type$,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Ternary op, //(op,e1,e2) $type$ e1, $type$ 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,$type$,$type$) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Ternary op, //(op,e1,e2,m) $type$ e1, $type$ e2, VectorMask<$Boxtype$> 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,$type$,$type$) * @see #lanewise(VectorOperators.Ternary,Vector,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Ternary op, //(op,v1,e2) Vector<$Boxtype$> v1, $type$ 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,$type$,$type$,VectorMask) * @see #lanewise(VectorOperators.Ternary,Vector,$type$) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Ternary op, //(op,v1,e2,m) Vector<$Boxtype$> v1, $type$ e2, VectorMask<$Boxtype$> 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,$type$,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Ternary op, //(op,e1,v2) $type$ e1, Vector<$Boxtype$> 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,$type$,Vector) */ @ForceInline public final $abstractvectortype$ lanewise(VectorOperators.Ternary op, //(op,e1,v2,m) $type$ e1, Vector<$Boxtype$> v2, VectorMask<$Boxtype$> 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($type$) */ @Override @ForceInline public final $abstractvectortype$ add(Vector<$Boxtype$> 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,$type$) * 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($type$) * @see #add($type$,VectorMask) * @see VectorOperators#ADD * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ add($type$ e) { return lanewise(ADD, e); } /** * {@inheritDoc} * @see #add($type$,VectorMask) */ @Override @ForceInline public final $abstractvectortype$ add(Vector<$Boxtype$> v, VectorMask<$Boxtype$> 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,$type$,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($type$) * @see #add($type$) * @see VectorOperators#ADD * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ add($type$ e, VectorMask<$Boxtype$> m) { return lanewise(ADD, e, m); } /** * {@inheritDoc} * @see #sub($type$) */ @Override @ForceInline public final $abstractvectortype$ sub(Vector<$Boxtype$> 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,$type$) * 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($type$) * @see #sub($type$,VectorMask) * @see VectorOperators#SUB * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ sub($type$ e) { return lanewise(SUB, e); } /** * {@inheritDoc} * @see #sub($type$,VectorMask) */ @Override @ForceInline public final $abstractvectortype$ sub(Vector<$Boxtype$> v, VectorMask<$Boxtype$> 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,$type$,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($type$) * @see #sub($type$) * @see VectorOperators#SUB * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ sub($type$ e, VectorMask<$Boxtype$> m) { return lanewise(SUB, e, m); } /** * {@inheritDoc} * @see #mul($type$) */ @Override @ForceInline public final $abstractvectortype$ mul(Vector<$Boxtype$> 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,$type$) * 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($type$) * @see #mul($type$,VectorMask) * @see VectorOperators#MUL * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ mul($type$ e) { return lanewise(MUL, e); } /** * {@inheritDoc} * @see #mul($type$,VectorMask) */ @Override @ForceInline public final $abstractvectortype$ mul(Vector<$Boxtype$> v, VectorMask<$Boxtype$> 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,$type$,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($type$) * @see #mul($type$) * @see VectorOperators#MUL * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ mul($type$ e, VectorMask<$Boxtype$> m) { return lanewise(MUL, e, m); } /** * {@inheritDoc} #if[FP] * @apiNote Because the underlying scalar operator is an IEEE * floating point number, division by zero in fact will * not throw an exception, but will yield a signed * infinity or NaN. #else[FP] * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. * @see #div($type$) #end[FP] */ @Override @ForceInline public final $abstractvectortype$ div(Vector<$Boxtype$> 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,$type$) * lanewise}{@code (}{@link VectorOperators#DIV * DIV}{@code , e)}. * #if[FP] * @apiNote Because the underlying scalar operator is an IEEE * floating point number, division by zero in fact will * not throw an exception, but will yield a signed * infinity or NaN. #else[FP] * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. #end[FP] * @see #div($type$) * * @param e the input scalar * @return the result of dividing each lane of this vector by the scalar * @see #div(Vector) * @see #broadcast($type$) * @see #div($type$,VectorMask) * @see VectorOperators#DIV * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ div($type$ e) { return lanewise(DIV, e); } /** * {@inheritDoc} * @see #div($type$,VectorMask) #if[FP] * @apiNote Because the underlying scalar operator is an IEEE * floating point number, division by zero in fact will * not throw an exception, but will yield a signed * infinity or NaN. #else[FP] * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. #end[FP] */ @Override @ForceInline public final $abstractvectortype$ div(Vector<$Boxtype$> v, VectorMask<$Boxtype$> 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,$type$,VectorMask) * lanewise}{@code (}{@link VectorOperators#DIV * DIV}{@code , s, m)}. * #if[FP] * @apiNote Because the underlying scalar operator is an IEEE * floating point number, division by zero in fact will * not throw an exception, but will yield a signed * infinity or NaN. #else[FP] * @apiNote If there is a zero divisor, {@code * ArithmeticException} will be thrown. #end[FP] * * @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($type$) * @see #div($type$) * @see VectorOperators#DIV * @see #lanewise(VectorOperators.Binary,Vector) * @see #lanewise(VectorOperators.Binary,$type$) */ @ForceInline public final $abstractvectortype$ div($type$ e, VectorMask<$Boxtype$> m) { return lanewise(DIV, e, m); } /// END OF FULL-SERVICE BINARY METHODS /// SECOND-TIER BINARY METHODS // // There are no masked versions. /** * {@inheritDoc} #if[FP] * @apiNote * For this method, floating point negative * zero {@code -0.0} is treated as a value distinct from, and less * than the default value(positive zero). #end[FP] */ @Override @ForceInline public final $abstractvectortype$ min(Vector<$Boxtype$> 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,$type$) * 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($type$) * @see VectorOperators#MIN * @see #lanewise(VectorOperators.Binary,$type$,VectorMask) #if[FP] * @apiNote * For this method, floating point negative * zero {@code -0.0} is treated as a value distinct from, and less * than the default value(positive zero). #end[FP] */ @ForceInline public final $abstractvectortype$ min($type$ e) { return lanewise(MIN, e); } /** * {@inheritDoc} #if[FP] * @apiNote * For this method, negative floating-point zero compares * less than the default value, positive zero. #end[FP] */ @Override @ForceInline public final $abstractvectortype$ max(Vector<$Boxtype$> 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,$type$) * 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($type$) * @see VectorOperators#MAX * @see #lanewise(VectorOperators.Binary,$type$,VectorMask) #if[FP] * @apiNote * For this method, negative floating-point zero compares * less than the default value, positive zero. #end[FP] */ @ForceInline public final $abstractvectortype$ max($type$ e) { return lanewise(MAX, e); } #if[BITWISE] // 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($type$) * @see #or(Vector) * @see #not() * @see VectorOperators#AND * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ and(Vector<$Boxtype$> 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 $abstractvectortype$ and($type$ 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($type$) * @see #and(Vector) * @see #not() * @see VectorOperators#OR * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ or(Vector<$Boxtype$> 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 $abstractvectortype$ or($type$ e) { return lanewise(OR, e); } #end[BITWISE] #if[FP] // common FP operator: pow /** * Raises this vector to the power of a second input vector. * * This is a lane-wise binary operation which applies the * method {@code Math.pow()} * to each pair of corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,Vector) * lanewise}{@code (}{@link VectorOperators#POW * POW}{@code , n)}. * *

* 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 n a vector exponent by which to raise this vector * @return the {@code n}-th power of this vector * @see #pow($type$) * @see VectorOperators#POW * @see #lanewise(VectorOperators.Binary,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ pow(Vector<$Boxtype$> n) { return lanewise(POW, n); } /** * Raises this vector to a scalar power. * * This is a lane-wise binary operation which applies the * method {@code Math.pow()} * to each pair of corresponding lane values. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Binary,Vector) * lanewise}{@code (}{@link VectorOperators#POW * POW}{@code , n)}. * * @param n a scalar exponent by which to raise this vector * @return the {@code n}-th power of this vector * @see #pow(Vector) * @see VectorOperators#POW * @see #lanewise(VectorOperators.Binary,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ pow($type$ n) { return lanewise(POW, n); } #end[FP] /// UNARY METHODS /** * {@inheritDoc} */ @Override @ForceInline public final $abstractvectortype$ neg() { return lanewise(NEG); } /** * {@inheritDoc} */ @Override @ForceInline public final $abstractvectortype$ abs() { return lanewise(ABS); } #if[BITWISE] // 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 $abstractvectortype$ not() { return lanewise(NOT); } #end[BITWISE] #if[FP] // sqrt /** * Computes the square root of this vector. * * This is a lane-wise unary operation which applies the * the method {@code Math.sqrt()} * to each lane value. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Unary) * lanewise}{@code (}{@link VectorOperators#SQRT * SQRT}{@code )}. * * @return the square root of this vector * @see VectorOperators#SQRT * @see #lanewise(VectorOperators.Unary,VectorMask) */ @ForceInline public final $abstractvectortype$ sqrt() { return lanewise(SQRT); } #end[FP] /// COMPARISONS /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask<$Boxtype$> eq(Vector<$Boxtype$> 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,$type$) */ @ForceInline public final VectorMask<$Boxtype$> eq($type$ e) { return compare(EQ, e); } /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask<$Boxtype$> lt(Vector<$Boxtype$> 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,$type$) */ @ForceInline public final VectorMask<$Boxtype$> lt($type$ e) { return compare(LT, e); } /** * {@inheritDoc} */ @Override public abstract VectorMask<$Boxtype$> test(VectorOperators.Test op); /*package-private*/ @ForceInline final > M testTemplate(Class maskType, Test op) { $Type$Species vsp = vspecies(); if (opKind(op, VO_SPECIAL)) { $Bitstype$Vector bits = this.viewAsIntegralLanes(); VectorMask<$Boxbitstype$> m; if (op == IS_DEFAULT) { m = bits.compare(EQ, ($bitstype$) 0); } else if (op == IS_NEGATIVE) { m = bits.compare(LT, ($bitstype$) 0); } #if[FP] else if (op == IS_FINITE || op == IS_NAN || op == IS_INFINITE) { // first kill the sign: bits = bits.and($Boxbitstype$.MAX_VALUE); // next find the bit pattern for infinity: $bitstype$ infbits = ($bitstype$) toBits($Boxtype$.POSITIVE_INFINITY); // now compare: if (op == IS_FINITE) { m = bits.compare(LT, infbits); } else if (op == IS_NAN) { m = bits.compare(GT, infbits); } else { m = bits.compare(EQ, infbits); } } #end[FP] else { throw new AssertionError(op); } return maskType.cast(m{#if[FP]?.cast(this.vspecies())}); } int opc = opCode(op); throw new AssertionError(op); } /** * {@inheritDoc} */ @Override @ForceInline public final VectorMask<$Boxtype$> test(VectorOperators.Test op, VectorMask<$Boxtype$> m) { return test(op).and(m); } /** * {@inheritDoc} */ @Override public abstract VectorMask<$Boxtype$> compare(VectorOperators.Comparison op, Vector<$Boxtype$> v); /*package-private*/ @ForceInline final > M compareTemplate(Class maskType, Comparison op, Vector<$Boxtype$> v) { Objects.requireNonNull(v); $Type$Species vsp = vspecies(); $abstractvectortype$ that = ($abstractvectortype$) v; that.check(this); int opc = opCode(op); return VectorIntrinsics.compare( opc, getClass(), maskType, $type$.class, length(), this, that, (cond, v0, v1) -> { AbstractMask<$Boxtype$> 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, $type$ a, $type$ 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<$Boxtype$> compare(VectorOperators.Comparison op, Vector<$Boxtype$> v, VectorMask<$Boxtype$> 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 $abstractvectortype$#compare(VectorOperators.Comparison,Vector) * @see #eq($type$) * @see #lt($type$) */ public abstract VectorMask<$Boxtype$> compare(Comparison op, $type$ e); /*package-private*/ @ForceInline final > M compareTemplate(Class maskType, Comparison op, $type$ 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 $abstractvectortype$#compare(VectorOperators.Comparison,Vector,VectorMask) */ @ForceInline public final VectorMask<$Boxtype$> compare(VectorOperators.Comparison op, $type$ e, VectorMask<$Boxtype$> m) { return compare(op, e).and(m); } #if[!long] /** * {@inheritDoc} */ @Override public abstract VectorMask<$Boxtype$> 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<$Boxtype$> compare(Comparison op, long e, VectorMask<$Boxtype$> m) { return compare(op, broadcast(e), m); } #end[!long] /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ blend(Vector<$Boxtype$> v, VectorMask<$Boxtype$> m); /*package-private*/ @ForceInline final > $abstractvectortype$ blendTemplate(Class maskType, $abstractvectortype$ v, M m) { v.check(this); return VectorIntrinsics.blend( getClass(), maskType, $type$.class, length(), this, v, m, (v0, v1, m_) -> v0.bOp(v1, m_, (i, a, b) -> b)); } /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ addIndex(int scale); /*package-private*/ @ForceInline final $abstractvectortype$ addIndexTemplate(int scale) { $Type$Species vsp = vspecies(); // make sure VLENGTH*scale doesn't overflow: vsp.checkScale(scale); return VectorIntrinsics.indexVector( getClass(), $type$.class, length(), this, scale, vsp, (v, scale_, s) -> { // If the platform doesn't support an INDEX // instruction directly, load IOTA from memory // and multiply. $abstractvectortype$ iota = s.iota(); $type$ sc = ($type$) 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 $abstractvectortype$ blend($type$ e, VectorMask<$Boxtype$> m) { return blend(broadcast(e), m); } #if[!long] /** * 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 $abstractvectortype$ blend(long e, VectorMask<$Boxtype$> m) { return blend(broadcast(e), m); } #end[!long] /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ slice(int origin, Vector<$Boxtype$> v1); /*package-private*/ final @ForceInline $abstractvectortype$ sliceTemplate(int origin, Vector<$Boxtype$> v1) { $abstractvectortype$ that = ($abstractvectortype$) v1; that.check(this); $type$[] a0 = this.vec(); $type$[] a1 = that.vec(); $type$[] res = new $type$[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 $abstractvectortype$ slice(int origin, Vector<$Boxtype$> w, VectorMask<$Boxtype$> m) { return broadcast(0).blend(slice(origin, w), m); } /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ slice(int origin); /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ unslice(int origin, Vector<$Boxtype$> w, int part); /*package-private*/ final @ForceInline $abstractvectortype$ unsliceTemplate(int origin, Vector<$Boxtype$> w, int part) { $abstractvectortype$ that = ($abstractvectortype$) w; that.check(this); $type$[] slice = this.vec(); $type$[] 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 > $abstractvectortype$ unsliceTemplate(Class maskType, int origin, Vector<$Boxtype$> w, int part, M m) { $abstractvectortype$ that = ($abstractvectortype$) w; that.check(this); $abstractvectortype$ slice = that.sliceTemplate(origin, that); slice = slice.blendTemplate(maskType, this, m); return slice.unsliceTemplate(origin, w, part); } /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ unslice(int origin, Vector<$Boxtype$> w, int part, VectorMask<$Boxtype$> m); /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ 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 $abstractvectortype$ rearrange(VectorShuffle<$Boxtype$> m); /*package-private*/ @ForceInline final > $abstractvectortype$ rearrangeTemplate(Class shuffletype, S shuffle) { shuffle.checkIndexes(); return VectorIntrinsics.rearrangeOp( getClass(), shuffletype, $type$.class, length(), this, shuffle, (v1, s_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); })); } /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ rearrange(VectorShuffle<$Boxtype$> s, VectorMask<$Boxtype$> m); /*package-private*/ @ForceInline final > $abstractvectortype$ rearrangeTemplate(Class shuffletype, S shuffle, VectorMask<$Boxtype$> m) { $abstractvectortype$ unmasked = VectorIntrinsics.rearrangeOp( getClass(), shuffletype, $type$.class, length(), this, shuffle, (v1, s_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return ei < 0 ? 0 : v1.lane(ei); })); VectorMask<$Boxtype$> valid = shuffle.laneIsValid(); if (m.andNot(valid).anyTrue()) { shuffle.checkIndexes(); throw new AssertionError(); } return broadcast(($type$)0).blend(unmasked, valid); } /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ rearrange(VectorShuffle<$Boxtype$> s, Vector<$Boxtype$> v); /*package-private*/ @ForceInline final > $abstractvectortype$ rearrangeTemplate(Class shuffletype, S shuffle, $abstractvectortype$ v) { VectorMask<$Boxtype$> valid = shuffle.laneIsValid(); S ws = shuffletype.cast(shuffle.wrapIndexes()); $abstractvectortype$ r0 = VectorIntrinsics.rearrangeOp( getClass(), shuffletype, $type$.class, length(), this, ws, (v0, s_) -> v0.uOp((i, a) -> { int ei = s_.laneSource(i); return v0.lane(ei); })); $abstractvectortype$ r1 = VectorIntrinsics.rearrangeOp( getClass(), shuffletype, $type$.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 $abstractvectortype$ selectFrom(Vector<$Boxtype$> v); /*package-private*/ @ForceInline final $abstractvectortype$ selectFromTemplate($abstractvectortype$ v) { return v.rearrange(this.toShuffle()); } /** * {@inheritDoc} */ @Override public abstract $abstractvectortype$ selectFrom(Vector<$Boxtype$> s, VectorMask<$Boxtype$> m); /*package-private*/ @ForceInline final $abstractvectortype$ selectFromTemplate($abstractvectortype$ v, AbstractMask<$Boxtype$> m) { return v.rearrange(this.toShuffle(), m); } /// Ternary operations #if[BITWISE] /** * 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($type$,$type$) * @see #bitwiseBlend($type$,Vector) * @see #bitwiseBlend(Vector,$type$) * @see VectorOperators#BITWISE_BLEND * @see #lanewise(VectorOperators.Ternary,Vector,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ bitwiseBlend(Vector<$Boxtype$> bits, Vector<$Boxtype$> 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,$type$,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ bitwiseBlend($type$ bits, $type$ 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,$type$,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ bitwiseBlend($type$ bits, Vector<$Boxtype$> 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,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ bitwiseBlend(Vector<$Boxtype$> bits, $type$ mask) { return lanewise(BITWISE_BLEND, bits, mask); } #end[BITWISE] #if[FP] /** * Multiplies this vector by a second input vector, and sums * the result with a third. * * Extended precision is used for the intermediate result, * avoiding possible loss of precision from rounding once * for each of the two operations. * The result is numerically close to {@code this.mul(b).add(c)}, * and is typically closer to the true mathematical result. * * This is a lane-wise ternary operation which applies the * {@link Math#fma($type$,$type$,$type$) Math#fma(a,b,c)} * operation to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Ternary,Vector,Vector) * lanewise}{@code (}{@link VectorOperators#FMA * FMA}{@code , b, c)}. * * @param b the second input vector, supplying multiplier values * @param c the third input vector, supplying addend values * @return the product of this vector and the second input vector * summed with the third input vector, using extended precision * for the intermediate result * @see #fma($type$,$type$) * @see VectorOperators#FMA * @see #lanewise(VectorOperators.Ternary,Vector,Vector,VectorMask) */ @ForceInline public final $abstractvectortype$ fma(Vector<$Boxtype$> b, Vector<$Boxtype$> c) { return lanewise(FMA, b, c); } /** * Multiplies this vector by a scalar multiplier, and sums * the result with a scalar addend. * * Extended precision is used for the intermediate result, * avoiding possible loss of precision from rounding once * for each of the two operations. * The result is numerically close to {@code this.mul(b).add(c)}, * and is typically closer to the true mathematical result. * * This is a lane-wise ternary operation which applies the * {@link Math#fma($type$,$type$,$type$) Math#fma(a,b,c)} * operation to each lane. * * This method is also equivalent to the expression * {@link #lanewise(VectorOperators.Ternary,Vector,Vector) * lanewise}{@code (}{@link VectorOperators#FMA * FMA}{@code , b, c)}. * * @param b the scalar multiplier * @param c the scalar addend * @return the product of this vector and the scalar multiplier * summed with scalar addend, using extended precision * for the intermediate result * @see #fma(Vector,Vector) * @see VectorOperators#FMA * @see #lanewise(VectorOperators.Ternary,$type$,$type$,VectorMask) */ @ForceInline public final $abstractvectortype$ fma($type$ b, $type$ c) { return lanewise(FMA, b, c); } // Don't bother with (Vector,$type$) and ($type$,Vector) overloadings. #end[FP] // 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. * #if[FP] * (As with {@code MAX} and {@code MIN}, floating point negative * zero {@code -0.0} is treated as a value distinct from * the default value, positive zero. So a first-nonzero lane reduction * might return {@code -0.0} even in the presence of non-zero * lane values.) #end[FP] * *
  • * 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. * *
* #if[FP] * @implNote * The value of a floating-point reduction may be a function * both of the input values as well as the order of scalar * operations which combine those values, specifically in the * case of {@code ADD} and {@code MUL} operations, where * details of rounding depend on operand order. * In those cases, the order of operations of this method is * intentionally not defined. This allows the JVM to generate * optimal machine code for the underlying platform at runtime. If * the platform supports a vector instruction to add or multiply * all values in the vector, or if there is some other efficient * machine code sequence, then the JVM has the option of * generating this machine code. Otherwise, the default * implementation is applied, which adds vector elements * sequentially from beginning to end. For this reason, the * output of this method may vary for the same input values, * if the selected operator is {@code ADD} or {@code MUL}. * #end[FP] * * @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) #if[BITWISE] * @see #and(Vector) * @see #or(Vector) * @see VectorOperators#XOR #end[BITWISE] * @see VectorOperators#FIRST_NONZERO */ public abstract $type$ 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 #if[BITWISE] * {@code ADD}, {@code XOR}, {@code OR}, #else[BITWISE] * {@code ADD} #end[BITWISE] * or {@code FIRST_NONZERO}, * then the identity value is {#if[FP]?positive }zero, the default {@code $type$} value. *
  • * If the operation is {@code MUL}, * then the identity value is one. #if[BITWISE] *
  • * 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 $Boxtype$.MIN_VALUE}. *
  • * If the operation is {@code MIN}, * then the identity value is {@code $Boxtype$.MAX_VALUE}. #end[BITWISE] #if[FP] *
  • * If the operation is {@code MAX}, * then the identity value is {@code $Boxtype$.NEGATIVE_INFINITY}. *
  • * If the operation is {@code MIN}, * then the identity value is {@code $Boxtype$.POSITIVE_INFINITY}. #end[FP] *
#if[FP] * * @implNote * The value of a floating-point reduction may be a function * both of the input values as well as the order of scalar * operations which combine those values, specifically in the * case of {@code ADD} and {@code MUL} operations, where * details of rounding depend on operand order. * See {@linkplain #reduceLanes(VectorOperators.Associative) * the unmasked version of this method} * for a discussion. * #end[FP] * * @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 $type$ reduceLanes(VectorOperators.Associative op, VectorMask<$Boxtype$> m); /*package-private*/ @ForceInline final $type$ reduceLanesTemplate(VectorOperators.Associative op, VectorMask<$Boxtype$> m) { $abstractvectortype$ v = reduceIdentityVector(op).blend(this, m); return v.reduceLanesTemplate(op); } /*package-private*/ @ForceInline final $type$ reduceLanesTemplate(VectorOperators.Associative op) { if (op == FIRST_NONZERO) { // FIXME: The JIT should handle this, and other scan ops alos. VectorMask<$Boxbitstype$> thisNZ = this.viewAsIntegralLanes().compare(NE, ($bitstype$) 0); return this.lane(thisNZ.firstTrue()); } int opc = opCode(op); return fromBits(VectorIntrinsics.reductionCoerced( opc, getClass(), $type$.class, length(), this, REDUCE_IMPL.find(op, opc, (opc_) -> { switch (opc_) { case VECTOR_OP_ADD: return v -> toBits(v.rOp(($type$)0, (i, a, b) -> ($type$)(a + b))); case VECTOR_OP_MUL: return v -> toBits(v.rOp(($type$)1, (i, a, b) -> ($type$)(a * b))); case VECTOR_OP_MIN: return v -> toBits(v.rOp(MAX_OR_INF, (i, a, b) -> ($type$) Math.min(a, b))); case VECTOR_OP_MAX: return v -> toBits(v.rOp(MIN_OR_INF, (i, a, b) -> ($type$) Math.max(a, b))); case VECTOR_OP_FIRST_NONZERO: return v -> toBits(v.rOp(($type$)0, (i, a, b) -> toBits(a) != 0 ? a : b)); #if[BITWISE] case VECTOR_OP_AND: return v -> toBits(v.rOp(($type$)-1, (i, a, b) -> ($type$)(a & b))); case VECTOR_OP_OR: return v -> toBits(v.rOp(($type$)0, (i, a, b) -> ($type$)(a | b))); case VECTOR_OP_XOR: return v -> toBits(v.rOp(($type$)0, (i, a, b) -> ($type$)(a ^ b))); #end[BITWISE] #if[FP] case VECTOR_OP_OR: return v -> toBits(v.rOp(($type$)0, (i, a, b) -> fromBits(toBits(a) | toBits(b)))); #end[FP] default: return null; }}))); } private static final ImplCache> REDUCE_IMPL = new ImplCache<>(Associative.class, $Type$Vector.class); private @ForceInline $abstractvectortype$ reduceIdentityVector(VectorOperators.Associative op) { int opc = opCode(op); UnaryOperator<$abstractvectortype$> 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, $Type$Vector.class); #if[FP] private static final $type$ MIN_OR_INF = $Boxtype$.NEGATIVE_INFINITY; private static final $type$ MAX_OR_INF = $Boxtype$.POSITIVE_INFINITY; #else[FP] private static final $type$ MIN_OR_INF = $Boxtype$.MIN_VALUE; private static final $type$ MAX_OR_INF = $Boxtype$.MAX_VALUE; #end[FP] public @Override abstract long reduceLanesToLong(VectorOperators.Associative op); public @Override abstract long reduceLanesToLong(VectorOperators.Associative op, VectorMask<$Boxtype$> 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 $type$ 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 $abstractvectortype$ withLane(int i, $type$ e); // Memory load operations /** * Returns an array of type {@code $type$[]} * 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($type$[], int) intoArray}) * and returns the array as follows: *

{@code
     *   $type$[] a = new $type$[this.length()];
     *   this.intoArray(a, 0);
     *   return a;
     * }
* * @return an array containing the lane values of this vector */ @ForceInline @Override public final $type$[] toArray() { $type$[] a = new $type$[vspecies().laneCount()]; intoArray(a, 0); return a; } #if[int] /** * {@inheritDoc} * This is an alias for {@link #toArray()} * When this method is used on used on vectors * of type {@code $abstractvectortype$}, * there will be no loss of range or precision. */ @ForceInline @Override public final int[] toIntArray() { return toArray(); } #else[int] /** {@inheritDoc} #if[!FP] #if[!long] * @implNote * When this method is used on used on vectors * of type {@code $abstractvectortype$}, * there will be no loss of precision or range, * and so no {@code IllegalArgumentException} will * be thrown. #end[!long] #end[!FP] */ @ForceInline @Override public final int[] toIntArray() { $type$[] a = toArray(); int[] res = new int[a.length]; for (int i = 0; i < a.length; i++) { $type$ e = a[i]; res[i] = (int) $Type$Species.toIntegralChecked(e, true); } return res; } #end[int] #if[long] /** * {@inheritDoc} * This is an alias for {@link #toArray()} * When this method is used on used on vectors * of type {@code $abstractvectortype$}, * there will be no loss of range or precision. */ @ForceInline @Override public final long[] toLongArray() { return toArray(); } #else[long] /** {@inheritDoc} #if[!FP] * @implNote * When this method is used on used on vectors * of type {@code $abstractvectortype$}, * there will be no loss of precision or range, * and so no {@code IllegalArgumentException} will * be thrown. #end[!FP] */ @ForceInline @Override public final long[] toLongArray() { $type$[] a = toArray(); long[] res = new long[a.length]; for (int i = 0; i < a.length; i++) { $type$ e = a[i]; res[i] = $Type$Species.toIntegralChecked(e, false); } return res; } #end[long] #if[double] /** {@inheritDoc} * @implNote * This is an alias for {@link #toArray()} * When this method is used on used on vectors * of type {@code $abstractvectortype$}, * there will be no loss of precision. */ @ForceInline @Override public final double[] toDoubleArray() { return toArray(); } #else[double] /** {@inheritDoc} #if[long] * @implNote * When this method is used on used on vectors * of type {@code $abstractvectortype$}, * up to nine bits of precision may be lost * for lane values of large magnitude. #else[long] * @implNote * When this method is used on used on vectors * of type {@code $abstractvectortype$}, * there will be no loss of precision. #end[long] */ @ForceInline @Override public final double[] toDoubleArray() { $type$[] a = toArray(); double[] res = new double[a.length]; for (int i = 0; i < a.length; i++) { res[i] = (double) a[i]; } return res; } #end[double] /** * 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 $abstractvectortype$ fromByteArray(VectorSpecies<$Boxtype$> 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 $abstractvectortype$ fromByteArray(VectorSpecies<$Boxtype$> species, byte[] a, int offset, ByteOrder bo) { $Type$Species vsp = ($Type$Species) 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 $type$} ({#if[FP]?positive }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 $abstractvectortype$ fromByteArray(VectorSpecies<$Boxtype$> species, byte[] a, int offset, VectorMask<$Boxtype$> 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 $type$} ({#if[FP]?positive }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 $abstractvectortype$ fromByteArray(VectorSpecies<$Boxtype$> species, byte[] a, int offset, ByteOrder bo, VectorMask<$Boxtype$> m) { $Type$Species vsp = ($Type$Species) species; $abstractvectortype$ zero = vsp.zero(); if (offset >= 0 && offset <= (a.length - vsp.length() * $sizeInBytes$)) { $abstractvectortype$ v = zero.fromByteArray0(a, offset); return zero.blend(v.maybeSwap(bo), m); } $abstractvectortype$ iota = zero.addIndex(1); ((AbstractMask<$Boxtype$>)m) .checkIndexByLane(offset, a.length, iota, $sizeInBytes$); $Type$Buffer tb = wrapper(a, offset, bo); return vsp.ldOp(tb, 0, (AbstractMask<$Boxtype$>)m, (tb_, __, i) -> tb_.get(i)); } /** * Loads a vector from an array of type {@code $type$[]} * 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 $abstractvectortype$ fromArray(VectorSpecies<$Boxtype$> species, $type$[] a, int offset) { $Type$Species vsp = ($Type$Species) species; offset = checkFromIndexSize(offset, vsp.laneCount(), a.length); return vsp.dummyVector().fromArray0(a, offset); } /** * Loads a vector from an array of type {@code $type$[]} * starting at an offset and using a mask. * Lanes where the mask is unset are filled with the default * value of {@code $type$} ({#if[FP]?positive }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 $abstractvectortype$ fromArray(VectorSpecies<$Boxtype$> species, $type$[] a, int offset, VectorMask<$Boxtype$> m) { $Type$Species vsp = ($Type$Species) species; if (offset >= 0 && offset <= (a.length - species.length())) { $abstractvectortype$ zero = vsp.zero(); return zero.blend(zero.fromArray0(a, offset), m); } $abstractvectortype$ iota = vsp.iota(); ((AbstractMask<$Boxtype$>)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 $type$[]}, * 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 $abstractvectortype$#toIntArray() */ #if[byteOrShort] @ForceInline public static $abstractvectortype$ fromArray(VectorSpecies<$Boxtype$> species, $type$[] a, int offset, int[] indexMap, int mapOffset) { $Type$Species vsp = ($Type$Species) species; return vsp.vOp(n -> a[offset + indexMap[mapOffset + n]]); } #else[byteOrShort] @ForceInline public static $abstractvectortype$ fromArray(VectorSpecies<$Boxtype$> species, $type$[] a, int offset, int[] indexMap, int mapOffset) { $Type$Species vsp = ($Type$Species) species; Objects.requireNonNull(a); Objects.requireNonNull(indexMap); Class vectorType = vsp.vectorType(); #if[longOrDouble] if (vsp.laneCount() == 1) { return $abstractvectortype$.fromArray(vsp, a, offset + indexMap[mapOffset]); } #end[longOrDouble] // Index vector: vix[0:n] = k -> offset + indexMap[mapOffset + k] IntVector vix = IntVector.fromArray(IntVector.species(vsp.indexShape()), indexMap, mapOffset).add(offset); vix = VectorIntrinsics.checkIndex(vix, a.length); return VectorIntrinsics.loadWithMap( vectorType, $type$.class, vsp.laneCount(), IntVector.species(vsp.indexShape()).vectorType(), a, ARRAY_BASE, vix, a, offset, indexMap, mapOffset, vsp, ($type$[] c, int idx, int[] iMap, int idy, $Type$Species s) -> s.vOp(n -> c[idx + iMap[idy+n]])); } #end[byteOrShort] /** * Gathers a new vector composed of elements from an array of type * {@code $type$[]}, * 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 $abstractvectortype$#toIntArray() */ @ForceInline public static $abstractvectortype$ fromArray(VectorSpecies<$Boxtype$> species, $type$[] a, int offset, int[] indexMap, int mapOffset, VectorMask<$Boxtype$> m) { $Type$Species vsp = ($Type$Species) species; #if[byteOrShort] // Do it the slow way. return vsp.vOp(m, n -> a[offset + indexMap[mapOffset + n]]); #else[byteOrShort] // FIXME This can result in out of bounds errors for unset mask lanes // FIX = Use a scatter instruction which routes the unwanted lanes // into a bit-bucket variable (private to implementation). // This requires a 2-D scatter in order to set a second base address. // See notes in https://bugs.openjdk.java.net/browse/JDK-8223367 assert(m.allTrue()); return ($abstractvectortype$) zero(species).blend(fromArray(species, a, offset, indexMap, mapOffset), m); #end[byteOrShort] } /** * Loads a vector from a {@linkplain ByteBuffer byte buffer} * starting at an offset into the byte buffer. #if[!byte] *

* Bytes are composed into primitive lane elements according to * {@link ByteOrder#LITTLE_ENDIAN little endian} byte order. * To avoid errors, the * {@linkplain ByteBuffer#order() intrinsic byte order} * of the buffer must be little-endian. #end[!byte] *

* 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 #if[!byte] * @throws IllegalArgumentException if byte order of bb * is not {@link ByteOrder#LITTLE_ENDIAN} #end[!byte] * @throws IndexOutOfBoundsException * if {@code offset+N*$sizeInBytes$ < 0} * or {@code offset+N*$sizeInBytes$ >= bb.limit()} * for any lane {@code N} in the vector */ @ForceInline public static $abstractvectortype$ fromByteBuffer(VectorSpecies<$Boxtype$> species, ByteBuffer bb, int offset, ByteOrder bo) { $Type$Species vsp = ($Type$Species) 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. #if[!byte] *

* Bytes are composed into primitive lane elements according to * {@link ByteOrder#LITTLE_ENDIAN little endian} byte order. * To avoid errors, the * {@linkplain ByteBuffer#order() intrinsic byte order} * of the buffer must be little-endian. #end[!byte] *

* 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 #if[!byte] * @throws IllegalArgumentException if byte order of bb * is not {@link ByteOrder#LITTLE_ENDIAN} #end[!byte] * @throws IndexOutOfBoundsException * if {@code offset+N*$sizeInBytes$ < 0} * or {@code offset+N*$sizeInBytes$ >= bb.limit()} * for any lane {@code N} in the vector * where the mask is set */ @ForceInline public static $abstractvectortype$ fromByteBuffer(VectorSpecies<$Boxtype$> species, ByteBuffer bb, int offset, ByteOrder bo, VectorMask<$Boxtype$> m) { if (m.allTrue()) { return fromByteBuffer(species, bb, offset, bo); } $Type$Species vsp = ($Type$Species) species; checkMaskFromIndexSize(offset, vsp, m, 1, bb.limit()); $abstractvectortype$ zero = zero(vsp); $abstractvectortype$ v = zero.fromByteBuffer0(bb, offset); return zero.blend(v.maybeSwap(bo), m); } // Memory store operations /** * Stores this vector into an array of type {@code $type$[]} * 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 $type$[]} * @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($type$[] a, int offset) { $Type$Species 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 $type$} * 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 $type$[]} * @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($type$[] a, int offset, VectorMask<$Boxtype$> 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 $type$[]} * 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 $abstractvectortype$#toIntArray() */ @ForceInline public final void intoArray($type$[] a, int offset, int[] indexMap, int mapOffset) { $Type$Species 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 $type$[]}, * 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 $abstractvectortype$#toIntArray() */ @ForceInline public final void intoArray($type$[] a, int offset, int[] indexMap, int mapOffset, VectorMask<$Boxtype$> m) { $Type$Species 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<$Boxtype$> m) { if (m.allTrue()) { intoByteArray(a, offset); return; } $Type$Species vsp = vspecies(); if (offset >= 0 && offset <= (a.length - vsp.length() * $sizeInBytes$)) { var oldVal = fromByteArray0(a, offset); var newVal = oldVal.blend(this, m); newVal.intoByteArray0(a, offset); } else { checkMaskFromIndexSize(offset, vsp, m, $sizeInBytes$, a.length); $Type$Buffer 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<$Boxtype$> 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<$Boxtype$> m) { if (m.allTrue()) { intoByteBuffer(bb, offset, bo); return; } $Type$Species vsp = vspecies(); checkMaskFromIndexSize(offset, vsp, m, $sizeInBytes$, bb.limit()); conditionalStoreNYI(offset, vsp, m, $sizeInBytes$, 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 $abstractvectortype$ fromArray0($type$[] a, int offset); @ForceInline final $abstractvectortype$ fromArray0Template($type$[] a, int offset) { $Type$Species 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 $abstractvectortype$ fromByteArray0(byte[] a, int offset); @ForceInline final $abstractvectortype$ fromByteArray0Template(byte[] a, int offset) { $Type$Species vsp = vspecies(); return VectorIntrinsics.load( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), a, byteArrayAddress(a, offset), a, offset, vsp, (arr, off, s) -> { $Type$Buffer tb = wrapper(arr, off, NATIVE_ENDIAN); return s.ldOp(tb, 0, (tb_, __, i) -> tb_.get(i)); }); } abstract $abstractvectortype$ fromByteBuffer0(ByteBuffer bb, int offset); @ForceInline final $abstractvectortype$ fromByteBuffer0Template(ByteBuffer bb, int offset) { $Type$Species vsp = vspecies(); return VectorIntrinsics.load( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), bufferBase(bb), bufferAddress(bb, offset), bb, offset, vsp, (buf, off, s) -> { $Type$Buffer 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($type$[] a, int offset); @ForceInline final void intoArray0Template($type$[] a, int offset) { $Type$Species 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) { $Type$Species vsp = vspecies(); VectorIntrinsics.store( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), a, byteArrayAddress(a, offset), this, a, offset, (arr, off, v) -> { $Type$Buffer 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) { $Type$Species vsp = vspecies(); VectorIntrinsics.store( vsp.vectorType(), vsp.elementType(), vsp.laneCount(), bufferBase(bb), bufferAddress(bb, offset), this, bb, offset, (buf, off, v) -> { $Type$Buffer 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, $Type$Species vsp, VectorMask<$Boxtype$> m, int scale, int limit) { ((AbstractMask<$Boxtype$>)m) .checkIndexByLane(offset, limit, vsp.iota(), scale); } @ForceInline private void conditionalStoreNYI(int offset, $Type$Species vsp, VectorMask<$Boxtype$> 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 $abstractvectortype$ maybeSwap(ByteOrder bo) { #if[!byte] if (bo != NATIVE_ENDIAN) { return this.reinterpretAsBytes() .rearrange(swapBytesShuffle()) .reinterpretAs$Type$s(); } #end[!byte] return this; } static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_$TYPE$_INDEX_SCALE); static final long ARRAY_BASE = Unsafe.ARRAY_$TYPE$_BASE_OFFSET; @ForceInline static long arrayAddress($type$[] 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 $Type$Buffer wrapper(ByteBuffer bb, int offset, ByteOrder bo) { return bb.duplicate().position(offset).slice() .order(bo){#if[byte]?;:.as$Type$Buffer();} } private static $Type$Buffer wrapper(byte[] a, int offset, ByteOrder bo) { return ByteBuffer.wrap(a, offset, a.length - offset) .order(bo){#if[byte]?;:.as$Type$Buffer();} } // ================================================ /// Reinterpreting view methods: // lanewise reinterpret: viewAsXVector() // keep shape, redraw lanes: reinterpretAsEs() /** * {@inheritDoc} */ @ForceInline @Override public final ByteVector reinterpretAsBytes() { #if[byte] return this; #else[byte] // Going to ByteVector, pay close attention to byte order. assert(REGISTER_ENDIAN == ByteOrder.LITTLE_ENDIAN); return asByteVectorRaw(); //return asByteVectorRaw().rearrange(swapBytesShuffle()); #end[byte] } /** * {@inheritDoc} */ @ForceInline @Override public final $Bitstype$Vector viewAsIntegralLanes() { #if[BITWISE] return this; #else[BITWISE] LaneType ilt = LaneType.$TYPE$.asIntegral(); return ($Bitstype$Vector) asVectorRaw(ilt); #end[BITWISE] } /** * {@inheritDoc} #if[byteOrShort] * * @implNote This method always throws * {@code IllegalArgumentException}, because there is no floating * point type of the same size as {@code $type$}. 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. #end[byteOrShort] */ @ForceInline @Override public final {#if[byteOrShort]?Vector:$Fptype$Vector} viewAsFloatingLanes() { #if[FP] return this; #else[FP] LaneType flt = LaneType.$TYPE$.asFloating(); #if[!byteOrShort] return ($Fptype$Vector) asVectorRaw(flt); #else[!byteOrShort] throw new AssertionError(); // should already throw IAE #end[byteOrShort] #end[FP] } // ================================================ /// 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($type$[]) Arrays.toString()}, * as appropriate to the {@code $type$} 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 $abstractvectortype$}'s of the same {@link VectorShape VectorShape}. */ /*package-private*/ static final class $Type$Species extends AbstractSpecies<$Boxtype$> { private $Type$Species(VectorShape shape, Class vectorType, Class> maskType, Function vectorFactory) { super(shape, LaneType.of($type$.class), vectorType, maskType, vectorFactory); assert(this.elementSize() == $Boxtype$.SIZE); } // Specializing overrides: @Override @ForceInline public final Class<$Boxtype$> elementType() { return $type$.class; } @Override @ForceInline public final Class<$Boxtype$> genericElementType() { return $Boxtype$.class; } @Override @ForceInline public final Class<$type$[]> arrayType() { return $type$[].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 $abstractvectortype$ broadcastBits(long bits) { return ($abstractvectortype$) VectorIntrinsics.broadcastCoerced( vectorType, $type$.class, laneCount, bits, this, (bits_, s_) -> s_.rvOp(i -> bits_)); } /*package-private*/ @ForceInline {#if[long]?public} final $abstractvectortype$ broadcast($type$ e) { return broadcastBits(toBits(e)); } #if[!long] @Override @ForceInline public final $abstractvectortype$ broadcast(long e) { return broadcastBits(longToElementBits(e)); } #end[!long] /*package-private*/ final @Override @ForceInline long longToElementBits(long value) { #if[long] // In this case, the conversion can never fail. return value; #else[long] // Do the conversion, and then test it for failure. $type$ e = ($type$) value; if ((long) e != value) { throw badElementBits(value, e); } return toBits(e); #end[long] } /*package-private*/ @ForceInline static long toIntegralChecked($type$ e, boolean convertToInt) { long value = convertToInt ? (int) e : (long) e; if (($type$) value != e) { throw badArrayBits(e, convertToInt, value); } return value; } @Override @ForceInline public final $abstractvectortype$ fromValues(long... values) { VectorIntrinsics.requireLength(values.length, laneCount); $type$[] va = new $type$[laneCount()]; for (int i = 0; i < va.length; i++) { long lv = values[i]; $type$ v = ($type$) 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 $abstractvectortype$ fromIntValues(int[] values) { VectorIntrinsics.requireLength(values.length, laneCount); $type$[] va = new $type$[laneCount()]; for (int i = 0; i < va.length; i++) { int lv = values[i]; $type$ v = ($type$) lv; va[i] = v; if ((int)v != lv) { throw badElementBits(lv, v); } } return dummyVector().fromArray0(va, 0); } // Virtual constructors @ForceInline @Override final public $abstractvectortype$ fromArray(Object a, int offset) { // User entry point: Be careful with inputs. return $abstractvectortype$ .fromArray(this, ($type$[]) a, offset); } @Override final $abstractvectortype$ dummyVector() { return ($abstractvectortype$) super.dummyVector(); } final $abstractvectortype$ vectorFactory($type$[] 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 $abstractvectortype$ rvOp(RVOp f) { $type$[] res = new $type$[laneCount()]; for (int i = 0; i < res.length; i++) { $bitstype$ bits = {#if[!long]?($bitstype$)} f.apply(i); res[i] = fromBits(bits); } return dummyVector().vectorFactory(res); } $Type$Vector vOp(FVOp f) { $type$[] res = new $type$[laneCount()]; for (int i = 0; i < res.length; i++) { res[i] = f.apply(i); } return dummyVector().vectorFactory(res); } $Type$Vector vOp(VectorMask<$Boxtype$> m, FVOp f) { $type$[] res = new $type$[laneCount()]; boolean[] mbits = ((AbstractMask<$Boxtype$>)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 $abstractvectortype$ ldOp(M memory, int offset, FLdOp f) { return dummyVector().ldOp(memory, offset, f); } /*package-private*/ @ForceInline $abstractvectortype$ ldOp(M memory, int offset, AbstractMask<$Boxtype$> 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<$Boxtype$> 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 $abstractvectortype$ zero() { if ((Class) vectorType() == $Type$MaxVector.class) return $Type$MaxVector.ZERO; switch (vectorBitSize()) { case 64: return $Type$64Vector.ZERO; case 128: return $Type$128Vector.ZERO; case 256: return $Type$256Vector.ZERO; case 512: return $Type$512Vector.ZERO; } throw new AssertionError(); } @Override @ForceInline public final $abstractvectortype$ iota() { if ((Class) vectorType() == $Type$MaxVector.class) return $Type$MaxVector.IOTA; switch (vectorBitSize()) { case 64: return $Type$64Vector.IOTA; case 128: return $Type$128Vector.IOTA; case 256: return $Type$256Vector.IOTA; case 512: return $Type$512Vector.IOTA; } throw new AssertionError(); } // Mask access @Override @ForceInline public final VectorMask<$Boxtype$> maskAll(boolean bit) { if ((Class) vectorType() == $Type$MaxVector.class) return $Type$MaxVector.$Type$MaxMask.maskAll(bit); switch (vectorBitSize()) { case 64: return $Type$64Vector.$Type$64Mask.maskAll(bit); case 128: return $Type$128Vector.$Type$128Mask.maskAll(bit); case 256: return $Type$256Vector.$Type$256Mask.maskAll(bit); case 512: return $Type$512Vector.$Type$512Mask.maskAll(bit); } throw new AssertionError(); } } /** * Finds a species for an element type of {@code $type$} and shape. * * @param s the shape * @return a species for an element type of {@code $type$} and shape * @throws IllegalArgumentException if no such species exists for the shape */ static $Type$Species species(VectorShape s) { Objects.requireNonNull(s); switch (s) { case S_64_BIT: return ($Type$Species) SPECIES_64; case S_128_BIT: return ($Type$Species) SPECIES_128; case S_256_BIT: return ($Type$Species) SPECIES_256; case S_512_BIT: return ($Type$Species) SPECIES_512; case S_Max_BIT: return ($Type$Species) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } /** Species representing {@link $Type$Vector}s of {@link VectorShape#S_64_BIT VectorShape.S_64_BIT}. */ public static final VectorSpecies<$Boxtype$> SPECIES_64 = new $Type$Species(VectorShape.S_64_BIT, $Type$64Vector.class, $Type$64Vector.$Type$64Mask.class, $Type$64Vector::new); /** Species representing {@link $Type$Vector}s of {@link VectorShape#S_128_BIT VectorShape.S_128_BIT}. */ public static final VectorSpecies<$Boxtype$> SPECIES_128 = new $Type$Species(VectorShape.S_128_BIT, $Type$128Vector.class, $Type$128Vector.$Type$128Mask.class, $Type$128Vector::new); /** Species representing {@link $Type$Vector}s of {@link VectorShape#S_256_BIT VectorShape.S_256_BIT}. */ public static final VectorSpecies<$Boxtype$> SPECIES_256 = new $Type$Species(VectorShape.S_256_BIT, $Type$256Vector.class, $Type$256Vector.$Type$256Mask.class, $Type$256Vector::new); /** Species representing {@link $Type$Vector}s of {@link VectorShape#S_512_BIT VectorShape.S_512_BIT}. */ public static final VectorSpecies<$Boxtype$> SPECIES_512 = new $Type$Species(VectorShape.S_512_BIT, $Type$512Vector.class, $Type$512Vector.$Type$512Mask.class, $Type$512Vector::new); /** Species representing {@link $Type$Vector}s of {@link VectorShape#S_Max_BIT VectorShape.S_Max_BIT}. */ public static final VectorSpecies<$Boxtype$> SPECIES_MAX = new $Type$Species(VectorShape.S_Max_BIT, $Type$MaxVector.class, $Type$MaxVector.$Type$MaxMask.class, $Type$MaxVector::new); /** * Preferred species for {@link $Type$Vector}s. * A preferred species is a species of maximal bit-size for the platform. */ public static final VectorSpecies<$Boxtype$> SPECIES_PREFERRED = ($Type$Species) VectorSpecies.ofPreferred($type$.class); }