Browse the docs

silk.simd.wasm.

WebAssembly SIMD instructions that the portable silk.simd.simd operations do not express: byte swizzles, dot products, and saturating narrows.

When to use#

Use this module in kernels such as UTF-8 validation and base64 decoding, where one of these instructions replaces several portable steps. Use silk.simd.simd for everything else.

Details#

Each function names the instruction it stands for and the feature that instruction needs. When the build targets wasm32 with that feature, the function compiles to the one instruction. Otherwise it computes the same lanes with portable code, which is correct on every target but slower. WebAssembly cannot detect features at run time, so a module built without simd128 always uses the portable code.

Examples#

Swizzle bytes#

silk
import silk.simd.wasm
import silk.simd.u8x16

pub fn main() -> i32 {
  let lanes = u8x16.fromArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
  let picked = wasm.swizzle(lanes, u8x16.splat(7))
  if u8x16.extract(picked, 9) != 7 || u8x16.extract(wasm.swizzle(lanes, u8x16.splat(99)), 0) != 0 {
    return 1
  }
  return 0
}

Import as wasm with import silk.simd.wasm as wasm.

Public declarations: 5.

swizzle#

silk
pub fn swizzle(table: simd<u8, 16>, indices: simd<u8, 16>) -> simd<u8, 16>

i8x16.swizzle (simd128): lane i is table[indices[i]], or 0 when indices[i] is 16 or more.

When the build targets wasm32 with the simd128 feature, it compiles to this one instruction. Otherwise it computes the same lanes with portable code, which is correct but slower. WebAssembly cannot detect features at run time.

relaxedSwizzle#

silk
pub fn relaxedSwizzle(table: simd<u8, 16>, indices: simd<u8, 16>) -> simd<u8, 16>

i8x16.relaxed_swizzle (relaxed-simd): lane i is table[indices[i]] when indices[i] is below 16. A lane whose index is 16 or more is unspecified and may differ between engines; the portable code makes it 0. Use swizzle when such a lane must be 0.

When the build targets wasm32 with the relaxed-simd feature, it compiles to this one instruction. Otherwise it computes the same lanes with portable code, which is correct but slower. WebAssembly cannot detect features at run time.

dot#

silk
pub fn dot(left: simd<i16, 8>, right: simd<i16, 8>) -> simd<i32, 4>

i32x4.dot_i16x8_s (simd128): each lane of left times that of right, with each adjacent pair of products summed into one i32 lane. The sum wraps only for four lanes of -32768.

When the build targets wasm32 with the simd128 feature, it compiles to this one instruction. Otherwise it computes the same lanes with portable code, which is correct but slower. WebAssembly cannot detect features at run time.

narrowUnsigned#

silk
pub fn narrowUnsigned(left: simd<i16, 8>, right: simd<i16, 8>) -> simd<u8, 16>

i8x16.narrow_i16x8_u (simd128): the lanes of left, then of right, each clamped to 0..=255.

When the build targets wasm32 with the simd128 feature, it compiles to this one instruction. Otherwise it computes the same lanes with portable code, which is correct but slower. WebAssembly cannot detect features at run time.

narrowSigned#

silk
pub fn narrowSigned(left: simd<i16, 8>, right: simd<i16, 8>) -> simd<i8, 16>

i8x16.narrow_i16x8_s (simd128): the lanes of left, then of right, each clamped to the i8 range.

When the build targets wasm32 with the simd128 feature, it compiles to this one instruction. Otherwise it computes the same lanes with portable code, which is correct but slower. WebAssembly cannot detect features at run time.

Category: SIMD.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.

View the source of this page