From 74e50349d67cdf1ba86eb0fa83ec3c40b34ab9a4 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 16 Jan 2018 14:20:02 -0800 Subject: [PATCH] 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) --- document/core/appendix/index-instructions.rst | 5 ++ document/core/binary/instructions.rst | 11 ++++ document/core/exec/numerics.rst | 13 +++++ document/core/syntax/instructions.rst | 9 +++- document/core/text/instructions.rst | 10 ++++ document/core/util/macros.def | 1 + interpreter/binary/decode.ml | 6 +++ interpreter/binary/encode.ml | 7 ++- interpreter/exec/eval_numeric.ml | 1 + interpreter/exec/int.ml | 5 ++ interpreter/runtime/memory.ml | 8 --- interpreter/runtime/memory.mli | 4 -- interpreter/syntax/ast.ml | 6 +-- interpreter/syntax/operators.ml | 7 ++- interpreter/syntax/types.ml | 8 +++ interpreter/text/arrange.ml | 23 +++++---- interpreter/text/lexer.mll | 3 ++ interpreter/valid/valid.ml | 15 ++++-- proposals/sign-extension-ops/Overview.md | 51 +++++++++++++++++++ test/core/i32.wast | 18 +++++++ test/core/i64.wast | 30 +++++++++++ 21 files changed, 208 insertions(+), 33 deletions(-) create mode 100644 proposals/sign-extension-ops/Overview.md diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 3ff74b2898..6720fe10ec 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -199,6 +199,11 @@ Instruction Binary Opcode Type :math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` :math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` :math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` :math:`\I32.\TRUNC\K{\_sat}\F32\K{\_s}` :math:`\hex{FC}~\hex{00}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` :math:`\I32.\TRUNC\K{\_sat}\F32\K{\_u}` :math:`\hex{FC}~\hex{01}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` :math:`\I32.\TRUNC\K{\_sat}\F64\K{\_s}` :math:`\hex{FC}~\hex{02}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index 0e58154497..198420c062 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -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 diff --git a/document/core/exec/numerics.rst b/document/core/exec/numerics.rst index 954c9e9fbf..4a5e5372bf 100644 --- a/document/core/exec/numerics.rst +++ b/document/core/exec/numerics.rst @@ -612,6 +612,19 @@ The integer result of predicates -- i.e., :ref:`tests ` 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: diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index f60f26d508..6ac02dbf66 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -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} ~|~ @@ -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 \\ diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index f813bae06c..5fba8289da 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -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: diff --git a/document/core/util/macros.def b/document/core/util/macros.def index c9e3cf0cec..fc086709ef 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -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}} diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index da291092a5..542cf5a700 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -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 diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 4fbb52b157..4baac46d73 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -130,7 +130,6 @@ let encode m = open Source open Ast open Values - open Memory let op n = u8 n let end_ () = op 0x0b @@ -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 diff --git a/interpreter/exec/eval_numeric.ml b/interpreter/exec/eval_numeric.ml index c8f634dfb5..f54a77f2c2 100644 --- a/interpreter/exec/eval_numeric.ml +++ b/interpreter/exec/eval_numeric.ml @@ -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 = diff --git a/interpreter/exec/int.ml b/interpreter/exec/int.ml index 81674b15fc..ff04c43699 100644 --- a/interpreter/exec/int.ml +++ b/interpreter/exec/int.ml @@ -58,6 +58,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 @@ -201,6 +202,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 diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index d1f2bce982..15794033f8 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -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 @@ -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 diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index 2a2b8ae47a..f611e46477 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -8,9 +8,6 @@ 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 @@ -18,7 +15,6 @@ 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 diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 4e3a3e396e..91c374d793 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -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 @@ -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 *) diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 17b424fdcc..d0ecd02351 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -1,7 +1,6 @@ open Source open Types open Values -open Memory open Ast @@ -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 diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 00b76f6c16..aeb398b021 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -16,6 +16,9 @@ type extern_type = | ExternMemoryType of memory_type | ExternGlobalType of global_type +type pack_size = Pack8 | Pack16 | Pack32 +type extension = SX | ZX + (* Attributes *) @@ -23,6 +26,11 @@ let size = function | I32Type | F32Type -> 4 | I64Type | F64Type -> 8 +let packed_size = function + | Pack8 -> 1 + | Pack16 -> 2 + | Pack32 -> 4 + (* Subtyping *) diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index e381b42fea..5d9151654c 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -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 *) @@ -101,6 +110,7 @@ struct | Clz -> "clz" | Ctz -> "ctz" | Popcnt -> "popcnt" + | ExtendS sz -> "extend" ^ pack_size sz ^ "_s" let binop xx = function | Add -> "add" @@ -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) ^ @@ -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 *) diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 3c8d56e90a..e31c4d41d0 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -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) } diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 44cbdb75d8..917694fada 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -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" @@ -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] diff --git a/proposals/sign-extension-ops/Overview.md b/proposals/sign-extension-ops/Overview.md new file mode 100644 index 0000000000..55df64b4cf --- /dev/null +++ b/proposals/sign-extension-ops/Overview.md @@ -0,0 +1,51 @@ +# Sign-extension operators proposal for WebAssembly + +This page describes a proposal for the post-MVP +[sign-extension operator feature][future sext]. + +This proposal adds five new integer instructions for sign-extending 8-bit, +16-bit, and 32-bit values. + +## New Sign-extending Operators + +To support sign-extending, five new sign-extension operators are added: + + * `i32.extend8_s`: extend a signed 8-bit integer to a 32-bit integer + * `i32.extend16_s`: extend a signed 16-bit integer to a 32-bit integer + * `i64.extend8_s`: extend a signed 8-bit integer to a 64-bit integer + * `i64.extend16_s`: extend a signed 16-bit integer to a 64-bit integer + * `i64.extend32_s`: extend a signed 32-bit integer to a 64-bit integer + +Note that `i64.extend32_s` was not originally included when this proposal was +discussed in the May 2017 CG meeting. The reason given was that +the behavior matches `i64.extend_s/i32`. It was later discovered that this is +not correct, as `i64.extend_s/i32` sign-extends an `i32` value to `i64`, +whereas `i64.extend32_s` sign-extends an `i64` value to `i64`. The behavior +of `i64.extend32_s` can be emulated with `i32.wrap/i64` followed by +`i64.extend_s/i32`, but the same can be said of the sign-extending load +operations. Therefore, `i64.extend32_s` has been added for consistency. + +## [Spec Changes][spec] + +The [instruction syntax][] is modified as follows: + +``` +instr ::= ... | + inn.extend8_s | inn.extend16_s | i64.extend32_s +``` + +The [instruction binary format][] is modified as follows: + +``` +instr ::= ... + | 0xC0 => i32.extend8_s + | 0xC1 => i32.extend16_s + | 0xC2 => i64.extend8_s + | 0xC3 => i64.extend16_s + | 0xC4 => i64.extend32_s +``` + +[future sext]: https://github.com/WebAssembly/design/blob/master/FutureFeatures.md#additional-integer-operators +[instruction syntax]: https://webassembly.github.io/spec/syntax/instructions.html +[instruction binary format]: https://webassembly.github.io/spec/binary/instructions.html +[spec]: https://webassembly.github.io/sign-extension-ops/ diff --git a/test/core/i32.wast b/test/core/i32.wast index 58c853a6ba..32862c3475 100644 --- a/test/core/i32.wast +++ b/test/core/i32.wast @@ -19,6 +19,8 @@ (func (export "clz") (param $x i32) (result i32) (i32.clz (local.get $x))) (func (export "ctz") (param $x i32) (result i32) (i32.ctz (local.get $x))) (func (export "popcnt") (param $x i32) (result i32) (i32.popcnt (local.get $x))) + (func (export "extend8_s") (param $x i32) (result i32) (i32.extend8_s (local.get $x))) + (func (export "extend16_s") (param $x i32) (result i32) (i32.extend16_s (local.get $x))) (func (export "eqz") (param $x i32) (result i32) (i32.eqz (local.get $x))) (func (export "eq") (param $x i32) (param $y i32) (result i32) (i32.eq (local.get $x) (local.get $y))) (func (export "ne") (param $x i32) (param $y i32) (result i32) (i32.ne (local.get $x) (local.get $y))) @@ -265,6 +267,22 @@ (assert_return (invoke "popcnt" (i32.const 0x55555555)) (i32.const 16)) (assert_return (invoke "popcnt" (i32.const 0xDEADBEEF)) (i32.const 24)) +(assert_return (invoke "extend8_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "extend8_s" (i32.const 0x7f)) (i32.const 127)) +(assert_return (invoke "extend8_s" (i32.const 0x80)) (i32.const -128)) +(assert_return (invoke "extend8_s" (i32.const 0xff)) (i32.const -1)) +(assert_return (invoke "extend8_s" (i32.const 0x012345_00)) (i32.const 0)) +(assert_return (invoke "extend8_s" (i32.const 0xfedcba_80)) (i32.const -0x80)) +(assert_return (invoke "extend8_s" (i32.const -1)) (i32.const -1)) + +(assert_return (invoke "extend16_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "extend16_s" (i32.const 0x7fff)) (i32.const 32767)) +(assert_return (invoke "extend16_s" (i32.const 0x8000)) (i32.const -32768)) +(assert_return (invoke "extend16_s" (i32.const 0xffff)) (i32.const -1)) +(assert_return (invoke "extend16_s" (i32.const 0x0123_0000)) (i32.const 0)) +(assert_return (invoke "extend16_s" (i32.const 0xfedc_8000)) (i32.const -0x8000)) +(assert_return (invoke "extend16_s" (i32.const -1)) (i32.const -1)) + (assert_return (invoke "eqz" (i32.const 0)) (i32.const 1)) (assert_return (invoke "eqz" (i32.const 1)) (i32.const 0)) (assert_return (invoke "eqz" (i32.const 0x80000000)) (i32.const 0)) diff --git a/test/core/i64.wast b/test/core/i64.wast index 5a8c1d6625..baeed0ce1b 100644 --- a/test/core/i64.wast +++ b/test/core/i64.wast @@ -19,6 +19,9 @@ (func (export "clz") (param $x i64) (result i64) (i64.clz (local.get $x))) (func (export "ctz") (param $x i64) (result i64) (i64.ctz (local.get $x))) (func (export "popcnt") (param $x i64) (result i64) (i64.popcnt (local.get $x))) + (func (export "extend8_s") (param $x i64) (result i64) (i64.extend8_s (local.get $x))) + (func (export "extend16_s") (param $x i64) (result i64) (i64.extend16_s (local.get $x))) + (func (export "extend32_s") (param $x i64) (result i64) (i64.extend32_s (local.get $x))) (func (export "eqz") (param $x i64) (result i32) (i64.eqz (local.get $x))) (func (export "eq") (param $x i64) (param $y i64) (result i32) (i64.eq (local.get $x) (local.get $y))) (func (export "ne") (param $x i64) (param $y i64) (result i32) (i64.ne (local.get $x) (local.get $y))) @@ -265,6 +268,33 @@ (assert_return (invoke "popcnt" (i64.const 0x99999999AAAAAAAA)) (i64.const 32)) (assert_return (invoke "popcnt" (i64.const 0xDEADBEEFDEADBEEF)) (i64.const 48)) +(assert_return (invoke "extend8_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend8_s" (i64.const 0x7f)) (i64.const 127)) +(assert_return (invoke "extend8_s" (i64.const 0x80)) (i64.const -128)) +(assert_return (invoke "extend8_s" (i64.const 0xff)) (i64.const -1)) +(assert_return (invoke "extend8_s" (i64.const 0x01234567_89abcd_00)) (i64.const 0)) +(assert_return (invoke "extend8_s" (i64.const 0xfedcba98_765432_80)) (i64.const -0x80)) +(assert_return (invoke "extend8_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "extend16_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend16_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "extend16_s" (i64.const 0x8000)) (i64.const -32768)) +(assert_return (invoke "extend16_s" (i64.const 0xffff)) (i64.const -1)) +(assert_return (invoke "extend16_s" (i64.const 0x12345678_9abc_0000)) (i64.const 0)) +(assert_return (invoke "extend16_s" (i64.const 0xfedcba98_7654_8000)) (i64.const -0x8000)) +(assert_return (invoke "extend16_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "extend32_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend32_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "extend32_s" (i64.const 0x8000)) (i64.const 32768)) +(assert_return (invoke "extend32_s" (i64.const 0xffff)) (i64.const 65535)) +(assert_return (invoke "extend32_s" (i64.const 0x7fffffff)) (i64.const 0x7fffffff)) +(assert_return (invoke "extend32_s" (i64.const 0x80000000)) (i64.const -0x80000000)) +(assert_return (invoke "extend32_s" (i64.const 0xffffffff)) (i64.const -1)) +(assert_return (invoke "extend32_s" (i64.const 0x01234567_00000000)) (i64.const 0)) +(assert_return (invoke "extend32_s" (i64.const 0xfedcba98_80000000)) (i64.const -0x80000000)) +(assert_return (invoke "extend32_s" (i64.const -1)) (i64.const -1)) + (assert_return (invoke "eqz" (i64.const 0)) (i32.const 1)) (assert_return (invoke "eqz" (i64.const 1)) (i32.const 0)) (assert_return (invoke "eqz" (i64.const 0x8000000000000000)) (i32.const 0))