/* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have * questions. */ package jdk.incubator.vector; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ReadOnlyBufferException; import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; import static jdk.incubator.vector.VectorIntrinsics.*; @SuppressWarnings("cast") final class ByteScalableVector extends ByteVector { static final ByteScalableSpecies SPECIES = new ByteScalableSpecies(); static final ByteScalableVector ZERO = new ByteScalableVector(); static final int LENGTH = SPECIES.length(); private final byte[] vec; // Don't access directly, use getElements() instead. private byte[] getElements() { return VectorIntrinsics.maybeRebox(this).vec; } ByteScalableVector() { vec = new byte[SPECIES.length()]; } ByteScalableVector(byte[] v) { vec = v; } @Override public int length() { return LENGTH; } // Unary operator @Override ByteScalableVector uOp(FUnOp f) { byte[] vec = getElements(); byte[] res = new byte[length()]; for (int i = 0; i < length(); i++) { res[i] = f.apply(i, vec[i]); } return new ByteScalableVector(res); } @Override ByteScalableVector uOp(Mask o, FUnOp f) { byte[] vec = getElements(); byte[] res = new byte[length()]; boolean[] mbits = ((ByteScalableMask)o).getBits(); for (int i = 0; i < length(); i++) { res[i] = mbits[i] ? f.apply(i, vec[i]) : vec[i]; } return new ByteScalableVector(res); } // Binary operator @Override ByteScalableVector bOp(Vector o, FBinOp f) { byte[] res = new byte[length()]; byte[] vec1 = this.getElements(); byte[] vec2 = ((ByteScalableVector)o).getElements(); for (int i = 0; i < length(); i++) { res[i] = f.apply(i, vec1[i], vec2[i]); } return new ByteScalableVector(res); } @Override ByteScalableVector bOp(Vector o1, Mask o2, FBinOp f) { byte[] res = new byte[length()]; byte[] vec1 = this.getElements(); byte[] vec2 = ((ByteScalableVector)o1).getElements(); boolean[] mbits = ((ByteScalableMask)o2).getBits(); for (int i = 0; i < length(); i++) { res[i] = mbits[i] ? f.apply(i, vec1[i], vec2[i]) : vec1[i]; } return new ByteScalableVector(res); } // Trinary operator @Override ByteScalableVector tOp(Vector o1, Vector o2, FTriOp f) { byte[] res = new byte[length()]; byte[] vec1 = this.getElements(); byte[] vec2 = ((ByteScalableVector)o1).getElements(); byte[] vec3 = ((ByteScalableVector)o2).getElements(); for (int i = 0; i < length(); i++) { res[i] = f.apply(i, vec1[i], vec2[i], vec3[i]); } return new ByteScalableVector(res); } @Override ByteScalableVector tOp(Vector o1, Vector o2, Mask o3, FTriOp f) { byte[] res = new byte[length()]; byte[] vec1 = getElements(); byte[] vec2 = ((ByteScalableVector)o1).getElements(); byte[] vec3 = ((ByteScalableVector)o2).getElements(); boolean[] mbits = ((ByteScalableMask)o3).getBits(); for (int i = 0; i < length(); i++) { res[i] = mbits[i] ? f.apply(i, vec1[i], vec2[i], vec3[i]) : vec1[i]; } return new ByteScalableVector(res); } @Override byte rOp(byte v, FBinOp f) { byte[] vec = getElements(); for (int i = 0; i < length(); i++) { v = f.apply(i, v, vec[i]); } return v; } // Binary operations with scalars @Override @ForceInline public ByteVector add(byte o) { return add(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector add(byte o, Mask m) { return add(SPECIES.broadcast(o), m); } @Override @ForceInline public ByteVector sub(byte o) { return sub(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector sub(byte o, Mask m) { return sub(SPECIES.broadcast(o), m); } @Override @ForceInline public ByteVector mul(byte o) { return mul(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector mul(byte o, Mask m) { return mul(SPECIES.broadcast(o), m); } @Override @ForceInline public ByteVector min(byte o) { return min(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector max(byte o) { return max(SPECIES.broadcast(o)); } @Override @ForceInline public Mask equal(byte o) { return equal(SPECIES.broadcast(o)); } @Override @ForceInline public Mask notEqual(byte o) { return notEqual(SPECIES.broadcast(o)); } @Override @ForceInline public Mask lessThan(byte o) { return lessThan(SPECIES.broadcast(o)); } @Override @ForceInline public Mask lessThanEq(byte o) { return lessThanEq(SPECIES.broadcast(o)); } @Override @ForceInline public Mask greaterThan(byte o) { return greaterThan(SPECIES.broadcast(o)); } @Override @ForceInline public Mask greaterThanEq(byte o) { return greaterThanEq(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector blend(byte o, Mask m) { return blend(SPECIES.broadcast(o), m); } @Override @ForceInline public ByteVector and(byte o) { return and(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector and(byte o, Mask m) { return and(SPECIES.broadcast(o), m); } @Override @ForceInline public ByteVector or(byte o) { return or(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector or(byte o, Mask m) { return or(SPECIES.broadcast(o), m); } @Override @ForceInline public ByteVector xor(byte o) { return xor(SPECIES.broadcast(o)); } @Override @ForceInline public ByteVector xor(byte o, Mask m) { return xor(SPECIES.broadcast(o), m); } @Override @ForceInline public ByteScalableVector neg() { return SPECIES.zero().sub(this); } // Unary operations @ForceInline @Override public ByteScalableVector neg(Mask m) { return blend(neg(), m); } @Override @ForceInline public ByteScalableVector abs() { return VectorIntrinsics.unaryOp( VECTOR_OP_ABS, ByteScalableVector.class, byte.class, LENGTH, this, v1 -> v1.uOp((i, a) -> (byte) Math.abs(a))); } @ForceInline @Override public ByteScalableVector abs(Mask m) { return blend(abs(), m); } @Override @ForceInline public ByteScalableVector not() { return VectorIntrinsics.unaryOp( VECTOR_OP_NOT, ByteScalableVector.class, byte.class, LENGTH, this, v1 -> v1.uOp((i, a) -> (byte) ~a)); } @ForceInline @Override public ByteScalableVector not(Mask m) { return blend(not(), m); } // Binary operations @Override @ForceInline public ByteScalableVector add(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.binaryOp( VECTOR_OP_ADD, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bOp(v2, (i, a, b) -> (byte)(a + b))); } @Override @ForceInline public ByteScalableVector add(Vector v, Mask m) { return blend(add(v), m); } @Override @ForceInline public ByteScalableVector sub(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.binaryOp( VECTOR_OP_SUB, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bOp(v2, (i, a, b) -> (byte)(a - b))); } @Override @ForceInline public ByteScalableVector sub(Vector v, Mask m) { return blend(sub(v), m); } @Override @ForceInline public ByteScalableVector mul(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.binaryOp( VECTOR_OP_MUL, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bOp(v2, (i, a, b) -> (byte)(a * b))); } @Override @ForceInline public ByteScalableVector mul(Vector v, Mask m) { return blend(mul(v), m); } @Override @ForceInline public ByteScalableVector min(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return (ByteScalableVector) VectorIntrinsics.binaryOp( VECTOR_OP_MIN, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> ((ByteScalableVector)v1).bOp(v2, (i, a, b) -> (byte) ((a < b) ? a : b))); } @Override @ForceInline public ByteScalableVector max(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.binaryOp( VECTOR_OP_MAX, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bOp(v2, (i, a, b) -> (byte) ((a > b) ? a : b))); } @Override @ForceInline public ByteScalableVector and(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.binaryOp( VECTOR_OP_AND, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bOp(v2, (i, a, b) -> (byte)(a & b))); } @Override @ForceInline public ByteScalableVector or(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.binaryOp( VECTOR_OP_OR, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bOp(v2, (i, a, b) -> (byte)(a | b))); } @Override @ForceInline public ByteScalableVector xor(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.binaryOp( VECTOR_OP_XOR, ByteScalableVector.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bOp(v2, (i, a, b) -> (byte)(a ^ b))); } @Override @ForceInline public ByteScalableVector and(Vector v, Mask m) { return blend(and(v), m); } @Override @ForceInline public ByteScalableVector or(Vector v, Mask m) { return blend(or(v), m); } @Override @ForceInline public ByteScalableVector xor(Vector v, Mask m) { return blend(xor(v), m); } // Ternary operations // Type specific horizontal reductions @Override @ForceInline public byte addAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_ADD, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp((byte) 0, (i, a, b) -> (byte) (a + b))); } @Override @ForceInline public byte andAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_AND, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp((byte) -1, (i, a, b) -> (byte) (a & b))); } @Override @ForceInline public byte andAll(Mask m) { return blend(SPECIES.broadcast((byte) -1), m).andAll(); } @Override @ForceInline public byte minAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_MIN, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp(Byte.MAX_VALUE , (i, a, b) -> (byte) ((a < b) ? a : b))); } @Override @ForceInline public byte maxAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_MAX, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp(Byte.MIN_VALUE , (i, a, b) -> (byte) ((a > b) ? a : b))); } @Override @ForceInline public byte mulAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_MUL, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp((byte) 1, (i, a, b) -> (byte) (a * b))); } @Override @ForceInline public byte subAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_SUB, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp((byte) 0, (i, a, b) -> (byte) (a - b))); } @Override @ForceInline public byte orAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_OR, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp((byte) 0, (i, a, b) -> (byte) (a | b))); } @Override @ForceInline public byte orAll(Mask m) { return blend(SPECIES.broadcast((byte) 0), m).orAll(); } @Override @ForceInline public byte xorAll() { return (byte) VectorIntrinsics.reductionCoerced( VECTOR_OP_XOR, ByteScalableVector.class, byte.class, LENGTH, this, v -> (long) v.rOp((byte) 0, (i, a, b) -> (byte) (a ^ b))); } @Override @ForceInline public byte xorAll(Mask m) { return blend(SPECIES.broadcast((byte) 0), m).xorAll(); } @Override @ForceInline public byte addAll(Mask m) { return blend(SPECIES.broadcast((byte) 0), m).addAll(); } @Override @ForceInline public byte subAll(Mask m) { return blend(SPECIES.broadcast((byte) 0), m).subAll(); } @Override @ForceInline public byte mulAll(Mask m) { return blend(SPECIES.broadcast((byte) 1), m).mulAll(); } @Override @ForceInline public byte minAll(Mask m) { return blend(SPECIES.broadcast(Byte.MAX_VALUE), m).minAll(); } @Override @ForceInline public byte maxAll(Mask m) { return blend(SPECIES.broadcast(Byte.MIN_VALUE), m).maxAll(); } @Override @ForceInline public Shuffle toShuffle() { byte[] a = toArray(); int[] sa = new int[a.length]; for (int i = 0; i < a.length; i++) { sa[i] = (int) a[i]; } return SPECIES.shuffleFromArray(sa, 0); } // Memory operations private static final int ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(Unsafe.ARRAY_BYTE_INDEX_SCALE); @Override @ForceInline public void intoArray(byte[] a, int ix) { Objects.requireNonNull(a); ix = VectorIntrinsics.checkIndex(ix, a.length, LENGTH); VectorIntrinsics.store(ByteScalableVector.class, byte.class, LENGTH, a, (((long) ix) << ARRAY_SHIFT) + Unsafe.ARRAY_BYTE_BASE_OFFSET, this, a, ix, (arr, idx, v) -> v.forEach((i, e) -> arr[idx + i] = e)); } @Override @ForceInline public final void intoArray(byte[] a, int ax, Mask m) { // @@@ This can result in out of bounds errors for unset mask lanes ByteScalableVector oldVal = SPECIES.fromArray(a, ax); ByteScalableVector newVal = oldVal.blend(this, m); newVal.intoArray(a, ax); } @Override @ForceInline public void intoByteArray(byte[] a, int ix) { // @@@ Endianess Objects.requireNonNull(a); ix = VectorIntrinsics.checkIndex(ix, a.length, bitSize() / Byte.SIZE); VectorIntrinsics.store(ByteScalableVector.class, byte.class, LENGTH, a, ((long) ix) + Unsafe.ARRAY_BYTE_BASE_OFFSET, this, a, ix, (c, idx, v) -> { ByteBuffer bbc = ByteBuffer.wrap(c, idx, c.length - idx).order(ByteOrder.nativeOrder()); ByteBuffer tb = bbc; v.forEach((i, e) -> tb.put(e)); }); } @Override @ForceInline public final void intoByteArray(byte[] a, int ix, Mask m) { // @@@ This can result in out of bounds errors for unset mask lanes ByteScalableVector oldVal = SPECIES.fromByteArray(a, ix); ByteScalableVector newVal = oldVal.blend(this, m); newVal.intoByteArray(a, ix); } @Override @ForceInline public void intoByteBuffer(ByteBuffer bb, int ix) { // @@@ Endianess if (bb.order() != ByteOrder.nativeOrder()) { throw new IllegalArgumentException(); } if (bb.isReadOnly()) { throw new ReadOnlyBufferException(); } ix = VectorIntrinsics.checkIndex(ix, bb.limit(), bitSize() / Byte.SIZE); VectorIntrinsics.store(ByteScalableVector.class, byte.class, LENGTH, U.getObject(bb, BYTE_BUFFER_HB), ix + U.getLong(bb, BUFFER_ADDRESS), this, bb, ix, (c, idx, v) -> { ByteBuffer bbc = c.duplicate().position(idx).order(ByteOrder.nativeOrder()); ByteBuffer tb = bbc; v.forEach((i, e) -> tb.put(e)); }); } @Override @ForceInline public void intoByteBuffer(ByteBuffer bb, int ix, Mask m) { // @@@ This can result in out of bounds errors for unset mask lanes ByteScalableVector oldVal = SPECIES.fromByteBuffer(bb, ix); ByteScalableVector newVal = oldVal.blend(this, m); newVal.intoByteBuffer(bb, ix); } // @Override public String toString() { return Arrays.toString(getElements()); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || this.getClass() != o.getClass()) return false; // @@@ Use equal op ByteScalableVector that = (ByteScalableVector) o; return Arrays.equals(this.getElements(), that.getElements()); } @Override public int hashCode() { return Arrays.hashCode(vec); } // Binary test @Override ByteScalableMask bTest(Vector o, FBinTest f) { byte[] vec1 = getElements(); byte[] vec2 = ((ByteScalableVector)o).getElements(); boolean[] bits = new boolean[length()]; for (int i = 0; i < length(); i++){ bits[i] = f.apply(i, vec1[i], vec2[i]); } return new ByteScalableMask(bits); } // Comparisons @Override @ForceInline public ByteScalableMask equal(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.compare( BT_eq, ByteScalableVector.class, ByteScalableMask.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bTest(v2, (i, a, b) -> a == b)); } @Override @ForceInline public ByteScalableMask notEqual(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.compare( BT_ne, ByteScalableVector.class, ByteScalableMask.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bTest(v2, (i, a, b) -> a != b)); } @Override @ForceInline public ByteScalableMask lessThan(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.compare( BT_lt, ByteScalableVector.class, ByteScalableMask.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bTest(v2, (i, a, b) -> a < b)); } @Override @ForceInline public ByteScalableMask lessThanEq(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.compare( BT_le, ByteScalableVector.class, ByteScalableMask.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bTest(v2, (i, a, b) -> a <= b)); } @Override @ForceInline public ByteScalableMask greaterThan(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return (ByteScalableMask) VectorIntrinsics.compare( BT_gt, ByteScalableVector.class, ByteScalableMask.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bTest(v2, (i, a, b) -> a > b)); } @Override @ForceInline public ByteScalableMask greaterThanEq(Vector o) { Objects.requireNonNull(o); ByteScalableVector v = (ByteScalableVector)o; return VectorIntrinsics.compare( BT_ge, ByteScalableVector.class, ByteScalableMask.class, byte.class, LENGTH, this, v, (v1, v2) -> v1.bTest(v2, (i, a, b) -> a >= b)); } // Foreach @Override void forEach(FUnCon f) { byte[] vec = getElements(); for (int i = 0; i < length(); i++) { f.apply(i, vec[i]); } } @Override void forEach(Mask o, FUnCon f) { boolean[] mbits = ((ByteScalableMask)o).getBits(); forEach((i, a) -> { if (mbits[i]) { f.apply(i, a); } }); } @Override public ByteScalableVector rotateEL(int j) { byte[] vec = getElements(); byte[] res = new byte[length()]; for (int i = 0; i < length(); i++){ res[(j + i) % length()] = vec[i]; } return new ByteScalableVector(res); } @Override public ByteScalableVector rotateER(int j) { byte[] vec = getElements(); byte[] res = new byte[length()]; for (int i = 0; i < length(); i++){ int z = i - j; if(j < 0) { res[length() + z] = vec[i]; } else { res[z] = vec[i]; } } return new ByteScalableVector(res); } @Override public ByteScalableVector shiftEL(int j) { byte[] vec = getElements(); byte[] res = new byte[length()]; for (int i = 0; i < length() - j; i++) { res[i] = vec[i + j]; } return new ByteScalableVector(res); } @Override public ByteScalableVector shiftER(int j) { byte[] vec = getElements(); byte[] res = new byte[length()]; for (int i = 0; i < length() - j; i++){ res[i + j] = vec[i]; } return new ByteScalableVector(res); } @Override @ForceInline public ByteScalableVector rearrange(Vector v, Shuffle s, Mask m) { return this.rearrange(s).blend(v.rearrange(s), m); } @Override public ByteScalableVector rearrange(Shuffle s) { return uOp((i, a) -> { byte[] vec = this.getElements(); int ei = s.getElement(i); return vec[ei]; }); } @Override @ForceInline public ByteScalableVector blend(Vector o1, Mask o2) { Objects.requireNonNull(o1); Objects.requireNonNull(o2); ByteScalableVector v = (ByteScalableVector)o1; ByteScalableMask m = (ByteScalableMask)o2; return VectorIntrinsics.blend( ByteScalableVector.class, ByteScalableMask.class, byte.class, LENGTH, this, v, m, (v1, v2, m_) -> v1.bOp(v2, (i, a, b) -> m_.getElement(i) ? b : a)); } // Accessors @Override public byte get(int i) { if (i < 0 || i >= LENGTH) { throw new IllegalArgumentException("Index " + i + " must be zero or positive, and less than " + LENGTH); } return (byte) VectorIntrinsics.extract( ByteScalableVector.class, byte.class, LENGTH, this, i, (vec, ix) -> { byte[] vecarr = vec.getElements(); return (long)vecarr[ix]; }); } @Override public ByteScalableVector with(int i, byte e) { if (i < 0 || i >= LENGTH) { throw new IllegalArgumentException("Index " + i + " must be zero or positive, and less than " + LENGTH); } return VectorIntrinsics.insert( ByteScalableVector.class, byte.class, LENGTH, this, i, (long)e, (v, ix, bits) -> { byte[] res = v.getElements().clone(); res[ix] = (byte)bits; return new ByteScalableVector(res); }); } // Mask static final class ByteScalableMask extends AbstractMask { static final ByteScalableMask TRUE_MASK = new ByteScalableMask(true); static final ByteScalableMask FALSE_MASK = new ByteScalableMask(false); // FIXME: was temporarily put here to simplify rematerialization support in the JVM private final boolean[] bits; // Don't access directly, use getBits() instead. public ByteScalableMask(boolean[] bits) { this(bits, 0); } public ByteScalableMask(boolean[] bits, int offset) { boolean[] a = new boolean[species().length()]; for (int i = 0; i < a.length; i++) { a[i] = bits[offset + i]; } this.bits = a; } public ByteScalableMask(boolean val) { boolean[] bits = new boolean[species().length()]; Arrays.fill(bits, val); this.bits = bits; } boolean[] getBits() { return VectorIntrinsics.maybeRebox(this).bits; } @Override ByteScalableMask uOp(MUnOp f) { boolean[] res = new boolean[species().length()]; boolean[] bits = getBits(); for (int i = 0; i < species().length(); i++) { res[i] = f.apply(i, bits[i]); } return new ByteScalableMask(res); } @Override ByteScalableMask bOp(Mask o, MBinOp f) { boolean[] res = new boolean[species().length()]; boolean[] bits = getBits(); boolean[] mbits = ((ByteScalableMask)o).getBits(); for (int i = 0; i < species().length(); i++) { res[i] = f.apply(i, bits[i], mbits[i]); } return new ByteScalableMask(res); } @Override public ByteScalableSpecies species() { return SPECIES; } @Override public ByteScalableVector toVector() { byte[] res = new byte[species().length()]; boolean[] bits = getBits(); for (int i = 0; i < species().length(); i++) { // -1 will result in the most significant bit being set in // addition to some or all other bits res[i] = (byte) (bits[i] ? -1 : 0); } return new ByteScalableVector(res); } // Unary operations @Override @ForceInline public ByteScalableMask not() { return (ByteScalableMask) VectorIntrinsics.unaryOp( VECTOR_OP_NOT, ByteScalableMask.class, byte.class, LENGTH, this, (m1) -> m1.uOp((i, a) -> !a)); } // Binary operations @Override @ForceInline public ByteScalableMask and(Mask o) { Objects.requireNonNull(o); ByteScalableMask m = (ByteScalableMask)o; return VectorIntrinsics.binaryOp(VECTOR_OP_AND, ByteScalableMask.class, byte.class, LENGTH, this, m, (m1, m2) -> m1.bOp(m2, (i, a, b) -> a & b)); } @Override @ForceInline public ByteScalableMask or(Mask o) { Objects.requireNonNull(o); ByteScalableMask m = (ByteScalableMask)o; return VectorIntrinsics.binaryOp(VECTOR_OP_OR, ByteScalableMask.class, byte.class, LENGTH, this, m, (m1, m2) -> m1.bOp(m2, (i, a, b) -> a | b)); } // Reductions @Override @ForceInline public boolean anyTrue() { return VectorIntrinsics.test(COND_notZero, ByteScalableMask.class, byte.class, LENGTH, this, this, (m1, m2) -> super.anyTrue()); } @Override @ForceInline public boolean allTrue() { return VectorIntrinsics.test(COND_carrySet, ByteScalableMask.class, byte.class, LENGTH, this, species().maskAllTrue(), (m1, m2) -> super.allTrue()); } } // Shuffle static final class ByteScalableShuffle extends AbstractShuffle { ByteScalableShuffle(byte[] reorder) { super(reorder); } public ByteScalableShuffle(int[] reorder) { super(reorder); } public ByteScalableShuffle(int[] reorder, int i) { super(reorder, i); } public ByteScalableShuffle(IntUnaryOperator f) { super(f); } @Override public ByteScalableSpecies species() { return SPECIES; } @Override public ByteScalableVector toVector() { byte[] va = new byte[SPECIES.length()]; for (int i = 0; i < va.length; i++) { va[i] = (byte) getElement(i); } return species().fromArray(va, 0); } @Override public ByteScalableShuffle rearrange(Vector.Shuffle o) { ByteScalableShuffle s = (ByteScalableShuffle) o; byte[] r = new byte[reorder.length]; for (int i = 0; i < reorder.length; i++) { r[i] = reorder[s.reorder[i]]; } return new ByteScalableShuffle(r); } } // Species @Override public ByteScalableSpecies species() { return SPECIES; } static final class ByteScalableSpecies extends ByteSpecies { static final int BIT_SIZE = Shapes.S_Scalable_BIT.bitSize(); static final int LENGTH = BIT_SIZE / Byte.SIZE; @Override public String toString() { StringBuilder sb = new StringBuilder("Shape["); sb.append(bitSize()).append(" bits, "); sb.append(length()).append(" ").append(byte.class.getSimpleName()).append("s x "); sb.append(elementSize()).append(" bits"); sb.append("]"); return sb.toString(); } @Override @ForceInline public int bitSize() { return BIT_SIZE; } @Override @ForceInline public int length() { return LENGTH; } @Override @ForceInline public Class elementType() { return byte.class; } @Override @ForceInline public int elementSize() { return Byte.SIZE; } @Override @ForceInline public Shapes.SScalableBit shape() { return Shapes.S_Scalable_BIT; } @Override ByteScalableVector op(FOp f) { byte[] res = new byte[length()]; for (int i = 0; i < length(); i++) { res[i] = f.apply(i); } return new ByteScalableVector(res); } @Override ByteScalableVector op(Mask o, FOp f) { byte[] res = new byte[length()]; boolean[] mbits = ((ByteScalableMask)o).getBits(); for (int i = 0; i < length(); i++) { if (mbits[i]) { res[i] = f.apply(i); } } return new ByteScalableVector(res); } // Factories @Override public ByteScalableMask maskFromValues(boolean... bits) { return new ByteScalableMask(bits); } @Override public ByteScalableMask maskFromArray(boolean[] bits, int i) { return new ByteScalableMask(bits, i); } @Override public ByteScalableShuffle shuffle(IntUnaryOperator f) { return new ByteScalableShuffle(f); } @Override public ByteScalableShuffle shuffleIota() { return new ByteScalableShuffle(AbstractShuffle.IDENTITY); } @Override public ByteScalableShuffle shuffleFromValues(int... ixs) { return new ByteScalableShuffle(ixs); } @Override public ByteScalableShuffle shuffleFromArray(int[] ixs, int i) { return new ByteScalableShuffle(ixs, i); } @Override @ForceInline public ByteScalableVector zero() { return VectorIntrinsics.broadcastCoerced(ByteScalableVector.class, byte.class, LENGTH, 0, (z -> ZERO)); } @Override @ForceInline public ByteScalableVector broadcast(byte e) { return VectorIntrinsics.broadcastCoerced( ByteScalableVector.class, byte.class, LENGTH, e, ((long bits) -> SPECIES.op(i -> (byte)bits))); } @Override @ForceInline public ByteScalableMask maskAllTrue() { return VectorIntrinsics.broadcastCoerced(ByteScalableMask.class, byte.class, LENGTH, (byte)-1, (z -> ByteScalableMask.TRUE_MASK)); } @Override @ForceInline public ByteScalableMask maskAllFalse() { return VectorIntrinsics.broadcastCoerced(ByteScalableMask.class, byte.class, LENGTH, 0, (z -> ByteScalableMask.FALSE_MASK)); } @Override @ForceInline public ByteScalableVector scalars(byte... es) { Objects.requireNonNull(es); int ix = VectorIntrinsics.checkIndex(0, es.length, LENGTH); return VectorIntrinsics.load(ByteScalableVector.class, byte.class, LENGTH, es, Unsafe.ARRAY_BYTE_BASE_OFFSET, es, ix, (c, idx) -> op(n -> c[idx + n])); } @Override @ForceInline public ByteScalableVector fromArray(byte[] a, int ix) { Objects.requireNonNull(a); ix = VectorIntrinsics.checkIndex(ix, a.length, LENGTH); return VectorIntrinsics.load(ByteScalableVector.class, byte.class, LENGTH, a, (((long) ix) << ARRAY_SHIFT) + Unsafe.ARRAY_BYTE_BASE_OFFSET, a, ix, (c, idx) -> op(n -> c[idx + n])); } @Override @ForceInline public ByteScalableVector fromArray(byte[] a, int ax, Mask m) { // @@@ This can result in out of bounds errors for unset mask lanes return zero().blend(fromArray(a, ax), m); } @Override @ForceInline public ByteScalableVector fromByteArray(byte[] a, int ix) { // @@@ Endianess Objects.requireNonNull(a); ix = VectorIntrinsics.checkIndex(ix, a.length, bitSize() / Byte.SIZE); return VectorIntrinsics.load(ByteScalableVector.class, byte.class, LENGTH, a, ((long) ix) + Unsafe.ARRAY_BYTE_BASE_OFFSET, a, ix, (c, idx) -> { ByteBuffer bbc = ByteBuffer.wrap(c, idx, a.length - idx).order(ByteOrder.nativeOrder()); ByteBuffer tb = bbc; return op(i -> tb.get()); }); } @Override @ForceInline public ByteScalableVector fromByteArray(byte[] a, int ix, Mask m) { // @@@ This can result in out of bounds errors for unset mask lanes return zero().blend(fromByteArray(a, ix), m); } @Override @ForceInline public ByteScalableVector fromByteBuffer(ByteBuffer bb, int ix) { // @@@ Endianess if (bb.order() != ByteOrder.nativeOrder()) { throw new IllegalArgumentException(); } ix = VectorIntrinsics.checkIndex(ix, bb.limit(), bitSize() / Byte.SIZE); return VectorIntrinsics.load(ByteScalableVector.class, byte.class, LENGTH, U.getObject(bb, BYTE_BUFFER_HB), U.getLong(bb, BUFFER_ADDRESS) + ix, bb, ix, (c, idx) -> { ByteBuffer bbc = c.duplicate().position(idx).order(ByteOrder.nativeOrder()); ByteBuffer tb = bbc; return op(i -> tb.get()); }); } @Override @ForceInline public ByteScalableVector fromByteBuffer(ByteBuffer bb, int ix, Mask m) { // @@@ This can result in out of bounds errors for unset mask lanes return zero().blend(fromByteBuffer(bb, ix), m); } @Override @ForceInline @SuppressWarnings("unchecked") public ByteScalableVector cast(Vector o) { if (o.length() != LENGTH) throw new IllegalArgumentException("Vector length this species length differ"); return VectorIntrinsics.cast( o.getClass(), o.elementType(), LENGTH, byte.class, LENGTH, o, this, (s, v) -> s.castDefault(v) ); } @SuppressWarnings("unchecked") @ForceInline private ByteScalableVector castDefault(Vector v) { // Allocate array of required size int limit = length(); byte[] a = new byte[limit]; Class vtype = v.species().elementType(); if (vtype == byte.class) { ByteVector tv = (ByteVector)v; for (int i = 0; i < limit; i++) { a[i] = (byte) tv.get(i); } } else if (vtype == short.class) { ShortVector tv = (ShortVector)v; for (int i = 0; i < limit; i++) { a[i] = (byte) tv.get(i); } } else if (vtype == int.class) { IntVector tv = (IntVector)v; for (int i = 0; i < limit; i++) { a[i] = (byte) tv.get(i); } } else if (vtype == long.class){ LongVector tv = (LongVector)v; for (int i = 0; i < limit; i++) { a[i] = (byte) tv.get(i); } } else if (vtype == float.class){ FloatVector tv = (FloatVector)v; for (int i = 0; i < limit; i++) { a[i] = (byte) tv.get(i); } } else if (vtype == double.class){ DoubleVector tv = (DoubleVector)v; for (int i = 0; i < limit; i++) { a[i] = (byte) tv.get(i); } } else { throw new UnsupportedOperationException("Bad lane type for casting."); } return scalars(a); } @Override @ForceInline public ByteScalableMask cast(Mask m) { if (m.length() != LENGTH) throw new IllegalArgumentException("Mask length this species length differ"); return new ByteScalableMask(m.toArray()); } @Override @ForceInline public ByteScalableShuffle cast(Shuffle s) { if (s.length() != LENGTH) throw new IllegalArgumentException("Shuffle length this species length differ"); return new ByteScalableShuffle(s.toArray()); } @Override @ForceInline @SuppressWarnings("unchecked") public ByteScalableVector rebracket(Vector o) { Objects.requireNonNull(o); if (o.elementType() == byte.class) { ByteScalableVector so = (ByteScalableVector)o; return VectorIntrinsics.reinterpret( ByteScalableVector.class, byte.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.elementType() == short.class) { ShortScalableVector so = (ShortScalableVector)o; return VectorIntrinsics.reinterpret( ShortScalableVector.class, short.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.elementType() == int.class) { IntScalableVector so = (IntScalableVector)o; return VectorIntrinsics.reinterpret( IntScalableVector.class, int.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.elementType() == long.class) { LongScalableVector so = (LongScalableVector)o; return VectorIntrinsics.reinterpret( LongScalableVector.class, long.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.elementType() == float.class) { FloatScalableVector so = (FloatScalableVector)o; return VectorIntrinsics.reinterpret( FloatScalableVector.class, float.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.elementType() == double.class) { DoubleScalableVector so = (DoubleScalableVector)o; return VectorIntrinsics.reinterpret( DoubleScalableVector.class, double.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else { throw new InternalError("Unimplemented type"); } } @Override @ForceInline @SuppressWarnings("unchecked") public ByteScalableVector resize(Vector o) { Objects.requireNonNull(o); if (o.bitSize() == 64) { Byte64Vector so = (Byte64Vector)o; return VectorIntrinsics.reinterpret( Byte64Vector.class, byte.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.bitSize() == 128) { Byte128Vector so = (Byte128Vector)o; return VectorIntrinsics.reinterpret( Byte128Vector.class, byte.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.bitSize() == 256) { Byte256Vector so = (Byte256Vector)o; return VectorIntrinsics.reinterpret( Byte256Vector.class, byte.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if (o.bitSize() == 512) { Byte512Vector so = (Byte512Vector)o; return VectorIntrinsics.reinterpret( Byte512Vector.class, byte.class, so.length(), byte.class, LENGTH, so, this, (s, v) -> (ByteScalableVector) s.reshape(v) ); } else if ((o.bitSize() <= 2048) && (o.bitSize() % 128 == 0)) { throw new InternalError("Resize to scalable shape unimplemented."); } else { throw new InternalError("Unimplemented size"); } } } }