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

Commit

Permalink
[interpreter] Implement i64x2.widen_{low,high}_i32x4_{s,u}
Browse files Browse the repository at this point in the history
This was merged in #290.

Also tweaked the file generation scripts:

- Make simd_arithmetic more generic (allow different instruction name
patterns)
- create a new file simd_int_to_int_widen to generate all integer
widening operations (including the ones implemented in this PR)
- remove widening tests from simd_conversions.wast
  • Loading branch information
ngzhian committed Feb 9, 2021
1 parent 34e195c commit 634be58
Show file tree
Hide file tree
Showing 11 changed files with 760 additions and 476 deletions.
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

0 comments on commit 634be58

Please sign in to comment.