Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge nontrapping-float-to-int proposal into spec #1143

Merged
merged 3 commits into from
Apr 9, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
400 changes: 204 additions & 196 deletions document/core/appendix/index-instructions.rst

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions document/core/binary/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,23 @@ All other numeric instructions are plain opcodes without any immediates.
\hex{BF} &\Rightarrow& \F64.\REINTERPRET\K{\_}\I64 \\
\end{array}

.. _binary-cvtop-trunc-sat:

The saturating truncation instructions all have a one byte prefix.

.. math::
\begin{array}{llclll}
\production{instruction} & \Binstr &::=& \dots && \phantom{thisshouldbeenough} \\&&|&
\hex{FC}~\hex{00} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
\hex{FC}~\hex{01} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
\hex{FC}~\hex{02} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
\hex{FC}~\hex{03} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|&
\hex{FC}~\hex{04} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
\hex{FC}~\hex{05} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
\hex{FC}~\hex{06} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
\hex{FC}~\hex{07} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\
\end{array}


.. index:: expression
pair: binary format; expression
Expand Down
56 changes: 56 additions & 0 deletions document/core/exec/numerics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,62 @@ Conversions
It is not defined for NaNs, infinities, or values for which the result is out of range.


.. _op-trunc_u_sat:

:math:`\truncusat_{M,N}(z)`
...........................

* If :math:`z` is a NaN, then return :math:`0`.

* Else if :math:`z` is negative infinity, then return :math:`0`.

* Else if :math:`z` is positive infinity, then return :math:`2^N - 1`.

* Else if :math:`\trunc(z)` is less than :math:`0`, then return :math:`0`.

* Else if :math:`\trunc(z)` is greater than :math:`2^N - 1`, then return :math:`2^N - 1`.

* Else, return :math:`\trunc(z)`.

.. math::
\begin{array}{lll@{\qquad}l}
\truncusat_{M,N}(\pm \NAN(n)) &=& 0 \\
\truncusat_{M,N}(- \infty) &=& 0 \\
\truncusat_{M,N}(+ \infty) &=& 2^N - 1 \\
\truncusat_{M,N}(- q) &=& 0 & (\iff \trunc(- q) < 0) \\
\truncusat_{M,N}(+ q) &=& 2^N - 1 & (\iff \trunc(+ q) > 2^N - 1) \\
\truncusat_{M,N}(\pm q) &=& \trunc(\pm q) & (otherwise) \\
\end{array}


.. _op-trunc_s_sat:

:math:`\truncssat_{M,N}(z)`
...........................

* If :math:`z` is a NaN, then return :math:`0`.

* Else if :math:`z` is negative infinity, then return :math:`-2^{N-1}`.

* Else if :math:`z` is positive infinity, then return :math:`2^{N-1} - 1`.

* Else if :math:`\trunc(z)` is less than :math:`-2^{N-1}`, then return :math:`-2^{N-1}`.

* Else if :math:`\trunc(z)` is greater than :math:`2^{N-1} - 1`, then return :math:`2^{N-1} - 1`.

* Else, return :math:`\trunc(z)`.

.. math::
\begin{array}{lll@{\qquad}l}
\truncssat_{M,N}(\pm \NAN(n)) &=& 0 \\
\truncssat_{M,N}(- \infty) &=& -2^{N-1} \\
\truncssat_{M,N}(+ \infty) &=& 2^{N-1}-1 \\
\truncssat_{M,N}(- q) &=& -2^{N-1} & (\iff \trunc(- q) < -2^{N-1}) \\
\truncssat_{M,N}(+ q) &=& 2^{N-1} - 1 & (\iff \trunc(+ q) > 2^{N-1} - 1) \\
\truncssat_{M,N}(\pm q) &=& \trunc(\pm q) & (otherwise) \\
\end{array}


.. _op-promote:

:math:`\promote_{M,N}(z)`
Expand Down
2 changes: 2 additions & 0 deletions document/core/syntax/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ These operations closely match respective operations available in hardware.
\K{i32.}\WRAP\K{\_i64} ~|~
\K{i64.}\EXTEND\K{\_i32}\K{\_}\sx ~|~
\K{i}\X{nn}\K{.}\TRUNC\K{\_f}\X{mm}\K{\_}\sx \\&&|&
\K{i}\X{nn}\K{.}\TRUNC\K{\_sat\_f}\X{mm}\K{\_}\sx \\&&|&
\K{f32.}\DEMOTE\K{\_f64} ~|~
\K{f64.}\PROMOTE\K{\_f32} ~|~
\K{f}\X{nn}\K{.}\CONVERT\K{\_i}\X{mm}\K{\_}\sx \\&&|&
Expand Down Expand Up @@ -160,6 +161,7 @@ Occasionally, it is convenient to group operators together according to the foll
\WRAP ~|~
\EXTEND ~|~
\TRUNC ~|~
\TRUNC\K{\_sat} ~|~
\CONVERT ~|~
\DEMOTE ~|~
\PROMOTE ~|~
Expand Down
8 changes: 8 additions & 0 deletions document/core/text/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -391,12 +391,20 @@ Numeric Instructions
\text{i32.trunc\_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F32\K{\_u} \\ &&|&
\text{i32.trunc\_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_s} \\ &&|&
\text{i32.trunc\_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_u} \\ &&|&
\text{i32.trunc\_sat_f32\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
\text{i32.trunc\_sat_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
\text{i32.trunc\_sat_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
\text{i32.trunc\_sat_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|&
\text{i64.extend\_i32\_s} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_s} \\ &&|&
\text{i64.extend\_i32\_u} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_u} \\ &&|&
\text{i64.trunc\_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_s} \\ &&|&
\text{i64.trunc\_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_u} \\ &&|&
\text{i64.trunc\_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_s} \\ &&|&
\text{i64.trunc\_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_u} \\ &&|&
\text{i64.trunc\_sat_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|&
\text{i64.trunc\_sat_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|&
\text{i64.trunc\_sat_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|&
\text{i64.trunc\_sat_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|&
\text{f32.convert\_i32\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_s} \\ &&|&
\text{f32.convert\_i32\_u} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_u} \\ &&|&
\text{f32.convert\_i64\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I64\K{\_s} \\ &&|&
Expand Down
2 changes: 2 additions & 0 deletions document/core/util/macros.def
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,8 @@
.. |wrap| mathdef:: \xref{exec/numerics}{op-wrap}{\F{wrap}}
.. |truncu| mathdef:: \xref{exec/numerics}{op-trunc_u}{\F{trunc}^{\K{u}}}
.. |truncs| mathdef:: \xref{exec/numerics}{op-trunc_s}{\F{trunc}^{\K{s}}}
.. |truncusat| mathdef:: \xref{exec/numerics}{op-trunc_sat_u}{\F{trunc\_sat\_u}}
.. |truncssat| mathdef:: \xref{exec/numerics}{op-trunc_sat_s}{\F{trunc\_sat\_s}}
.. |promote| mathdef:: \xref{exec/numerics}{op-promote}{\F{promote}}
.. |demote| mathdef:: \xref{exec/numerics}{op-demote}{\F{demote}}
.. |convertu| mathdef:: \xref{exec/numerics}{op-convert_u}{\F{convert}^{\K{u}}}
Expand Down
15 changes: 15 additions & 0 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,19 @@ let memop s =
let offset = vu32 s in
Int32.to_int align, offset

let math_prefix s =
let pos = pos s in
match op s with
| 0x00 -> i32_trunc_sat_f32_s
| 0x01 -> i32_trunc_sat_f32_u
| 0x02 -> i32_trunc_sat_f64_s
| 0x03 -> i32_trunc_sat_f64_u
| 0x04 -> i64_trunc_sat_f32_s
| 0x05 -> i64_trunc_sat_f32_u
| 0x06 -> i64_trunc_sat_f64_s
| 0x07 -> i64_trunc_sat_f64_u
| b -> illegal s pos b

let rec instr s =
let pos = pos s in
match op s with
Expand Down Expand Up @@ -432,6 +445,8 @@ let rec instr s =
| 0xbe -> f32_reinterpret_i32
| 0xbf -> f64_reinterpret_i64

| 0xfc -> math_prefix s

| b -> illegal s pos b

and instr_block s = List.rev (instr_block' s [])
Expand Down
8 changes: 8 additions & 0 deletions interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ let encode m =
| Convert (I32 I32Op.TruncUF32) -> op 0xa9
| Convert (I32 I32Op.TruncSF64) -> op 0xaa
| Convert (I32 I32Op.TruncUF64) -> op 0xab
| Convert (I32 I32Op.TruncSSatF32) -> op 0xfc; op 0x00
| Convert (I32 I32Op.TruncUSatF32) -> op 0xfc; op 0x01
| Convert (I32 I32Op.TruncSSatF64) -> op 0xfc; op 0x02
| Convert (I32 I32Op.TruncUSatF64) -> op 0xfc; op 0x03
| Convert (I32 I32Op.ReinterpretFloat) -> op 0xbc

| Convert (I64 I64Op.ExtendSI32) -> op 0xac
Expand All @@ -345,6 +349,10 @@ let encode m =
| Convert (I64 I64Op.TruncUF32) -> op 0xaf
| Convert (I64 I64Op.TruncSF64) -> op 0xb0
| Convert (I64 I64Op.TruncUF64) -> op 0xb1
| Convert (I64 I64Op.TruncSSatF32) -> op 0xfc; op 0x04
| Convert (I64 I64Op.TruncUSatF32) -> op 0xfc; op 0x05
| Convert (I64 I64Op.TruncSSatF64) -> op 0xfc; op 0x06
| Convert (I64 I64Op.TruncUSatF64) -> op 0xfc; op 0x07
| Convert (I64 I64Op.ReinterpretFloat) -> op 0xbd

| Convert (F32 F32Op.ConvertSI32) -> op 0xb2
Expand Down
8 changes: 8 additions & 0 deletions interpreter/exec/eval_numeric.ml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ struct
| TruncUF32 -> I32 (I32_convert.trunc_f32_u (F32Op.of_value 1 v))
| TruncSF64 -> I32 (I32_convert.trunc_f64_s (F64Op.of_value 1 v))
| TruncUF64 -> I32 (I32_convert.trunc_f64_u (F64Op.of_value 1 v))
| TruncSSatF32 -> I32 (I32_convert.trunc_sat_f32_s (F32Op.of_value 1 v))
| TruncUSatF32 -> I32 (I32_convert.trunc_sat_f32_u (F32Op.of_value 1 v))
| TruncSSatF64 -> I32 (I32_convert.trunc_sat_f64_s (F64Op.of_value 1 v))
| TruncUSatF64 -> I32 (I32_convert.trunc_sat_f64_u (F64Op.of_value 1 v))
| ReinterpretFloat -> I32 (I32_convert.reinterpret_f32 (F32Op.of_value 1 v))
| ExtendSI32 -> raise (TypeError (1, v, I32Type))
| ExtendUI32 -> raise (TypeError (1, v, I32Type))
Expand All @@ -147,6 +151,10 @@ struct
| TruncUF32 -> I64 (I64_convert.trunc_f32_u (F32Op.of_value 1 v))
| TruncSF64 -> I64 (I64_convert.trunc_f64_s (F64Op.of_value 1 v))
| TruncUF64 -> I64 (I64_convert.trunc_f64_u (F64Op.of_value 1 v))
| TruncSSatF32 -> I64 (I64_convert.trunc_sat_f32_s (F32Op.of_value 1 v))
| TruncUSatF32 -> I64 (I64_convert.trunc_sat_f32_u (F32Op.of_value 1 v))
| TruncSSatF64 -> I64 (I64_convert.trunc_sat_f64_s (F64Op.of_value 1 v))
| TruncUSatF64 -> I64 (I64_convert.trunc_sat_f64_u (F64Op.of_value 1 v))
| ReinterpretFloat -> I64 (I64_convert.reinterpret_f64 (F64Op.of_value 1 v))
| WrapI64 -> raise (TypeError (1, v, I64Type))
end
Expand Down
48 changes: 48 additions & 0 deletions interpreter/exec/i32_convert.ml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,52 @@ let trunc_f64_u x =
else
Int64.(to_int32 (of_float xf))

let trunc_sat_f32_s x =
if F32.ne x x then
0l
else
let xf = F32.to_float x in
if xf < Int32.(to_float min_int) then
Int32.min_int
else if xf >= -.Int32.(to_float min_int) then
Int32.max_int
else
Int32.of_float xf

let trunc_sat_f32_u x =
if F32.ne x x then
0l
else
let xf = F32.to_float x in
if xf <= -1.0 then
0l
else if xf >= -.Int32.(to_float min_int) *. 2.0 then
-1l
else
Int64.(to_int32 (of_float xf))

let trunc_sat_f64_s x =
if F64.ne x x then
0l
else
let xf = F64.to_float x in
if xf < Int32.(to_float min_int) then
Int32.min_int
else if xf >= -.Int32.(to_float min_int) then
Int32.max_int
else
Int32.of_float xf

let trunc_sat_f64_u x =
if F64.ne x x then
0l
else
let xf = F64.to_float x in
if xf <= -1.0 then
0l
else if xf >= -.Int32.(to_float min_int) *. 2.0 then
-1l
else
Int64.(to_int32 (of_float xf))

let reinterpret_f32 = F32.to_bits
4 changes: 4 additions & 0 deletions interpreter/exec/i32_convert.mli
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ val trunc_f32_s : F32.t -> I32.t
val trunc_f32_u : F32.t -> I32.t
val trunc_f64_s : F64.t -> I32.t
val trunc_f64_u : F64.t -> I32.t
val trunc_sat_f32_s : F32.t -> I32.t
val trunc_sat_f32_u : F32.t -> I32.t
val trunc_sat_f64_s : F64.t -> I32.t
val trunc_sat_f64_u : F64.t -> I32.t
val reinterpret_f32 : F32.t -> I32.t
52 changes: 52 additions & 0 deletions interpreter/exec/i64_convert.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,56 @@ let trunc_f64_u x =
else
Int64.of_float xf

let trunc_sat_f32_s x =
if F32.ne x x then
0L
else
let xf = F32.to_float x in
if xf < Int64.(to_float min_int) then
Int64.min_int
else if xf >= -.Int64.(to_float min_int) then
Int64.max_int
else
Int64.of_float xf

let trunc_sat_f32_u x =
if F32.ne x x then
0L
else
let xf = F32.to_float x in
if xf <= -1.0 then
0L
else if xf >= -.Int64.(to_float min_int) *. 2.0 then
-1L
else if xf >= -.Int64.(to_float min_int) then
Int64.(logxor (of_float (xf -. 9223372036854775808.0)) min_int)
else
Int64.of_float xf

let trunc_sat_f64_s x =
if F64.ne x x then
0L
else
let xf = F64.to_float x in
if xf < Int64.(to_float min_int) then
Int64.min_int
else if xf >= -.Int64.(to_float min_int) then
Int64.max_int
else
Int64.of_float xf

let trunc_sat_f64_u x =
if F64.ne x x then
0L
else
let xf = F64.to_float x in
if xf <= -1.0 then
0L
else if xf >= -.Int64.(to_float min_int) *. 2.0 then
-1L
else if xf >= -.Int64.(to_float min_int) then
Int64.(logxor (of_float (xf -. 9223372036854775808.0)) min_int)
else
Int64.of_float xf

let reinterpret_f64 = F64.to_bits
4 changes: 4 additions & 0 deletions interpreter/exec/i64_convert.mli
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ val trunc_f32_s : F32.t -> I64.t
val trunc_f32_u : F32.t -> I64.t
val trunc_f64_s : F64.t -> I64.t
val trunc_f64_u : F64.t -> I64.t
val trunc_sat_f32_s : F32.t -> I64.t
val trunc_sat_f32_u : F32.t -> I64.t
val trunc_sat_f64_s : F64.t -> I64.t
val trunc_sat_f64_u : F64.t -> I64.t
val reinterpret_f64 : F64.t -> I64.t
1 change: 1 addition & 0 deletions interpreter/syntax/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct
type relop = Eq | Ne | LtS | LtU | GtS | GtU | LeS | LeU | GeS | GeU
type cvtop = ExtendSI32 | ExtendUI32 | WrapI64
| TruncSF32 | TruncUF32 | TruncSF64 | TruncUF64
| TruncSSatF32 | TruncUSatF32 | TruncSSatF64 | TruncUSatF64
| ReinterpretFloat
end

Expand Down
8 changes: 8 additions & 0 deletions interpreter/syntax/operators.ml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ let i32_trunc_f32_s = Convert (I32 I32Op.TruncSF32)
let i32_trunc_f32_u = Convert (I32 I32Op.TruncUF32)
let i32_trunc_f64_s = Convert (I32 I32Op.TruncSF64)
let i32_trunc_f64_u = Convert (I32 I32Op.TruncUF64)
let i32_trunc_sat_f32_s = Convert (I32 I32Op.TruncSSatF32)
let i32_trunc_sat_f32_u = Convert (I32 I32Op.TruncUSatF32)
let i32_trunc_sat_f64_s = Convert (I32 I32Op.TruncSSatF64)
let i32_trunc_sat_f64_u = Convert (I32 I32Op.TruncUSatF64)
let i64_extend_i32_s = Convert (I64 I64Op.ExtendSI32)
let i64_extend_i32_u = Convert (I64 I64Op.ExtendUI32)
let i64_trunc_f32_s = Convert (I64 I64Op.TruncSF32)
Expand All @@ -188,6 +192,10 @@ let f32_convert_i32_s = Convert (F32 F32Op.ConvertSI32)
let f32_convert_i32_u = Convert (F32 F32Op.ConvertUI32)
let f32_convert_i64_s = Convert (F32 F32Op.ConvertSI64)
let f32_convert_i64_u = Convert (F32 F32Op.ConvertUI64)
let i64_trunc_sat_f32_s = Convert (I64 I64Op.TruncSSatF32)
let i64_trunc_sat_f32_u = Convert (I64 I64Op.TruncUSatF32)
let i64_trunc_sat_f64_s = Convert (I64 I64Op.TruncSSatF64)
let i64_trunc_sat_f64_u = Convert (I64 I64Op.TruncUSatF64)
let f32_demote_f64 = Convert (F32 F32Op.DemoteF64)
let f64_convert_i32_s = Convert (F64 F64Op.ConvertSI32)
let f64_convert_i32_u = Convert (F64 F64Op.ConvertUI32)
Expand Down
4 changes: 4 additions & 0 deletions interpreter/text/arrange.ml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ struct
| TruncUF32 -> "trunc_f32_u"
| TruncSF64 -> "trunc_f64_s"
| TruncUF64 -> "trunc_f64_u"
| TruncSSatF32 -> "trunc_sat_f32_s"
| TruncUSatF32 -> "trunc_sat_f32_u"
| TruncSSatF64 -> "trunc_sat_f64_s"
| TruncUSatF64 -> "trunc_sat_f64_u"
| ReinterpretFloat -> "reinterpret_f" ^ xx
end

Expand Down
8 changes: 8 additions & 0 deletions interpreter/text/lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ rule token = parse
{ CONVERT (intop t i32_trunc_f64_s i64_trunc_f64_s) }
| (ixx as t)".trunc_f64_u"
{ CONVERT (intop t i32_trunc_f64_u i64_trunc_f64_u) }
| (ixx as t)".trunc_sat_f32_s"
{ CONVERT (intop t i32_trunc_sat_f32_s i64_trunc_sat_f32_s) }
| (ixx as t)".trunc_sat_f32_u"
{ CONVERT (intop t i32_trunc_sat_f32_u i64_trunc_sat_f32_u) }
| (ixx as t)".trunc_sat_f64_s"
{ CONVERT (intop t i32_trunc_sat_f64_s i64_trunc_sat_f64_s) }
| (ixx as t)".trunc_sat_f64_u"
{ CONVERT (intop t i32_trunc_sat_f64_u i64_trunc_sat_f64_u) }
| (fxx as t)".convert_i32_s"
{ CONVERT (floatop t f32_convert_i32_s f64_convert_i32_s) }
| (fxx as t)".convert_i32_u"
Expand Down