Skip to content

Commit 74e5034

Browse files
committed
Merge sign-extension-ops proposal into spec
See the sign-extension-ops proposal here: https://github.com/WebAssembly/sign-extension-ops This PR is built on top of #1143 (merge nontrapping-float-to-int)
1 parent 87c5f75 commit 74e5034

File tree

21 files changed

+208
-33
lines changed

21 files changed

+208
-33
lines changed

document/core/appendix/index-instructions.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@ Instruction Binary Opcode Type
199199
:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-reinterpret>`
200200
:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-reinterpret>`
201201
:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation <valid-cvtop>` :ref:`execution <exec-cvtop>`, :ref:`operator <op-reinterpret>`
202+
: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>`
203+
: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>`
204+
: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>`
205+
: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>`
206+
: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>`
202207
: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>`
203208
: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>`
204209
: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>`

document/core/binary/instructions.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,17 @@ The saturating truncation instructions all have a one byte prefix.
381381
\end{array}
382382
383383
384+
.. math::
385+
\begin{array}{llclll}
386+
\phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|&
387+
\hex{C0} &\Rightarrow& \I32.\EXTEND\K{8\_s} \\ &&|&
388+
\hex{C1} &\Rightarrow& \I32.\EXTEND\K{16\_s} \\ &&|&
389+
\hex{C2} &\Rightarrow& \I64.\EXTEND\K{8\_s} \\ &&|&
390+
\hex{C3} &\Rightarrow& \I64.\EXTEND\K{16\_s} \\ &&|&
391+
\hex{C4} &\Rightarrow& \I64.\EXTEND\K{32\_s} \\
392+
\end{array}
393+
394+
384395
.. index:: expression
385396
pair: binary format; expression
386397
single: expression; constant

document/core/exec/numerics.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,19 @@ The integer result of predicates -- i.e., :ref:`tests <syntax-testop>` and :ref:
612612
\end{array}
613613
614614
615+
.. _op-iextendn_s:
616+
617+
:math:`\iextendns_N(i)`
618+
.......................
619+
620+
* Return :math:`\extends_{M,N}(i)`.
621+
622+
.. math::
623+
\begin{array}{lll@{\qquad}l}
624+
\iextendns_{N}(i) &=& \extends_{M,N}(i) \\
625+
\end{array}
626+
627+
615628
.. index:: floating-point, IEEE 754
616629
.. _float-ops:
617630

document/core/syntax/instructions.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ These operations closely match respective operations available in hardware.
6464
\K{i}\X{nn}\K{.}\itestop \\&&|&
6565
\K{i}\X{nn}\K{.}\irelop ~|~
6666
\K{f}\X{nn}\K{.}\frelop \\&&|&
67-
\K{i32.}\WRAP\K{\_i64} ~|~
67+
\K{i}\X{nn}\K{.}\EXTEND\K{8\_s} ~|~
68+
\K{i}\X{nn}\K{.}\EXTEND\K{16\_s} ~|~
6869
\K{i64.}\EXTEND\K{\_i32}\K{\_}\sx ~|~
70+
\K{i32.}\WRAP\K{\_i64} ~|~
6971
\K{i}\X{nn}\K{.}\TRUNC\K{\_f}\X{mm}\K{\_}\sx \\&&|&
7072
\K{i}\X{nn}\K{.}\TRUNC\K{\_sat\_f}\X{mm}\K{\_}\sx \\&&|&
7173
\K{f32.}\DEMOTE\K{\_f64} ~|~
@@ -153,7 +155,10 @@ Occasionally, it is convenient to group operators together according to the foll
153155

154156
.. math::
155157
\begin{array}{llll}
156-
\production{unary operator} & \unop &::=& \iunop ~|~ \funop \\
158+
\production{unary operator} & \unop &::=&
159+
\iunop ~|~
160+
\funop ~|~
161+
\EXTEND{N}\K{\_s} ~|~ \\
157162
\production{binary operator} & \binop &::=& \ibinop ~|~ \fbinop \\
158163
\production{test operator} & \testop &::=& \itestop \\
159164
\production{relational operator} & \relop &::=& \irelop ~|~ \frelop \\

document/core/text/instructions.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,16 @@ Numeric Instructions
421421
\text{f64.reinterpret\_i64} &\Rightarrow& \F64.\REINTERPRET\K{\_}\I64 \\
422422
\end{array}
423423
424+
.. math::
425+
\begin{array}{llclll}
426+
\phantom{\production{instruction}} & \phantom{\Tplaininstr_I} &\phantom{::=}& \phantom{thisisenough} && \phantom{thisshouldbeenough} \\[-2ex] &&|&
427+
\text{i32.extend8\_s} &\Rightarrow& \I32.\EXTEND\K{8\_s} \\ &&|&
428+
\text{i32.extend16\_s} &\Rightarrow& \I32.\EXTEND\K{16\_s} \\ &&|&
429+
\text{i64.extend8\_s} &\Rightarrow& \I64.\EXTEND\K{8\_s} \\ &&|&
430+
\text{i64.extend16\_s} &\Rightarrow& \I64.\EXTEND\K{16\_s} \\ &&|&
431+
\text{i64.extend32\_s} &\Rightarrow& \I64.\EXTEND\K{32\_s} \\
432+
\end{array}
433+
424434
425435
.. index:: ! folded instruction, S-expression
426436
.. _text-foldedinstr:

document/core/util/macros.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@
920920
.. |iles| mathdef:: \xref{exec/numerics}{op-ile_s}{\F{ile\_s}}
921921
.. |igeu| mathdef:: \xref{exec/numerics}{op-ige_u}{\F{ige\_u}}
922922
.. |iges| mathdef:: \xref{exec/numerics}{op-ige_s}{\F{ige\_s}}
923+
.. |iextendns| mathdef:: \xref{exec/numerics}{op-iextendn_s}{\F{iextend}M\F{\_s}}
923924

924925
.. |fadd| mathdef:: \xref{exec/numerics}{op-fadd}{\F{fadd}}
925926
.. |fsub| mathdef:: \xref{exec/numerics}{op-fsub}{\F{fsub}}

interpreter/binary/decode.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,12 @@ let rec instr s =
445445
| 0xbe -> f32_reinterpret_i32
446446
| 0xbf -> f64_reinterpret_i64
447447

448+
| 0xc0 -> i32_extend8_s
449+
| 0xc1 -> i32_extend16_s
450+
| 0xc2 -> i64_extend8_s
451+
| 0xc3 -> i64_extend16_s
452+
| 0xc4 -> i64_extend32_s
453+
448454
| 0xfc -> math_prefix s
449455

450456
| b -> illegal s pos b

interpreter/binary/encode.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ let encode m =
130130
open Source
131131
open Ast
132132
open Values
133-
open Memory
134133

135134
let op n = u8 n
136135
let end_ () = op 0x0b
@@ -260,10 +259,16 @@ let encode m =
260259
| Unary (I32 I32Op.Clz) -> op 0x67
261260
| Unary (I32 I32Op.Ctz) -> op 0x68
262261
| Unary (I32 I32Op.Popcnt) -> op 0x69
262+
| Unary (I32 (I32Op.ExtendS Pack8)) -> op 0xc0
263+
| Unary (I32 (I32Op.ExtendS Pack16)) -> op 0xc1
264+
| Unary (I32 (I32Op.ExtendS Pack32)) -> assert false
263265

264266
| Unary (I64 I64Op.Clz) -> op 0x79
265267
| Unary (I64 I64Op.Ctz) -> op 0x7a
266268
| Unary (I64 I64Op.Popcnt) -> op 0x7b
269+
| Unary (I64 (I64Op.ExtendS Pack8)) -> op 0xc2
270+
| Unary (I64 (I64Op.ExtendS Pack16)) -> op 0xc3
271+
| Unary (I64 (I64Op.ExtendS Pack32)) -> op 0xc4
267272

268273
| Unary (F32 F32Op.Abs) -> op 0x8b
269274
| Unary (F32 F32Op.Neg) -> op 0x8c

interpreter/exec/eval_numeric.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct
2424
| Clz -> IXX.clz
2525
| Ctz -> IXX.ctz
2626
| Popcnt -> IXX.popcnt
27+
| ExtendS sz -> IXX.extend_s (8 * packed_size sz)
2728
in fun v -> to_value (f (of_value 1 v))
2829

2930
let binop op =

interpreter/exec/int.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ sig
5858
val clz : t -> t
5959
val ctz : t -> t
6060
val popcnt : t -> t
61+
val extend_s : int -> t -> t
6162
val eqz : t -> bool
6263
val eq : t -> t -> bool
6364
val ne : t -> t -> bool
@@ -201,6 +202,10 @@ struct
201202
loop acc' (i - 1) (Rep.shift_right_logical n 1)
202203
in Rep.of_int (loop 0 Rep.bitwidth x)
203204

205+
let extend_s n x =
206+
let shift = Rep.bitwidth - n in
207+
Rep.shift_right (Rep.shift_left x shift) shift
208+
204209
let eqz x = x = Rep.zero
205210

206211
let eq x y = x = y

interpreter/runtime/memory.ml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ type size = int32 (* number of pages *)
77
type address = int64
88
type offset = int32
99

10-
type pack_size = Pack8 | Pack16 | Pack32
11-
type extension = SX | ZX
12-
1310
type memory' = (int, int8_unsigned_elt, c_layout) Array1.t
1411
type memory = {mutable content : memory'; max : size option}
1512
type t = memory
@@ -22,11 +19,6 @@ exception OutOfMemory
2219

2320
let page_size = 0x10000L (* 64 KiB *)
2421

25-
let packed_size = function
26-
| Pack8 -> 1
27-
| Pack16 -> 2
28-
| Pack32 -> 4
29-
3022
let within_limits n = function
3123
| None -> true
3224
| Some max -> I32.le_u n max

interpreter/runtime/memory.mli

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,13 @@ type size = int32 (* number of pages *)
88
type address = int64
99
type offset = int32
1010

11-
type pack_size = Pack8 | Pack16 | Pack32
12-
type extension = SX | ZX
13-
1411
exception Type
1512
exception Bounds
1613
exception SizeOverflow
1714
exception SizeLimit
1815
exception OutOfMemory
1916

2017
val page_size : int64
21-
val packed_size : pack_size -> int
2218

2319
val alloc : memory_type -> memory (* raises SizeOverflow, OutOfMemory *)
2420
val type_of : memory -> memory_type

interpreter/syntax/ast.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ open Types
2323

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

5959
type 'a memop =
6060
{ty : value_type; align : int; offset : Memory.offset; sz : 'a option}
61-
type loadop = (Memory.pack_size * Memory.extension) memop
62-
type storeop = Memory.pack_size memop
61+
type loadop = (pack_size * extension) memop
62+
type storeop = pack_size memop
6363

6464

6565
(* Expressions *)

interpreter/syntax/operators.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
open Source
22
open Types
33
open Values
4-
open Memory
54
open Ast
65

76

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

209+
let i32_extend8_s = Unary (I32 (I32Op.ExtendS Pack8))
210+
let i32_extend16_s = Unary (I32 (I32Op.ExtendS Pack16))
211+
let i64_extend8_s = Unary (I64 (I64Op.ExtendS Pack8))
212+
let i64_extend16_s = Unary (I64 (I64Op.ExtendS Pack16))
213+
let i64_extend32_s = Unary (I64 (I64Op.ExtendS Pack32))
214+
210215
let memory_size = MemorySize
211216
let memory_grow = MemoryGrow
212217

interpreter/syntax/types.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,21 @@ type extern_type =
1616
| ExternMemoryType of memory_type
1717
| ExternGlobalType of global_type
1818

19+
type pack_size = Pack8 | Pack16 | Pack32
20+
type extension = SX | ZX
21+
1922

2023
(* Attributes *)
2124

2225
let size = function
2326
| I32Type | F32Type -> 4
2427
| I64Type | F64Type -> 8
2528

29+
let packed_size = function
30+
| Pack8 -> 1
31+
| Pack16 -> 2
32+
| Pack32 -> 4
33+
2634

2735
(* Subtyping *)
2836

interpreter/text/arrange.ml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ let global_type = function
7575
| GlobalType (t, Immutable) -> atom string_of_value_type t
7676
| GlobalType (t, Mutable) -> Node ("mut", [atom string_of_value_type t])
7777

78+
let pack_size = function
79+
| Pack8 -> "8"
80+
| Pack16 -> "16"
81+
| Pack32 -> "32"
82+
83+
let extension = function
84+
| SX -> "_s"
85+
| ZX -> "_u"
86+
7887

7988
(* Operators *)
8089

@@ -101,6 +110,7 @@ struct
101110
| Clz -> "clz"
102111
| Ctz -> "ctz"
103112
| Popcnt -> "popcnt"
113+
| ExtendS sz -> "extend" ^ pack_size sz ^ "_s"
104114

105115
let binop xx = function
106116
| Add -> "add"
@@ -191,15 +201,6 @@ let testop = oper (IntOp.testop, FloatOp.testop)
191201
let relop = oper (IntOp.relop, FloatOp.relop)
192202
let cvtop = oper (IntOp.cvtop, FloatOp.cvtop)
193203

194-
let pack_size = function
195-
| Memory.Pack8 -> "8"
196-
| Memory.Pack16 -> "16"
197-
| Memory.Pack32 -> "32"
198-
199-
let extension = function
200-
| Memory.SX -> "_s"
201-
| Memory.ZX -> "_u"
202-
203204
let memop name {ty; align; offset; _} sz =
204205
value_type ty ^ "." ^ name ^
205206
(if offset = 0l then "" else " offset=" ^ nat32 offset) ^
@@ -209,12 +210,12 @@ let loadop op =
209210
match op.sz with
210211
| None -> memop "load" op (size op.ty)
211212
| Some (sz, ext) ->
212-
memop ("load" ^ pack_size sz ^ extension ext) op (Memory.packed_size sz)
213+
memop ("load" ^ pack_size sz ^ extension ext) op (packed_size sz)
213214

214215
let storeop op =
215216
match op.sz with
216217
| None -> memop "store" op (size op.ty)
217-
| Some sz -> memop ("store" ^ pack_size sz) op (Memory.packed_size sz)
218+
| Some sz -> memop ("store" ^ pack_size sz) op (packed_size sz)
218219

219220

220221
(* Expressions *)

interpreter/text/lexer.mll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ rule token = parse
238238
| (ixx as t)".clz" { UNARY (intop t i32_clz i64_clz) }
239239
| (ixx as t)".ctz" { UNARY (intop t i32_ctz i64_ctz) }
240240
| (ixx as t)".popcnt" { UNARY (intop t i32_popcnt i64_popcnt) }
241+
| (ixx as t)".extend8_s" { UNARY (intop t i32_extend8_s i64_extend8_s) }
242+
| (ixx as t)".extend16_s" { UNARY (intop t i32_extend16_s i64_extend16_s) }
243+
| "i64.extend32_s" { UNARY i64_extend32_s }
241244
| (fxx as t)".neg" { UNARY (floatop t f32_neg f64_neg) }
242245
| (fxx as t)".abs" { UNARY (floatop t f32_abs f64_abs) }
243246
| (fxx as t)".sqrt" { UNARY (floatop t f32_sqrt f64_sqrt) }

interpreter/valid/valid.ml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,23 @@ let type_cvtop at = function
139139

140140
(* Expressions *)
141141

142+
let check_pack sz t at =
143+
require (packed_size sz < size t) at "invalid sign extension"
144+
145+
let check_unop unop at =
146+
match unop with
147+
| Values.I32 (IntOp.ExtendS sz) | Values.I64 (IntOp.ExtendS sz) ->
148+
check_pack sz (Values.type_of unop) at
149+
| _ -> ()
150+
142151
let check_memop (c : context) (memop : 'a memop) get_sz at =
143152
ignore (memory c (0l @@ at));
144153
let size =
145154
match get_sz memop.sz with
146155
| None -> size memop.ty
147156
| Some sz ->
148-
require (memop.ty = I64Type || sz <> Memory.Pack32) at
149-
"memory size too big";
150-
Memory.packed_size sz
157+
check_pack sz memop.ty at;
158+
packed_size sz
151159
in
152160
require (1 lsl memop.align <= size) at
153161
"alignment must not be larger than natural"
@@ -279,6 +287,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
279287
[t; t] --> [I32Type]
280288

281289
| Unary unop ->
290+
check_unop unop e.at;
282291
let t = type_unop unop in
283292
[t] --> [t]
284293

0 commit comments

Comments
 (0)