Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

[interpreter] Implement i64x2.widen_{low,high}_i32x4_{s,u} #446

Merged
merged 1 commit into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ let simd_prefix s =
| 0xc0l -> i64x2_eq
| 0xc1l -> i64x2_neg
| 0xc4l -> i64x2_bitmask
| 0xc7l -> i64x2_widen_low_i32x4_s
| 0xc8l -> i64x2_widen_high_i32x4_s
| 0xc9l -> i64x2_widen_low_i32x4_u
| 0xcal -> i64x2_widen_high_i32x4_u
| 0xcbl -> i64x2_shl
| 0xccl -> i64x2_shr_s
| 0xcdl -> i64x2_shr_u
Expand Down
4 changes: 4 additions & 0 deletions interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ let encode m =
| Unary (V128 V128Op.(I32x4 WidenLowU)) -> simd_op 0xa9l
| Unary (V128 V128Op.(I32x4 WidenHighU)) -> simd_op 0xaal
| Unary (V128 V128Op.(I64x2 Neg)) -> simd_op 0xc1l
| Unary (V128 V128Op.(I64x2 WidenLowS)) -> simd_op 0xc7l
| Unary (V128 V128Op.(I64x2 WidenHighS)) -> simd_op 0xc8l
| Unary (V128 V128Op.(I64x2 WidenLowU)) -> simd_op 0xc9l
| Unary (V128 V128Op.(I64x2 WidenHighU)) -> simd_op 0xcal
| Unary (V128 V128Op.(F32x4 Ceil)) -> simd_op 0xd8l
| Unary (V128 V128Op.(F32x4 Floor)) -> simd_op 0xd9l
| Unary (V128 V128Op.(F32x4 Trunc)) -> simd_op 0xdal
Expand Down
4 changes: 4 additions & 0 deletions interpreter/exec/eval_simd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ module SimdOp (SXX : Simd.S) (Value : ValueType with type t = SXX.t) = struct
| I32x4 TruncSatF32x4S -> to_value (SXX.I32x4_convert.trunc_sat_f32x4_s (of_value 1 v))
| I32x4 TruncSatF32x4U -> to_value (SXX.I32x4_convert.trunc_sat_f32x4_u (of_value 1 v))
| I64x2 Neg -> to_value (SXX.I64x2.neg (of_value 1 v))
| I64x2 WidenLowS -> to_value (SXX.I64x2_convert.widen_low_s (of_value 1 v))
| I64x2 WidenHighS -> to_value (SXX.I64x2_convert.widen_high_s (of_value 1 v))
| I64x2 WidenLowU -> to_value (SXX.I64x2_convert.widen_low_u (of_value 1 v))
| I64x2 WidenHighU -> to_value (SXX.I64x2_convert.widen_high_u (of_value 1 v))
| F32x4 Abs -> to_value (SXX.F32x4.abs (of_value 1 v))
| F32x4 Neg -> to_value (SXX.F32x4.neg (of_value 1 v))
| F32x4 Sqrt -> to_value (SXX.F32x4.sqrt (of_value 1 v))
Expand Down
4 changes: 4 additions & 0 deletions interpreter/syntax/operators.ml
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ let i32x4_extmul_high_i16x8_u = Binary (V128 V128Op.(I32x4 ExtMulHighU))
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_widen_low_i32x4_s = Unary (V128 V128Op.(I64x2 WidenLowS))
let i64x2_widen_high_i32x4_s = Unary (V128 V128Op.(I64x2 WidenHighS))
let i64x2_widen_low_i32x4_u = Unary (V128 V128Op.(I64x2 WidenLowU))
let i64x2_widen_high_i32x4_u = Unary (V128 V128Op.(I64x2 WidenHighU))
let i64x2_eq = Binary (V128 V128Op.(I64x2 Eq))
let i64x2_ne = Binary (V128 V128Op.(I64x2 Ne))
let i64x2_neg = Unary (V128 V128Op.(I64x2 Neg))
Expand Down
4 changes: 4 additions & 0 deletions interpreter/text/arrange.ml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ struct
| I32x4 TruncSatF32x4S -> "i32x4.trunc_sat_f32x4_s"
| I32x4 TruncSatF32x4U -> "i32x4.trunc_sat_f32x4_u"
| I64x2 Neg -> "i64x2.neg"
| I64x2 WidenLowS -> "i64x2.widen_low_i32x4_s"
| I64x2 WidenHighS -> "i64x2.widen_high_i32x4_s"
| I64x2 WidenLowU -> "i64x2.widen_low_i32x4_u"
| I64x2 WidenHighU -> "i64x2.widen_high_i32x4_u"
| F32x4 Ceil -> "f32x4.ceil"
| F32x4 Floor -> "f32x4.floor"
| F32x4 Trunc -> "f32x4.trunc"
Expand Down
4 changes: 4 additions & 0 deletions interpreter/text/lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ rule token = parse
{ UNARY (ext s i32x4_widen_low_i16x8_s i32x4_widen_low_i16x8_u) }
| "i32x4.widen_high_i16x8_"(sign as s)
{ UNARY (ext s i32x4_widen_high_i16x8_s i32x4_widen_high_i16x8_u) }
| "i64x2.widen_low_i32x4_"(sign as s)
{ UNARY (ext s i64x2_widen_low_i32x4_s i64x2_widen_low_i32x4_u) }
| "i64x2.widen_high_i32x4_"(sign as s)
{ UNARY (ext s i64x2_widen_high_i32x4_s i64x2_widen_high_i32x4_u) }

| "i8x16.add_sat_"(sign as s)
{ BINARY (ext s i8x16_add_sat_s i8x16_add_sat_u) }
Expand Down
1 change: 1 addition & 0 deletions test/core/simd/meta/gen_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'simd_i32x4_dot_i16x8',
'simd_load_lane',
'simd_ext_mul',
'simd_int_to_int_widen',
)


Expand Down
35 changes: 23 additions & 12 deletions test/core/simd/meta/simd_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ class SimdArithmeticCase:
BINARY_OPS = ('add', 'sub', 'mul')
LANE_VALUE = {'i8x16': i8, 'i16x8': i16, 'i32x4': i32, 'i64x2': i64}

TEST_FUNC_TEMPLATE_HEADER = (
';; Tests for {} arithmetic operations on major boundary values and all special values.\n\n')

def op_name(self, op):
""" Full instruction name.
Subclasses can overwrite to provide custom instruction names that don't
fit the default of {shape}.{op}.
"""
return '{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op)

def __str__(self):
return self.get_all_cases()

Expand Down Expand Up @@ -150,15 +160,14 @@ def combine_binary_arith_test_data(self):

def gen_test_func_template(self):
template = [
';; Tests for {} arithmetic operations on major boundary values and all special values.\n\n'.format(
self.LANE_TYPE), '(module']
self.TEST_FUNC_TEMPLATE_HEADER.format(self.LANE_TYPE), '(module']

for op in self.BINARY_OPS:
template.append(' (func (export "{lane_type}.%s") (param v128 v128) (result v128) '
'({lane_type}.%s (local.get 0) (local.get 1)))' % (op, op))
template.append(' (func (export "{op}") (param v128 v128) (result v128) '
'({op} (local.get 0) (local.get 1)))'.format(op=self.op_name(op)))
for op in self.UNARY_OPS:
template.append(' (func (export "{lane_type}.%s") (param v128) (result v128) '
'({lane_type}.%s (local.get 0)))' % (op, op))
template.append(' (func (export "{op}") (param v128) (result v128) '
'({op} (local.get 0)))'.format(op=self.op_name(op)))

template.append(')\n')
return template
Expand Down Expand Up @@ -203,16 +212,18 @@ def get_case_data(self):

def get_invalid_cases(self):
invalid_cases = [';; type check']

unary_template = '(assert_invalid (module (func (result v128) '\
'({lane_type}.{op} ({operand})))) "type mismatch")'
'({name} ({operand})))) "type mismatch")'
binary_template = '(assert_invalid (module (func (result v128) '\
'({lane_type}.{op} ({operand_1}) ({operand_2})))) "type mismatch")'
'({name} ({operand_1}) ({operand_2})))) "type mismatch")'


for op in self.UNARY_OPS:
invalid_cases.append(unary_template.format(lane_type=self.LANE_TYPE, op=op,
invalid_cases.append(unary_template.format(name=self.op_name(op),
operand='i32.const 0'))
for op in self.BINARY_OPS:
invalid_cases.append(binary_template.format(lane_type=self.LANE_TYPE, op=op,
invalid_cases.append(binary_template.format(name=self.op_name(op),
operand_1='i32.const 0',
operand_2='f32.const 0.0'))

Expand All @@ -234,13 +245,13 @@ def argument_empty_test(self):
}

for op in self.UNARY_OPS:
case_data['op'] = '{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op)
case_data['op'] = self.op_name(op)
case_data['extended_name'] = 'arg-empty'
case_data['params'] = ''
cases.append(AssertInvalid.get_arg_empty_test(**case_data))

for op in self.BINARY_OPS:
case_data['op'] = '{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op)
case_data['op'] = self.op_name(op)
case_data['extended_name'] = '1st-arg-empty'
case_data['params'] = SIMD.v128_const('0', self.LANE_TYPE)
cases.append(AssertInvalid.get_arg_empty_test(**case_data))
Expand Down
113 changes: 113 additions & 0 deletions test/core/simd/meta/simd_int_to_int_widen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env python3

"""
Generates all integer-to-integer widening test cases.
"""

from simd import SIMD
from simd_arithmetic import SimdArithmeticCase
from test_assert import AssertReturn, AssertInvalid


class SimdIntToIntWiden(SimdArithmeticCase):
LANE_TYPE = "" # unused, can be anything
BINARY_OPS = ()
UNARY_OPS = (
"i16x8.widen_high_i8x16_s",
"i16x8.widen_high_i8x16_u",
"i16x8.widen_low_i8x16_s",
"i16x8.widen_low_i8x16_u",
"i32x4.widen_high_i16x8_s",
"i32x4.widen_high_i16x8_u",
"i32x4.widen_low_i16x8_s",
"i32x4.widen_low_i16x8_u",
"i64x2.widen_high_i32x4_s",
"i64x2.widen_high_i32x4_u",
"i64x2.widen_low_i32x4_s",
"i64x2.widen_low_i32x4_u",
)

TEST_FUNC_TEMPLATE_HEADER = ";; Tests for int-to-int widening operations.\n"

def op_name(self, op):
# Override base class implementation, since the lane type is already
# part of the op name.
return "{op}".format(lane_type=self.LANE_TYPE, op=op)

def is_unsigned(self, op):
return op.endswith("_u")

def src_lane_type(self, op):
return op[-7:-2]

def dst_lane_type(self, op):
return op[0:5]

def get_test_cases(self, src_value):
return [
(0, 0),
(0, 1),
(0, -1),
(1, 0),
(-1, 0),
(1, -1),
((-1, 1)),
((src_value.max - 1), (src_value.max)),
((src_value.max), (src_value.max - 1)),
((src_value.max), (src_value.max)),
((src_value.min), (src_value.min)),
((src_value.max), (src_value.min)),
((src_value.min), (src_value.max)),
((src_value.max), -1),
(-1, (src_value.max)),
(((src_value.min + 1), (src_value.min))),
((src_value.min), (src_value.min + 1)),
((src_value.min), (-1)),
((-1), (src_value.min)),
]

def get_normal_case(self):
cases = []

for op in self.UNARY_OPS:
src_lane_type = self.src_lane_type(op)
src_value = self.LANE_VALUE[src_lane_type]
operands = self.get_test_cases(src_value)

for (low, high) in operands:
result = low if "low" in op else high

if self.is_unsigned(op):
# Unsign-extend, mask top bits.
result = result & src_value.mask

cases.append(
str(
AssertReturn(
op,
[SIMD.v128_const([str(low), str(high)], src_lane_type)],
SIMD.v128_const(str(result), self.dst_lane_type(op)),
)
)
)

cases.append("")

return "\n".join(cases)

def gen_test_cases(self):
wast_filename = "../simd_int_to_int_widen.wast"
with open(wast_filename, "w") as fp:
fp.write(self.get_all_cases())

def get_combine_cases(self):
return ""


def gen_test_cases():
simd_int_to_int_widen = SimdIntToIntWiden()
simd_int_to_int_widen.gen_test_cases()


if __name__ == "__main__":
gen_test_cases()
Loading