Skip to content

Commit e4c911d

Browse files
committed
[interpreter] Implement i16x8.qmulr_sat_s
This was merged in WebAssembly#365.
1 parent 6dcabf6 commit e4c911d

13 files changed

+177
-3
lines changed

interpreter/binary/decode.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ let simd_prefix s =
370370
| 0x99l -> i16x8_max_u
371371
| 0x9al -> i16x8_extmul_low_i8x16_s
372372
| 0x9bl -> i16x8_avgr_u
373+
| 0x9cl -> i16x8_q15mulr_sat_s
373374
| 0x9dl -> i16x8_extmul_high_i8x16_s
374375
| 0x9el -> i16x8_extmul_low_i8x16_u
375376
| 0x9fl -> i16x8_extmul_high_i8x16_u

interpreter/binary/encode.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ let encode m =
477477
| Binary (V128 V128Op.(I16x8 ExtMulHighS)) -> simd_op 0x9dl
478478
| Binary (V128 V128Op.(I16x8 ExtMulLowU)) -> simd_op 0x9el
479479
| Binary (V128 V128Op.(I16x8 ExtMulHighU)) -> simd_op 0x9fl
480+
| Binary (V128 V128Op.(I16x8 Q15MulRSatS)) -> simd_op 0x9cl
480481
| Binary (V128 V128Op.(I32x4 Add)) -> simd_op 0xael
481482
| Binary (V128 V128Op.(I32x4 Sub)) -> simd_op 0xb1l
482483
| Binary (V128 V128Op.(I32x4 MinS)) -> simd_op 0xb6l

interpreter/exec/eval_simd.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ module SimdOp (SXX : Simd.S) (Value : ValueType with type t = SXX.t) = struct
111111
| I16x8 ExtMulHighS -> SXX.I16x8_convert.extmul_high_s
112112
| I16x8 ExtMulLowU -> SXX.I16x8_convert.extmul_low_u
113113
| I16x8 ExtMulHighU -> SXX.I16x8_convert.extmul_high_u
114+
| I16x8 Q15MulRSatS -> SXX.I16x8.q15mulr_sat_s
114115
| I32x4 Add -> SXX.I32x4.add
115116
| I32x4 Sub -> SXX.I32x4.sub
116117
| I32x4 MinS -> SXX.I32x4.min_s

interpreter/exec/int.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ sig
9393
val add_sat_u : t -> t -> t
9494
val sub_sat_s : t -> t -> t
9595
val sub_sat_u : t -> t -> t
96+
val q15mulr_sat_s : t -> t -> t
9697

9798
val of_int_s : int -> t
9899
val of_int_u : int -> t
@@ -289,6 +290,15 @@ struct
289290
let sub_sat_s x y = saturate_s (sub x y)
290291
let sub_sat_u x y = saturate_u (sub (as_unsigned x) (as_unsigned y))
291292

293+
let q15mulr_sat_s x y =
294+
(* mul x64 y64 can overflow int64 when both are int32 min, but this is only
295+
* used by i16x8, so we are fine for now. *)
296+
assert (Rep.bitwidth < 32);
297+
let open Int64 in
298+
let x64 = Rep.to_int64 x in
299+
let y64 = Rep.to_int64 y in
300+
Rep.of_int64 ((shift_right (add (mul x64 y64) 0x4000L) 15))
301+
292302
let to_int_s = Rep.to_int
293303
let to_int_u i = Rep.to_int i land (Rep.to_int Rep.max_int lsl 1) lor 1
294304

interpreter/exec/simd.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ sig
9090
val add_sat_u : t -> t -> t
9191
val sub_sat_s : t -> t -> t
9292
val sub_sat_u : t -> t -> t
93+
val q15mulr_sat_s : t -> t -> t
9394
end
9495

9596
(* This signature defines the types and operations SIMD floats can expose. *)
@@ -353,6 +354,8 @@ struct
353354
let add_sat_u = binop Int.add_sat_u
354355
let sub_sat_s = binop Int.sub_sat_s
355356
let sub_sat_u = binop Int.sub_sat_u
357+
(* The intermediate will overflow lane.t, so have Int implement this. *)
358+
let q15mulr_sat_s = binop Int.q15mulr_sat_s
356359
end
357360

358361
module V8x16 = struct

interpreter/syntax/ast.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ struct
5555
| Eq | Ne | LtS | LtU | LeS | LeU | GtS | GtU | GeS | GeU
5656
| Swizzle | Shuffle of int list | NarrowS | NarrowU
5757
| AddSatS | AddSatU | SubSatS | SubSatU
58-
| DotI16x8S
58+
| DotI16x8S | Q15MulRSatS
5959
| ExtMulLowS | ExtMulHighS | ExtMulLowU | ExtMulHighU
6060
type funop = Abs | Neg | Sqrt
6161
| Ceil | Floor | Trunc | Nearest

interpreter/syntax/operators.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ let i16x8_extmul_low_i8x16_s = Binary (V128 V128Op.(I16x8 ExtMulLowS))
345345
let i16x8_extmul_high_i8x16_s = Binary (V128 V128Op.(I16x8 ExtMulHighS))
346346
let i16x8_extmul_low_i8x16_u = Binary (V128 V128Op.(I16x8 ExtMulLowU))
347347
let i16x8_extmul_high_i8x16_u = Binary (V128 V128Op.(I16x8 ExtMulHighU))
348+
let i16x8_q15mulr_sat_s = Binary (V128 V128Op.(I16x8 Q15MulRSatS))
348349

349350
let i32x4_splat = Convert (V128 V128Op.(I32x4 Splat))
350351
let i32x4_extract_lane imm = SimdExtract (V128Op.I32x4 (ZX, imm))

interpreter/text/arrange.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ struct
312312
| I16x8 ExtMulHighS -> "i16x8.extmul_high_i8x16_s"
313313
| I16x8 ExtMulLowU -> "i16x8.extmul_low_i8x16_u"
314314
| I16x8 ExtMulHighU -> "i16x8.extmul_high_i8x16_u"
315+
| I16x8 Q15MulRSatS -> "i16x8.q15mulr_sat_s"
315316
| I32x4 Add -> "i32x4.add"
316317
| I32x4 Sub -> "i32x4.sub"
317318
| I32x4 Mul -> "i32x4.mul"

interpreter/text/lexer.mll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ rule token = parse
588588
{ BINARY (ext s i64x2_extmul_low_i32x4_s i64x2_extmul_low_i32x4_u) }
589589
| "i64x2.extmul_high_i32x4_"(sign as s)
590590
{ BINARY (ext s i64x2_extmul_high_i32x4_s i64x2_extmul_high_i32x4_u) }
591+
| "i16x8.q15mulr_sat_s"
592+
{ BINARY i16x8_q15mulr_sat_s }
591593

592594
| (simd_shape as s) { SIMD_SHAPE (simd_shape s) }
593595

test/core/simd/meta/gen_tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
'simd_load_lane',
3636
'simd_ext_mul',
3737
'simd_int_to_int_widen',
38+
'simd_i16x8_q15mulr_sat_s',
3839
)
3940

4041

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env python3
2+
3+
from simd_arithmetic import SimdArithmeticCase
4+
5+
6+
"""Generate test cases for i16x8.mulr_sat_s
7+
"""
8+
class SimdI16x8Q15MulRSatS(SimdArithmeticCase):
9+
LANE_TYPE = 'i16x8'
10+
UNARY_OPS = ()
11+
BINARY_OPS = ('q15mulr_sat_s',)
12+
13+
@property
14+
def full_bin_test_data(self):
15+
return []
16+
17+
@property
18+
def hex_binary_op_test_data(self):
19+
return []
20+
21+
def get_combine_cases(self):
22+
return ''
23+
24+
def gen_test_cases(self):
25+
wast_filename = '../simd_i16x8_q15mulr_sat_s.wast'
26+
with open(wast_filename, 'w') as fp:
27+
fp.write(self.get_all_cases())
28+
29+
30+
def gen_test_cases():
31+
simd_i16x8_q16mulr_sat_s = SimdI16x8Q15MulRSatS()
32+
simd_i16x8_q16mulr_sat_s.gen_test_cases()
33+
34+
35+
if __name__ == '__main__':
36+
gen_test_cases()

test/core/simd/meta/simd_integer_op.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ def binary_op(self, operand1, operand2, src_lane, dst_lane=None):
133133
add, sub, mul,
134134
add_sat_s, add_sat_u,
135135
sub_sat_s, sub_sat_u,
136-
min_s, min_u, max_s, max_u, avgr_u
137-
ext_mul_s, ext_mul_u (same as mul)
136+
min_s, min_u, max_s, max_u, avgr_u,
137+
ext_mul_s, ext_mul_u (same as mul),
138+
q15mulr_sat_s
138139
139140
:param operand1: the operand 1, integer or literal string in hex or decimal format
140141
:param operand2: the operand 2, integer or literal string in hex or decimal format
@@ -170,6 +171,12 @@ def binary_op(self, operand1, operand2, src_lane, dst_lane=None):
170171
i1 = self.get_valid_value(v1, src_lane, signed=False)
171172
i2 = self.get_valid_value(v2, src_lane, signed=False)
172173
value = i1 * i2
174+
elif self.op == 'q15mulr_sat_s':
175+
# This should be before 'sat' case.
176+
i1 = ArithmeticOp.get_valid_value(v1, src_lane)
177+
i2 = ArithmeticOp.get_valid_value(v2, src_lane)
178+
result = (i1 * i2 + 0x4000) >> 15
179+
return ArithmeticOp.get_valid_value(result, src_lane)
173180
elif 'sat' in self.op:
174181
value = self._saturate(v1, v2, src_lane)
175182
if self.op.endswith('_u'):
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
;; Tests for i16x8 arithmetic operations on major boundary values and all special values.
2+
3+
4+
(module
5+
(func (export "i16x8.q15mulr_sat_s") (param v128 v128) (result v128) (i16x8.q15mulr_sat_s (local.get 0) (local.get 1)))
6+
)
7+
8+
9+
;; i16x8.q15mulr_sat_s
10+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 0 0 0 0 0 0 0 0)
11+
(v128.const i16x8 0 0 0 0 0 0 0 0))
12+
(v128.const i16x8 0 0 0 0 0 0 0 0))
13+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 0 0 0 0 0 0 0 0)
14+
(v128.const i16x8 1 1 1 1 1 1 1 1))
15+
(v128.const i16x8 0 0 0 0 0 0 0 0))
16+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 1 1 1 1 1 1 1 1)
17+
(v128.const i16x8 1 1 1 1 1 1 1 1))
18+
(v128.const i16x8 0 0 0 0 0 0 0 0))
19+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 0 0 0 0 0 0 0 0)
20+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
21+
(v128.const i16x8 0 0 0 0 0 0 0 0))
22+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 1 1 1 1 1 1 1 1)
23+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
24+
(v128.const i16x8 0 0 0 0 0 0 0 0))
25+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1)
26+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
27+
(v128.const i16x8 0 0 0 0 0 0 0 0))
28+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 16383 16383 16383 16383 16383 16383 16383 16383)
29+
(v128.const i16x8 16384 16384 16384 16384 16384 16384 16384 16384))
30+
(v128.const i16x8 8192 8192 8192 8192 8192 8192 8192 8192))
31+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 16384 16384 16384 16384 16384 16384 16384 16384)
32+
(v128.const i16x8 16384 16384 16384 16384 16384 16384 16384 16384))
33+
(v128.const i16x8 8192 8192 8192 8192 8192 8192 8192 8192))
34+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -16383 -16383 -16383 -16383 -16383 -16383 -16383 -16383)
35+
(v128.const i16x8 -16384 -16384 -16384 -16384 -16384 -16384 -16384 -16384))
36+
(v128.const i16x8 8192 8192 8192 8192 8192 8192 8192 8192))
37+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -16384 -16384 -16384 -16384 -16384 -16384 -16384 -16384)
38+
(v128.const i16x8 -16384 -16384 -16384 -16384 -16384 -16384 -16384 -16384))
39+
(v128.const i16x8 8192 8192 8192 8192 8192 8192 8192 8192))
40+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -16385 -16385 -16385 -16385 -16385 -16385 -16385 -16385)
41+
(v128.const i16x8 -16384 -16384 -16384 -16384 -16384 -16384 -16384 -16384))
42+
(v128.const i16x8 8193 8193 8193 8193 8193 8193 8193 8193))
43+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 32765 32765 32765 32765 32765 32765 32765 32765)
44+
(v128.const i16x8 1 1 1 1 1 1 1 1))
45+
(v128.const i16x8 1 1 1 1 1 1 1 1))
46+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 32766 32766 32766 32766 32766 32766 32766 32766)
47+
(v128.const i16x8 1 1 1 1 1 1 1 1))
48+
(v128.const i16x8 1 1 1 1 1 1 1 1))
49+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 32768 32768 32768 32768 32768 32768 32768 32768)
50+
(v128.const i16x8 1 1 1 1 1 1 1 1))
51+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
52+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -32766 -32766 -32766 -32766 -32766 -32766 -32766 -32766)
53+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
54+
(v128.const i16x8 1 1 1 1 1 1 1 1))
55+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -32767 -32767 -32767 -32767 -32767 -32767 -32767 -32767)
56+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
57+
(v128.const i16x8 1 1 1 1 1 1 1 1))
58+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768)
59+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
60+
(v128.const i16x8 1 1 1 1 1 1 1 1))
61+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 32767 32767 32767 32767 32767 32767 32767 32767)
62+
(v128.const i16x8 32767 32767 32767 32767 32767 32767 32767 32767))
63+
(v128.const i16x8 32766 32766 32766 32766 32766 32766 32766 32766))
64+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768)
65+
(v128.const i16x8 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768))
66+
(v128.const i16x8 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768))
67+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768)
68+
(v128.const i16x8 -32767 -32767 -32767 -32767 -32767 -32767 -32767 -32767))
69+
(v128.const i16x8 32767 32767 32767 32767 32767 32767 32767 32767))
70+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 65535 65535 65535 65535 65535 65535 65535 65535)
71+
(v128.const i16x8 0 0 0 0 0 0 0 0))
72+
(v128.const i16x8 0 0 0 0 0 0 0 0))
73+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 65535 65535 65535 65535 65535 65535 65535 65535)
74+
(v128.const i16x8 1 1 1 1 1 1 1 1))
75+
(v128.const i16x8 0 0 0 0 0 0 0 0))
76+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 65535 65535 65535 65535 65535 65535 65535 65535)
77+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
78+
(v128.const i16x8 0 0 0 0 0 0 0 0))
79+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 65535 65535 65535 65535 65535 65535 65535 65535)
80+
(v128.const i16x8 32767 32767 32767 32767 32767 32767 32767 32767))
81+
(v128.const i16x8 -1 -1 -1 -1 -1 -1 -1 -1))
82+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 65535 65535 65535 65535 65535 65535 65535 65535)
83+
(v128.const i16x8 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768))
84+
(v128.const i16x8 1 1 1 1 1 1 1 1))
85+
(assert_return (invoke "i16x8.q15mulr_sat_s" (v128.const i16x8 65535 65535 65535 65535 65535 65535 65535 65535)
86+
(v128.const i16x8 65535 65535 65535 65535 65535 65535 65535 65535))
87+
(v128.const i16x8 0 0 0 0 0 0 0 0))
88+
89+
;; type check
90+
(assert_invalid (module (func (result v128) (i16x8.q15mulr_sat_s (i32.const 0) (f32.const 0.0)))) "type mismatch")
91+
92+
;; Test operation with empty argument
93+
94+
(assert_invalid
95+
(module
96+
(func $i16x8.q15mulr_sat_s-1st-arg-empty (result v128)
97+
(i16x8.q15mulr_sat_s (v128.const i16x8 0 0 0 0 0 0 0 0))
98+
)
99+
)
100+
"type mismatch"
101+
)
102+
(assert_invalid
103+
(module
104+
(func $i16x8.q15mulr_sat_s-arg-empty (result v128)
105+
(i16x8.q15mulr_sat_s)
106+
)
107+
)
108+
"type mismatch"
109+
)
110+

0 commit comments

Comments
 (0)