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

Commit

Permalink
Rename LaneIdx{2,4,8,16,32} to ImmLaneIdx{2,4,8,16,32} (#34)
Browse files Browse the repository at this point in the history
* Rename LaneIdx{2,4,8,16,32} to ImmLaneIdx{2,4,8,16,32}

This makes it clear everywhere that `ImmLaneIdx` is an immediate operand and also makes the nomenclature for immediate operands consistent (both `ImmByte` and `ImmLaneIdx`  start with the prefix `Imm`) .

See #33 .

* further clarify the representation hierarchies and immediate mode operands

* memarg is an immediate mode argument

* reference scalar load/stores spec

* Fix typo: floating-point value to integer-value

* Fix memarg

* Fix language in replace value

* Update "hierarchy" of types paragraph
  • Loading branch information
gnzlbg authored and dtig committed Dec 17, 2018
1 parent 81081fe commit 324cfa1
Showing 1 changed file with 68 additions and 42 deletions.
110 changes: 68 additions & 42 deletions proposals/simd/SIMD.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ of immediate operands used by the SIMD instructions.

## SIMD value type

The `v128` value type has a concrete mapping to a 128-bit representation with bits
numbered 0–127. The `v128` type corresponds to a vector register in a typical
SIMD ISA. The interpretation of the 128 bits in the vector register is provided
by the individual instructions. When a `v128` value is represented as 16 bytes,
bits 0-7 go in the first byte with bit 0 as the LSB, bits 8-15 go in the second
byte, etc.
The `v128` value type is the _only_ type introduced in this extension. It has a
concrete mapping to a 128-bit representation with bits numbered 0–127. The
`v128` type corresponds to a vector register in a typical SIMD ISA. The
interpretation of the 128 bits in the vector register is provided by the
individual instructions. When a `v128` value is represented as 16 bytes, bits
0-7 go in the first byte with bit 0 as the LSB, bits 8-15 go in the second byte,
etc.

## Immediate operands

Expand All @@ -27,17 +28,32 @@ encoded as individual bytes in the binary encoding. Many have a limited valid
range, and it is a validation error if the immediate operands are out of range.

* `ImmByte`: A single unconstrained byte (0-255).
* `LaneIdx2`: A byte with values in the range 0–1 identifying a lane.
* `LaneIdx4`: A byte with values in the range 0–3 identifying a lane.
* `LaneIdx8`: A byte with values in the range 0–7 identifying a lane.
* `LaneIdx16`: A byte with values in the range 0–15 identifying a lane.
* `LaneIdx32`: A byte with values in the range 0–31 identifying a lane.
* `ImmLaneIdx2`: A byte with values in the range 0–1 identifying a lane.
* `ImmLaneIdx4`: A byte with values in the range 0–3 identifying a lane.
* `ImmLaneIdx8`: A byte with values in the range 0–7 identifying a lane.
* `ImmLaneIdx16`: A byte with values in the range 0–15 identifying a lane.
* `ImmLaneIdx32`: A byte with values in the range 0–31 identifying a lane.

## Interpreting the SIMD value type
## Operations on the SIMD value type

The single `v128` SIMD type can represent packed data in multiple ways.
Instructions specify how the bits should be interpreted through a hierarchy of
*interpretations*.
The _single_ `v128` SIMD type can be used to represent different types of packed
data, e.g., it can represent four 32-bit floating point values, 8 16-bit signed
or unsigned integer values, etc.

The instructions introduced in this specification are named according to the
following schema: `{interpretation}.{operation}`. Where the `{interpretation}`
prefix denotes how the bytes of the `v128` type are interpreted by the `{operation}`.

For example, the instructions `f32x4.extract_lane` and `i64x2.extract_lane`
perform the same semantic operation: extracting the scalar value of a vector
lane. However, the `f32x4.extract_lane` instruction returns a 32-bit wide
floating point value, while the `i64x2.extract_lane` instruction returns a
64-bit wide integer value.

The `v128` vector type interpretation interprets the vector as a bag of bits.
The `v{lane_width}x{n}` interpretations (e.g. `v32x4`) interpret the vector as
`n` lanes of `lane_width` bits. The `{t}{lane_width}x{n}` interpretations (e.g.
`i32x4` or `f32x4`) interpret the vector as `n` lanes of type `{t}{lane_width}`.

### Lane division interpretation

Expand Down Expand Up @@ -162,7 +178,7 @@ The setter of the value attribute of Global will throw a [`TypeError`](https://t

The SIMD operations described in this sections are generally named
`S.Op`, where `S` is either a SIMD type or one of the interpretations
of a SIMD type.
of a SIMD type. Immediate mode operands are prefixed with `imm`.

Many operations are simply the lane-wise application of a scalar operation:

Expand Down Expand Up @@ -197,9 +213,9 @@ def S.lanewise_comparison(func, a, b):
### Constant
* `v128.const(imm: ImmByte[16]) -> v128`

Materialize a constant SIMD value from the immediate operands. The `v128.const`
instruction is encoded with 16 immediate bytes which provide the bits of the
vector directly.
Materialize a constant `v128` SIMD value from the 16 immediate bytes in the
immediate mode operand `imm` . The `v128.const` instruction is encoded with 16
immediate bytes which provide the bits of the vector directly.

### Create vector with identical lanes
* `i8x16.splat(x: i32) -> v128`
Expand All @@ -222,16 +238,18 @@ def S.splat(x):
## Accessing lanes

### Extract lane as a scalar
* `i8x16.extract_lane_s(a: v128, i: LaneIdx16) -> i32`
* `i8x16.extract_lane_u(a: v128, i: LaneIdx16) -> i32`
* `i16x8.extract_lane_s(a: v128, i: LaneIdx8) -> i32`
* `i16x8.extract_lane_u(a: v128, i: LaneIdx8) -> i32`
* `i32x4.extract_lane(a: v128, i: LaneIdx4) -> i32`
* `i64x2.extract_lane(a: v128, i: LaneIdx2) -> i64`
* `f32x4.extract_lane(a: v128, i: LaneIdx4) -> f32`
* `f64x2.extract_lane(a: v128, i: LaneIdx2) -> f64`

Extract the value of lane `i` in `a`.
* `i8x16.extract_lane_s(a: v128, imm: ImmLaneIdx16) -> i32`
* `i8x16.extract_lane_u(a: v128, imm: ImmLaneIdx16) -> i32`
* `i16x8.extract_lane_s(a: v128, imm: ImmLaneIdx8) -> i32`
* `i16x8.extract_lane_u(a: v128, imm: ImmLaneIdx8) -> i32`
* `i32x4.extract_lane(a: v128, imm: ImmLaneIdx4) -> i32`
* `i64x2.extract_lane(a: v128, imm: ImmLaneIdx2) -> i64`
* `f32x4.extract_lane(a: v128, imm: ImmLaneIdx4) -> f32`
* `f64x2.extract_lane(a: v128, imm: ImmLaneIdx2) -> f64`

Extract the scalar value of lane specified in the immediate mode operand `imm`
in `a`. The `{interpretation}.extract_lane{_s}{_u}` instructions are encoded
with one immediate byte providing the index of the lane to extract.

```python
def S.extract_lane(a, i):
Expand All @@ -242,15 +260,17 @@ The `_s` and `_u` variants will sign-extend or zero-extend the lane value to
`i32` respectively.

### Replace lane value
* `i8x16.replace_lane(a: v128, i: LaneIdx16, x: i32) -> v128`
* `i16x8.replace_lane(a: v128, i: LaneIdx8, x: i32) -> v128`
* `i32x4.replace_lane(a: v128, i: LaneIdx4, x: i32) -> v128`
* `i64x2.replace_lane(a: v128, i: LaneIdx2, x: i64) -> v128`
* `f32x4.replace_lane(a: v128, i: LaneIdx4, x: f32) -> v128`
* `f64x2.replace_lane(a: v128, i: LaneIdx2, x: f64) -> v128`

Return a new vector with lanes identical to `a`, except for lane `i` which has
the value `x`.
* `i8x16.replace_lane(a: v128, imm: ImmLaneIdx16, x: i32) -> v128`
* `i16x8.replace_lane(a: v128, imm: ImmLaneIdx8, x: i32) -> v128`
* `i32x4.replace_lane(a: v128, imm: ImmLaneIdx4, x: i32) -> v128`
* `i64x2.replace_lane(a: v128, imm: ImmLaneIdx2, x: i64) -> v128`
* `f32x4.replace_lane(a: v128, imm: ImmLaneIdx4, x: f32) -> v128`
* `f64x2.replace_lane(a: v128, imm: ImmLaneIdx2, x: f64) -> v128`

Return a new vector with lanes identical to `a`, except for the lane specified
in the immediate mode operand `imm` which has the value `x`. The
`{interpretation}.replace_lane` instructions are encoded with an immediate byte
providing the index of the lane the value of which is to be replaced.

```python
def S.replace_lane(a, i, x):
Expand All @@ -265,9 +285,13 @@ The input lane value, `x`, is interpreted the same way as for the splat
instructions. For the `i8` and `i16` lanes, the high bits of `x` are ignored.

### Shuffle lanes
* `v8x16.shuffle(a: v128, b: v128, s: LaneIdx32[16]) -> v128`
* `v8x16.shuffle(a: v128, b: v128, imm: ImmLaneIdx32[16]) -> v128`

Create vector with lanes selected from the lanes of two input vectors:
Returns a new vector with lanes selected from the lanes of the two input vectors
`a` and `b` specified in the 16 byte wide immediate mode operand `imm`. This
instruction is encoded with 16 bytes providing the indices of the elements to
return. The indices `i` in range `[0, 15]` select the `i`-th element of `a`. The
indices in range `[16, 31]` select the `i - 16`-th element of `b`.

```python
def S.shuffle(a, b, s):
Expand Down Expand Up @@ -612,8 +636,10 @@ def S.ne(a, b):

Load and store operations are provided for the `v128` vectors. The memory
operations take the same arguments and have the same semantics as the existing
scalar WebAssembly load and store instructions. The difference is that the
memory access size is 16 bytes which is also the natural alignment.
scalar WebAssembly load and store instructions (see
[memarg](https://webassembly.github.io/spec/core/bikeshed/index.html#syntax-memarg).
The difference is that the memory access size is 16 bytes which is also the
natural alignment.

### Load

Expand Down

0 comments on commit 324cfa1

Please sign in to comment.