/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.objects.simd;
import static com.github.anba.es6draft.runtime.AbstractOperations.*;
import static com.github.anba.es6draft.runtime.internal.Errors.newRangeError;
import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError;
import static com.github.anba.es6draft.runtime.internal.Properties.createProperties;
import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.CreateByteDataBlock;
import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.IsDetachedBuffer;
import static com.github.anba.es6draft.runtime.objects.simd.SIMDType.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.function.*;
import java.util.stream.Collectors;
import com.github.anba.es6draft.runtime.AbstractOperations;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.CompatibilityOption;
import com.github.anba.es6draft.runtime.internal.Initializable;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.internal.Properties.CompatibilityExtension;
import com.github.anba.es6draft.runtime.internal.Properties.Prototype;
import com.github.anba.es6draft.runtime.internal.Properties.Value;
import com.github.anba.es6draft.runtime.objects.binary.TypedArrayObject;
import com.github.anba.es6draft.runtime.types.Intrinsics;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.Type;
import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject;
/**
* The %SIMD% intrinsic object.
*/
public final class SIMD extends OrdinaryObject implements Initializable {
private static final boolean FLUSH_DENORMAL = false;
public SIMD(Realm realm) {
super(realm);
}
@Override
public void initialize(Realm realm) {
createProperties(realm, this, Properties.class);
createProperties(realm, this, AdditionalProperties.class);
}
/**
* {@link BiPredicate} specialized for {@code double} arguments.
*/
@FunctionalInterface
public interface DoubleBiPredicate {
boolean test(double left, double right);
}
/**
* {@link BiPredicate} specialized for {@code int} arguments.
*/
@FunctionalInterface
public interface IntBiPredicate {
boolean test(int left, int right);
}
/**
* {@link UnaryOperator} specialized for {@code boolean} arguments.
*/
@FunctionalInterface
public interface BooleanUnaryOperator {
boolean applyAsBoolean(boolean operand);
}
/**
* {@link BinaryOperator} specialized for {@code boolean} arguments.
*/
@FunctionalInterface
public interface BooleanBinaryOperator {
boolean applyAsBoolean(boolean left, boolean right);
}
/**
* {@link Function} specialized for {@code boolean} return type.
*/
@FunctionalInterface
public interface ToBooleanFunction<T> {
boolean applyAsBoolean(T value);
}
/**
* ToString ( argument )
*
* @param value
* the argument value
* @return the string result
*/
public static String ToString(SIMDValue value) {
return value.toString();
}
/**
* SameValue(x, y)
*
* @param x
* the first operand
* @param y
* the second operand
* @return {@code true} if both operands have the same value
*/
public static boolean SameValue(SIMDValue x, SIMDValue y) {
if (x.getType() != y.getType()) {
return false;
}
switch (x.getType()) {
case Float64x2:
case Float32x4:
return compareSIMDFloat(x, y, AbstractOperations::SameValue);
case Int32x4:
case Int16x8:
case Int8x16:
case Uint32x4:
case Uint16x8:
case Uint8x16:
return Arrays.equals(x.asInt(), y.asInt());
case Bool64x2:
case Bool32x4:
case Bool16x8:
case Bool8x16:
return Arrays.equals(x.asBoolean(), y.asBoolean());
default:
throw new AssertionError();
}
}
/**
* SameValueZero(x, y)
*
* @param x
* the first operand
* @param y
* the second operand
* @return {@code true} if both operands have the same value
*/
public static boolean SameValueZero(SIMDValue x, SIMDValue y) {
if (x.getType() != y.getType()) {
return false;
}
switch (x.getType()) {
case Float64x2:
case Float32x4:
return compareSIMDFloat(x, y, AbstractOperations::SameValueZero);
case Int32x4:
case Int16x8:
case Int8x16:
case Uint32x4:
case Uint16x8:
case Uint8x16:
return Arrays.equals(x.asInt(), y.asInt());
case Bool64x2:
case Bool32x4:
case Bool16x8:
case Bool8x16:
return Arrays.equals(x.asBoolean(), y.asBoolean());
default:
throw new AssertionError();
}
}
/**
* Strict Equality Comparison
*
* @param x
* the first operand
* @param y
* the second operand
* @return the comparison result
*/
public static boolean StrictEquality(SIMDValue x, SIMDValue y) {
if (x.getType() != y.getType()) {
return false;
}
switch (x.getType()) {
case Float64x2:
case Float32x4:
return compareSIMDFloat(x, y, (a, b) -> a == b);
case Int32x4:
case Int16x8:
case Int8x16:
case Uint32x4:
case Uint16x8:
case Uint8x16:
return Arrays.equals(x.asInt(), y.asInt());
case Bool64x2:
case Bool32x4:
case Bool16x8:
case Bool8x16:
return Arrays.equals(x.asBoolean(), y.asBoolean());
default:
throw new AssertionError();
}
}
private static boolean compareSIMDFloat(SIMDValue x, SIMDValue y, DoubleBiPredicate compare) {
double[] a = x.asDouble(), b = y.asDouble();
for (int i = 0; i < a.length; ++i) {
if (!compare.test(a[i], b[i])) {
return false;
}
}
return true;
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDCreate( descriptor, vectorElements )
*
* @param cx
* the execution context
* @param descriptor
* the SIMD type descriptor
* @param vectorElements
* the SIMD vector elements
* @param cast
* the cast function
* @return the new SIMD value
*/
public static SIMDValue SIMDCreateFloat(ExecutionContext cx, SIMDType descriptor, Object[] vectorElements,
ToDoubleBiFunction<ExecutionContext, Object> cast) {
/* steps 1-2 (not applicable) */
/* step 3 */
assert vectorElements.length == descriptor.getVectorLength();
/* step 4 */
double[] list = new double[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
list[i] = cast.applyAsDouble(cx, vectorElements[i]);
}
/* step 6 */
return new SIMDValue(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDCreate( descriptor, vectorElements )
*
* @param cx
* the execution context
* @param descriptor
* the SIMD type descriptor
* @param vectorElements
* the SIMD vector elements
* @param cast
* the cast function
* @return the new SIMD value
*/
public static SIMDValue SIMDCreateInt(ExecutionContext cx, SIMDType descriptor, Object[] vectorElements,
ToIntBiFunction<ExecutionContext, Object> cast) {
/* steps 1-2 (not applicable) */
/* step 3 */
assert vectorElements.length == descriptor.getVectorLength();
/* step 4 */
int[] list = new int[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
list[i] = cast.applyAsInt(cx, vectorElements[i]);
}
/* step 6 */
return new SIMDValue(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDCreate( descriptor, vectorElements )
*
* @param cx
* the execution context
* @param descriptor
* the SIMD type descriptor
* @param vectorElements
* the SIMD vector elements
* @param cast
* the cast function
* @return the new SIMD value
*/
public static SIMDValue SIMDCreateBool(ExecutionContext cx, SIMDType descriptor, Object[] vectorElements,
ToBooleanFunction<Object> cast) {
/* steps 1-2 (not applicable) */
/* step 3 */
assert vectorElements.length == descriptor.getVectorLength();
/* step 4 */
boolean[] list = new boolean[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
list[i] = cast.applyAsBoolean(vectorElements[i]);
}
/* step 6 */
return new SIMDValue(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDCreate( descriptor, vectorElements )
*
* @param descriptor
* the SIMD type descriptor
* @param vectorElements
* the SIMD vector elements
* @return the new SIMD value
*/
public static SIMDValue SIMDCreate(SIMDType descriptor, double[] vectorElements) {
/* steps 1-2 (not applicable) */
/* step 3 */
assert vectorElements.length == descriptor.getVectorLength();
/* steps 4-5 (not applicable) */
/* step 6 */
return new SIMDValue(descriptor, vectorElements);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDCreate( descriptor, vectorElements )
*
* @param descriptor
* the SIMD type descriptor
* @param vectorElements
* the SIMD vector elements
* @return the new SIMD value
*/
public static SIMDValue SIMDCreate(SIMDType descriptor, int[] vectorElements) {
/* steps 1-2 (not applicable) */
/* step 3 */
assert vectorElements.length == descriptor.getVectorLength();
/* steps 4-5 (not applicable) */
/* step 6 */
return new SIMDValue(descriptor, vectorElements);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDCreate( descriptor, vectorElements )
*
* @param descriptor
* the SIMD type descriptor
* @param vectorElements
* the SIMD vector elements
* @return the new SIMD value
*/
public static SIMDValue SIMDCreate(SIMDType descriptor, boolean[] vectorElements) {
/* steps 1-2 (not applicable) */
/* step 3 */
assert vectorElements.length == descriptor.getVectorLength();
/* steps 4-5 (not applicable) */
/* step 6 */
return new SIMDValue(descriptor, vectorElements);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDToLane( max, lane )
*
* @param cx
* the execution context
* @param max
* the maximum lane index
* @param lane
* the lane index
* @return the SIMD lane index
*/
public static int SIMDToLane(ExecutionContext cx, int max, Object lane) {
/* steps 1-2 */
double index = ToNumber(cx, lane);
/* step 3 */
// FIXME: spec issue - SameValueZero not required or useful here, change to normal == comparison? (check NaN!)
// FIXME: spec issue - ToLength expected semantics here, ToInteger probably more correct...?!
if (!AbstractOperations.SameValueZero(index, ToLength(index)) || index < 0 || index >= max) {
throw newRangeError(cx, Messages.Key.SIMDInvalidLane);
}
/* step 4 */
return (int) index;
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDExtractLane( value, lane )
*
* @param value
* the SIMD value
* @param lane
* the lane index
* @return the lane value
*/
public static double SIMDExtractLaneFloat(SIMDValue value, int lane) {
/* step 1 (not applicable) */
/* steps 2-3 */
assert 0 <= lane && lane < value.getType().getVectorLength();
int index = lane;
/* step 4 */
return value.asDouble()[index];
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDExtractLane( value, lane )
*
* @param value
* the SIMD value
* @param lane
* the lane index
* @return the lane value
*/
public static int SIMDExtractLaneInt(SIMDValue value, int lane) {
/* step 1 (not applicable) */
/* steps 2-3 */
assert 0 <= lane && lane < value.getType().getVectorLength();
int index = lane;
/* step 4 */
return value.asInt()[index];
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDExtractLane( value, lane )
*
* @param value
* the SIMD value
* @param lane
* the lane index
* @return the lane value
*/
public static boolean SIMDExtractLaneBool(SIMDValue value, int lane) {
/* step 1 (not applicable) */
/* steps 2-3 */
assert 0 <= lane && lane < value.getType().getVectorLength();
int index = lane;
/* step 4 */
return value.asBoolean()[index];
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDReplaceLane( value, lane, replacement )
*
* @param cx
* the execution context
* @param value
* the SIMD value
* @param lane
* the lane index
* @param replacement
* the replacement value
* @param cast
* the cast function
* @return the new SIMD value
*/
public static SIMDValue SIMDReplaceLaneFloat(ExecutionContext cx, SIMDValue value, Object lane, Object replacement,
ToDoubleBiFunction<ExecutionContext, Object> cast) {
/* step 1 (not applicable) */
/* step 2 */
SIMDType descriptor = value.getType();
/* steps 3-4 */
int index = SIMDToLane(cx, descriptor.getVectorLength(), lane);
/* step 5 */
double[] list = value.asDouble().clone();
/* step 6 (inlined SIMDCreate - [[Cast]]) */
list[index] = cast.applyAsDouble(cx, replacement);
/* step 7 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDReplaceLane( value, lane, replacement )
*
* @param cx
* the execution context
* @param value
* the SIMD value
* @param lane
* the lane index
* @param replacement
* the replacement value
* @param cast
* the cast function
* @return the new SIMD value
*/
public static SIMDValue SIMDReplaceLaneInt(ExecutionContext cx, SIMDValue value, Object lane, Object replacement,
ToIntBiFunction<ExecutionContext, Object> cast) {
/* step 1 (not applicable) */
/* step 2 */
SIMDType descriptor = value.getType();
/* steps 3-4 */
int index = SIMDToLane(cx, descriptor.getVectorLength(), lane);
/* step 5 */
int[] list = value.asInt().clone();
/* step 6 (inlined SIMDCreate - [[Cast]]) */
list[index] = cast.applyAsInt(cx, replacement);
/* step 7 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDReplaceLane( value, lane, replacement )
*
* @param cx
* the execution context
* @param value
* the SIMD value
* @param lane
* the lane index
* @param replacement
* the replacement value
* @param cast
* the cast function
* @return the new SIMD value
*/
public static SIMDValue SIMDReplaceLaneBool(ExecutionContext cx, SIMDValue value, Object lane, Object replacement,
ToBooleanFunction<Object> cast) {
/* step 1 (not applicable) */
/* step 2 */
SIMDType descriptor = value.getType();
/* steps 3-4 */
int index = SIMDToLane(cx, descriptor.getVectorLength(), lane);
/* step 5 */
boolean[] list = value.asBoolean().clone();
/* step 6 (inlined SIMDCreate - [[Cast]]) */
list[index] = cast.applyAsBoolean(replacement);
/* step 7 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* MaybeFlushDenormal( n, descriptor )
*
* @param n
* the number value
* @return the number value
*/
public static double MaybeFlushDenormalFloat(double n) {
/* steps 1-4 */
if (FLUSH_DENORMAL) {
if (isDenormalized((float) n)) {
return n > 0 ? +0d : -0d;
}
}
/* step 5/1 */
return n;
}
private static boolean isDenormalized(float f) {
return f != 0 && f > -Float.MIN_NORMAL && f < Float.MIN_NORMAL;
}
/**
* Internal algorithms on SIMD types
* <p>
* MaybeFlushDenormal( n, descriptor )
*
* @param n
* the number value
* @return the number value
*/
public static double MaybeFlushDenormalDouble(double n) {
/* steps 1-4 */
if (FLUSH_DENORMAL) {
if (isDenormalized(n)) {
return n > 0 ? +0d : -0d;
}
}
/* step 5/1 */
return n;
}
private static boolean isDenormalized(double d) {
return d != 0 && d > -Double.MIN_NORMAL && d < Double.MIN_NORMAL;
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBinaryOp( a, b, op, outputDescriptor )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDBinaryOpFloat(SIMDValue a, SIMDValue b, DoubleBinaryOperator op) {
/* step 1 */
assert a.getType() == b.getType();
assert a.getType() == SIMDType.Float32x4;
/* step 2 */
SIMDType descriptor = a.getType();
/* step 3 */
SIMDType outputDescriptor = a.getType();
/* step 4 */
double[] list = new double[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
double ax = MaybeFlushDenormalFloat(SIMDExtractLaneFloat(a, i));
/* step 5.b */
double bx = MaybeFlushDenormalFloat(SIMDExtractLaneFloat(b, i));
/* steps 5.c-d */
double res = op.applyAsDouble(ax, bx);
/* step 5.e */
res = MaybeFlushDenormalFloat(res);
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(outputDescriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBinaryOp( a, b, op, outputDescriptor )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDBinaryOpDouble(SIMDValue a, SIMDValue b, DoubleBinaryOperator op) {
/* step 1 */
assert a.getType() == b.getType();
assert a.getType() == SIMDType.Float64x2;
/* step 2 */
SIMDType descriptor = a.getType();
/* step 3 */
SIMDType outputDescriptor = a.getType();
/* step 4 */
double[] list = new double[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
double ax = MaybeFlushDenormalDouble(SIMDExtractLaneFloat(a, i));
/* step 5.b */
double bx = MaybeFlushDenormalDouble(SIMDExtractLaneFloat(b, i));
/* steps 5.c-d */
double res = op.applyAsDouble(ax, bx);
/* step 5.e */
res = MaybeFlushDenormalDouble(res);
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(outputDescriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBinaryOp( a, b, op, outputDescriptor )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @param outputDescriptor
* the output type descriptor, always boolean SIMD type
* @return the new SIMD value
*/
public static SIMDValue SIMDBinaryOpFloat(SIMDValue a, SIMDValue b, DoubleBiPredicate op,
SIMDType outputDescriptor) {
/* step 1 */
assert a.getType() == b.getType();
assert a.getType() == SIMDType.Float32x4 && outputDescriptor == SIMDType.Bool32x4;
/* step 2 */
SIMDType descriptor = a.getType();
/* step 3 (not applicable) */
/* step 4 */
boolean[] list = new boolean[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
double ax = MaybeFlushDenormalFloat(SIMDExtractLaneFloat(a, i));
/* step 5.b */
double bx = MaybeFlushDenormalFloat(SIMDExtractLaneFloat(b, i));
/* steps 5.c-d */
boolean res = op.test(ax, bx);
/* step 5.e (not applicable) */
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(outputDescriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBinaryOp( a, b, op, outputDescriptor )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @param outputDescriptor
* the output type descriptor, always boolean SIMD type
* @return the new SIMD value
*/
public static SIMDValue SIMDBinaryOpDouble(SIMDValue a, SIMDValue b, DoubleBiPredicate op,
SIMDType outputDescriptor) {
/* step 1 */
assert a.getType() == b.getType();
assert a.getType() == SIMDType.Float64x2 && outputDescriptor == SIMDType.Bool64x2;
/* step 2 */
SIMDType descriptor = a.getType();
/* step 3 (not applicable) */
/* step 4 */
boolean[] list = new boolean[outputDescriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
double ax = MaybeFlushDenormalDouble(SIMDExtractLaneFloat(a, i));
/* step 5.b */
double bx = MaybeFlushDenormalDouble(SIMDExtractLaneFloat(b, i));
/* steps 5.c-d */
boolean res = op.test(ax, bx);
/* step 5.e (not applicable) */
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(outputDescriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBinaryOp( a, b, op, outputDescriptor )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDBinaryOpInt(SIMDValue a, SIMDValue b, IntBinaryOperator op) {
/* step 1 */
assert a.getType() == b.getType();
assert a.getType().isInteger();
/* step 2 */
SIMDType descriptor = a.getType();
/* step 3 */
SIMDType outputDescriptor = a.getType();
/* step 4 */
int[] list = new int[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
int ax = SIMDExtractLaneInt(a, i);
/* step 5.b */
int bx = SIMDExtractLaneInt(b, i);
/* steps 5.c-d */
int res = op.applyAsInt(ax, bx);
/* step 5.e (not applicable) */
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(outputDescriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBinaryOp( a, b, op, outputDescriptor )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @param outputDescriptor
* the output type descriptor, always boolean SIMD type
* @return the new SIMD value
*/
public static SIMDValue SIMDBinaryOpInt(SIMDValue a, SIMDValue b, IntBiPredicate op, SIMDType outputDescriptor) {
/* step 1 */
assert a.getType() == b.getType();
assert a.getType().getVectorLength() == outputDescriptor.getVectorLength();
assert a.getType().isInteger() && outputDescriptor.isBoolean();
/* step 2 */
SIMDType descriptor = a.getType();
/* step 3 (not applicable) */
/* step 4 */
boolean[] list = new boolean[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
int ax = SIMDExtractLaneInt(a, i);
/* step 5.b */
int bx = SIMDExtractLaneInt(b, i);
/* steps 5.c-d */
boolean res = op.test(ax, bx);
/* step 5.e (not applicable) */
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(outputDescriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBinaryOp( a, b, op, outputDescriptor )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDBinaryOpBool(SIMDValue a, SIMDValue b, BooleanBinaryOperator op) {
/* step 1 */
assert a.getType() == b.getType();
assert a.getType().isBoolean();
/* step 2 */
SIMDType descriptor = a.getType();
/* step 3 */
SIMDType outputDescriptor = a.getType();
/* step 4 */
boolean[] list = new boolean[descriptor.getVectorLength()];
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
boolean ax = SIMDExtractLaneBool(a, i);
/* step 5.b */
boolean bx = SIMDExtractLaneBool(b, i);
/* steps 5.c-d */
boolean res = op.applyAsBoolean(ax, bx);
/* step 5.e (not applicable) */
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(outputDescriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDUnaryOp( a, op [ , flushDenormal ] )
*
* @param a
* the operand value
* @param op
* the unary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDUnaryOpFloat(SIMDValue a, DoubleUnaryOperator op) {
return SIMDUnaryOpFloat(a, op, true);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDUnaryOp( a, op [ , flushDenormal ] )
*
* @param a
* the operand value
* @param op
* the unary operator
* @param flushDenormal
* if {@code true} denormals are flushed to zero
* @return the new SIMD value
*/
public static SIMDValue SIMDUnaryOpFloat(SIMDValue a, DoubleUnaryOperator op, boolean flushDenormal) {
/* step 1 */
SIMDType descriptor = a.getType();
assert descriptor == SIMDType.Float32x4;
/* step 2 (not applicable) */
/* step 3 */
double[] list = new double[descriptor.getVectorLength()];
/* step 4 (FIXME: spec bug) */
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
double ax = SIMDExtractLaneFloat(a, i);
/* step 5.b */
if (flushDenormal) {
ax = MaybeFlushDenormalFloat(ax);
}
/* steps 5.c-d */
double res = op.applyAsDouble(ax);
/* step 5.e */
if (flushDenormal) {
res = MaybeFlushDenormalFloat(res);
}
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDUnaryOp( a, op [ , flushDenormal ] )
*
* @param a
* the operand value
* @param op
* the unary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDUnaryOpDouble(SIMDValue a, DoubleUnaryOperator op) {
return SIMDUnaryOpDouble(a, op, true);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDUnaryOp( a, op [ , flushDenormal ] )
*
* @param a
* the operand value
* @param op
* the unary operator
* @param flushDenormal
* if {@code true} denormals are flushed to zero
* @return the new SIMD value
*/
public static SIMDValue SIMDUnaryOpDouble(SIMDValue a, DoubleUnaryOperator op, boolean flushDenormal) {
/* step 1 */
SIMDType descriptor = a.getType();
assert descriptor == SIMDType.Float64x2;
/* step 2 (not applicable) */
/* step 3 */
double[] list = new double[descriptor.getVectorLength()];
/* step 4 (FIXME: spec bug) */
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
double ax = SIMDExtractLaneFloat(a, i);
/* step 5.b */
if (flushDenormal) {
ax = MaybeFlushDenormalDouble(ax);
}
/* steps 5.c-d */
double res = op.applyAsDouble(ax);
/* step 5.e */
if (flushDenormal) {
res = MaybeFlushDenormalDouble(res);
}
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDUnaryOp( a, op [ , flushDenormal ] )
*
* @param a
* the operand value
* @param op
* the unary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDUnaryOpInt(SIMDValue a, IntUnaryOperator op) {
/* step 1 */
SIMDType descriptor = a.getType();
assert descriptor.isInteger();
/* step 2 (not applicable) */
/* step 3 */
int[] list = new int[descriptor.getVectorLength()];
/* step 4 (FIXME: spec bug) */
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
int ax = SIMDExtractLaneInt(a, i);
/* step 5.b (not applicable) */
/* steps 5.c-d */
int res = op.applyAsInt(ax);
/* step 5.e (not applicable) */
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDUnaryOp( a, op [ , flushDenormal ] )
*
* @param a
* the operand value
* @param op
* the unary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDUnaryOpBool(SIMDValue a, BooleanUnaryOperator op) {
/* step 1 */
SIMDType descriptor = a.getType();
assert descriptor.isBoolean();
/* step 2 (not applicable) */
/* step 3 */
boolean[] list = new boolean[descriptor.getVectorLength()];
/* step 4 (FIXME: spec bug) */
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
boolean ax = SIMDExtractLaneBool(a, i);
/* step 5.b (not applicable) */
/* steps 5.c-d */
boolean res = op.applyAsBoolean(ax);
/* step 5.e (not applicable) */
/* step 5.f */
list[i] = res;
}
/* step 6 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDScalarOp( a, scalar, op )
*
* @param a
* the operand value
* @param scalar
* the scalar value
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDScalarOp(SIMDValue a, int scalar, IntBinaryOperator op) {
/* step 1 */
SIMDType descriptor = a.getType();
assert descriptor.isInteger();
/* step 2 */
// FIXME: spec issue - instead assert descriptor is integer type!
assert !descriptor.isFloatingPoint();
/* step 3 */
int[] list = new int[descriptor.getVectorLength()];
/* step 4 (FIXME: spec bug) */
/* step 5 */
for (int i = 0, len = descriptor.getVectorLength(); i < len; ++i) {
/* step 5.a */
int ax = SIMDExtractLaneInt(a, i);
/* steps 5.b-c */
int res = op.applyAsInt(ax, scalar);
/* step 5.d */
list[i] = res;
}
/* step 6 */
return SIMDCreate(descriptor, list);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDLoad( dataBlock, descriptor, byteOffset [, length] )
*
* @param dataBlock
* the data block
* @param descriptor
* the SIMD type descriptor
* @param byteOffset
* the byte offset
* @return the new SIMD value
*/
public static SIMDValue SIMDLoad(ByteBuffer dataBlock, SIMDType descriptor, long byteOffset) {
return SIMDLoad(dataBlock, descriptor, byteOffset, descriptor.getVectorLength());
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDLoad( dataBlock, descriptor, byteOffset [, length] )
*
* @param dataBlock
* the data block
* @param descriptor
* the SIMD type descriptor
* @param byteOffset
* the byte offset
* @param length
* the read length
* @return the new SIMD value
*/
public static SIMDValue SIMDLoad(ByteBuffer dataBlock, SIMDType descriptor, long byteOffset, int length) {
assert !descriptor.isBoolean() : "Cannot deserialize boolean";
/* step 1 (not applicable) */
/* step 2 */
assert 0 < length && length <= descriptor.getVectorLength();
/* step 3 */
assert 0 <= byteOffset && byteOffset <= (dataBlock.capacity() - descriptor.getElementSize() * length);
/* steps 4-5 */
Object list;
switch (descriptor) {
case Float64x2:
list = SIMDLoadFloat64x2(dataBlock, (int) byteOffset, length);
break;
case Float32x4:
list = SIMDLoadFloat32x4(dataBlock, (int) byteOffset, length);
break;
case Int32x4:
list = SIMDLoadInt32x4(dataBlock, (int) byteOffset, length);
break;
case Int16x8:
list = SIMDLoadInt16x8(dataBlock, (int) byteOffset, length);
break;
case Int8x16:
list = SIMDLoadInt8x16(dataBlock, (int) byteOffset, length);
break;
case Uint32x4:
list = SIMDLoadUint32x4(dataBlock, (int) byteOffset, length);
break;
case Uint16x8:
list = SIMDLoadUint16x8(dataBlock, (int) byteOffset, length);
break;
case Uint8x16:
list = SIMDLoadUint8x16(dataBlock, (int) byteOffset, length);
break;
case Bool64x2:
case Bool32x4:
case Bool16x8:
case Bool8x16:
default:
throw new AssertionError();
}
/* step 6 */
return new SIMDValue(descriptor, list);
}
private static double[] SIMDLoadFloat64x2(ByteBuffer dataBlock, int byteOffset, int length) {
double[] list = new double[SIMDType.Float64x2.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Float64x2.getElementSize();
list[i] = DeserializeFloat64(dataBlock, offset);
}
return list;
}
private static double[] SIMDLoadFloat32x4(ByteBuffer dataBlock, int byteOffset, int length) {
double[] list = new double[SIMDType.Float32x4.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Float32x4.getElementSize();
list[i] = DeserializeFloat32(dataBlock, offset);
}
return list;
}
private static int[] SIMDLoadInt32x4(ByteBuffer dataBlock, int byteOffset, int length) {
int[] list = new int[SIMDType.Int32x4.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Int32x4.getElementSize();
list[i] = DeserializeInt32(dataBlock, offset);
}
return list;
}
private static int[] SIMDLoadInt16x8(ByteBuffer dataBlock, int byteOffset, int length) {
int[] list = new int[SIMDType.Int16x8.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Int16x8.getElementSize();
list[i] = DeserializeInt16(dataBlock, offset);
}
return list;
}
private static int[] SIMDLoadInt8x16(ByteBuffer dataBlock, int byteOffset, int length) {
int[] list = new int[SIMDType.Int8x16.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Int8x16.getElementSize();
list[i] = DeserializeInt8(dataBlock, offset);
}
return list;
}
private static int[] SIMDLoadUint32x4(ByteBuffer dataBlock, int byteOffset, int length) {
int[] list = new int[SIMDType.Uint32x4.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Uint32x4.getElementSize();
list[i] = DeserializeUint32(dataBlock, offset);
}
return list;
}
private static int[] SIMDLoadUint16x8(ByteBuffer dataBlock, int byteOffset, int length) {
int[] list = new int[SIMDType.Uint16x8.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Uint16x8.getElementSize();
list[i] = DeserializeUint16(dataBlock, offset);
}
return list;
}
private static int[] SIMDLoadUint8x16(ByteBuffer dataBlock, int byteOffset, int length) {
int[] list = new int[SIMDType.Uint8x16.getVectorLength()];
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Uint8x16.getElementSize();
list[i] = DeserializeUint8(dataBlock, offset);
}
return list;
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDLoadFromTypedArray( tarray, index, descriptor [, length] )
*
* @param cx
* the execution context
* @param tarray
* the typed array
* @param index
* the read index
* @param descriptor
* the SIMD type descriptor
* @return the new SIMD value
*/
public static SIMDValue SIMDLoadFromTypedArray(ExecutionContext cx, Object tarray, Object index,
SIMDType descriptor) {
return SIMDLoadFromTypedArray(cx, tarray, index, descriptor, descriptor.getVectorLength());
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDLoadFromTypedArray( tarray, index, descriptor [, length] )
*
* @param cx
* the execution context
* @param tarray
* the typed array
* @param index
* the read index
* @param descriptor
* the SIMD type descriptor
* @param length
* the read length
* @return the new SIMD value
*/
public static SIMDValue SIMDLoadFromTypedArray(ExecutionContext cx, Object tarray, Object index,
SIMDType descriptor, int length) {
/* step 1 */
// FIXME: spec bug - missing type check Type(tarray) = Object
if (!(tarray instanceof TypedArrayObject)) {
throw newTypeError(cx, Messages.Key.IncompatibleObject);
}
TypedArrayObject typedArray = (TypedArrayObject) tarray;
/* step 2 */
assert 0 < length && length <= descriptor.getVectorLength();
// FIXME: spec bug - missing ToNumber call
// FIXME: ToNumber(index) comparing against ToLength(ToNumber(index)) does not match any ES2015 pattern.
// FIXME: spec issue - range checking does not match Mozilla SIMD.
double numIndex = ToNumber(cx, index);
/* step 3 */
if (IsDetachedBuffer(typedArray.getBuffer())) {
throw newTypeError(cx, Messages.Key.BufferDetached);
}
/* step 4 */
// FIXME: spec issue - allow shared array buffers?
ByteBuffer block = typedArray.getBuffer().getData();
/* step 5 */
if (numIndex != ToLength(numIndex)) {
throw newTypeError(cx, Messages.Key.InvalidByteOffset);
}
/* step 6 */
// FIXME: spec issue - should use typedArray.[[TypedArrayName]] and retrieve element size from table 49.
// FIXME: spec issue - rename elementLength to elementSize to match ES2015.
// long elementLength = typedArray.getByteLength() / typedArray.getArrayLength();
long elementLength = typedArray.getElementType().size();
/* step 7 */
double byteIndex = numIndex * elementLength;
/* step 8 */
if (byteIndex < 0 || byteIndex + descriptor.getElementSize() * length > typedArray.getByteLength()) {
throw newRangeError(cx, Messages.Key.InvalidByteOffset);
}
/* step 9 */
return SIMDLoad(block, descriptor, (long) byteIndex, length);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDStore( dataBlock, descriptor, byteOffset, n [, length] )
*
* @param dataBlock
* the data block
* @param descriptor
* the SIMD type descriptor
* @param byteOffset
* the byte offset
* @param n
* the SIMD value
*/
public static void SIMDStore(ByteBuffer dataBlock, SIMDType descriptor, long byteOffset, SIMDValue n) {
SIMDStore(dataBlock, descriptor, byteOffset, n, descriptor.getVectorLength());
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDStore( dataBlock, descriptor, byteOffset, n [, length] )
*
* @param dataBlock
* the data block
* @param descriptor
* the SIMD type descriptor
* @param byteOffset
* the byte offset
* @param n
* the SIMD value
* @param length
* the write length
*/
public static void SIMDStore(ByteBuffer dataBlock, SIMDType descriptor, long byteOffset, SIMDValue n, int length) {
assert !descriptor.isBoolean() : "Cannot serialize boolean";
assert descriptor == n.getType();
/* step 1 (not applicable) */
/* step 2 */
assert 0 < length && length <= descriptor.getVectorLength();
/* step 3 */
assert 0 <= byteOffset && byteOffset <= (dataBlock.capacity() - descriptor.getElementSize() * length);
/* step 4 */
switch (descriptor) {
case Float64x2:
SIMDStoreFloat64x2(dataBlock, (int) byteOffset, n, length);
break;
case Float32x4:
SIMDStoreFloat32x4(dataBlock, (int) byteOffset, n, length);
break;
case Int32x4:
SIMDStoreInt32x4(dataBlock, (int) byteOffset, n, length);
break;
case Int16x8:
SIMDStoreInt16x8(dataBlock, (int) byteOffset, n, length);
break;
case Int8x16:
SIMDStoreInt8x16(dataBlock, (int) byteOffset, n, length);
break;
case Uint32x4:
SIMDStoreUint32x4(dataBlock, (int) byteOffset, n, length);
break;
case Uint16x8:
SIMDStoreUint16x8(dataBlock, (int) byteOffset, n, length);
break;
case Uint8x16:
SIMDStoreUint8x16(dataBlock, (int) byteOffset, n, length);
break;
case Bool64x2:
case Bool32x4:
case Bool16x8:
case Bool8x16:
default:
throw new AssertionError();
}
}
private static void SIMDStoreFloat64x2(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Float64x2.getElementSize();
double value = n.asDouble()[i];
SerializeFloat64(dataBlock, offset, value);
}
}
private static void SIMDStoreFloat32x4(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Float32x4.getElementSize();
double value = n.asDouble()[i];
SerializeFloat32(dataBlock, offset, value);
}
}
private static void SIMDStoreInt32x4(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Int32x4.getElementSize();
int value = n.asInt()[i];
SerializeInt32(dataBlock, offset, value);
}
}
private static void SIMDStoreInt16x8(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Int16x8.getElementSize();
int value = n.asInt()[i];
SerializeInt16(dataBlock, offset, value);
}
}
private static void SIMDStoreInt8x16(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Int8x16.getElementSize();
int value = n.asInt()[i];
SerializeInt8(dataBlock, offset, value);
}
}
private static void SIMDStoreUint32x4(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Uint32x4.getElementSize();
int value = n.asInt()[i];
SerializeUint32(dataBlock, offset, value);
}
}
private static void SIMDStoreUint16x8(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Uint16x8.getElementSize();
int value = n.asInt()[i];
SerializeUint16(dataBlock, offset, value);
}
}
private static void SIMDStoreUint8x16(ByteBuffer dataBlock, int byteOffset, SIMDValue n, int length) {
for (int i = 0; i < length; ++i) {
int offset = byteOffset + i * SIMDType.Uint8x16.getElementSize();
int value = n.asInt()[i];
SerializeUint8(dataBlock, offset, value);
}
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDStoreInTypedArray( tarray, index, descriptor, n [, length] )
*
* @param cx
* the execution context
* @param tarray
* the typed array
* @param index
* the write index
* @param descriptor
* the SIMD type descriptor
* @param n
* the SIMD value
* @return the input SIMD value
*/
public static SIMDValue SIMDStoreInTypedArray(ExecutionContext cx, Object tarray, Object index, SIMDType descriptor,
SIMDValue n) {
return SIMDStoreInTypedArray(cx, tarray, index, descriptor, n, descriptor.getVectorLength());
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDStoreInTypedArray( tarray, index, descriptor, n [, length] )
*
* @param cx
* the execution context
* @param tarray
* the typed array
* @param index
* the write index
* @param descriptor
* the SIMD type descriptor
* @param n
* the SIMD value
* @param length
* the write length
* @return the input SIMD value
*/
public static SIMDValue SIMDStoreInTypedArray(ExecutionContext cx, Object tarray, Object index, SIMDType descriptor,
SIMDValue n, int length) {
/* step 1 */
// FIXME: spec bug - incorrect variable name in spec
if (n.getType() != descriptor) {
throw newTypeError(cx, Messages.Key.SIMDInvalidType);
}
/* step 4 */
// FIXME: spec bug - missing type check Type(tarray) = Object
// FIXME: spec bug - type check at wrong position
if (!(tarray instanceof TypedArrayObject)) {
throw newTypeError(cx, Messages.Key.IncompatibleObject);
}
TypedArrayObject typedArray = (TypedArrayObject) tarray;
/* step 2 */
assert 0 < length && length <= descriptor.getVectorLength();
// FIXME: spec bug - missing ToNumber call
// FIXME: ToNumber(index) comparing against ToLength(ToNumber(index)) does not match any ES2015 pattern.
double numIndex = ToNumber(cx, index);
/* step 3 */
if (IsDetachedBuffer(typedArray.getBuffer())) {
throw newTypeError(cx, Messages.Key.BufferDetached);
}
/* step 5 */
// FIXME: spec issue - allow shared array buffers?
ByteBuffer block = typedArray.getBuffer().getData();
/* step 6 */
if (numIndex != ToLength(numIndex)) {
throw newTypeError(cx, Messages.Key.InvalidByteOffset);
}
/* step 7 */
// FIXME: spec issue - should use typedArray.[[TypedArrayName]] and retrieve element size from table 49.
// FIXME: spec issue - rename elementLength to elementSize to match ES2015.
// long elementLength = typedArray.getByteLength() / typedArray.getArrayLength();
long elementLength = typedArray.getElementType().size();
/* step 8 */
double byteIndex = numIndex * elementLength;
/* step 9 */
if (byteIndex < 0 || byteIndex + descriptor.getElementSize() * length > typedArray.getByteLength()) {
throw newRangeError(cx, Messages.Key.InvalidByteOffset);
}
/* step 10 */
// FIXME: spec bug - wrong variable name `simd` -> `n`
SIMDStore(block, descriptor, (long) byteIndex, n, length);
/* step 11 */
return n;
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDReinterpretCast( value, newDescriptor )
*
* @param cx
* the execution context
* @param value
* the SIMD value
* @param newDescriptor
* the new SIMD type descriptor
* @return the new SIMD value
*/
public static SIMDValue SIMDReinterpretCast(ExecutionContext cx, SIMDValue value, SIMDType newDescriptor) {
/* step 1 */
assert value.getType().getVectorLength() * value.getType().getElementSize() == newDescriptor.getVectorLength()
* newDescriptor.getElementSize();
/* step 2 */
int bytes = newDescriptor.getVectorLength() * newDescriptor.getElementSize();
/* steps 3-4 */
ByteBuffer block = CreateByteDataBlock(cx, bytes);
/* step 5 */
// FIXME: spec bug - invalid parameters for SIMDStore
SIMDStore(block, value.getType(), 0, value);
/* step 6 */
return SIMDLoad(block, newDescriptor, 0);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDBoolType( descriptor )
*
* @param descriptor
* the SIMD type descriptor
* @return the boolean SIMD type descriptor
*/
public static SIMDType SIMDBoolType(SIMDType descriptor) {
/* step 1 */
// FIXME: spec bug - either test for == 16 or add multiplicator (*8).
assert descriptor.getVectorLength() * descriptor.getElementSize() * 8 == 128;
/* step 2 */
int length = descriptor.getVectorLength();
if (length == 2) {
return SIMDType.Bool64x2;
}
/* step 3 */
if (length == 4) {
return SIMDType.Bool32x4;
}
/* step 4 */
if (length == 8) {
return SIMDType.Bool16x8;
}
/* step 5 */
assert length == 16;
/* step 6 */
return SIMDType.Bool8x16;
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDRelationalOp( a, b, op )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDRelationalOpFloat(SIMDValue a, SIMDValue b, DoubleBiPredicate op) {
/* step 1 */
SIMDType outputDescriptor = SIMDBoolType(a.getType());
/* step 2 */
return SIMDBinaryOpFloat(a, b, op, outputDescriptor);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDRelationalOp( a, b, op )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDRelationalOpDouble(SIMDValue a, SIMDValue b, DoubleBiPredicate op) {
/* step 1 */
SIMDType outputDescriptor = SIMDBoolType(a.getType());
/* step 2 */
return SIMDBinaryOpDouble(a, b, op, outputDescriptor);
}
/**
* Internal algorithms on SIMD types
* <p>
* SIMDRelationalOp( a, b, op )
*
* @param a
* the first operand
* @param b
* the second operand
* @param op
* the binary operator
* @return the new SIMD value
*/
public static SIMDValue SIMDRelationalOpInt(SIMDValue a, SIMDValue b, IntBiPredicate op) {
/* step 1 */
SIMDType outputDescriptor = SIMDBoolType(a.getType());
/* step 2 */
return SIMDBinaryOpInt(a, b, op, outputDescriptor);
}
/**
* Converts the input value to a 32-bit floating point number.
*
* @param cx
* the execution context
* @param v
* the input value
* @return the 32-bit floating point number
*/
public static float ToFloat32(ExecutionContext cx, Object v) {
return (float) ToNumber(cx, v);
}
/**
* Internal algorithms on SIMD types
* <p>
* ArrayJoin( array, separator )
*
* @param cx
* the execution context
* @param array
* the array object
* @param separator
* the separator string
* @return the result string
*/
public static String ArrayJoin(ExecutionContext cx, Object array, Object separator) {
/* steps 1-2 */
ScriptObject o = ToObject(cx, array);
/* steps 3-4 */
long len = ToLength(cx, Get(cx, o, "length"));
/* step 5 */
if (Type.isUndefined(separator)) {
separator = "";
}
/* steps 6-7 */
String sep = ToFlatString(cx, separator);
/* step 8 */
if (len == 0) {
return "";
}
StringBuilder r = new StringBuilder();
/* step 9 */
Object element0 = Get(cx, o, 0);
/* steps 10-11 */
if (!Type.isUndefinedOrNull(element0)) {
r.append(AbstractOperations.ToString(cx, element0));
}
/* steps 12-13 */
for (int k = 1; k < len; ++k) {
/* step 13.a */
r.append(sep);
/* step 13.b */
Object element = Get(cx, o, k);
/* steps 13.c-e */
if (!Type.isUndefinedOrNull(element)) {
r.append(AbstractOperations.ToString(cx, element));
}
}
/* step 14 */
return r.toString();
}
/**
* Internal algorithms on SIMD types
* <p>
* ArrayJoin( array, separator )
*
* @param array
* the string array
* @param separator
* the string separator
* @return the result string
*/
static String ArrayJoin(CharSequence[] array, String separator) {
/* steps 1-14 */
return Arrays.stream(array).collect(Collectors.joining(separator));
}
public enum Properties {
;
@Prototype
public static final Intrinsics __proto__ = Intrinsics.ObjectPrototype;
/**
* SIMD.Float32x4
*/
@Value(name = "Float32x4")
public static final Intrinsics Float32x4 = Intrinsics.SIMD_Float32x4;
/**
* SIMD.Int32x4
*/
@Value(name = "Int32x4")
public static final Intrinsics Int32x4 = Intrinsics.SIMD_Int32x4;
/**
* SIMD.Int16x8
*/
@Value(name = "Int16x8")
public static final Intrinsics Int16x8 = Intrinsics.SIMD_Int16x8;
/**
* SIMD.Int32x4
*/
@Value(name = "Int8x16")
public static final Intrinsics Int8x16 = Intrinsics.SIMD_Int8x16;
/**
* SIMD.Uint32x4
*/
@Value(name = "Uint32x4")
public static final Intrinsics Uint32x4 = Intrinsics.SIMD_Uint32x4;
/**
* SIMD.Uint16x8
*/
@Value(name = "Uint16x8")
public static final Intrinsics Uint16x8 = Intrinsics.SIMD_Uint16x8;
/**
* SIMD.Uint32x4
*/
@Value(name = "Uint8x16")
public static final Intrinsics Uint8x16 = Intrinsics.SIMD_Uint8x16;
/**
* SIMD.Bool32x4
*/
@Value(name = "Bool32x4")
public static final Intrinsics Bool32x4 = Intrinsics.SIMD_Bool32x4;
/**
* SIMD.Bool16x8
*/
@Value(name = "Bool16x8")
public static final Intrinsics Bool16x8 = Intrinsics.SIMD_Bool16x8;
/**
* SIMD.Bool32x4
*/
@Value(name = "Bool8x16")
public static final Intrinsics Bool8x16 = Intrinsics.SIMD_Bool8x16;
}
/**
* Extension: SIMD.Float64x2 and SIMD.Bool64x2
*/
@CompatibilityExtension(CompatibilityOption.SIMD_Phase2)
public enum AdditionalProperties {
;
/**
* SIMD.Float64x2
*/
@Value(name = "Float64x2")
public static final Intrinsics Float64x2 = Intrinsics.SIMD_Float64x2;
/**
* SIMD.Bool64x2
*/
@Value(name = "Bool64x2")
public static final Intrinsics Bool64x2 = Intrinsics.SIMD_Bool64x2;
}
}