silk.simd.aarch64.
AArch64 NEON instructions that the portable silk.simd.simd operations do not express: table
lookups, dot products, pairwise sums, and AES round steps.
When to use#
Use this module in kernels such as UTF-8 validation, base64 decoding, and checksums, 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 CPU feature that instruction
needs. When the build targets AArch64 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. Every AArch64 build has NEON; the dot products need the dotprod
feature, and the AES steps the aes feature.
Examples#
Look up bytes in a table#
import silk.simd.aarch64
import silk.simd.u8x16
pub fn main() -> i32 {
let squares = u8x16.fromArray([0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225])
let picked = aarch64.tableLookup(squares, u8x16.splat(12))
if u8x16.extract(picked, 0) != 144 || u8x16.extract(aarch64.tableLookup(squares, u8x16.splat(16)), 0) != 0 {
return 1
}
return 0
}Import as aarch64 with import silk.simd.aarch64 as aarch64.
Public declarations: 14.
tableLookup#
pub fn tableLookup(table: simd<u8, 16>, indices: simd<u8, 16>) -> simd<u8, 16>tbl (NEON): lane i is table[indices[i]], or 0 when indices[i] is 16 or more.
Every AArch64 build has NEON, so on AArch64 it compiles to this one instruction. On another target it computes the same lanes with portable code, which is correct but slower.
dotProduct#
pub fn dotProduct(sum: simd<u32, 4>, left: simd<u8, 16>, right: simd<u8, 16>) -> simd<u32, 4>udot (dotprod): lane i of sum plus the products of bytes 4 * i to 4 * i + 3 of
left and right, wrapping.
When the build targets AArch64 with the dotprod feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
dotProductSigned#
pub fn dotProductSigned(sum: simd<i32, 4>, left: simd<i8, 16>, right: simd<i8, 16>) -> simd<i32, 4>sdot (dotprod): lane i of sum plus the products of signed bytes 4 * i to 4 * i + 3 of
left and right, wrapping.
When the build targets AArch64 with the dotprod feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
pairwiseAdd8#
pub fn pairwiseAdd8(left: simd<u8, 16>, right: simd<u8, 16>) -> simd<u8, 16>addp (NEON): the wrapping sums of adjacent lane pairs of left, then of right.
Every AArch64 build has NEON, so on AArch64 it compiles to this one instruction. On another target it computes the same lanes with portable code, which is correct but slower.
pairwiseAdd16#
pub fn pairwiseAdd16(left: simd<u16, 8>, right: simd<u16, 8>) -> simd<u16, 8>addp (NEON): the wrapping sums of adjacent sixteen-bit lane pairs of left, then of right.
Every AArch64 build has NEON, so on AArch64 it compiles to this one instruction. On another target it computes the same lanes with portable code, which is correct but slower.
pairwiseAdd32#
pub fn pairwiseAdd32(left: simd<u32, 4>, right: simd<u32, 4>) -> simd<u32, 4>addp (NEON): the wrapping sums of adjacent 32-bit lane pairs of left, then of right.
Every AArch64 build has NEON, so on AArch64 it compiles to this one instruction. On another target it computes the same lanes with portable code, which is correct but slower.
aesEncrypt#
pub fn aesEncrypt(state: simd<u8, 16>, key: simd<u8, 16>) -> simd<u8, 16>aese (AES): key added to state, then ShiftRows and SubBytes. An encryption round is
aesMixColumns of this result.
When the build targets AArch64 with the aes feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
aesDecrypt#
pub fn aesDecrypt(state: simd<u8, 16>, key: simd<u8, 16>) -> simd<u8, 16>aesd (AES): key added to state, then InvShiftRows and InvSubBytes.
When the build targets AArch64 with the aes feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
aesMixColumns#
pub fn aesMixColumns(state: simd<u8, 16>) -> simd<u8, 16>aesmc (AES): AES MixColumns.
When the build targets AArch64 with the aes feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
aesInverseMixColumns#
pub fn aesInverseMixColumns(state: simd<u8, 16>) -> simd<u8, 16>aesimc (AES): AES InvMixColumns.
When the build targets AArch64 with the aes feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
sha256Hash#
pub fn sha256Hash(abcd: simd<u32, 4>, efgh: simd<u32, 4>, wk: simd<u32, 4>) -> simd<u32, 4>sha256h (SHA2): four SHA-256 rounds over A..D in abcd and E..H in efgh, with the
four message words plus round constants in wk. Returns the new A..D.
When the build targets AArch64 with the sha2 feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
sha256Hash2#
pub fn sha256Hash2(efgh: simd<u32, 4>, abcd: simd<u32, 4>, wk: simd<u32, 4>) -> simd<u32, 4>sha256h2 (SHA2): the same four rounds as sha256Hash, with efgh first, returning
the new E..H. Pass the A..D from before sha256Hash.
When the build targets AArch64 with the sha2 feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
sha256ScheduleUpdate0#
pub fn sha256ScheduleUpdate0(left: simd<u32, 4>, right: simd<u32, 4>) -> simd<u32, 4>sha256su0 (SHA2): the first step of the next four SHA-256 message words. With W[0..3]
in left and W[4] in lane 0 of right, lane i is W[i] + sigma0(W[i + 1]).
When the build targets AArch64 with the sha2 feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
sha256ScheduleUpdate1#
pub fn sha256ScheduleUpdate1(partial: simd<u32, 4>, middle: simd<u32, 4>, last: simd<u32, 4>) -> simd<u32, 4>sha256su1 (SHA2): the next four message words W[16..19], from the
sha256ScheduleUpdate0 result partial, W[8..11] in middle and W[12..15] in last.
When the build targets AArch64 with the sha2 feature, it compiles to this one instruction.
Otherwise it computes the same lanes with portable code, which is correct but slower.
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.