diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index aad434808..3e76724e0 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -385,11 +385,13 @@ let simd_prefix s = | 0xb8l -> i32x4_max_s | 0xb9l -> i32x4_max_u | 0xbal -> i32x4_dot_i16x8_s + | 0xc0l -> i64x2_eq | 0xc1l -> i64x2_neg | 0xcbl -> i64x2_shl | 0xccl -> i64x2_shr_s | 0xcdl -> i64x2_shr_u | 0xcel -> i64x2_add + | 0xd0l -> i64x2_ne | 0xd1l -> i64x2_sub | 0xd5l -> i64x2_mul | 0xd8l -> f32x4_ceil diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 4e76e91e2..8d2a207f3 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -488,6 +488,8 @@ let encode m = | Binary (V128 V128Op.(I64x2 Add)) -> simd_op 0xcel | Binary (V128 V128Op.(I64x2 Sub)) -> simd_op 0xd1l | Binary (V128 V128Op.(I64x2 Mul)) -> simd_op 0xd5l + | Binary (V128 V128Op.(I64x2 Eq)) -> simd_op 0xc0l + | Binary (V128 V128Op.(I64x2 Ne)) -> simd_op 0xd0l | Binary (V128 V128Op.(F32x4 Eq)) -> simd_op 0x41l | Binary (V128 V128Op.(F32x4 Ne)) -> simd_op 0x42l | Binary (V128 V128Op.(F32x4 Lt)) -> simd_op 0x43l diff --git a/interpreter/exec/eval_simd.ml b/interpreter/exec/eval_simd.ml index 28b0585b1..ac3539207 100644 --- a/interpreter/exec/eval_simd.ml +++ b/interpreter/exec/eval_simd.ml @@ -119,6 +119,8 @@ module SimdOp (SXX : Simd.S) (Value : ValueType with type t = SXX.t) = struct | I32x4 GeS -> SXX.I32x4.ge_s | I32x4 GeU -> SXX.I32x4.ge_u | I32x4 DotI16x8S -> SXX.I32x4_convert.dot_i16x8_s + | I64x2 Eq -> SXX.I64x2.eq + | I64x2 Ne -> SXX.I64x2.ne | I64x2 Add -> SXX.I64x2.add | I64x2 Sub -> SXX.I64x2.sub | I64x2 Mul -> SXX.I64x2.mul diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 44f7b9fd6..09d2ef2a7 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -379,6 +379,8 @@ let i32x4_dot_i16x8_s = Binary (V128 V128Op.(I32x4 DotI16x8S)) let i64x2_splat = Convert (V128 V128Op.(I64x2 Splat)) let i64x2_extract_lane imm = SimdExtract (V128Op.I64x2 (ZX, imm)) let i64x2_replace_lane imm = SimdReplace (V128Op.I64x2 imm) +let i64x2_eq = Binary (V128 V128Op.(I64x2 Eq)) +let i64x2_ne = Binary (V128 V128Op.(I64x2 Ne)) let i64x2_neg = Unary (V128 V128Op.(I64x2 Neg)) let i64x2_add = Binary (V128 V128Op.(I64x2 Add)) let i64x2_sub = Binary (V128 V128Op.(I64x2 Sub)) diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 8302bcd93..74ed20cbc 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -269,6 +269,8 @@ struct | I32x4 LeU -> "i32x4.le_u" | I32x4 GeS -> "i32x4.ge_s" | I32x4 GeU -> "i32x4.ge_u" + | I64x2 Eq -> "i64x2.eq" + | I64x2 Ne -> "i64x2.ne" | I8x16 NarrowS -> "i8x16.narrow_i16x8_s" | I8x16 NarrowU -> "i8x16.narrow_i16x8_u" | I8x16 Add -> "i8x16.add" diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 2bf89c9bf..0c59eba51 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -458,11 +458,9 @@ rule token = parse | "output" { OUTPUT } | (simd_shape as s)".eq" - { except ["i64x2"] s lexbuf; - BINARY (simdop s i8x16_eq i16x8_eq i32x4_eq unreachable f32x4_eq f64x2_eq) } + { BINARY (simdop s i8x16_eq i16x8_eq i32x4_eq i64x2_eq f32x4_eq f64x2_eq) } | (simd_shape as s)".ne" - { except ["i64x2"] s lexbuf; - BINARY (simdop s i8x16_ne i16x8_ne i32x4_ne unreachable f32x4_ne f64x2_ne) } + { BINARY (simdop s i8x16_ne i16x8_ne i32x4_ne i64x2_ne f32x4_ne f64x2_ne) } | (simd_int_shape as s)".lt_s" { except ["i64x2"] s lexbuf; BINARY (simd_int_op s i8x16_lt_s i16x8_lt_s i32x4_lt_s unreachable) } diff --git a/test/core/simd/meta/gen_tests.py b/test/core/simd/meta/gen_tests.py index e1c03ecd2..3508df113 100644 --- a/test/core/simd/meta/gen_tests.py +++ b/test/core/simd/meta/gen_tests.py @@ -13,6 +13,7 @@ 'simd_i8x16_cmp', 'simd_i16x8_cmp', 'simd_i32x4_cmp', + 'simd_i64x2_cmp', 'simd_f32x4_cmp', 'simd_f64x2_cmp', 'simd_i8x16_arith', diff --git a/test/core/simd/meta/simd_i64x2_cmp.py b/test/core/simd/meta/simd_i64x2_cmp.py new file mode 100644 index 000000000..d22f51baf --- /dev/null +++ b/test/core/simd/meta/simd_i64x2_cmp.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +from simd_compare import SimdCmpCase + + +# Generate i64x2 test case +class Simdi64x2CmpCase(SimdCmpCase): + LANE_TYPE = 'i64x2' + + BINARY_OPS = ['eq', 'ne'] + + # Override this since i64x2 does not support as many comparison instructions. + CASE_TXT = """ +;; Test all the {lane_type} comparison operators on major boundary values and all special values. + +(module + (func (export "eq") (param $x v128) (param $y v128) (result v128) ({lane_type}.eq (local.get $x) (local.get $y))) + (func (export "ne") (param $x v128) (param $y v128) (result v128) ({lane_type}.ne (local.get $x) (local.get $y))) +) + +{normal_case} + +;; Type check + +(assert_invalid (module (func (result v128) ({lane_type}.eq (i32.const 0) (f32.const 0)))) "type mismatch") +(assert_invalid (module (func (result v128) ({lane_type}.ne (i32.const 0) (f32.const 0)))) "type mismatch") +""" + + def get_case_data(self): + forms = ['i64x2'] * 3 + case_data = [] + + case_data.append(['#', 'eq']) + case_data.append(['#', 'i64x2.eq (i64x2) (i64x2)']) + case_data.append(['eq', ['0xFFFFFFFFFFFFFFFF', '0xFFFFFFFFFFFFFFFF'], '-1', forms]) + case_data.append(['eq', ['0x0000000000000000', '0x0000000000000000'], '-1', forms]) + case_data.append(['eq', ['0xF0F0F0F0F0F0F0F0', '0xF0F0F0F0F0F0F0F0'], '-1', forms]) + case_data.append(['eq', ['0x0F0F0F0F0F0F0F0F', '0x0F0F0F0F0F0F0F0F'], '-1', forms]) + case_data.append(['eq', [['0xFFFFFFFFFFFFFFFF', '0x0000000000000000'], ['0xFFFFFFFFFFFFFFFF', '0x0000000000000000']], '-1', forms]) + case_data.append(['eq', [['0x0000000000000000', '0xFFFFFFFFFFFFFFFF'], ['0x0000000000000000', '0xFFFFFFFFFFFFFFFF']], '-1', forms]) + case_data.append(['eq', [['0x03020100', '0x11100904', '0x1A0B0A12', '0xFFABAA1B'], + ['0x03020100', '0x11100904', '0x1A0B0A12', '0xFFABAA1B']], '-1', forms]) + case_data.append(['eq', ['0xFFFFFFFFFFFFFFFF', '0x0FFFFFFFFFFFFFFF'], '0', forms]) + case_data.append(['eq', ['0x1', '0x2'], '0', forms]) + + case_data.append(['#', 'ne']) + case_data.append(['#', 'i64x2.ne (i64x2) (i64x2)']) + + # hex vs hex + case_data.append(['#', 'hex vs hex']) + case_data.append(['ne', ['0xFFFFFFFFFFFFFFFF', '0xFFFFFFFFFFFFFFFF'], '0', forms]) + case_data.append(['ne', ['0x0000000000000000', '0x0000000000000000'], '0', forms]) + case_data.append(['ne', ['0xF0F0F0F0F0F0F0F0', '0xF0F0F0F0F0F0F0F0'], '0', forms]) + case_data.append(['ne', ['0x0F0F0F0F0F0F0F0F', '0x0F0F0F0F0F0F0F0F'], '0', forms]) + case_data.append(['ne', [['0xFFFFFFFFFFFFFFFF', '0x0000000000000000'], ['0xFFFFFFFFFFFFFFFF', '0x0000000000000000']], '0', forms]) + case_data.append(['ne', [['0x0000000000000000', '0xFFFFFFFFFFFFFFFF'], ['0x0000000000000000', '0xFFFFFFFFFFFFFFFF']], '0', forms]) + case_data.append(['ne', [['0x03020100', '0x11100904', '0x1A0B0A12', '0xFFABAA1B'], + ['0x03020100', '0x11100904', '0x1A0B0A12', '0xFFABAA1B']], '0', forms]) + + return case_data + + +def gen_test_cases(): + i64x2 = Simdi64x2CmpCase() + i64x2.gen_test_cases() + + +if __name__ == '__main__': + i64x2 = Simdi64x2CmpCase() + i64x2.gen_test_cases() diff --git a/test/core/simd/simd_i64x2_cmp.wast b/test/core/simd/simd_i64x2_cmp.wast new file mode 100644 index 000000000..9f4cc0edf --- /dev/null +++ b/test/core/simd/simd_i64x2_cmp.wast @@ -0,0 +1,106 @@ + +;; Test all the i64x2 comparison operators on major boundary values and all special values. + +(module + (func (export "eq") (param $x v128) (param $y v128) (result v128) (i64x2.eq (local.get $x) (local.get $y))) + (func (export "ne") (param $x v128) (param $y v128) (result v128) (i64x2.ne (local.get $x) (local.get $y))) +) + + +;; eq + +;; i64x2.eq (i64x2) (i64x2) +(assert_return (invoke "eq" (v128.const i64x2 0xFFFFFFFFFFFFFFFF 0xFFFFFFFFFFFFFFFF) + (v128.const i64x2 0xFFFFFFFFFFFFFFFF 0xFFFFFFFFFFFFFFFF)) + (v128.const i64x2 -1 -1)) +(assert_return (invoke "eq" (v128.const i64x2 0x0000000000000000 0x0000000000000000) + (v128.const i64x2 0x0000000000000000 0x0000000000000000)) + (v128.const i64x2 -1 -1)) +(assert_return (invoke "eq" (v128.const i64x2 0xF0F0F0F0F0F0F0F0 0xF0F0F0F0F0F0F0F0) + (v128.const i64x2 0xF0F0F0F0F0F0F0F0 0xF0F0F0F0F0F0F0F0)) + (v128.const i64x2 -1 -1)) +(assert_return (invoke "eq" (v128.const i64x2 0x0F0F0F0F0F0F0F0F 0x0F0F0F0F0F0F0F0F) + (v128.const i64x2 0x0F0F0F0F0F0F0F0F 0x0F0F0F0F0F0F0F0F)) + (v128.const i64x2 -1 -1)) +(assert_return (invoke "eq" (v128.const i64x2 0xFFFFFFFFFFFFFFFF 0x0000000000000000) + (v128.const i64x2 0xFFFFFFFFFFFFFFFF 0x0000000000000000)) + (v128.const i64x2 -1 -1)) +(assert_return (invoke "eq" (v128.const i64x2 0x0000000000000000 0xFFFFFFFFFFFFFFFF) + (v128.const i64x2 0x0000000000000000 0xFFFFFFFFFFFFFFFF)) + (v128.const i64x2 -1 -1)) +(assert_return (invoke "eq" (v128.const i64x2 0x03020100 0x11100904) + (v128.const i64x2 0x03020100 0x11100904)) + (v128.const i64x2 -1 -1)) +(assert_return (invoke "eq" (v128.const i64x2 0xFFFFFFFFFFFFFFFF 0xFFFFFFFFFFFFFFFF) + (v128.const i64x2 0x0FFFFFFFFFFFFFFF 0x0FFFFFFFFFFFFFFF)) + (v128.const i64x2 0 0)) +(assert_return (invoke "eq" (v128.const i64x2 0x1 0x1) + (v128.const i64x2 0x2 0x2)) + (v128.const i64x2 0 0)) + +;; ne + +;; i64x2.ne (i64x2) (i64x2) + +;; hex vs hex +(assert_return (invoke "ne" (v128.const i64x2 0xFFFFFFFF 0xFFFFFFFF) + (v128.const i64x2 0xFFFFFFFF 0xFFFFFFFF)) + (v128.const i64x2 0 0)) +(assert_return (invoke "ne" (v128.const i64x2 0x00000000 0x00000000) + (v128.const i64x2 0x00000000 0x00000000)) + (v128.const i64x2 0 0)) +(assert_return (invoke "ne" (v128.const i64x2 0xF0F0F0F0 0xF0F0F0F0) + (v128.const i64x2 0xF0F0F0F0 0xF0F0F0F0)) + (v128.const i64x2 0 0)) +(assert_return (invoke "ne" (v128.const i64x2 0x0F0F0F0F 0x0F0F0F0F) + (v128.const i64x2 0x0F0F0F0F 0x0F0F0F0F)) + (v128.const i64x2 0 0)) +(assert_return (invoke "ne" (v128.const i64x2 0xFFFFFFFF 0x00000000) + (v128.const i64x2 0xFFFFFFFF 0x00000000)) + (v128.const i64x2 0 0)) +(assert_return (invoke "ne" (v128.const i64x2 0x00000000 0xFFFFFFFF) + (v128.const i64x2 0x00000000 0xFFFFFFFF)) + (v128.const i64x2 0 0)) +(assert_return (invoke "ne" (v128.const i64x2 0x03020100 0x11100904) + (v128.const i64x2 0x03020100 0x11100904)) + (v128.const i64x2 0 0)) + +;; Type check + +(assert_invalid (module (func (result v128) (i64x2.eq (i32.const 0) (f32.const 0)))) "type mismatch") +(assert_invalid (module (func (result v128) (i64x2.ne (i32.const 0) (f32.const 0)))) "type mismatch") + +;; Test operation with empty argument + +(assert_invalid + (module + (func $i64x2.eq-1st-arg-empty (result v128) + (i64x2.eq (v128.const i64x2 0 0)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (func $i64x2.eq-arg-empty (result v128) + (i64x2.eq) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (func $i64x2.ne-1st-arg-empty (result v128) + (i64x2.ne (v128.const i64x2 0 0)) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (func $i64x2.ne-arg-empty (result v128) + (i64x2.ne) + ) + ) + "type mismatch" +) \ No newline at end of file