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

Commit 634be58

Browse files
committed
[interpreter] Implement i64x2.widen_{low,high}_i32x4_{s,u}
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
1 parent 34e195c commit 634be58

File tree

11 files changed

+760
-476
lines changed

11 files changed

+760
-476
lines changed

interpreter/binary/decode.ml

+4
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,10 @@ let simd_prefix s =
396396
| 0xc0l -> i64x2_eq
397397
| 0xc1l -> i64x2_neg
398398
| 0xc4l -> i64x2_bitmask
399+
| 0xc7l -> i64x2_widen_low_i32x4_s
400+
| 0xc8l -> i64x2_widen_high_i32x4_s
401+
| 0xc9l -> i64x2_widen_low_i32x4_u
402+
| 0xcal -> i64x2_widen_high_i32x4_u
399403
| 0xcbl -> i64x2_shl
400404
| 0xccl -> i64x2_shr_s
401405
| 0xcdl -> i64x2_shr_u

interpreter/binary/encode.ml

+4
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,10 @@ let encode m =
350350
| Unary (V128 V128Op.(I32x4 WidenLowU)) -> simd_op 0xa9l
351351
| Unary (V128 V128Op.(I32x4 WidenHighU)) -> simd_op 0xaal
352352
| Unary (V128 V128Op.(I64x2 Neg)) -> simd_op 0xc1l
353+
| Unary (V128 V128Op.(I64x2 WidenLowS)) -> simd_op 0xc7l
354+
| Unary (V128 V128Op.(I64x2 WidenHighS)) -> simd_op 0xc8l
355+
| Unary (V128 V128Op.(I64x2 WidenLowU)) -> simd_op 0xc9l
356+
| Unary (V128 V128Op.(I64x2 WidenHighU)) -> simd_op 0xcal
353357
| Unary (V128 V128Op.(F32x4 Ceil)) -> simd_op 0xd8l
354358
| Unary (V128 V128Op.(F32x4 Floor)) -> simd_op 0xd9l
355359
| Unary (V128 V128Op.(F32x4 Trunc)) -> simd_op 0xdal

interpreter/exec/eval_simd.ml

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ module SimdOp (SXX : Simd.S) (Value : ValueType with type t = SXX.t) = struct
3131
| I32x4 TruncSatF32x4S -> to_value (SXX.I32x4_convert.trunc_sat_f32x4_s (of_value 1 v))
3232
| I32x4 TruncSatF32x4U -> to_value (SXX.I32x4_convert.trunc_sat_f32x4_u (of_value 1 v))
3333
| I64x2 Neg -> to_value (SXX.I64x2.neg (of_value 1 v))
34+
| I64x2 WidenLowS -> to_value (SXX.I64x2_convert.widen_low_s (of_value 1 v))
35+
| I64x2 WidenHighS -> to_value (SXX.I64x2_convert.widen_high_s (of_value 1 v))
36+
| I64x2 WidenLowU -> to_value (SXX.I64x2_convert.widen_low_u (of_value 1 v))
37+
| I64x2 WidenHighU -> to_value (SXX.I64x2_convert.widen_high_u (of_value 1 v))
3438
| F32x4 Abs -> to_value (SXX.F32x4.abs (of_value 1 v))
3539
| F32x4 Neg -> to_value (SXX.F32x4.neg (of_value 1 v))
3640
| F32x4 Sqrt -> to_value (SXX.F32x4.sqrt (of_value 1 v))

interpreter/syntax/operators.ml

+4
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ let i32x4_extmul_high_i16x8_u = Binary (V128 V128Op.(I32x4 ExtMulHighU))
387387
let i64x2_splat = Convert (V128 V128Op.(I64x2 Splat))
388388
let i64x2_extract_lane imm = SimdExtract (V128Op.I64x2 (ZX, imm))
389389
let i64x2_replace_lane imm = SimdReplace (V128Op.I64x2 imm)
390+
let i64x2_widen_low_i32x4_s = Unary (V128 V128Op.(I64x2 WidenLowS))
391+
let i64x2_widen_high_i32x4_s = Unary (V128 V128Op.(I64x2 WidenHighS))
392+
let i64x2_widen_low_i32x4_u = Unary (V128 V128Op.(I64x2 WidenLowU))
393+
let i64x2_widen_high_i32x4_u = Unary (V128 V128Op.(I64x2 WidenHighU))
390394
let i64x2_eq = Binary (V128 V128Op.(I64x2 Eq))
391395
let i64x2_ne = Binary (V128 V128Op.(I64x2 Ne))
392396
let i64x2_neg = Unary (V128 V128Op.(I64x2 Neg))

interpreter/text/arrange.ml

+4
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ struct
217217
| I32x4 TruncSatF32x4S -> "i32x4.trunc_sat_f32x4_s"
218218
| I32x4 TruncSatF32x4U -> "i32x4.trunc_sat_f32x4_u"
219219
| I64x2 Neg -> "i64x2.neg"
220+
| I64x2 WidenLowS -> "i64x2.widen_low_i32x4_s"
221+
| I64x2 WidenHighS -> "i64x2.widen_high_i32x4_s"
222+
| I64x2 WidenLowU -> "i64x2.widen_low_i32x4_u"
223+
| I64x2 WidenHighU -> "i64x2.widen_high_i32x4_u"
220224
| F32x4 Ceil -> "f32x4.ceil"
221225
| F32x4 Floor -> "f32x4.floor"
222226
| F32x4 Trunc -> "f32x4.trunc"

interpreter/text/lexer.mll

+4
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,10 @@ rule token = parse
562562
{ UNARY (ext s i32x4_widen_low_i16x8_s i32x4_widen_low_i16x8_u) }
563563
| "i32x4.widen_high_i16x8_"(sign as s)
564564
{ UNARY (ext s i32x4_widen_high_i16x8_s i32x4_widen_high_i16x8_u) }
565+
| "i64x2.widen_low_i32x4_"(sign as s)
566+
{ UNARY (ext s i64x2_widen_low_i32x4_s i64x2_widen_low_i32x4_u) }
567+
| "i64x2.widen_high_i32x4_"(sign as s)
568+
{ UNARY (ext s i64x2_widen_high_i32x4_s i64x2_widen_high_i32x4_u) }
565569

566570
| "i8x16.add_sat_"(sign as s)
567571
{ BINARY (ext s i8x16_add_sat_s i8x16_add_sat_u) }

test/core/simd/meta/gen_tests.py

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
'simd_i32x4_dot_i16x8',
3535
'simd_load_lane',
3636
'simd_ext_mul',
37+
'simd_int_to_int_widen',
3738
)
3839

3940

test/core/simd/meta/simd_arithmetic.py

+23-12
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ class SimdArithmeticCase:
2828
BINARY_OPS = ('add', 'sub', 'mul')
2929
LANE_VALUE = {'i8x16': i8, 'i16x8': i16, 'i32x4': i32, 'i64x2': i64}
3030

31+
TEST_FUNC_TEMPLATE_HEADER = (
32+
';; Tests for {} arithmetic operations on major boundary values and all special values.\n\n')
33+
34+
def op_name(self, op):
35+
""" Full instruction name.
36+
Subclasses can overwrite to provide custom instruction names that don't
37+
fit the default of {shape}.{op}.
38+
"""
39+
return '{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op)
40+
3141
def __str__(self):
3242
return self.get_all_cases()
3343

@@ -150,15 +160,14 @@ def combine_binary_arith_test_data(self):
150160

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

156165
for op in self.BINARY_OPS:
157-
template.append(' (func (export "{lane_type}.%s") (param v128 v128) (result v128) '
158-
'({lane_type}.%s (local.get 0) (local.get 1)))' % (op, op))
166+
template.append(' (func (export "{op}") (param v128 v128) (result v128) '
167+
'({op} (local.get 0) (local.get 1)))'.format(op=self.op_name(op)))
159168
for op in self.UNARY_OPS:
160-
template.append(' (func (export "{lane_type}.%s") (param v128) (result v128) '
161-
'({lane_type}.%s (local.get 0)))' % (op, op))
169+
template.append(' (func (export "{op}") (param v128) (result v128) '
170+
'({op} (local.get 0)))'.format(op=self.op_name(op)))
162171

163172
template.append(')\n')
164173
return template
@@ -203,16 +212,18 @@ def get_case_data(self):
203212

204213
def get_invalid_cases(self):
205214
invalid_cases = [';; type check']
215+
206216
unary_template = '(assert_invalid (module (func (result v128) '\
207-
'({lane_type}.{op} ({operand})))) "type mismatch")'
217+
'({name} ({operand})))) "type mismatch")'
208218
binary_template = '(assert_invalid (module (func (result v128) '\
209-
'({lane_type}.{op} ({operand_1}) ({operand_2})))) "type mismatch")'
219+
'({name} ({operand_1}) ({operand_2})))) "type mismatch")'
220+
210221

211222
for op in self.UNARY_OPS:
212-
invalid_cases.append(unary_template.format(lane_type=self.LANE_TYPE, op=op,
223+
invalid_cases.append(unary_template.format(name=self.op_name(op),
213224
operand='i32.const 0'))
214225
for op in self.BINARY_OPS:
215-
invalid_cases.append(binary_template.format(lane_type=self.LANE_TYPE, op=op,
226+
invalid_cases.append(binary_template.format(name=self.op_name(op),
216227
operand_1='i32.const 0',
217228
operand_2='f32.const 0.0'))
218229

@@ -234,13 +245,13 @@ def argument_empty_test(self):
234245
}
235246

236247
for op in self.UNARY_OPS:
237-
case_data['op'] = '{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op)
248+
case_data['op'] = self.op_name(op)
238249
case_data['extended_name'] = 'arg-empty'
239250
case_data['params'] = ''
240251
cases.append(AssertInvalid.get_arg_empty_test(**case_data))
241252

242253
for op in self.BINARY_OPS:
243-
case_data['op'] = '{lane_type}.{op}'.format(lane_type=self.LANE_TYPE, op=op)
254+
case_data['op'] = self.op_name(op)
244255
case_data['extended_name'] = '1st-arg-empty'
245256
case_data['params'] = SIMD.v128_const('0', self.LANE_TYPE)
246257
cases.append(AssertInvalid.get_arg_empty_test(**case_data))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Generates all integer-to-integer widening test cases.
5+
"""
6+
7+
from simd import SIMD
8+
from simd_arithmetic import SimdArithmeticCase
9+
from test_assert import AssertReturn, AssertInvalid
10+
11+
12+
class SimdIntToIntWiden(SimdArithmeticCase):
13+
LANE_TYPE = "" # unused, can be anything
14+
BINARY_OPS = ()
15+
UNARY_OPS = (
16+
"i16x8.widen_high_i8x16_s",
17+
"i16x8.widen_high_i8x16_u",
18+
"i16x8.widen_low_i8x16_s",
19+
"i16x8.widen_low_i8x16_u",
20+
"i32x4.widen_high_i16x8_s",
21+
"i32x4.widen_high_i16x8_u",
22+
"i32x4.widen_low_i16x8_s",
23+
"i32x4.widen_low_i16x8_u",
24+
"i64x2.widen_high_i32x4_s",
25+
"i64x2.widen_high_i32x4_u",
26+
"i64x2.widen_low_i32x4_s",
27+
"i64x2.widen_low_i32x4_u",
28+
)
29+
30+
TEST_FUNC_TEMPLATE_HEADER = ";; Tests for int-to-int widening operations.\n"
31+
32+
def op_name(self, op):
33+
# Override base class implementation, since the lane type is already
34+
# part of the op name.
35+
return "{op}".format(lane_type=self.LANE_TYPE, op=op)
36+
37+
def is_unsigned(self, op):
38+
return op.endswith("_u")
39+
40+
def src_lane_type(self, op):
41+
return op[-7:-2]
42+
43+
def dst_lane_type(self, op):
44+
return op[0:5]
45+
46+
def get_test_cases(self, src_value):
47+
return [
48+
(0, 0),
49+
(0, 1),
50+
(0, -1),
51+
(1, 0),
52+
(-1, 0),
53+
(1, -1),
54+
((-1, 1)),
55+
((src_value.max - 1), (src_value.max)),
56+
((src_value.max), (src_value.max - 1)),
57+
((src_value.max), (src_value.max)),
58+
((src_value.min), (src_value.min)),
59+
((src_value.max), (src_value.min)),
60+
((src_value.min), (src_value.max)),
61+
((src_value.max), -1),
62+
(-1, (src_value.max)),
63+
(((src_value.min + 1), (src_value.min))),
64+
((src_value.min), (src_value.min + 1)),
65+
((src_value.min), (-1)),
66+
((-1), (src_value.min)),
67+
]
68+
69+
def get_normal_case(self):
70+
cases = []
71+
72+
for op in self.UNARY_OPS:
73+
src_lane_type = self.src_lane_type(op)
74+
src_value = self.LANE_VALUE[src_lane_type]
75+
operands = self.get_test_cases(src_value)
76+
77+
for (low, high) in operands:
78+
result = low if "low" in op else high
79+
80+
if self.is_unsigned(op):
81+
# Unsign-extend, mask top bits.
82+
result = result & src_value.mask
83+
84+
cases.append(
85+
str(
86+
AssertReturn(
87+
op,
88+
[SIMD.v128_const([str(low), str(high)], src_lane_type)],
89+
SIMD.v128_const(str(result), self.dst_lane_type(op)),
90+
)
91+
)
92+
)
93+
94+
cases.append("")
95+
96+
return "\n".join(cases)
97+
98+
def gen_test_cases(self):
99+
wast_filename = "../simd_int_to_int_widen.wast"
100+
with open(wast_filename, "w") as fp:
101+
fp.write(self.get_all_cases())
102+
103+
def get_combine_cases(self):
104+
return ""
105+
106+
107+
def gen_test_cases():
108+
simd_int_to_int_widen = SimdIntToIntWiden()
109+
simd_int_to_int_widen.gen_test_cases()
110+
111+
112+
if __name__ == "__main__":
113+
gen_test_cases()

0 commit comments

Comments
 (0)