Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Commit b295c5d

Browse files
authored
Implement SIMD load splat and load extend (#307)
* Implement SIMD load splat and load extend Add more pack types for SIMD load splat and load extends. * Create new pack_simd type and SimdLoad AST * Reorder functions * Formatting * Simplify simd packed loads * Add SimdStore and make simd_loadop more consistent New AST nodes SimdLoad and SimdStore.
2 parents 403859f + e8b2f1f commit b295c5d

12 files changed

Lines changed: 130 additions & 17 deletions

File tree

interpreter/binary/encode.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,8 @@ let encode m =
567567
| SimdBitmask V128Op.(I32x4 Bitmask) -> simd_op 0xa4l
568568
| SimdBitmask (_) -> assert false
569569

570+
| _ -> assert false
571+
570572
let const c =
571573
list instr c.it; end_ ()
572574

interpreter/exec/eval.ml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,17 @@ let rec step (c : config) : config =
220220
in v :: vs', []
221221
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
222222

223+
| SimdLoad {offset; ty; sz; _}, I32 i :: vs' ->
224+
let mem = memory frame.inst (0l @@ e.at) in
225+
let addr = I64_convert.extend_i32_u i in
226+
(try
227+
let v =
228+
match sz with
229+
| None -> Memory.load_value mem addr offset ty
230+
| Some (pack_size, simd_load) -> Memory.load_simd_packed pack_size simd_load mem addr offset ty
231+
in v :: vs', []
232+
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
233+
223234
| Store {offset; sz; _}, v :: I32 i :: vs' ->
224235
let mem = memory frame.inst (0l @@ e.at) in
225236
let addr = I64_convert.extend_i32_u i in
@@ -231,6 +242,14 @@ let rec step (c : config) : config =
231242
vs', []
232243
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]);
233244

245+
| SimdStore {offset; sz; _}, v :: I32 i :: vs' ->
246+
let mem = memory frame.inst (0l @@ e.at) in
247+
let addr = I64_convert.extend_i32_u i in
248+
(try
249+
Memory.store_value mem addr offset v;
250+
vs', []
251+
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]);
252+
234253
| MemorySize, vs ->
235254
let mem = memory frame.inst (0l @@ e.at) in
236255
I32 (Memory.size mem) :: vs, []

interpreter/exec/simd.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ sig
180180
val widen_low_u : t -> t
181181
val widen_high_u : t -> t
182182
end
183+
module I64x2_convert : sig
184+
val widen_low_s : t -> t
185+
val widen_low_u : t -> t
186+
end
183187
module F32x4_convert : sig
184188
val convert_i32x4_s : t -> t
185189
val convert_i32x4_u : t -> t
@@ -415,6 +419,16 @@ struct
415419
let widen_high_u = widen Lib.List.drop 0xffffl
416420
end
417421

422+
module I64x2_convert = struct
423+
let widen mask x =
424+
Rep.of_i64x2
425+
(List.map
426+
(fun i32 -> Int64.(logand mask (of_int32 i32)))
427+
(Lib.List.take 2 (Rep.to_i32x4 x)))
428+
let widen_low_s = widen 0xffffffffffffffffL
429+
let widen_low_u = widen 0xffffffffL
430+
end
431+
418432
module F32x4_convert = struct
419433
let convert f v = Rep.of_f32x4 (List.map f (Rep.to_i32x4 v))
420434
let convert_i32x4_s = convert F32_convert.convert_i32_s

interpreter/runtime/memory.ml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,26 @@ let load_packed sz ext mem a o t =
131131
| I64Type -> I64 x
132132
| _ -> raise Type
133133

134+
let load_simd_packed pack_size simd_load mem a o t =
135+
let n = packed_size pack_size in
136+
assert (n <= Types.size t);
137+
let x = loadn mem a o n in
138+
let b = Bytes.create 16 in
139+
Bytes.set_int64_le b 0 x;
140+
let v = V128.of_bits (Bytes.to_string b) in
141+
match pack_size, simd_load with
142+
| Pack64, Pack8x8 SX -> V128 (V128.I16x8_convert.widen_low_s v)
143+
| Pack64, Pack8x8 ZX -> V128 (V128.I16x8_convert.widen_low_u v)
144+
| Pack64, Pack16x4 SX -> V128 (V128.I32x4_convert.widen_low_s v)
145+
| Pack64, Pack16x4 ZX -> V128 (V128.I32x4_convert.widen_low_u v)
146+
| Pack64, Pack32x2 SX -> V128 (V128.I64x2_convert.widen_low_s v)
147+
| Pack64, Pack32x2 ZX -> V128 (V128.I64x2_convert.widen_low_u v)
148+
| Pack8, PackSplat -> V128 (V128.I8x16.splat (I8.of_int_s (Int64.to_int x)))
149+
| Pack16, PackSplat -> V128 (V128.I16x8.splat (I16.of_int_s (Int64.to_int x)))
150+
| Pack32, PackSplat -> V128 (V128.I32x4.splat (I32.of_int_s (Int64.to_int x)))
151+
| Pack64, PackSplat -> V128 (V128.I64x2.splat x)
152+
| _ -> assert false
153+
134154
let store_packed sz mem a o v =
135155
assert (packed_size sz <= Types.size (Values.type_of v));
136156
let n = packed_size sz in

interpreter/runtime/memory.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ val store_value :
3535
val load_packed :
3636
pack_size -> extension -> memory -> address -> offset -> value_type -> value
3737
(* raises Type, Bounds *)
38+
val load_simd_packed :
39+
pack_size -> pack_simd -> memory -> address -> offset -> value_type -> value
40+
(* raises Type, Bounds *)
3841
val store_packed :
3942
pack_size -> memory -> address -> offset -> value -> unit
4043
(* raises Type, Bounds *)

interpreter/syntax/ast.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ type 'a memop =
111111
type loadop = (pack_size * extension) memop
112112
type storeop = pack_size memop
113113

114+
type simd_loadop = (pack_size * pack_simd) memop
115+
type empty = |
116+
type simd_storeop = empty memop
114117

115118
(* Expressions *)
116119

@@ -142,6 +145,8 @@ and instr' =
142145
| GlobalSet of var (* write global variable *)
143146
| Load of loadop (* read memory at address *)
144147
| Store of storeop (* write memory at address *)
148+
| SimdLoad of simd_loadop (* read memory at address *)
149+
| SimdStore of simd_storeop (* write memory at address *)
145150
| MemorySize (* size of linear memory *)
146151
| MemoryGrow (* grow linear memory *)
147152
| Const of literal (* constant *)

interpreter/syntax/operators.ml

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,29 @@ let memory_size = MemorySize
217217
let memory_grow = MemoryGrow
218218

219219
(* SIMD *)
220-
let v128_load align offset = Load {ty = V128Type; align; offset; sz = None}
221-
let v128_store align offset = Store {ty = V128Type; align; offset; sz = None}
220+
let v128_load align offset = SimdLoad {ty = V128Type; align; offset; sz = None}
221+
let i16x8_load8x8_s align offset =
222+
SimdLoad {ty = V128Type; align; offset; sz = Some (Pack64, Pack8x8 SX)}
223+
let i16x8_load8x8_u align offset =
224+
SimdLoad {ty = V128Type; align; offset; sz = Some (Pack64, Pack8x8 ZX)}
225+
let i32x4_load16x4_s align offset =
226+
SimdLoad {ty = V128Type; align; offset; sz = Some (Pack64, Pack16x4 SX)}
227+
let i32x4_load16x4_u align offset =
228+
SimdLoad {ty = V128Type; align; offset; sz = Some (Pack64, Pack16x4 ZX)}
229+
let i64x2_load32x2_s align offset =
230+
SimdLoad {ty = V128Type; align; offset; sz = Some (Pack64, Pack32x2 SX)}
231+
let i64x2_load32x2_u align offset =
232+
SimdLoad {ty = V128Type; align; offset; sz = Some (Pack64, Pack32x2 ZX)}
233+
let v8x16_load_splat align offset =
234+
SimdLoad {ty= V128Type; align; offset; sz = Some (Pack8, PackSplat)}
235+
let v16x8_load_splat align offset =
236+
SimdLoad {ty= V128Type; align; offset; sz = Some (Pack16, PackSplat)}
237+
let v32x4_load_splat align offset =
238+
SimdLoad {ty= V128Type; align; offset; sz = Some (Pack32, PackSplat)}
239+
let v64x2_load_splat align offset =
240+
SimdLoad {ty= V128Type; align; offset; sz = Some (Pack64, PackSplat)}
241+
let v128_store align offset = SimdStore {ty = V128Type; align; offset; sz = None}
242+
222243
let v128_not = Unary (V128 (V128Op.V128 V128Op.Not))
223244
let v128_and = Binary (V128 (V128Op.V128 V128Op.And))
224245
let v128_andnot = Binary (V128 (V128Op.V128 V128Op.AndNot))

interpreter/syntax/types.ml

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

19-
type pack_size = Pack8 | Pack16 | Pack32
19+
type pack_size = Pack8 | Pack16 | Pack32 | Pack64
2020
type extension = SX | ZX
21-
21+
type pack_simd =
22+
| PackSplat
23+
| Pack8x8 of extension
24+
| Pack16x4 of extension
25+
| Pack32x2 of extension
2226

2327
(* Attributes *)
2428

@@ -31,7 +35,7 @@ let packed_size = function
3135
| Pack8 -> 1
3236
| Pack16 -> 2
3337
| Pack32 -> 4
34-
38+
| Pack64 -> 8
3539

3640
(* Subtyping *)
3741

interpreter/text/arrange.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ let pack_size = function
7777
| Pack8 -> "8"
7878
| Pack16 -> "16"
7979
| Pack32 -> "32"
80+
| Pack64 -> "64"
8081

8182
let extension = function
8283
| SX -> "_s"
@@ -463,6 +464,8 @@ let rec instr e =
463464
| GlobalGet x -> "global.get " ^ var x, []
464465
| GlobalSet x -> "global.set " ^ var x, []
465466
| Load op -> loadop op, []
467+
| SimdLoad op -> failwith "unimplemented SimdLoad arrange"
468+
| SimdStore op -> failwith "unimplemented SimdStore arrange"
466469
| Store op -> storeop op, []
467470
| MemorySize -> "memory.size", []
468471
| MemoryGrow -> "memory.grow", []

interpreter/text/lexer.mll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,20 @@ rule token = parse
288288
(ext s i64_load8_s i64_load8_u (opt a 0))
289289
(ext s i64_load16_s i64_load16_u (opt a 1))
290290
(ext s i64_load32_s i64_load32_u (opt a 2)) o)) }
291+
| "i16x8.load8x8_"(sign as s)
292+
{ LOAD (fun a o -> (ext s i16x8_load8x8_s i16x8_load8x8_u (opt a 3)) o) }
293+
| "i32x4.load16x4_"(sign as s)
294+
{ LOAD (fun a o -> (ext s i32x4_load16x4_s i32x4_load16x4_u (opt a 3)) o) }
295+
| "i64x2.load32x2_"(sign as s)
296+
{ LOAD (fun a o -> (ext s i64x2_load32x2_s i64x2_load32x2_u (opt a 3)) o) }
297+
| "v8x16.load_splat"
298+
{ LOAD (fun a o -> (v8x16_load_splat (opt a 0)) o) }
299+
| "v16x8.load_splat"
300+
{ LOAD (fun a o -> (v16x8_load_splat (opt a 1)) o) }
301+
| "v32x4.load_splat"
302+
{ LOAD (fun a o -> (v32x4_load_splat (opt a 2)) o) }
303+
| "v64x2.load_splat"
304+
{ LOAD (fun a o -> (v64x2_load_splat (opt a 3)) o) }
291305
| (ixx as t)".store"(mem_size as sz)
292306
{ if t = "i32" && sz = "32" then error lexbuf "unknown operator";
293307
STORE (fun a o ->

0 commit comments

Comments
 (0)