Skip to content

Commit

Permalink
Merge pull request #22 from WebAssembly/update-interpreter
Browse files Browse the repository at this point in the history
Add initial tests and interpreter support
  • Loading branch information
alexcrichton authored Oct 17, 2024
2 parents bbf4e37 + 6270ae8 commit d2b3d04
Show file tree
Hide file tree
Showing 18 changed files with 576 additions and 10 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-interpreter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ jobs:
with:
ocaml-compiler: 4.14.x
- name: Setup OCaml tools
run: opam install --yes ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0
run: opam install --yes ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 stdint.0.7.2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 19.x
- name: Build interpreter
run: cd interpreter && opam exec make
- name: Run tests
run: cd interpreter && opam exec make JS=node ci
run: cd interpreter && opam exec make ci
4 changes: 4 additions & 0 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,10 @@ let rec instr s =
| 0x0fl -> table_grow (at var s)
| 0x10l -> table_size (at var s)
| 0x11l -> table_fill (at var s)
| 0x13l -> i64_add128
| 0x14l -> i64_sub128
| 0x15l -> i64_mul_wide_s
| 0x16l -> i64_mul_wide_u

| n -> illegal2 s pos b n
)
Expand Down
5 changes: 5 additions & 0 deletions interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,11 @@ struct
| VecReplace (V128 (F32x4 (V128Op.Replace i))) -> vecop 0x20l; byte i
| VecReplace (V128 (F64x2 (V128Op.Replace i))) -> vecop 0x22l; byte i

| Binary128 Add128 -> op 0xfc; u32 0x13l
| Binary128 Sub128 -> op 0xfc; u32 0x14l
| BinaryWide MulS -> op 0xfc; u32 0x15l
| BinaryWide MulU -> op 0xfc; u32 0x16l

let const c =
list instr c.it; end_ ()

Expand Down
1 change: 1 addition & 0 deletions interpreter/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
(library
(public_name wasm)
(modules :standard \ main wasm wast smallint)
(libraries stdint)
)

(executable
Expand Down
1 change: 1 addition & 0 deletions interpreter/dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
(depends
(ocaml (>= 4.12))
(menhir (>= 20220210))
(stdint (>= 0.7.2))
)
)
8 changes: 8 additions & 0 deletions interpreter/exec/eval.ml
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,14 @@ let rec step (c : config) : config =
(try Vec (Eval_vec.eval_replaceop replaceop v r) :: vs', []
with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at])

| Binary128 op, Num rhs_hi :: Num rhs_lo :: Num lhs_hi :: Num lhs_lo :: vs ->
let (lo, hi) = Eval_num.eval_binop128 op lhs_lo lhs_hi rhs_lo rhs_hi
in Num hi :: Num lo :: vs, []

| BinaryWide op, Num rhs :: Num lhs :: vs ->
let (lo, hi) = Eval_num.eval_binop_wide op lhs rhs
in Num hi :: Num lo :: vs, []

| _ ->
let s1 = string_of_values (List.rev vs) in
let s2 = string_of_value_types (List.map type_of_value (List.rev vs)) in
Expand Down
24 changes: 23 additions & 1 deletion interpreter/exec/eval_num.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,27 @@ struct
end

module I32Op = IntOp (I32) (I32Num)
module I64Op = IntOp (I64) (I64Num)
module I64Op = struct
include IntOp (I64) (I64Num)

open I64Num

let binop128 op =
let f = match op with
| Ast.Add128 -> I64.add128
| Ast.Sub128 -> I64.sub128
in fun v1 v2 v3 v4 ->
let (a, b) = f (of_num 1 v1) (of_num 2 v2) (of_num 3 v3) (of_num 4 v4)
in (to_num a, to_num b)

let binop_wide op =
let f = match op with
| Ast.MulS -> I64.mul_wide_s
| Ast.MulU -> I64.mul_wide_u
in fun v1 v2 ->
let (a, b) = f (of_num 1 v1) (of_num 2 v2)
in (to_num a, to_num b)
end


(* Float operators *)
Expand Down Expand Up @@ -195,3 +215,5 @@ let eval_binop = op I32Op.binop I64Op.binop F32Op.binop F64Op.binop
let eval_testop = op I32Op.testop I64Op.testop F32Op.testop F64Op.testop
let eval_relop = op I32Op.relop I64Op.relop F32Op.relop F64Op.relop
let eval_cvtop = op I32CvtOp.cvtop I64CvtOp.cvtop F32CvtOp.cvtop F64CvtOp.cvtop
let eval_binop128 = I64Op.binop128
let eval_binop_wide = I64Op.binop_wide
2 changes: 2 additions & 0 deletions interpreter/exec/eval_num.mli
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ val eval_binop : Ast.binop -> num -> num -> num
val eval_testop : Ast.testop -> num -> bool
val eval_relop : Ast.relop -> num -> num -> bool
val eval_cvtop : Ast.cvtop -> num -> num
val eval_binop128 : Ast.binop128 -> num -> num -> num -> num -> num * num
val eval_binop_wide : Ast.binop_wide -> num -> num -> num * num
22 changes: 22 additions & 0 deletions interpreter/exec/i64.ml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,25 @@ include Ixx.Make
let of_int64 i = i
let to_int64 i = i
end)

open Stdint

let to_i128 lo hi =
let lo = Int128.of_uint64 (Uint64.of_int64 lo) in
let hi = Int128.of_uint64 (Uint64.of_int64 hi) in
Int128.logor lo (Int128.shift_left hi 64)

let split_i128 v =
let lo = Int64.of_int128 v in
let hi = Int64.of_int128 (Int128.shift_right v 64) in
(lo, hi)

let add128 a b c d = split_i128 (Int128.add (to_i128 a b) (to_i128 c d))
let sub128 a b c d = split_i128 (Int128.sub (to_i128 a b) (to_i128 c d))

let mul_wide_s a b = split_i128 (Int128.mul (Int128.of_int64 a) (Int128.of_int64 b))
let mul_wide_u a b =
let a = Uint64.of_int64 a in
let b = Uint64.of_int64 b in
let c = Uint128.mul (Uint128.of_uint64 a) (Uint128.of_uint64 b) in
split_i128 (Int128.of_uint128 c)
4 changes: 4 additions & 0 deletions interpreter/syntax/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ type unop = (I32Op.unop, I64Op.unop, F32Op.unop, F64Op.unop) Values.op
type binop = (I32Op.binop, I64Op.binop, F32Op.binop, F64Op.binop) Values.op
type relop = (I32Op.relop, I64Op.relop, F32Op.relop, F64Op.relop) Values.op
type cvtop = (I32Op.cvtop, I64Op.cvtop, F32Op.cvtop, F64Op.cvtop) Values.op
type binop128 = Add128 | Sub128
type binop_wide = MulS | MulU

type vec_testop = (V128Op.testop) Values.vecop
type vec_relop = (V128Op.relop) Values.vecop
Expand Down Expand Up @@ -182,6 +184,8 @@ and instr' =
| Compare of relop (* numeric comparison *)
| Unary of unop (* unary numeric operator *)
| Binary of binop (* binary numeric operator *)
| Binary128 of binop128 (* 128-bit operation taking 4 arguments *)
| BinaryWide of binop_wide (* wide-arithmetic binop *)
| Convert of cvtop (* conversion *)
| VecConst of vec (* constant *)
| VecTest of vec_testop (* vector test *)
Expand Down
1 change: 1 addition & 0 deletions interpreter/syntax/free.ml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ let rec instr (e : instr) =
memories zero
| MemoryInit x -> memories zero ++ datas (var x)
| DataDrop x -> datas (var x)
| Binary128 _ | BinaryWide _ -> empty

and block (es : instr list) =
let free = list instr es in {free with labels = shift free.labels}
Expand Down
5 changes: 5 additions & 0 deletions interpreter/syntax/operators.ml
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,8 @@ let f64x2_pmax = VecBinary (V128 (F64x2 V128Op.Pmax))
let f64x2_promote_low_f32x4 = VecConvert (V128 (F64x2 V128Op.PromoteLowF32x4))
let f64x2_convert_low_i32x4_s = VecConvert (V128 (F64x2 V128Op.ConvertSI32x4))
let f64x2_convert_low_i32x4_u = VecConvert (V128 (F64x2 V128Op.ConvertUI32x4))

let i64_add128 = Binary128 Add128
let i64_sub128 = Binary128 Sub128
let i64_mul_wide_s = BinaryWide MulS
let i64_mul_wide_u = BinaryWide MulU
10 changes: 10 additions & 0 deletions interpreter/text/arrange.ml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ struct
| TruncSatSF64 -> "trunc_sat_f64_s"
| TruncSatUF64 -> "trunc_sat_f64_u"
| ReinterpretFloat -> "reinterpret_f" ^ xx

let binop128 op = match op with
| Add128 -> "add128"
| Sub128 -> "sub128"

let binop_wide op = match op with
| MulS -> "mul_wide_s"
| MulU -> "mul_wide_u"
end

module FloatOp =
Expand Down Expand Up @@ -504,6 +512,8 @@ let rec instr e =
| VecSplat op -> vec_splatop op, []
| VecExtract op -> vec_extractop op, []
| VecReplace op -> vec_replaceop op, []
| Binary128 op -> "i64." ^ (IntOp.binop128 op), []
| BinaryWide op -> "i64." ^ (IntOp.binop_wide op), []
in Node (head, inner)

let const head c =
Expand Down
7 changes: 6 additions & 1 deletion interpreter/text/lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ let character =
[^'"''\\''\x00'-'\x1f''\x7f'-'\xff']
| utf8enc
| '\\'escape
| '\\'hexdigit hexdigit
| '\\'hexdigit hexdigit
| "\\u{" hexnum '}'

let nat = num | "0x" hexnum
Expand Down Expand Up @@ -655,6 +655,11 @@ rule token = parse
| "f32x4.replace_lane" -> VEC_REPLACE f32x4_replace_lane
| "f64x2.replace_lane" -> VEC_REPLACE f64x2_replace_lane

| "i64.add128" -> BINARY i64_add128
| "i64.sub128" -> BINARY i64_sub128
| "i64.mul_wide_s" -> BINARY i64_mul_wide_s
| "i64.mul_wide_u" -> BINARY i64_mul_wide_u

| "type" -> TYPE
| "func" -> FUNC
| "param" -> PARAM
Expand Down
6 changes: 6 additions & 0 deletions interpreter/valid/valid.ml
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,12 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type
"invalid lane index";
[t; NumType t2] --> [t]

| Binary128 _ ->
[NumType I64Type; NumType I64Type; NumType I64Type; NumType I64Type] --> [NumType I64Type; NumType I64Type]

| BinaryWide _ ->
[NumType I64Type; NumType I64Type] --> [NumType I64Type; NumType I64Type]

and check_seq (c : context) (s : infer_result_type) (es : instr list)
: infer_result_type =
match es with
Expand Down
1 change: 1 addition & 0 deletions interpreter/wasm.opam
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ depends: [
"dune" {>= "2.9"}
"ocaml" {>= "4.12"}
"menhir" {>= "20220210"}
"stdint" {>= "0.7.2"}
"odoc" {with-doc}
]
build: [
Expand Down
11 changes: 5 additions & 6 deletions proposals/wide-arithmetic/Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,12 @@ plaininstr_l ::= ...

Tests:

* [ ] Core spec tests
* [example test in Wasmtime](https://github.com/bytecodealliance/wasmtime/blob/bc6b0fe4cb7c0d6f2fa436e185411db705e4a4ff/tests/misc_testsuite/wide-arithmetic.wast)
* [x] [Core spec tests](https://github.com/WebAssembly/wide-arithmetic/pull/22)

Engines:

* [x] [Wasmtime](https://github.com/bytecodealliance/wasmtime/pull/9403)
* [ ] Reference interpreter
* [x] [Reference interpreter](https://github.com/WebAssembly/wide-arithmetic/pull/22)

Toolchains:

Expand All @@ -296,12 +295,12 @@ Toolchains:
Binary Decoders:

* [x] [`wasmparser` in `wasm-tools`](https://github.com/bytecodealliance/wasm-tools/pull/1853)
* [ ] Reference interpreter
* [x] [Reference interpreter](https://github.com/WebAssembly/wide-arithmetic/pull/22)

Validation:

* [x] [`wasmparser` in `wasm-tools`](https://github.com/bytecodealliance/wasm-tools/pull/1853)
* [ ] Reference interpreter
* [x] [Reference interpreter](https://github.com/WebAssembly/wide-arithmetic/pull/22)

Binary encoders:

Expand All @@ -310,7 +309,7 @@ Binary encoders:
Text parsers:

* [x] [`wast` in `wasm-tools`](https://github.com/bytecodealliance/wasm-tools/pull/1853)
* [ ] Reference interpreter
* [x] [Reference interpreter](https://github.com/WebAssembly/wide-arithmetic/pull/22)

Fuzzing and test-case generation:

Expand Down
Loading

0 comments on commit d2b3d04

Please sign in to comment.