/** * 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 java.nio.ByteBuffer; import java.nio.ByteOrder; /** * <h1>SIMD</h1> * <h2>SIMD objects</h2> * <ul> * <li>SIMD type descriptors * </ul> */ public enum SIMDType { /** * Float64x2 */ Float64x2(2, 8), /** * Float32x4 */ Float32x4(4, 4), /** * Int32x4 */ Int32x4(4, 4), /** * Int16x8 */ Int16x8(8, 2), /** * Int8x16 */ Int8x16(16, 1), /** * Uint32x4 */ Uint32x4(4, 4), /** * Uint16x8 */ Uint16x8(8, 2), /** * Uint8x16 */ Uint8x16(16, 1), /** * Bool64x2 */ Bool64x2(2, 0), /** * Bool32x4 */ Bool32x4(4, 0), /** * Bool16x8 */ Bool16x8(8, 0), /** * Bool8x16 */ Bool8x16(16, 0); private final int vectorLength; private final int elementSize; private SIMDType(int vectorLength, int elementSize) { this.vectorLength = vectorLength; this.elementSize = elementSize; } /** * [[VectorLength]] * * @return the vector length */ public int getVectorLength() { return vectorLength; } /** * [[ElementSize]] * * @return the element size */ public int getElementSize() { return elementSize; } /** * Returns the {@code typeof} description for this SIMD type. * * @return the {@code typeof} description */ public String typeof() { switch (this) { case Float64x2: return "float64x2"; case Float32x4: return "float32x4"; case Int32x4: return "int32x4"; case Int16x8: return "int16x8"; case Int8x16: return "int8x16"; case Uint32x4: return "uint32x4"; case Uint16x8: return "uint16x8"; case Uint8x16: return "uint8x16"; case Bool64x2: return "bool64x2"; case Bool32x4: return "bool32x4"; case Bool16x8: return "bool16x8"; case Bool8x16: return "bool8x16"; default: throw new AssertionError(); } } /** * Returns the SIMD type for a {@code typeof} name. * * @param typeName * the SIMD typeof name * @return the SIMD type */ public static SIMDType from(String typeName) { switch (typeName) { case "float64x2": return Float64x2; case "float32x4": return Float32x4; case "int32x4": return Int32x4; case "int16x8": return Int16x8; case "int8x16": return Int8x16; case "uint32x4": return Uint32x4; case "uint16x8": return Uint16x8; case "uint8x16": return Uint8x16; case "bool64x2": return Bool64x2; case "bool32x4": return Bool32x4; case "bool16x8": return Bool16x8; case "bool8x16": return Bool8x16; default: throw new IllegalArgumentException(typeName); } } /** * Returns {@code true} for floating point SIMD types. * * @return {@code true} if the {@code this} object describes a floating point SIMD type. */ public boolean isFloatingPoint() { switch (this) { case Float64x2: case Float32x4: return true; case Bool64x2: case Bool32x4: case Bool16x8: case Bool8x16: case Int32x4: case Int16x8: case Int8x16: case Uint32x4: case Uint16x8: case Uint8x16: return false; default: throw new AssertionError(); } } /** * Returns {@code true} for integer SIMD types. * * @return {@code true} if the {@code this} object describes an integer SIMD type. */ public boolean isInteger() { switch (this) { case Int32x4: case Int16x8: case Int8x16: case Uint32x4: case Uint16x8: case Uint8x16: return true; case Float64x2: case Float32x4: case Bool64x2: case Bool32x4: case Bool16x8: case Bool8x16: return false; default: throw new AssertionError(); } } /** * Returns {@code true} for boolean SIMD types. * * @return {@code true} if the {@code this} object describes a boolean SIMD type. */ public boolean isBoolean() { switch (this) { case Bool64x2: case Bool32x4: case Bool16x8: case Bool8x16: return true; case Float64x2: case Float32x4: case Int32x4: case Int16x8: case Int8x16: case Uint32x4: case Uint16x8: case Uint8x16: return false; default: throw new AssertionError(); } } private static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; private static ByteBuffer byteBuffer(ByteBuffer block, boolean isLittleEndian) { // NB: Byte order is not reset after this call. if ((block.order() == ByteOrder.LITTLE_ENDIAN) != isLittleEndian) { block.order(isLittleEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); } return block; } /** * SerializeFloat64( block, offset, value, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeFloat64(ByteBuffer block, int offset, double value) { SerializeFloat64(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeFloat64( block, offset, value, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeFloat64(ByteBuffer block, int offset, double value, boolean isLittleEndian) { /* steps 1-3 (not applicable) */ /* step 4 */ assert 0 <= offset && offset + 8 <= block.capacity(); /* steps 5-6 */ byteBuffer(block, isLittleEndian).putDouble(offset, value); } /** * DeserializeFloat64( block, offset, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static double DeserializeFloat64(ByteBuffer block, int offset) { return DeserializeFloat64(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeFloat64( block, offset, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return value the number value */ public static double DeserializeFloat64(ByteBuffer block, int offset, boolean isLittleEndian) { // FIXME: spec bug - isLittleEndian never used as argument to [[DeserializeElement]] /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 8 <= block.capacity(); /* steps 4-6 */ double value = byteBuffer(block, isLittleEndian).getDouble(offset); /* steps 7-8 */ // FIXME: spec issue? - canonicalization breaks moz-tests // return Double.isNaN(value) ? Double.NaN : value; return value; } /** * SerializeFloat32( block, offset, value, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeFloat32(ByteBuffer block, int offset, double value) { SerializeFloat32(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeFloat32( block, offset, value, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeFloat32(ByteBuffer block, int offset, double value, boolean isLittleEndian) { /* steps 1-3 (not applicable) */ /* step 4 */ assert 0 <= offset && offset + 4 <= block.capacity(); /* steps 5-6 */ byteBuffer(block, isLittleEndian).putFloat(offset, (float) value); } /** * DeserializeFloat32( block, offset, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static double DeserializeFloat32(ByteBuffer block, int offset) { return DeserializeFloat32(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeFloat32( block, offset, isLittleEndian ) * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return value the number value */ public static double DeserializeFloat32(ByteBuffer block, int offset, boolean isLittleEndian) { // FIXME: spec bug - isLittleEndian never used as argument to [[DeserializeElement]] /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 4 <= block.capacity(); /* steps 4-6 */ float value = byteBuffer(block, isLittleEndian).getFloat(offset); /* steps 7-8 */ // FIXME: spec issue? - canonicalization breaks moz-tests // return Float.isNaN(value) ? Float.NaN : value; return value; } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Int32x4 * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeInt32(ByteBuffer block, int offset, int value) { SerializeInt32(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Int32x4 * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeInt32(ByteBuffer block, int offset, int value, boolean isLittleEndian) { /* steps 1-4 (not applicable) */ /* step 5 */ assert 0 <= offset && offset + 4 <= block.capacity(); /* steps 6-7 */ byteBuffer(block, isLittleEndian).putInt(offset, value); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Int32x4 * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static int DeserializeInt32(ByteBuffer block, int offset) { return DeserializeInt32(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Int32x4 * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return the number value */ public static int DeserializeInt32(ByteBuffer block, int offset, boolean isLittleEndian) { /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 4 <= block.capacity(); /* steps 4-7 */ return byteBuffer(block, isLittleEndian).getInt(offset); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Int16x8 * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeInt16(ByteBuffer block, int offset, int value) { SerializeInt16(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Int16x8 * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeInt16(ByteBuffer block, int offset, int value, boolean isLittleEndian) { /* steps 1-3 (not applicable) */ /* step 4 */ assert value == (short) value; /* step 5 */ assert 0 <= offset && offset + 2 <= block.capacity(); /* steps 6-7 */ byteBuffer(block, isLittleEndian).putShort(offset, (short) value); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Int16x8 * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static int DeserializeInt16(ByteBuffer block, int offset) { return DeserializeInt16(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Int16x8 * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return the number value */ public static int DeserializeInt16(ByteBuffer block, int offset, boolean isLittleEndian) { /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 2 <= block.capacity(); /* steps 4-7 */ return byteBuffer(block, isLittleEndian).getShort(offset); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Int8x16 * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeInt8(ByteBuffer block, int offset, int value) { SerializeInt8(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Int8x16 * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeInt8(ByteBuffer block, int offset, int value, boolean isLittleEndian) { /* steps 1-3 (not applicable) */ /* step 4 */ assert value == (byte) value; /* step 5 */ assert 0 <= offset && offset + 1 <= block.capacity(); /* steps 6-7 */ block.put(offset, (byte) value); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Int8x16 * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static int DeserializeInt8(ByteBuffer block, int offset) { return DeserializeInt8(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Int8x16 * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return the number value */ public static int DeserializeInt8(ByteBuffer block, int offset, boolean isLittleEndian) { /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 1 <= block.capacity(); /* steps 4-7 */ return block.get(offset); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Uint32x4 * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeUint32(ByteBuffer block, int offset, int value) { SerializeUint32(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Uint32x4 * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeUint32(ByteBuffer block, int offset, int value, boolean isLittleEndian) { /* steps 1-4 (not applicable) */ /* step 5 */ assert 0 <= offset && offset + 4 <= block.capacity(); /* steps 6-7 */ byteBuffer(block, isLittleEndian).putInt(offset, value); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Uint32x4 * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static int DeserializeUint32(ByteBuffer block, int offset) { return DeserializeUint32(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Uint32x4 * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return the number value */ public static int DeserializeUint32(ByteBuffer block, int offset, boolean isLittleEndian) { /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 4 <= block.capacity(); /* steps 4-7 */ return byteBuffer(block, isLittleEndian).getInt(offset); // Value returned as signed int32. } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Uint16x8 * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeUint16(ByteBuffer block, int offset, int value) { SerializeUint16(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Uint16x8 * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeUint16(ByteBuffer block, int offset, int value, boolean isLittleEndian) { /* steps 1-3 (not applicable) */ /* step 4 */ assert value == (value & 0xffff); /* step 5 */ assert 0 <= offset && offset + 2 <= block.capacity(); /* steps 6-7 */ byteBuffer(block, isLittleEndian).putShort(offset, (short) value); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Uint16x8 * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static int DeserializeUint16(ByteBuffer block, int offset) { return DeserializeUint16(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Uint16x8 * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return the number value */ public static int DeserializeUint16(ByteBuffer block, int offset, boolean isLittleEndian) { /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 2 <= block.capacity(); /* steps 4-7 */ return byteBuffer(block, isLittleEndian).getShort(offset) & 0xffff; } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Uint8x16 * * @param block * the data block * @param offset * the data block offset * @param value * the number value */ public static void SerializeUint8(ByteBuffer block, int offset, int value) { SerializeUint8(block, offset, value, IS_LITTLE_ENDIAN); } /** * SerializeInt( descriptor )( block, offset, n, isLittleEndian ), descriptor = Uint8x16 * * @param block * the data block * @param offset * the data block offset * @param value * the number value * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order */ public static void SerializeUint8(ByteBuffer block, int offset, int value, boolean isLittleEndian) { /* steps 1-3 (not applicable) */ /* step 4 */ assert value == (value & 0xff); /* step 5 */ assert 0 <= offset && offset + 1 <= block.capacity(); /* steps 6-7 */ block.put(offset, (byte) value); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Uint8x16 * * @param block * the data block * @param offset * the data block offset * @return the number value */ public static int DeserializeUint8(ByteBuffer block, int offset) { return DeserializeUint8(block, offset, IS_LITTLE_ENDIAN); } /** * DeserializeInt( descriptor )( block, offset, isLittleEndian ), descriptor = Uint8x16 * * @param block * the data block * @param offset * the data block offset * @param isLittleEndian * {@code true} if little endian order, otherwise big endian order * @return the number value */ public static int DeserializeUint8(ByteBuffer block, int offset, boolean isLittleEndian) { /* steps 1-2 (not applicable) */ /* step 3 */ assert 0 <= offset && offset + 1 <= block.capacity(); /* steps 4-7 */ return block.get(offset) & 0xff; } }