Skip to content

Commit c8fd933

Browse files
authored
Merge nontrapping-float-to-int proposal into spec (#1143)
See the non-trapping-float-to-int-conversions proposal here: https://github.com/WebAssembly/nontrapping-float-to-int-conversions
1 parent 704d9d9 commit c8fd933

20 files changed

Lines changed: 747 additions & 200 deletions

File tree

‎document/core/appendix/index-instructions.rst‎

Lines changed: 204 additions & 196 deletions
Large diffs are not rendered by default.

‎document/core/binary/instructions.rst‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,23 @@ All other numeric instructions are plain opcodes without any immediates.
363363
\hex{BF} &\Rightarrow& \F64.\REINTERPRET\K{\_}\I64 \\
364364
\end{array}
365365
366+
.. _binary-cvtop-trunc-sat:
367+
368+
The saturating truncation instructions all have a one byte prefix.
369+
370+
.. math::
371+
\begin{array}{llclll}
372+
\production{instruction} & \Binstr &::=& \dots && \phantom{thisshouldbeenough} \\&&|&
373+
\hex{FC}~\hex{00} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
374+
\hex{FC}~\hex{01} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
375+
\hex{FC}~\hex{02} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
376+
\hex{FC}~\hex{03} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|&
377+
\hex{FC}~\hex{04} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
378+
\hex{FC}~\hex{05} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
379+
\hex{FC}~\hex{06} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
380+
\hex{FC}~\hex{07} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\
381+
\end{array}
382+
366383
367384
.. index:: expression
368385
pair: binary format; expression

‎document/core/exec/numerics.rst‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,6 +1464,62 @@ Conversions
14641464
It is not defined for NaNs, infinities, or values for which the result is out of range.
14651465

14661466

1467+
.. _op-trunc_u_sat:
1468+
1469+
:math:`\truncusat_{M,N}(z)`
1470+
...........................
1471+
1472+
* If :math:`z` is a NaN, then return :math:`0`.
1473+
1474+
* Else if :math:`z` is negative infinity, then return :math:`0`.
1475+
1476+
* Else if :math:`z` is positive infinity, then return :math:`2^N - 1`.
1477+
1478+
* Else if :math:`\trunc(z)` is less than :math:`0`, then return :math:`0`.
1479+
1480+
* Else if :math:`\trunc(z)` is greater than :math:`2^N - 1`, then return :math:`2^N - 1`.
1481+
1482+
* Else, return :math:`\trunc(z)`.
1483+
1484+
.. math::
1485+
\begin{array}{lll@{\qquad}l}
1486+
\truncusat_{M,N}(\pm \NAN(n)) &=& 0 \\
1487+
\truncusat_{M,N}(- \infty) &=& 0 \\
1488+
\truncusat_{M,N}(+ \infty) &=& 2^N - 1 \\
1489+
\truncusat_{M,N}(- q) &=& 0 & (\iff \trunc(- q) < 0) \\
1490+
\truncusat_{M,N}(+ q) &=& 2^N - 1 & (\iff \trunc(+ q) > 2^N - 1) \\
1491+
\truncusat_{M,N}(\pm q) &=& \trunc(\pm q) & (otherwise) \\
1492+
\end{array}
1493+
1494+
1495+
.. _op-trunc_s_sat:
1496+
1497+
:math:`\truncssat_{M,N}(z)`
1498+
...........................
1499+
1500+
* If :math:`z` is a NaN, then return :math:`0`.
1501+
1502+
* Else if :math:`z` is negative infinity, then return :math:`-2^{N-1}`.
1503+
1504+
* Else if :math:`z` is positive infinity, then return :math:`2^{N-1} - 1`.
1505+
1506+
* Else if :math:`\trunc(z)` is less than :math:`-2^{N-1}`, then return :math:`-2^{N-1}`.
1507+
1508+
* Else if :math:`\trunc(z)` is greater than :math:`2^{N-1} - 1`, then return :math:`2^{N-1} - 1`.
1509+
1510+
* Else, return :math:`\trunc(z)`.
1511+
1512+
.. math::
1513+
\begin{array}{lll@{\qquad}l}
1514+
\truncssat_{M,N}(\pm \NAN(n)) &=& 0 \\
1515+
\truncssat_{M,N}(- \infty) &=& -2^{N-1} \\
1516+
\truncssat_{M,N}(+ \infty) &=& 2^{N-1}-1 \\
1517+
\truncssat_{M,N}(- q) &=& -2^{N-1} & (\iff \trunc(- q) < -2^{N-1}) \\
1518+
\truncssat_{M,N}(+ q) &=& 2^{N-1} - 1 & (\iff \trunc(+ q) > 2^{N-1} - 1) \\
1519+
\truncssat_{M,N}(\pm q) &=& \trunc(\pm q) & (otherwise) \\
1520+
\end{array}
1521+
1522+
14671523
.. _op-promote:
14681524

14691525
:math:`\promote_{M,N}(z)`

‎document/core/syntax/instructions.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ These operations closely match respective operations available in hardware.
6767
\K{i32.}\WRAP\K{\_i64} ~|~
6868
\K{i64.}\EXTEND\K{\_i32}\K{\_}\sx ~|~
6969
\K{i}\X{nn}\K{.}\TRUNC\K{\_f}\X{mm}\K{\_}\sx \\&&|&
70+
\K{i}\X{nn}\K{.}\TRUNC\K{\_sat\_f}\X{mm}\K{\_}\sx \\&&|&
7071
\K{f32.}\DEMOTE\K{\_f64} ~|~
7172
\K{f64.}\PROMOTE\K{\_f32} ~|~
7273
\K{f}\X{nn}\K{.}\CONVERT\K{\_i}\X{mm}\K{\_}\sx \\&&|&
@@ -160,6 +161,7 @@ Occasionally, it is convenient to group operators together according to the foll
160161
\WRAP ~|~
161162
\EXTEND ~|~
162163
\TRUNC ~|~
164+
\TRUNC\K{\_sat} ~|~
163165
\CONVERT ~|~
164166
\DEMOTE ~|~
165167
\PROMOTE ~|~

‎document/core/text/instructions.rst‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,20 @@ Numeric Instructions
391391
\text{i32.trunc\_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F32\K{\_u} \\ &&|&
392392
\text{i32.trunc\_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_s} \\ &&|&
393393
\text{i32.trunc\_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_u} \\ &&|&
394+
\text{i32.trunc\_sat_f32\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
395+
\text{i32.trunc\_sat_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
396+
\text{i32.trunc\_sat_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
397+
\text{i32.trunc\_sat_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|&
394398
\text{i64.extend\_i32\_s} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_s} \\ &&|&
395399
\text{i64.extend\_i32\_u} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_u} \\ &&|&
396400
\text{i64.trunc\_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_s} \\ &&|&
397401
\text{i64.trunc\_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_u} \\ &&|&
398402
\text{i64.trunc\_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_s} \\ &&|&
399403
\text{i64.trunc\_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_u} \\ &&|&
404+
\text{i64.trunc\_sat_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
405+
\text{i64.trunc\_sat_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
406+
\text{i64.trunc\_sat_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
407+
\text{i64.trunc\_sat_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|&
400408
\text{f32.convert\_i32\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_s} \\ &&|&
401409
\text{f32.convert\_i32\_u} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_u} \\ &&|&
402410
\text{f32.convert\_i64\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I64\K{\_s} \\ &&|&

‎document/core/util/macros.def‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,8 @@
948948
.. |wrap| mathdef:: \xref{exec/numerics}{op-wrap}{\F{wrap}}
949949
.. |truncu| mathdef:: \xref{exec/numerics}{op-trunc_u}{\F{trunc}^{\K{u}}}
950950
.. |truncs| mathdef:: \xref{exec/numerics}{op-trunc_s}{\F{trunc}^{\K{s}}}
951+
.. |truncusat| mathdef:: \xref{exec/numerics}{op-trunc_sat_u}{\F{trunc\_sat\_u}}
952+
.. |truncssat| mathdef:: \xref{exec/numerics}{op-trunc_sat_s}{\F{trunc\_sat\_s}}
951953
.. |promote| mathdef:: \xref{exec/numerics}{op-promote}{\F{promote}}
952954
.. |demote| mathdef:: \xref{exec/numerics}{op-demote}{\F{demote}}
953955
.. |convertu| mathdef:: \xref{exec/numerics}{op-convert_u}{\F{convert}^{\K{u}}}

‎interpreter/binary/decode.ml‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,19 @@ let memop s =
200200
let offset = vu32 s in
201201
Int32.to_int align, offset
202202

203+
let math_prefix s =
204+
let pos = pos s in
205+
match op s with
206+
| 0x00 -> i32_trunc_sat_f32_s
207+
| 0x01 -> i32_trunc_sat_f32_u
208+
| 0x02 -> i32_trunc_sat_f64_s
209+
| 0x03 -> i32_trunc_sat_f64_u
210+
| 0x04 -> i64_trunc_sat_f32_s
211+
| 0x05 -> i64_trunc_sat_f32_u
212+
| 0x06 -> i64_trunc_sat_f64_s
213+
| 0x07 -> i64_trunc_sat_f64_u
214+
| b -> illegal s pos b
215+
203216
let rec instr s =
204217
let pos = pos s in
205218
match op s with
@@ -432,6 +445,8 @@ let rec instr s =
432445
| 0xbe -> f32_reinterpret_i32
433446
| 0xbf -> f64_reinterpret_i64
434447

448+
| 0xfc -> math_prefix s
449+
435450
| b -> illegal s pos b
436451

437452
and instr_block s = List.rev (instr_block' s [])

‎interpreter/binary/encode.ml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ let encode m =
336336
| Convert (I32 I32Op.TruncUF32) -> op 0xa9
337337
| Convert (I32 I32Op.TruncSF64) -> op 0xaa
338338
| Convert (I32 I32Op.TruncUF64) -> op 0xab
339+
| Convert (I32 I32Op.TruncSSatF32) -> op 0xfc; op 0x00
340+
| Convert (I32 I32Op.TruncUSatF32) -> op 0xfc; op 0x01
341+
| Convert (I32 I32Op.TruncSSatF64) -> op 0xfc; op 0x02
342+
| Convert (I32 I32Op.TruncUSatF64) -> op 0xfc; op 0x03
339343
| Convert (I32 I32Op.ReinterpretFloat) -> op 0xbc
340344

341345
| Convert (I64 I64Op.ExtendSI32) -> op 0xac
@@ -345,6 +349,10 @@ let encode m =
345349
| Convert (I64 I64Op.TruncUF32) -> op 0xaf
346350
| Convert (I64 I64Op.TruncSF64) -> op 0xb0
347351
| Convert (I64 I64Op.TruncUF64) -> op 0xb1
352+
| Convert (I64 I64Op.TruncSSatF32) -> op 0xfc; op 0x04
353+
| Convert (I64 I64Op.TruncUSatF32) -> op 0xfc; op 0x05
354+
| Convert (I64 I64Op.TruncSSatF64) -> op 0xfc; op 0x06
355+
| Convert (I64 I64Op.TruncUSatF64) -> op 0xfc; op 0x07
348356
| Convert (I64 I64Op.ReinterpretFloat) -> op 0xbd
349357

350358
| Convert (F32 F32Op.ConvertSI32) -> op 0xb2

‎interpreter/exec/eval_numeric.ml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ struct
130130
| TruncUF32 -> I32 (I32_convert.trunc_f32_u (F32Op.of_value 1 v))
131131
| TruncSF64 -> I32 (I32_convert.trunc_f64_s (F64Op.of_value 1 v))
132132
| TruncUF64 -> I32 (I32_convert.trunc_f64_u (F64Op.of_value 1 v))
133+
| TruncSSatF32 -> I32 (I32_convert.trunc_sat_f32_s (F32Op.of_value 1 v))
134+
| TruncUSatF32 -> I32 (I32_convert.trunc_sat_f32_u (F32Op.of_value 1 v))
135+
| TruncSSatF64 -> I32 (I32_convert.trunc_sat_f64_s (F64Op.of_value 1 v))
136+
| TruncUSatF64 -> I32 (I32_convert.trunc_sat_f64_u (F64Op.of_value 1 v))
133137
| ReinterpretFloat -> I32 (I32_convert.reinterpret_f32 (F32Op.of_value 1 v))
134138
| ExtendSI32 -> raise (TypeError (1, v, I32Type))
135139
| ExtendUI32 -> raise (TypeError (1, v, I32Type))
@@ -147,6 +151,10 @@ struct
147151
| TruncUF32 -> I64 (I64_convert.trunc_f32_u (F32Op.of_value 1 v))
148152
| TruncSF64 -> I64 (I64_convert.trunc_f64_s (F64Op.of_value 1 v))
149153
| TruncUF64 -> I64 (I64_convert.trunc_f64_u (F64Op.of_value 1 v))
154+
| TruncSSatF32 -> I64 (I64_convert.trunc_sat_f32_s (F32Op.of_value 1 v))
155+
| TruncUSatF32 -> I64 (I64_convert.trunc_sat_f32_u (F32Op.of_value 1 v))
156+
| TruncSSatF64 -> I64 (I64_convert.trunc_sat_f64_s (F64Op.of_value 1 v))
157+
| TruncUSatF64 -> I64 (I64_convert.trunc_sat_f64_u (F64Op.of_value 1 v))
150158
| ReinterpretFloat -> I64 (I64_convert.reinterpret_f64 (F64Op.of_value 1 v))
151159
| WrapI64 -> raise (TypeError (1, v, I64Type))
152160
end

‎interpreter/exec/i32_convert.ml‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,52 @@ let trunc_f64_u x =
4242
else
4343
Int64.(to_int32 (of_float xf))
4444

45+
let trunc_sat_f32_s x =
46+
if F32.ne x x then
47+
0l
48+
else
49+
let xf = F32.to_float x in
50+
if xf < Int32.(to_float min_int) then
51+
Int32.min_int
52+
else if xf >= -.Int32.(to_float min_int) then
53+
Int32.max_int
54+
else
55+
Int32.of_float xf
56+
57+
let trunc_sat_f32_u x =
58+
if F32.ne x x then
59+
0l
60+
else
61+
let xf = F32.to_float x in
62+
if xf <= -1.0 then
63+
0l
64+
else if xf >= -.Int32.(to_float min_int) *. 2.0 then
65+
-1l
66+
else
67+
Int64.(to_int32 (of_float xf))
68+
69+
let trunc_sat_f64_s x =
70+
if F64.ne x x then
71+
0l
72+
else
73+
let xf = F64.to_float x in
74+
if xf < Int32.(to_float min_int) then
75+
Int32.min_int
76+
else if xf >= -.Int32.(to_float min_int) then
77+
Int32.max_int
78+
else
79+
Int32.of_float xf
80+
81+
let trunc_sat_f64_u x =
82+
if F64.ne x x then
83+
0l
84+
else
85+
let xf = F64.to_float x in
86+
if xf <= -1.0 then
87+
0l
88+
else if xf >= -.Int32.(to_float min_int) *. 2.0 then
89+
-1l
90+
else
91+
Int64.(to_int32 (of_float xf))
92+
4593
let reinterpret_f32 = F32.to_bits

0 commit comments

Comments
 (0)