package jdk.incubator.vector;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import java.nio.ByteOrder;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
abstract class AbstractSpecies<E> extends jdk.internal.vm.vector.VectorSupport.VectorSpecies<E>
implements VectorSpecies<E> {
@Stable
final VectorShape vectorShape;
@Stable
final LaneType laneType;
@Stable
final int laneCount;
@Stable
final int laneCountLog2P1;
@Stable
final Class<? extends AbstractVector<E>> vectorType;
@Stable
final Class<? extends AbstractMask<E>> maskType;
@Stable
final Function<Object, ? extends AbstractVector<E>> vectorFactory;
@Stable
final VectorShape indexShape;
@Stable
final int maxScale, minScale;
@Stable
final int vectorBitSize, vectorByteSize;
AbstractSpecies(VectorShape vectorShape,
LaneType laneType,
Class<? extends AbstractVector<E>> vectorType,
Class<? extends AbstractMask<E>> maskType,
Function<Object, ? extends AbstractVector<E>> vectorFactory) {
this.vectorShape = vectorShape;
this.laneType = laneType;
this.vectorType = vectorType;
this.maskType = maskType;
this.vectorFactory = vectorFactory;
int bitSize = vectorShape.vectorBitSize();
int byteSize = bitSize / Byte.SIZE;
assert(byteSize * 8 == bitSize);
this.vectorBitSize = bitSize;
this.vectorByteSize = byteSize;
int elementSize = laneType.elementSize;
this.laneCount = bitSize / elementSize;
assert(laneCount > 0);
this.laneCountLog2P1 = Integer.numberOfTrailingZeros(laneCount) + 1;
int indexBitSize = Integer.SIZE * laneCount;
this.indexShape = VectorShape.forIndexBitSize(indexBitSize, elementSize);
int precision = laneType.elementPrecision;
if (precision >= Integer.SIZE) {
this.maxScale = Integer.MAX_VALUE;
this.minScale = Integer.MIN_VALUE;
} else {
boolean isfp = (laneType.elementKind == 'F');
long x = laneCount;
long maxScale = ((1L << precision)-(isfp?0:1)) / x;
long minScale = (-1L << precision) / x;
this.maxScale = (int) maxScale;
this.minScale = (int) minScale;
}
}
@Stable
AbstractSpecies<Integer> indexSpecies;
@Stable
AbstractShuffle<Byte> swapBytesShuffle;
@Stable
AbstractVector<E> dummyVector;
@Override
@ForceInline
public final int length() {
return laneCount;
}
@ForceInline
final int laneCount() {
return laneCount;
}
@ForceInline
final int laneCountLog2() {
return laneCountLog2P1 - 1;
}
@Override
@ForceInline
@SuppressWarnings("unchecked")
public Class<E> elementType() {
return (Class<E>) laneType.elementType;
}
@ForceInline
@SuppressWarnings("unchecked")
Class<E> genericElementType() {
return (Class<E>) laneType.genericElementType;
}
@Override
@ForceInline
public Class<? extends AbstractVector<E>> vectorType() {
return vectorType;
}
@Override
@ForceInline
public final Class<? extends AbstractMask<E>> maskType() {
return maskType;
}
@Override
@ForceInline
public final int elementSize() {
return laneType.elementSize;
}
@ForceInline
final int elementByteSize() {
return laneType.elementSize / Byte.SIZE;
}
@Override
@ForceInline
public final VectorShape vectorShape() {
return vectorShape;
}
@ForceInline
final VectorShape indexShape() {
return indexShape;
}
@Override
@ForceInline
public final int vectorBitSize() {
return vectorBitSize;
}
@Override
@ForceInline
public final int vectorByteSize() {
return vectorByteSize;
}
@Override
@ForceInline
public final int loopBound(int length) {
return VectorIntrinsics.roundDown(length, laneCount);
}
@Override
@ForceInline
public final VectorMask<E> indexInRange(int offset, int limit) {
return maskAll(true).indexInRange(offset, limit);
}
@Override
@ForceInline
public final <F> VectorSpecies<F> withLanes(Class<F> newType) {
return withLanes(LaneType.of(newType)).check(newType);
}
@ForceInline
final
AbstractSpecies<?> withLanes(LaneType newType) {
if (newType == laneType) return this;
return findSpecies(newType, vectorShape);
}
@ForceInline
AbstractSpecies<?> asIntegral() {
return withLanes(laneType.asIntegral());
}
@ForceInline
AbstractSpecies<?> asFloating() {
return withLanes(laneType.asFloating());
}
@Override
@ForceInline
@SuppressWarnings("unchecked")
public final VectorSpecies<E> withShape(VectorShape newShape) {
if (newShape == vectorShape) return this;
return (VectorSpecies<E>) findSpecies(laneType, newShape);
}
@ForceInline
AbstractSpecies<Integer> indexSpecies() {
AbstractSpecies<Integer> sp = indexSpecies;
if (sp != null) return sp;
return indexSpecies = findSpecies(LaneType.INT, indexShape).check0(int.class);
}
@ForceInline
@SuppressWarnings("unchecked")
AbstractSpecies<Byte> byteSpecies() {
return (AbstractSpecies<Byte>) withLanes(LaneType.BYTE);
}
@ForceInline
AbstractShuffle<Byte> swapBytesShuffle() {
AbstractShuffle<Byte> sh = swapBytesShuffle;
if (sh != null) return sh;
return swapBytesShuffle = makeSwapBytesShuffle();
}
private AbstractShuffle<Byte> makeSwapBytesShuffle() {
int vbytes = vectorByteSize();
int lbytes = elementByteSize();
int[] sourceIndexes = new int[vbytes];
for (int i = 0; i < vbytes; i++) {
sourceIndexes[i] = i ^ (lbytes-1);
}
return (AbstractShuffle<Byte>)
VectorShuffle.fromValues(byteSpecies(), sourceIndexes);
}
abstract Vector<E> fromIntValues(int[] values);
@ForceInline
AbstractVector<E> dummyVector() {
AbstractVector<E> dummy = dummyVector;
if (dummy != null) return dummy;
return makeDummyVector();
}
private AbstractVector<E> makeDummyVector() {
Object za = Array.newInstance(elementType(), laneCount);
return dummyVector = vectorFactory.apply(za);
}
@ForceInline
AbstractMask<E> maskFactory(boolean[] bits) {
return dummyVector().maskFromArray(bits);
}
public final
@Override
@ForceInline
VectorShuffle<E> shuffleFromArray(int[] sourceIndexes, int offset) {
return dummyVector().shuffleFromArray(sourceIndexes, offset);
}
public final
@Override
@ForceInline
VectorShuffle<E> shuffleFromValues(int... sourceIndexes) {
return dummyVector().shuffleFromArray(sourceIndexes, 0);
}
public final
@Override
@ForceInline
VectorShuffle<E> shuffleFromOp(IntUnaryOperator fn) {
return dummyVector().shuffleFromOp(fn);
}
public final
@Override
@ForceInline
VectorShuffle<E> iotaShuffle(int start, int step, boolean wrap) {
AbstractShuffle<E> res;
if (start == 0 && step == 1)
return dummyVector().iotaShuffle();
else
return dummyVector().iotaShuffle(start, step, wrap);
}
@ForceInline
@Override
public final Vector<E> fromByteArray(byte[] a, int offset, ByteOrder bo) {
return dummyVector()
.fromByteArray0(a, offset)
.maybeSwap(bo);
}
@Override
public VectorMask<E> loadMask(boolean[] bits, int offset) {
return VectorMask.fromArray(this, bits, offset);
}
public abstract AbstractVector<E> zero();
abstract AbstractVector<E> iota();
abstract long longToElementBits(long e);
abstract AbstractVector<E> broadcastBits(long bits);
final IllegalArgumentException badElementBits(long iv, Object cv) {
String msg = String.format("Vector creation failed: "+
"value %s cannot be represented in ETYPE %s"+
"; result of cast is %s",
iv,
elementType(),
cv);
return new IllegalArgumentException(msg);
}
static
final IllegalArgumentException badArrayBits(Object iv,
boolean isInt,
long cv) {
String msg = String.format("Array creation failed: "+
"lane value %s cannot be represented in %s"+
"; result of cast is %s",
iv,
(isInt ? "int" : "long"),
cv);
return new IllegalArgumentException(msg);
}
Object iotaArray() {
Object ia = Array.newInstance(laneType.elementType,
laneCount);
assert(ia.getClass() == laneType.arrayType);
checkValue(laneCount-1);
for (int i = 0; i < laneCount; i++) {
if ((byte)i == i)
Array.setByte(ia, i, (byte)i);
else if ((short)i == i)
Array.setShort(ia, i, (short)i);
else
Array.setInt(ia, i, i);
assert(Array.getDouble(ia, i) == i);
}
return ia;
}
@ForceInline
void checkScale(int scale) {
if (scale > 0) {
if (scale <= maxScale) return;
} else {
if (scale >= minScale) return;
}
throw checkScaleFailed(scale);
}
private IllegalArgumentException checkScaleFailed(int scale) {
String msg = String.format("%s: cannot represent VLENGTH*%d",
this, scale);
return new IllegalArgumentException(msg);
}
interface RVOp {
long apply(int i);
}
abstract AbstractVector<E> rvOp(RVOp f);
interface FOpm {
boolean apply(int i);
}
AbstractMask<E> opm(FOpm f) {
boolean[] res = new boolean[laneCount];
for (int i = 0; i < res.length; i++) {
res[i] = f.apply(i);
}
return dummyVector().maskFromArray(res);
}
@Override
@ForceInline
public final
<F> VectorSpecies<F> check(Class<F> elementType) {
return check0(elementType);
}
@ForceInline
@SuppressWarnings("unchecked")
final
<F> AbstractSpecies<F> check0(Class<F> elementType) {
if (elementType != this.elementType()) {
throw AbstractSpecies.checkFailed(this, elementType);
}
return (AbstractSpecies<F>) this;
}
@ForceInline
AbstractSpecies<E> check(LaneType laneType) {
if (laneType != this.laneType) {
throw AbstractSpecies.checkFailed(this, laneType);
}
return this;
}
@Override
@ForceInline
public int partLimit(VectorSpecies<?> toSpecies, boolean lanewise) {
AbstractSpecies<?> rsp = (AbstractSpecies<?>) toSpecies;
int inSizeLog2 = this.vectorShape.vectorBitSizeLog2;
int outSizeLog2 = rsp.vectorShape.vectorBitSizeLog2;
if (lanewise) {
inSizeLog2 += (rsp.laneType.elementSizeLog2 -
this.laneType.elementSizeLog2);
}
int diff = (inSizeLog2 - outSizeLog2);
int sign = (diff >> -1);
int d = (diff ^ sign) - sign;
return ((sign | 1) << d) & ~1;
}
static ClassCastException checkFailed(Object what, Object required) {
AbstractSpecies<?> whatSpecies = null;
String where;
if (what instanceof VectorSpecies) {
whatSpecies = (AbstractSpecies<?>) what;
where = whatSpecies.toString();
} else if (what instanceof Vector) {
whatSpecies = (AbstractSpecies<?>) ((Vector<?>) what).species();
where = "a Vector<"+whatSpecies.genericElementType()+">";
} else if (what instanceof VectorMask) {
whatSpecies = (AbstractSpecies<?>) ((VectorMask<?>) what).vectorSpecies();
where = "a VectorMask<"+whatSpecies.genericElementType()+">";
} else if (what instanceof VectorShuffle) {
whatSpecies = (AbstractSpecies<?>) ((VectorShuffle<?>) what).vectorSpecies();
where = "a VectorShuffle<"+whatSpecies.genericElementType()+">";
} else {
where = what.toString();
}
Object found = null;
if (whatSpecies != null) {
if (required instanceof VectorSpecies) {
found = whatSpecies;
} else if (required instanceof Vector) {
found = whatSpecies;
required = ((Vector<?>)required).species();
} else if (required instanceof Class) {
Class<?> requiredClass = (Class<?>) required;
LaneType requiredType = LaneType.forClassOrNull(requiredClass);
found = whatSpecies.elementType();
if (requiredType == null) {
required = required + " (not a valid lane type)";
} else if (!requiredClass.isPrimitive()) {
required = required + " (should be " + requiredType + ")";
}
} else if (required instanceof LaneType) {
required = ((LaneType) required).elementType;
found = whatSpecies.elementType();
} else if (required instanceof Integer) {
required = required + " lanes";
found = whatSpecies.length();
}
}
if (found == null) found = "bad value";
String msg = where+": required "+required+" but found "+found;
return new ClassCastException(msg);
}
private static final @Stable AbstractSpecies<?>[][] CACHES
= new AbstractSpecies<?>[LaneType.SK_LIMIT][VectorShape.SK_LIMIT];
@ForceInline
static <E>
AbstractSpecies<E> findSpecies(Class<E> elementType,
LaneType laneType,
VectorShape shape) {
assert(elementType == laneType.elementType);
return findSpecies(laneType, shape).check0(elementType);
}
@ForceInline
static
AbstractSpecies<?> findSpecies(LaneType laneType,
VectorShape shape) {
AbstractSpecies<?> s = CACHES[laneType.switchKey][shape.switchKey];
if (s != null) return s;
return computeSpecies(laneType, shape);
}
private static
AbstractSpecies<?> computeSpecies(LaneType laneType,
VectorShape shape) {
AbstractSpecies<?> s = null;
switch (laneType.switchKey) {
case LaneType.SK_FLOAT:
s = FloatVector.species(shape); break;
case LaneType.SK_DOUBLE:
s = DoubleVector.species(shape); break;
case LaneType.SK_BYTE:
s = ByteVector.species(shape); break;
case LaneType.SK_SHORT:
s = ShortVector.species(shape); break;
case LaneType.SK_INT:
s = IntVector.species(shape); break;
case LaneType.SK_LONG:
s = LongVector.species(shape); break;
}
if (s == null) {
throw new AssertionError("bootstrap problem");
}
assert(s.laneType == laneType) : s + "!=" + laneType;
assert(s.vectorShape == shape) : s + "!=" + shape;
CACHES[laneType.switchKey][shape.switchKey] = s;
return s;
}
@Override
public final String toString() {
return "Species["+laneType+", "+laneCount+", "+vectorShape+"]";
}
@Override
public final boolean equals(Object obj) {
if (obj instanceof AbstractSpecies) {
AbstractSpecies<?> that = (AbstractSpecies<?>) obj;
return (this.laneType == that.laneType &&
this.laneCount == that.laneCount &&
this.vectorShape == that.vectorShape);
}
return this == obj;
}
@Override
public final int hashCode() {
int[] a = { laneType.ordinal(), laneCount, vectorShape.ordinal() };
return Arrays.hashCode(a);
}
}