Repository navigation
[spec] i32x4.relaxed_dot_i8x16_i7x16_add_s disagrees with the reference interpreter and the test suite #2311
Description
Summary
The spec defines i32x4.relaxed_dot_i8x16_i7x16_add_s as RELAXED_DOT (the i16x8 relaxed dot product), then EXTADD_PAIRWISE, then ADD (3.2-numerics.vector.spectec L401-L406, numerics.rst L2236-L2252). Since #2252, RELAXED_DOT allows two behaviours (L371-L372, L381-L382). In both, the first operand is read as signed.
$R_idot = 0(also the deterministic profile): second operand read as signed, 16-bit pair sums wrapped$R_idot = 1: second operand read as unsigned, 16-bit pair sums saturated
RELAXED_DOT_ADD inherits exactly these two. This leads to two mismatches:
- When a signed pair sum overflows i16, the spec excludes the reference interpreter's result (Example 1). This is new since Fix i16x8.relaxed_dot_i8x16_i7x16_s pairwise add #2252. Before it,
RELAXED_DOTalways saturated, so (signed, saturated) was allowed, which is what the reference interpreter'sdot_add_simplements. - The spec excludes two of the four results that
relaxed_dot_product.wastaccepts (Example 2). This was already the case before Fix i16x8.relaxed_dot_i8x16_i7x16_s pairwise add #2252.
Example 1: the reference interpreter's result is outside the spec
(module
(func (export "dot") (result v128)
(i32x4.relaxed_dot_i8x16_i7x16_add_s
(v128.const i8x16 -128 -128 -128 -128 0 0 0 0 0 0 0 0 0 0 0 0) ;; a
(v128.const i8x16 -128 -128 -128 -128 0 0 0 0 0 0 0 0 0 0 0 0) ;; b
(v128.const i32x4 0 0 0 0)))) ;; c
(invoke "dot")This input is not from the test suite. It differs from the add_s case at relaxed_dot_product.wast L82-L90 only in b (-128 instead of -127). With b = -127, a signed pair sum is 32512 and fits in i16, so none of the add_s tests has a signed pair sum that overflows.
Lane 0 is the sum of two pair sums, each (-128)·b + (-128)·b:
| Behaviour | b read as |
Pair sum | Lane 0 |
|---|---|---|---|
Spec, $R_idot = 0 (signed, wrap) |
-128 | 32768, wraps to -32768 | -65536 |
Spec, $R_idot = 1 (unsigned, saturate) |
128 | -32768 (fits) | -65536 |
Reference interpreter dot_add_s (signed, saturate; v128.ml L428-L440) |
-128 | 32768, saturates to 32767 | 65534 |
Signed, no 16-bit intermediate (e.g. Arm SDOT, x86 VPDPBSSD) |
-128 | 32768 | 65536 |
So the spec allows only -65536, for either value of $R_idot. The reference interpreter prints 65_534 0 0 0 : [v128]. Its i16x8 dot_s (v128.ml L387-L396) wraps, which matches $R_idot = 0. Only dot_add_s saturates.
Example 2: results listed in the test suite are not allowed
relaxed_dot_product.wast L76-L90 accepts four results in lane 0 for a = -128 ×4, b = -127 ×4, c = (1, 2, 3, 4):
| Lane 0 | Comment in the test | Allowed by the spec |
|---|---|---|
| -66047 | signed * unsigned (VPDPBUSD) |
no |
| -65535 | signed * unsigned with intermediate saturation (PMADDUBSW) |
yes ($R_idot = 1) |
| 65025 | signed * signed | yes ($R_idot = 0) |
| 66049 | unsigned * unsigned | no |
-66047 needs an unsigned b with a pair sum wider than 16 bits. 66049 reads a as unsigned, which the proposal pseudo-code does not allow either (lhs = as_signed(a[i])).
The test passes on both the SpecTec interpreter and the reference interpreter, which both return 65025. An either assertion only checks that the result is in the list. It does not check that every listed result is allowed by the spec.
Questions
- Is the 16-bit intermediate part of the intended semantics? In the proposal pseudo-code, each pair sum
tmpis either the plain sum or the sum saturated to i16, but the width oftmpis not stated. Iftmpis 16 bits, the plain sum wraps (-65536 in Example 1). If it is wider, it stays exact (65536, as withSDOT/VPDPBSSD). The spec takes the 16-bit reading, and so do the tests proposed in test/relaxed_dot: add i16-intermediate overflow boundary cases #2228. - Depending on the answer, which should change?
- the allowed results of
RELAXED_DOT_ADD(e.g. add signed + saturate, and possibly the exact sum) - the reference interpreter's
dot_add_s(e.g. wrap, as its i16x8dot_sdoes) - the
eitherlist inrelaxed_dot_product.wast: -66047 (if the 16-bit intermediate is intended) and 66049 (which the proposal does not allow)
- the allowed results of
cc @brendandahl, since you mentioned in #2252 that there are also issues with i32x4.relaxed_dot_i8x16_i7x16_add_s to address in a separate PR.
Activity
brendandahl commentedon Oct 29, 2026
I uploaded #2312 with some proposed changes based on what engines are actually emitting.