diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java b/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java index a84f4ca2e..7451b1a0d 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/Validator.java @@ -1169,6 +1169,60 @@ public void validateFunction(int funcIdx, FunctionBody body, FunctionType functi getElement(index); break; } + case V128_LOAD: + { + popVal(ValueType.I32); + pushVal(ValueType.V128); + break; + } + case V128_CONST: + { + pushVal(ValueType.V128); + break; + } + case I8x16_ALL_TRUE: + case I8x16_EXTRACT_LANE_S: + { + popVal(ValueType.V128); + pushVal(ValueType.I32); + break; + } + case I8x16_EQ: + case I8x16_SUB: + case I8x16_ADD: + case I8x16_SWIZZLE: + case F32x4_MUL: + case F32x4_MIN: + { + popVal(ValueType.V128); + popVal(ValueType.V128); + pushVal(ValueType.V128); + break; + } + case F32x4_ABS: + case I32x4_TRUNC_SAT_F32X4_S: + case F32x4_CONVERT_I32x4_U: + case V128_NOT: + { + popVal(ValueType.V128); + pushVal(ValueType.V128); + break; + } + case V128_BITSELECT: + { + popVal(ValueType.V128); + popVal(ValueType.V128); + popVal(ValueType.V128); + pushVal(ValueType.V128); + break; + } + case I8x16_SHL: + { + popVal(ValueType.I32); + popVal(ValueType.V128); + pushVal(ValueType.V128); + break; + } default: throw new IllegalArgumentException( "Missing type validation opcode handling for " + op.opcode()); diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/types/OpCode.java b/wasm/src/main/java/com/dylibso/chicory/wasm/types/OpCode.java index 8b1d8ef68..abc0f99b7 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/types/OpCode.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/types/OpCode.java @@ -211,7 +211,24 @@ public enum OpCode { TABLE_COPY(0xFC0E, List.of(VARUINT, VARUINT)), TABLE_GROW(0xFC0F, List.of(VARUINT)), TABLE_SIZE(0xFC10, List.of(VARUINT)), - TABLE_FILL(0xFC11, List.of(VARUINT)); + TABLE_FILL(0xFC11, List.of(VARUINT)), + V128_LOAD(0xFD00, List.of(VARUINT, VARUINT)), + I8x16_SWIZZLE(0xFD0E), + V128_CONST(0xFD0C, List.of(VEC_VARUINT)), + I8x16_EXTRACT_LANE_S(0xFD15, List.of(VARUINT)), + I8x16_EQ(0xFD23), + V128_NOT(0xFD4D), + V128_BITSELECT(0xFD52), + I8x16_SHL(0xFD6B), + I8x16_ADD(0xFD6E), + I8x16_SUB(0xFD71), + F32x4_MUL(0xFDE6), + F32x4_ABS(0xFDE0), + F32x4_MIN(0xFDE8), + I32x4_TRUNC_SAT_F32X4_S(0xFDF8), + F32x4_CONVERT_I32x4_U(0xFDFB), + I8x16_ALL_TRUE(0xFD63), + ; private static final int OP_CODES_SIZE = 0xFF00; diff --git a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java index 55930780b..1c8fa642a 100644 --- a/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java +++ b/wasm/src/main/java/com/dylibso/chicory/wasm/types/Value.java @@ -102,6 +102,79 @@ public Value(ValueType type, long value) { data = value; } + @SuppressWarnings("checkstyle:modifiedcontrolvariable") + public static byte[] vecTo8(long[] values) { + var result = new byte[values.length * 8]; + var valueIdx = 0; + for (int i = 0; i < result.length; i++) { + var v = values[valueIdx++]; + result[i] = (byte) (v & 0xFFL); + result[++i] = (byte) ((v >> 8) & 0xFFL); + result[++i] = (byte) ((v >> 16) & 0xFFL); + result[++i] = (byte) ((v >> 24) & 0xFFL); + result[++i] = (byte) ((v >> 32) & 0xFFL); + result[++i] = (byte) ((v >> 40) & 0xFFL); + result[++i] = (byte) ((v >> 48) & 0xFFL); + result[++i] = (byte) ((v >> 56) & 0xFFL); + } + return result; + } + + @SuppressWarnings("checkstyle:modifiedcontrolvariable") + public static long[] bytesToVec(byte[] bytes) { + var result = new long[bytes.length / 8]; + var valueIdx = 0; + for (int i = 0; i < bytes.length; i++) { + result[valueIdx++] = + Byte.toUnsignedLong(bytes[i]) + (Byte.toUnsignedLong(bytes[++i]) << 8L) + | (Byte.toUnsignedLong(bytes[++i]) << 16L) + | (Byte.toUnsignedLong(bytes[++i]) << 24L) + | (Byte.toUnsignedLong(bytes[++i]) << 32L) + | (Byte.toUnsignedLong(bytes[++i]) << 40L) + | (Byte.toUnsignedLong(bytes[++i]) << 48L) + | (Byte.toUnsignedLong(bytes[++i]) << 56L); + } + return result; + } + + @SuppressWarnings("checkstyle:modifiedcontrolvariable") + public static int[] vecTo16(long[] values) { + var result = new int[values.length * 4]; + var valueIdx = 0; + for (int i = 0; i < result.length; i++) { + var v = values[valueIdx++]; + result[i] = (int) (v & 0xFFFFL); + result[++i] = (int) ((v >> 16) & 0xFFFFL); + result[++i] = (int) ((v >> 32) & 0xFFFFL); + result[++i] = (int) ((v >> 48) & 0xFFFFL); + } + return result; + } + + @SuppressWarnings("checkstyle:modifiedcontrolvariable") + public static long[] vecTo32(long[] values) { + var result = new long[values.length * 2]; + var valueIdx = 0; + for (int i = 0; i < result.length; i++) { + var v = values[valueIdx++]; + result[i] = (v & 0xFFFFFFFFL); + result[++i] = ((v >> 32) & 0xFFFFFFFFL); + } + return result; + } + + @SuppressWarnings("checkstyle:modifiedcontrolvariable") + public static float[] vecToF32(long[] values) { + var result = new float[values.length * 2]; + var valueIdx = 0; + for (int i = 0; i < result.length; i++) { + var v = values[valueIdx++]; + result[i] = Float.intBitsToFloat((int) (v & 0xFFFFFFFFL)); + result[++i] = Float.intBitsToFloat((int) ((v >> 32) & 0xFFFFFFFFL)); + } + return result; + } + /** * Create a zeroed value for the particular type. * @@ -135,6 +208,8 @@ public String toString() { return longToFloat(data) + "@f32"; case F64: return longToDouble(data) + "@f64"; + case V128: + return data + "@v128"; case FuncRef: return "func[" + (int) data + "]"; case ExternRef: diff --git a/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java b/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java index 19b42747d..fd4e36be6 100644 --- a/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java +++ b/wasm/src/test/java/com/dylibso/chicory/wasm/ParserTest.java @@ -221,4 +221,11 @@ public void shouldParseNamesSection() throws IOException { assertEquals(".rodata", nameSec.nameOfData(0)); } } + + @Test + public void shouldParseSIMD() throws IOException { + try (InputStream is = getClass().getResourceAsStream("/wasm/simd_load.0.wasm")) { + Parser.parse(is); + } + } } diff --git a/wasm/src/test/java/com/dylibso/chicory/wasm/types/ValueTest.java b/wasm/src/test/java/com/dylibso/chicory/wasm/types/ValueTest.java index 35bec5c12..7ad830c9e 100644 --- a/wasm/src/test/java/com/dylibso/chicory/wasm/types/ValueTest.java +++ b/wasm/src/test/java/com/dylibso/chicory/wasm/types/ValueTest.java @@ -71,4 +71,57 @@ public void toStringContract() { var i32FortyTwo = Value.i32(42); assertNotNull(i32FortyTwo.toString()); } + + @Test + public void shouldConvertToArrays() { + long x = 0x0706_0504_0302_0100L; + var result = Value.vecTo8(new long[] {x}); + + assertEquals(8, result.length); + assertEquals(0, result[0]); + assertEquals(1, result[1]); + assertEquals(2, result[2]); + assertEquals(3, result[3]); + assertEquals(4, result[4]); + assertEquals(5, result[5]); + assertEquals(6, result[6]); + assertEquals(7, result[7]); + } + + @Test + public void shouldConvertToArraysHL() { + long xLo = 0x0706_0504_0302_0100L; + long xHi = 0x0F0E_0D0C_0B0A_0908L; + var result = Value.vecTo8(new long[] {xLo, xHi}); + + assertEquals(16, result.length); + assertEquals(0, result[0]); + assertEquals(1, result[1]); + assertEquals(2, result[2]); + assertEquals(3, result[3]); + assertEquals(4, result[4]); + assertEquals(5, result[5]); + assertEquals(6, result[6]); + assertEquals(7, result[7]); + assertEquals(8, result[8]); + assertEquals(9, result[9]); + assertEquals(10, result[10]); + assertEquals(11, result[11]); + assertEquals(12, result[12]); + assertEquals(13, result[13]); + assertEquals(14, result[14]); + assertEquals(15, result[15]); + } + + @Test + public void shouldConvertBackFromBytes() { + var value = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + var result = Value.bytesToVec(value); + long xLo = 0x0706_0504_0302_0100L; + long xHi = 0x0F0E_0D0C_0B0A_0908L; + + assertEquals(2, result.length); + assertEquals(xLo, result[0]); + assertEquals(xHi, result[1]); + } } diff --git a/wasm/src/test/resources/wasm/simd_load.0.wasm b/wasm/src/test/resources/wasm/simd_load.0.wasm new file mode 100644 index 000000000..507cd9172 Binary files /dev/null and b/wasm/src/test/resources/wasm/simd_load.0.wasm differ