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

Commit 0cd0a20

Browse files
authored
[interpreter] Implement load lane instructions (#428)
v128.load8_lane v128.load16_lane v128.load32_lane v128.load64_lane Introduce a new ast type, SimdLoadLane, since it takes a lane index immediate, on top of the usual memarg, and also pops a v128 off, in addition to the index. The exact binary opcodes for these instructions are not yet fixed, I've used the ones currently implement in V8 and LLVM/Binaryen, we can change those later. Also added a new test generation script, and the generated test files.
1 parent ffe1db3 commit 0cd0a20

18 files changed

+1087
-17
lines changed

interpreter/binary/decode.ml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,22 @@ let simd_prefix s =
304304
| 0x50l -> v128_or
305305
| 0x51l -> v128_xor
306306
| 0x52l -> v128_bitselect
307+
| 0x58l ->
308+
let a, o = memop s in
309+
let lane = u8 s in
310+
v128_load8_lane a o lane
311+
| 0x59l ->
312+
let a, o = memop s in
313+
let lane = u8 s in
314+
v128_load16_lane a o lane
315+
| 0x5al ->
316+
let a, o = memop s in
317+
let lane = u8 s in
318+
v128_load32_lane a o lane
319+
| 0x5bl ->
320+
let a, o = memop s in
321+
let lane = u8 s in
322+
v128_load64_lane a o lane
307323
| 0x60l -> i8x16_abs
308324
| 0x61l -> i8x16_neg
309325
| 0x62l -> v128_any_true

interpreter/binary/encode.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,15 @@ let encode m =
225225
| SimdLoad ({ty= V128Type; sz = Some (Pack64, PackZero); _} as mo) ->
226226
simd_op 0xfdl; memop mo
227227

228+
| SimdLoadLane ({ty = V128Type; sz = Some Pack8; _} as mo, i) ->
229+
simd_op 0x58l; memop mo; u8 i;
230+
| SimdLoadLane ({ty = V128Type; sz = Some Pack16; _} as mo, i) ->
231+
simd_op 0x59l; memop mo; u8 i;
232+
| SimdLoadLane ({ty = V128Type; sz = Some Pack32; _} as mo, i) ->
233+
simd_op 0x5al; memop mo; u8 i;
234+
| SimdLoadLane ({ty = V128Type; sz = Some Pack64; _} as mo, i) ->
235+
simd_op 0x5bl; memop mo; u8 i;
236+
228237
| Store ({ty = I32Type; sz = None; _} as mo) -> op 0x36; memop mo
229238
| Store ({ty = I64Type; sz = None; _} as mo) -> op 0x37; memop mo
230239
| Store ({ty = F32Type; sz = None; _} as mo) -> op 0x38; memop mo

interpreter/exec/eval.ml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,20 @@ let rec step (c : config) : config =
227227
let v =
228228
match sz with
229229
| 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
230+
| Some (pack_size, simd_load) ->
231+
V128 (Memory.load_simd_packed pack_size simd_load mem addr offset ty)
232+
in v :: vs', []
233+
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
234+
235+
| SimdLoadLane ({offset; ty; sz; _}, j), V128 v128 :: I32 i :: vs' ->
236+
let mem = memory frame.inst (0l @@ e.at) in
237+
let addr = I64_convert.extend_i32_u i in
238+
(try
239+
let v =
240+
match sz with
241+
| None -> assert false
242+
| Some pack_size ->
243+
V128 (Memory.load_simd_lane v128 pack_size mem addr offset ty j)
231244
in v :: vs', []
232245
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
233246

interpreter/runtime/memory.ml

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -139,20 +139,30 @@ let load_simd_packed pack_size simd_load mem a o t =
139139
Bytes.set_int64_le b 0 x;
140140
let v = V128.of_bits (Bytes.to_string b) in
141141
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-
| Pack32, PackZero -> V128 v
153-
| Pack64, PackZero -> V128 v
142+
| Pack64, Pack8x8 SX -> V128.I16x8_convert.widen_low_s v
143+
| Pack64, Pack8x8 ZX -> V128.I16x8_convert.widen_low_u v
144+
| Pack64, Pack16x4 SX -> V128.I32x4_convert.widen_low_s v
145+
| Pack64, Pack16x4 ZX -> V128.I32x4_convert.widen_low_u v
146+
| Pack64, Pack32x2 SX -> V128.I64x2_convert.widen_low_s v
147+
| Pack64, Pack32x2 ZX -> V128.I64x2_convert.widen_low_u v
148+
| Pack8, PackSplat -> V128.I8x16.splat (I8.of_int_s (Int64.to_int x))
149+
| Pack16, PackSplat -> V128.I16x8.splat (I16.of_int_s (Int64.to_int x))
150+
| Pack32, PackSplat -> V128.I32x4.splat (I32.of_int_s (Int64.to_int x))
151+
| Pack64, PackSplat -> V128.I64x2.splat x
152+
| Pack32, PackZero -> v
153+
| Pack64, PackZero -> v
154154
| _ -> assert false
155155

156+
let load_simd_lane v pack_size mem a o t laneidx =
157+
let n = packed_size pack_size in
158+
assert (n < Types.size t);
159+
let x = loadn mem a o n in
160+
match pack_size with
161+
| Pack8 -> V128.I8x16.replace_lane laneidx v (Int64.to_int32 x)
162+
| Pack16 -> V128.I16x8.replace_lane laneidx v (Int64.to_int32 x)
163+
| Pack32 -> V128.I32x4.replace_lane laneidx v (Int64.to_int32 x)
164+
| Pack64 -> V128.I64x2.replace_lane laneidx v x
165+
156166
let store_packed sz mem a o v =
157167
assert (packed_size sz <= Types.size (Values.type_of v));
158168
let n = packed_size sz in

interpreter/runtime/memory.mli

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ val load_packed :
3636
pack_size -> extension -> memory -> address -> offset -> value_type -> value
3737
(* raises Type, Bounds *)
3838
val load_simd_packed :
39-
pack_size -> pack_simd -> memory -> address -> offset -> value_type -> value
39+
pack_size -> pack_simd -> memory -> address -> offset -> value_type -> V128.t
4040
(* raises Type, Bounds *)
41+
val load_simd_lane :
42+
V128.t -> pack_size -> memory -> address -> offset -> value_type -> int (* lane index *) -> V128.t
4143
val store_packed :
4244
pack_size -> memory -> address -> offset -> value -> unit
4345
(* raises Type, Bounds *)

interpreter/syntax/ast.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ type storeop = pack_size memop
114114
type simd_loadop = (pack_size * pack_simd) memop
115115
type empty
116116
type simd_storeop = empty memop
117+
type simd_laneop = pack_size memop * int
117118

118119
(* Expressions *)
119120

@@ -146,6 +147,7 @@ and instr' =
146147
| Load of loadop (* read memory at address *)
147148
| Store of storeop (* write memory at address *)
148149
| SimdLoad of simd_loadop (* read memory at address *)
150+
| SimdLoadLane of simd_laneop (* read single lane at address *)
149151
| SimdStore of simd_storeop (* write memory at address *)
150152
| MemorySize (* size of linear memory *)
151153
| MemoryGrow (* grow linear memory *)

interpreter/syntax/operators.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ let v128_load32_splat align offset =
239239
let v128_load64_splat align offset =
240240
SimdLoad {ty= V128Type; align; offset; sz = Some (Pack64, PackSplat)}
241241

242+
let v128_load8_lane align offset imm =
243+
SimdLoadLane ({ty = V128Type; align; offset; sz = Some Pack8}, imm)
244+
let v128_load16_lane align offset imm =
245+
SimdLoadLane ({ty = V128Type; align; offset; sz = Some Pack16}, imm)
246+
let v128_load32_lane align offset imm =
247+
SimdLoadLane ({ty = V128Type; align; offset; sz = Some Pack32}, imm)
248+
let v128_load64_lane align offset imm =
249+
SimdLoadLane ({ty = V128Type; align; offset; sz = Some Pack64}, imm)
250+
242251
let v128_load32_zero align offset =
243252
SimdLoad {ty= V128Type; align; offset; sz = Some (Pack32, PackZero)}
244253
let v128_load64_zero align offset =

interpreter/text/arrange.ml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,18 @@ let simd_loadop (op : simd_loadop) =
450450
) in
451451
memop ("load" ^ suffix) op (packed_size sz)
452452

453+
let simd_laneop (op, i) =
454+
match op.sz with
455+
| None -> assert false
456+
| Some sz ->
457+
let suffix =
458+
match sz with
459+
| Pack8 -> "8_lane"
460+
| Pack16 -> "16_lane"
461+
| Pack32 -> "32_lane"
462+
| Pack64 -> "64_lane"
463+
in memop ("load" ^ suffix) op (packed_size sz) ^ " " ^ (nat i)
464+
453465
let storeop op =
454466
match op.sz with
455467
| None -> memop "store" op (size op.ty)
@@ -501,6 +513,7 @@ let rec instr e =
501513
| GlobalSet x -> "global.set " ^ var x, []
502514
| Load op -> loadop op, []
503515
| SimdLoad op -> simd_loadop op, []
516+
| SimdLoadLane op -> simd_laneop op, []
504517
| SimdStore op -> simd_storeop op, []
505518
| Store op -> storeop op, []
506519
| MemorySize -> "memory.size", []

interpreter/text/lexer.mll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,14 @@ rule token = parse
306306
{ LOAD (fun a o -> (v128_load32_zero (opt a 2)) o) }
307307
| "v128.load64_zero"
308308
{ LOAD (fun a o -> (v128_load64_zero (opt a 3)) o) }
309+
| "v128.load8_lane"
310+
{ SIMD_LOAD_LANE (fun a o i -> (v128_load8_lane (opt a 0)) o i) }
311+
| "v128.load16_lane"
312+
{ SIMD_LOAD_LANE (fun a o i -> (v128_load16_lane (opt a 1)) o i) }
313+
| "v128.load32_lane"
314+
{ SIMD_LOAD_LANE (fun a o i -> (v128_load32_lane (opt a 2)) o i) }
315+
| "v128.load64_lane"
316+
{ SIMD_LOAD_LANE (fun a o i -> (v128_load64_lane (opt a 3)) o i) }
309317
| (ixx as t)".store"(mem_size as sz)
310318
{ if t = "i32" && sz = "32" then error lexbuf "unknown operator";
311319
STORE (fun a o ->

interpreter/text/parser.mly

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ let inline_type_explicit (c : context) x ft at =
204204
%token NOP DROP BLOCK END IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE
205205
%token CALL CALL_INDIRECT RETURN
206206
%token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET
207-
%token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
207+
%token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT SIMD_LOAD_LANE
208208
%token SPLAT EXTRACT_LANE REPLACE_LANE SHIFT SHUFFLE
209209
%token CONST V128_CONST UNARY BINARY TERNARY TEST COMPARE CONVERT
210210
%token UNREACHABLE MEMORY_SIZE MEMORY_GROW
@@ -232,6 +232,7 @@ let inline_type_explicit (c : context) x ft at =
232232
%token<Ast.instr'> COMPARE
233233
%token<Ast.instr'> CONVERT
234234
%token<int option -> Memory.offset -> Ast.instr'> LOAD
235+
%token<int option -> Memory.offset -> int -> Ast.instr'> SIMD_LOAD_LANE
235236
%token<Ast.instr'> SPLAT
236237
%token<int -> Ast.instr'> EXTRACT_LANE
237238
%token<int -> Ast.instr'> REPLACE_LANE
@@ -385,6 +386,7 @@ plain_instr :
385386
| GLOBAL_GET var { fun c -> global_get ($2 c global) }
386387
| GLOBAL_SET var { fun c -> global_set ($2 c global) }
387388
| LOAD offset_opt align_opt { fun c -> $1 $3 $2 }
389+
| SIMD_LOAD_LANE offset_opt align_opt NAT { let at = at () in fun c -> $1 $3 $2 (simd_lane_index $4 at) }
388390
| STORE offset_opt align_opt { fun c -> $1 $3 $2 }
389391
| MEMORY_SIZE { fun c -> memory_size }
390392
| MEMORY_GROW { fun c -> memory_grow }

interpreter/valid/valid.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,14 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
307307
check_memop c memop (Lib.Option.map fst) e.at;
308308
[I32Type] --> [memop.ty]
309309

310+
| SimdLoadLane (memop, i) ->
311+
check_memop c memop (fun o -> o) e.at;
312+
(match memop.sz with
313+
| Some pack_size ->
314+
require (i < 16 / packed_size pack_size) e.at "invalid lane index";
315+
[I32Type; V128Type] --> [memop.ty]
316+
| _ -> assert false)
317+
310318
| Store memop ->
311319
check_memop c memop (fun sz -> sz) e.at;
312320
[I32Type; memop.ty] --> []

test/core/simd/meta/gen_tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
'simd_f32x4_pmin_pmax',
3232
'simd_f64x2_pmin_pmax',
3333
'simd_i32x4_dot_i16x8',
34+
'simd_load_lane',
3435
)
3536

3637

test/core/simd/meta/simd.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def const(value, value_type):
2222
value: constant data, string or list,
2323
lane_type: lane type, [i32, i64, f32, f64]
2424
"""
25-
return SIMD.CONST.format(value_type=value_type, value=''.join(value))
25+
return SIMD.CONST.format(value_type=value_type, value=''.join(str(value)))
2626

2727
@staticmethod
2828
def v128_const(value, lane_type):
@@ -81,4 +81,4 @@ def v128_const(value, lane_type):
8181
data_elem = ' '.join(data_elem)
8282

8383
# Returns v128 constant text
84-
return SIMD.V128_CONST.format(lane_type=lane_type, value=data_elem)
84+
return SIMD.V128_CONST.format(lane_type=lane_type, value=data_elem)

0 commit comments

Comments
 (0)