Skip to content

Merge sign-extension-ops proposal into spec #1144

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

Merged
merged 1 commit into from
Apr 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions document/core/appendix/index-instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ Instruction Binary Opcode Type
:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-reinterpret>`
:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-reinterpret>`
:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-reinterpret>`
:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation <valid-unop>` :ref:`execution <exec-unop>`, :ref:`operator <op-iextendn_s>`
:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation <valid-unop>` :ref:`execution <exec-unop>`, :ref:`operator <op-iextendn_s>`
:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation <valid-unop>` :ref:`execution <exec-unop>`, :ref:`operator <op-iextendn_s>`
:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation <valid-unop>` :ref:`execution <exec-unop>`, :ref:`operator <op-iextendn_s>`
:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation <valid-unop>` :ref:`execution <exec-unop>`, :ref:`operator <op-iextendn_s>`
:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{00}` :math:`[\F32] \to [\I32]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-trunc_s_sat>`
:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{01}` :math:`[\F32] \to [\I32]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-trunc_u_sat>`
:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{02}` :math:`[\F64] \to [\I32]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-trunc_s_sat>`
Expand Down
11 changes: 11 additions & 0 deletions document/core/binary/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,17 @@ The saturating truncation instructions all have a one byte prefix.
\end{array}


.. math::
\begin{array}{llclll}
\phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|&
\hex{C0} &\Rightarrow& \I32.\EXTEND\K{8\_s} \\ &&|&
\hex{C1} &\Rightarrow& \I32.\EXTEND\K{16\_s} \\ &&|&
\hex{C2} &\Rightarrow& \I64.\EXTEND\K{8\_s} \\ &&|&
\hex{C3} &\Rightarrow& \I64.\EXTEND\K{16\_s} \\ &&|&
\hex{C4} &\Rightarrow& \I64.\EXTEND\K{32\_s} \\
\end{array}


.. index:: expression
pair: binary format; expression
single: expression; constant
Expand Down
13 changes: 13 additions & 0 deletions document/core/exec/numerics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,19 @@ The integer result of predicates -- i.e., :ref:`tests <syntax-testop>` and :ref:
\end{array}


.. _op-iextendn_s:

:math:`\iextendns_N(i)`
.......................

* Return :math:`\extends_{M,N}(i)`.

.. math::
\begin{array}{lll@{\qquad}l}
\iextendns_{N}(i) &=& \extends_{M,N}(i) \\
\end{array}


.. index:: floating-point, IEEE 754
.. _float-ops:

Expand Down
9 changes: 7 additions & 2 deletions document/core/syntax/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ These operations closely match respective operations available in hardware.
\K{i}\X{nn}\K{.}\itestop \\&&|&
\K{i}\X{nn}\K{.}\irelop ~|~
\K{f}\X{nn}\K{.}\frelop \\&&|&
\K{i32.}\WRAP\K{\_i64} ~|~
\K{i}\X{nn}\K{.}\EXTEND\K{8\_s} ~|~
\K{i}\X{nn}\K{.}\EXTEND\K{16\_s} ~|~
\K{i64.}\EXTEND\K{\_i32}\K{\_}\sx ~|~
\K{i32.}\WRAP\K{\_i64} ~|~
\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} ~|~
Expand Down Expand Up @@ -153,7 +155,10 @@ Occasionally, it is convenient to group operators together according to the foll

.. math::
\begin{array}{llll}
\production{unary operator} & \unop &::=& \iunop ~|~ \funop \\
\production{unary operator} & \unop &::=&
\iunop ~|~
\funop ~|~
\EXTEND{N}\K{\_s} ~|~ \\
\production{binary operator} & \binop &::=& \ibinop ~|~ \fbinop \\
\production{test operator} & \testop &::=& \itestop \\
\production{relational operator} & \relop &::=& \irelop ~|~ \frelop \\
Expand Down
10 changes: 10 additions & 0 deletions document/core/text/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,16 @@ Numeric Instructions
\text{f64.reinterpret\_i64} &\Rightarrow& \F64.\REINTERPRET\K{\_}\I64 \\
\end{array}

.. math::
\begin{array}{llclll}
\phantom{\production{instruction}} & \phantom{\Tplaininstr_I} &\phantom{::=}& \phantom{thisisenough} && \phantom{thisshouldbeenough} \\[-2ex] &&|&
\text{i32.extend8\_s} &\Rightarrow& \I32.\EXTEND\K{8\_s} \\ &&|&
\text{i32.extend16\_s} &\Rightarrow& \I32.\EXTEND\K{16\_s} \\ &&|&
\text{i64.extend8\_s} &\Rightarrow& \I64.\EXTEND\K{8\_s} \\ &&|&
\text{i64.extend16\_s} &\Rightarrow& \I64.\EXTEND\K{16\_s} \\ &&|&
\text{i64.extend32\_s} &\Rightarrow& \I64.\EXTEND\K{32\_s} \\
\end{array}


.. index:: ! folded instruction, S-expression
.. _text-foldedinstr:
Expand Down
1 change: 1 addition & 0 deletions document/core/util/macros.def
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,7 @@
.. |iles| mathdef:: \xref{exec/numerics}{op-ile_s}{\F{ile\_s}}
.. |igeu| mathdef:: \xref{exec/numerics}{op-ige_u}{\F{ige\_u}}
.. |iges| mathdef:: \xref{exec/numerics}{op-ige_s}{\F{ige\_s}}
.. |iextendns| mathdef:: \xref{exec/numerics}{op-iextendn_s}{\F{iextend}M\F{\_s}}

.. |fadd| mathdef:: \xref{exec/numerics}{op-fadd}{\F{fadd}}
.. |fsub| mathdef:: \xref{exec/numerics}{op-fsub}{\F{fsub}}
Expand Down
6 changes: 6 additions & 0 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,12 @@ let rec instr s =
| 0xbe -> f32_reinterpret_i32
| 0xbf -> f64_reinterpret_i64

| 0xc0 -> i32_extend8_s
| 0xc1 -> i32_extend16_s
| 0xc2 -> i64_extend8_s
| 0xc3 -> i64_extend16_s
| 0xc4 -> i64_extend32_s

| 0xfc -> math_prefix s

| b -> illegal s pos b
Expand Down
7 changes: 6 additions & 1 deletion interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ let encode m =
open Source
open Ast
open Values
open Memory

let op n = u8 n
let end_ () = op 0x0b
Expand Down Expand Up @@ -260,10 +259,16 @@ let encode m =
| Unary (I32 I32Op.Clz) -> op 0x67
| Unary (I32 I32Op.Ctz) -> op 0x68
| Unary (I32 I32Op.Popcnt) -> op 0x69
| Unary (I32 (I32Op.ExtendS Pack8)) -> op 0xc0
| Unary (I32 (I32Op.ExtendS Pack16)) -> op 0xc1
| Unary (I32 (I32Op.ExtendS Pack32)) -> assert false

| Unary (I64 I64Op.Clz) -> op 0x79
| Unary (I64 I64Op.Ctz) -> op 0x7a
| Unary (I64 I64Op.Popcnt) -> op 0x7b
| Unary (I64 (I64Op.ExtendS Pack8)) -> op 0xc2
| Unary (I64 (I64Op.ExtendS Pack16)) -> op 0xc3
| Unary (I64 (I64Op.ExtendS Pack32)) -> op 0xc4

| Unary (F32 F32Op.Abs) -> op 0x8b
| Unary (F32 F32Op.Neg) -> op 0x8c
Expand Down
1 change: 1 addition & 0 deletions interpreter/exec/eval_numeric.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct
| Clz -> IXX.clz
| Ctz -> IXX.ctz
| Popcnt -> IXX.popcnt
| ExtendS sz -> IXX.extend_s (8 * packed_size sz)
in fun v -> to_value (f (of_value 1 v))

let binop op =
Expand Down
5 changes: 5 additions & 0 deletions interpreter/exec/int.ml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ sig
val clz : t -> t
val ctz : t -> t
val popcnt : t -> t
val extend_s : int -> t -> t
val eqz : t -> bool
val eq : t -> t -> bool
val ne : t -> t -> bool
Expand Down Expand Up @@ -203,6 +204,10 @@ struct
loop acc' (i - 1) (Rep.shift_right_logical n 1)
in Rep.of_int (loop 0 Rep.bitwidth x)

let extend_s n x =
let shift = Rep.bitwidth - n in
Rep.shift_right (Rep.shift_left x shift) shift

let eqz x = x = Rep.zero

let eq x y = x = y
Expand Down
8 changes: 0 additions & 8 deletions interpreter/runtime/memory.ml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ type size = int32 (* number of pages *)
type address = int64
type offset = int32

type pack_size = Pack8 | Pack16 | Pack32
type extension = SX | ZX

type memory' = (int, int8_unsigned_elt, c_layout) Array1.t
type memory = {mutable content : memory'; max : size option}
type t = memory
Expand All @@ -22,11 +19,6 @@ exception OutOfMemory

let page_size = 0x10000L (* 64 KiB *)

let packed_size = function
| Pack8 -> 1
| Pack16 -> 2
| Pack32 -> 4

let within_limits n = function
| None -> true
| Some max -> I32.le_u n max
Expand Down
4 changes: 0 additions & 4 deletions interpreter/runtime/memory.mli
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@ type size = int32 (* number of pages *)
type address = int64
type offset = int32

type pack_size = Pack8 | Pack16 | Pack32
type extension = SX | ZX

exception Type
exception Bounds
exception SizeOverflow
exception SizeLimit
exception OutOfMemory

val page_size : int64
val packed_size : pack_size -> int

val alloc : memory_type -> memory (* raises SizeOverflow, OutOfMemory *)
val type_of : memory -> memory_type
Expand Down
6 changes: 3 additions & 3 deletions interpreter/syntax/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ open Types

module IntOp =
struct
type unop = Clz | Ctz | Popcnt
type unop = Clz | Ctz | Popcnt | ExtendS of pack_size
type binop = Add | Sub | Mul | DivS | DivU | RemS | RemU
| And | Or | Xor | Shl | ShrS | ShrU | Rotl | Rotr
type testop = Eqz
Expand Down Expand Up @@ -58,8 +58,8 @@ type cvtop = (I32Op.cvtop, I64Op.cvtop, F32Op.cvtop, F64Op.cvtop) Values.op

type 'a memop =
{ty : value_type; align : int; offset : Memory.offset; sz : 'a option}
type loadop = (Memory.pack_size * Memory.extension) memop
type storeop = Memory.pack_size memop
type loadop = (pack_size * extension) memop
type storeop = pack_size memop


(* Expressions *)
Expand Down
7 changes: 6 additions & 1 deletion interpreter/syntax/operators.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
open Source
open Types
open Values
open Memory
open Ast


Expand Down Expand Up @@ -207,6 +206,12 @@ let i64_reinterpret_f64 = Convert (I64 I64Op.ReinterpretFloat)
let f32_reinterpret_i32 = Convert (F32 F32Op.ReinterpretInt)
let f64_reinterpret_i64 = Convert (F64 F64Op.ReinterpretInt)

let i32_extend8_s = Unary (I32 (I32Op.ExtendS Pack8))
let i32_extend16_s = Unary (I32 (I32Op.ExtendS Pack16))
let i64_extend8_s = Unary (I64 (I64Op.ExtendS Pack8))
let i64_extend16_s = Unary (I64 (I64Op.ExtendS Pack16))
let i64_extend32_s = Unary (I64 (I64Op.ExtendS Pack32))

let memory_size = MemorySize
let memory_grow = MemoryGrow

8 changes: 8 additions & 0 deletions interpreter/syntax/types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ type extern_type =
| ExternMemoryType of memory_type
| ExternGlobalType of global_type

type pack_size = Pack8 | Pack16 | Pack32
type extension = SX | ZX


(* Attributes *)

let size = function
| I32Type | F32Type -> 4
| I64Type | F64Type -> 8

let packed_size = function
| Pack8 -> 1
| Pack16 -> 2
| Pack32 -> 4


(* Subtyping *)

Expand Down
23 changes: 12 additions & 11 deletions interpreter/text/arrange.ml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ let global_type = function
| GlobalType (t, Immutable) -> atom string_of_value_type t
| GlobalType (t, Mutable) -> Node ("mut", [atom string_of_value_type t])

let pack_size = function
| Pack8 -> "8"
| Pack16 -> "16"
| Pack32 -> "32"

let extension = function
| SX -> "_s"
| ZX -> "_u"


(* Operators *)

Expand All @@ -101,6 +110,7 @@ struct
| Clz -> "clz"
| Ctz -> "ctz"
| Popcnt -> "popcnt"
| ExtendS sz -> "extend" ^ pack_size sz ^ "_s"

let binop xx = function
| Add -> "add"
Expand Down Expand Up @@ -191,15 +201,6 @@ let testop = oper (IntOp.testop, FloatOp.testop)
let relop = oper (IntOp.relop, FloatOp.relop)
let cvtop = oper (IntOp.cvtop, FloatOp.cvtop)

let pack_size = function
| Memory.Pack8 -> "8"
| Memory.Pack16 -> "16"
| Memory.Pack32 -> "32"

let extension = function
| Memory.SX -> "_s"
| Memory.ZX -> "_u"

let memop name {ty; align; offset; _} sz =
value_type ty ^ "." ^ name ^
(if offset = 0l then "" else " offset=" ^ nat32 offset) ^
Expand All @@ -209,12 +210,12 @@ let loadop op =
match op.sz with
| None -> memop "load" op (size op.ty)
| Some (sz, ext) ->
memop ("load" ^ pack_size sz ^ extension ext) op (Memory.packed_size sz)
memop ("load" ^ pack_size sz ^ extension ext) op (packed_size sz)

let storeop op =
match op.sz with
| None -> memop "store" op (size op.ty)
| Some sz -> memop ("store" ^ pack_size sz) op (Memory.packed_size sz)
| Some sz -> memop ("store" ^ pack_size sz) op (packed_size sz)


(* Expressions *)
Expand Down
3 changes: 3 additions & 0 deletions interpreter/text/lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ rule token = parse
| (ixx as t)".clz" { UNARY (intop t i32_clz i64_clz) }
| (ixx as t)".ctz" { UNARY (intop t i32_ctz i64_ctz) }
| (ixx as t)".popcnt" { UNARY (intop t i32_popcnt i64_popcnt) }
| (ixx as t)".extend8_s" { UNARY (intop t i32_extend8_s i64_extend8_s) }
| (ixx as t)".extend16_s" { UNARY (intop t i32_extend16_s i64_extend16_s) }
| "i64.extend32_s" { UNARY i64_extend32_s }
| (fxx as t)".neg" { UNARY (floatop t f32_neg f64_neg) }
| (fxx as t)".abs" { UNARY (floatop t f32_abs f64_abs) }
| (fxx as t)".sqrt" { UNARY (floatop t f32_sqrt f64_sqrt) }
Expand Down
15 changes: 12 additions & 3 deletions interpreter/valid/valid.ml
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,23 @@ let type_cvtop at = function

(* Expressions *)

let check_pack sz t at =
require (packed_size sz < size t) at "invalid sign extension"

let check_unop unop at =
match unop with
| Values.I32 (IntOp.ExtendS sz) | Values.I64 (IntOp.ExtendS sz) ->
check_pack sz (Values.type_of unop) at
| _ -> ()

let check_memop (c : context) (memop : 'a memop) get_sz at =
ignore (memory c (0l @@ at));
let size =
match get_sz memop.sz with
| None -> size memop.ty
| Some sz ->
require (memop.ty = I64Type || sz <> Memory.Pack32) at
"memory size too big";
Memory.packed_size sz
check_pack sz memop.ty at;
packed_size sz
in
require (1 lsl memop.align <= size) at
"alignment must not be larger than natural"
Expand Down Expand Up @@ -279,6 +287,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
[t; t] --> [I32Type]

| Unary unop ->
check_unop unop e.at;
let t = type_unop unop in
[t] --> [t]

Expand Down
Loading