go-simd documentation¶
Pure-Go SIMD drop-ins for the Go standard library — byte-identical fast
paths for encoding/base64, encoding/base32, encoding/hex,
encoding/ascii85, unicode/utf8, hash/adler32, hash/crc32, hash/crc64,
strconv, encoding/json.Valid, ASCII case folding, and the SIMD-amenable
primitives under and around them — 21 repositories in all, plus a
proof-of-concept 7th (wasm-SIMD v128) target for matchlen in
matchlen-wasm (not a kernel
package with a docs page of its own).
Every hot loop is real SIMD assembly generated by
go-asmgen across all six of Go's
64-bit SIMD targets — amd64, arm64, riscv64, loong64, ppc64le (VSX) and
s390x (vector facility, big-endian) — on plain go build, CGO_ENABLED=0,
stable Go, no GOEXPERIMENT. Each package is a drop-in: the same signatures and
byte-identical output (and, where applicable, byte-identical errors) as
the stdlib package it accelerates, with the short tail delegated back to the
standard library so results match exactly.
Six SIMD targets, validated on seven architectures. A single
go-asmgen builder (v0.5.0) over a shared ABI0 layout emits the
kernels for all six targets; cmd/asm encodes them. As of 2026-06,
ppc64le (real POWER9), riscv64 (real SpacemiT X60, RVV 1.0) and loong64 (real
Loongson 3A5000) are natively measured on the
GCC Compile Farm — not just qemu-validated — and the
portable scalar fallback is additionally build+test-validated on a seventh arch,
ppc64 (big-endian), on real POWER9. Most repos are now natively measured
on real IBM z15 (VXE2, 2026-07-03, -count=6) — the vector-facility kernels
post clear wins (bitpack ~34×, streamvbyte decode ~20×, hex encode ~18×,
matchlen ~9.2×, crc64 ~9.1×). Two repos — jsonvalidate and ascii85 — still
carry the older qemu-validated-for-correctness framing, native z15 throughput
pending for those two. Headline numbers come from native measurement and are
never extrapolated. Two results stand out: base32 gets real SIMD on ppc64le
(VSRH) and s390x (VMLHH) where the arm64 NEON port could not on stable Go
(Go's arm64 assembler gained the register-variable shift and integer vector
multiply only in Go 1.27), and every kernel is bit-exact on big-endian s390x —
a genuine cross-endian validation.
The honesty policy¶
These numbers are benchmarked, not hand-waved. Every page reports the honest headline — the wins and the parities and the cases where SIMD genuinely does not help. A multi-table scalar loop that beats the vector unit (histogram), or a checksum that lands ~7% behind the best competitor (adler32), is reported as such. The credibility is the honesty.
Stdlib drop-ins¶
| Package | Accelerates | Honest headline |
|---|---|---|
base64 |
encoding/base64 |
encode ~17× stdlib; beats emmansun/base64 ~5–6% |
base32 |
encoding/base32 |
encode ~7.9× stdlib (AVX2); real SIMD on ppc64le VSRH + s390x VMLHH where arm64 can't; no prior pure-Go SIMD base32 |
hex |
encoding/hex |
beats tmthrgd/go-hex both ways — encode 20.4×, decode 6.24× stdlib |
utf8 |
unicode/utf8 |
Valid ~19× stdlib, edges stuartcarnie/go-simd ~3.5% |
ascii85 |
encoding/ascii85 |
first SIMD ascii85, SIMD encode and decode on all 6 arches; arm64 NEON kernel on Go 1.27 (~3.0×; fused-scalar ~1.9× on stable Go ≤ 1.26); native ppc64le POWER9 ~2.9×, riscv64 X60 ~4.0×, loong64 ~4.3× |
ascii |
ASCII case (bytes/strings) |
branchless vector case-fold, byte-identical to stdlib; real SIMD on all 6 arches incl. arm64; ~4.9× stdlib (ToUpper) |
adler32 |
hash/adler32 |
~12–14× stdlib, but ~7% behind mhr3/adler32-simd — honest |
crc64 |
hash/crc64 |
first pure-Go SIMD crc64 (CLMUL folding); arm64 ~4.2× stdlib |
crc32 |
hash/crc32 |
arm64-only, deliberately: stdlib IEEE path is already hardware-assisted elsewhere; PMULL/PMULL2 fold-by-eight beats arm64's serial CRC32X |
strconv |
strconv (base-10 parse + ParseFloat) |
ParseInt/Atoi ~2.2–2.7×; added SIMD ParseFloat (~1.1–1.36×); never regresses |
jsonvalidate |
encoding/json.Valid |
byte-identical verdict; only SIMD JSON validator on 6 arches; ~1.4× on string-heavy JSON (number/structure-heavy stays scalar) |
Primitives¶
| Package | Accelerates | Honest headline |
|---|---|---|
matchlen |
LZ match-finder | ~10× scalar (NEON); real SIMD on all 6 arches; native ppc64le POWER9 ~6.3×, riscv64 X60 ~5.8×, loong64 ~11.4× |
bitpack |
FastPFOR / simdcomp | ~21–32× scalar — byte-exact vs Lemire's simdcomp; native ppc64le POWER9 Pack ~7.0× / Unpack ~11.3× |
popcount |
Hamming weight over []byte |
size-dependent: ~9–12× in-cache, memory-bound out-of-cache; native loong64 ~6.1×, ppc64le POWER9 ~2.9× |
histogram |
byte-value histogram | multi-table scalar — SIMD doesn't help (no scatter) |
streamvbyte |
Stream VByte uint32 codec |
first Go port on all 6 arches; full codec — SIMD encode and decode, decode arm64 ~10×; native ppc64le POWER9 ~11.6×, riscv64 X60 ~4.5×, loong64 ~11.8× |
xxhash |
XXH3-64 | first Go XXH3 on all 6 arches, bit-exact; honest: zeebo faster on arm64 — but riscv64 RVV ~2.5–3.5× zeebo and ppc64le ~0.91× on real silicon (zeebo has no kernel there) |
floats |
float32/64 reductions (vector search) | only pure-Go full vector-search API on all 6 arches; arm64 ~2× scalar; native ppc64le POWER9 f32 ~1.55–1.61× (f64 routes to gc-autovectorized scalar — honest) |
bitset |
bulk []uint64 set ops |
SIMD And/Or/AndNot/Xor + fused Count; amd64 Count ~3–3.9×; logical ops bandwidth-bound (honest) |
int8dot |
int8 quantized dot (ML embeddings) | bit-exact INT8 MAC; amd64 AVX2 ~4×; arm64 NEON on Go 1.27 (~2.4×, scalar below); native riscv64 X60 ~9.1× (biggest RVV win), loong64 ~8.9×, ppc64le POWER9 ~4.1× |
levenshtein |
edit distance | Myers bit-parallel, 62–142× vs agnivade; honest: pure-Go bit-parallel, not vector-SIMD |
Five repos — ascii, levenshtein,
bitset, int8dot and
jsonvalidate — rounded the suite out to 20, and
crc32 makes 21. jsonvalidate
is the only SIMD JSON validator covering all six arches (byte-identical to
encoding/json.Valid); levenshtein is honestly
pure-Go bit-parallel, not vector-SIMD — its word-serial Myers column has
no lane parallelism (documented) — yet still 62–142× vs agnivade;
bitset and int8dot are vector
primitives (int8dot's arm64 NEON kernel needs Go 1.27, scalar below);
ascii runs real SIMD case-folding on arm64 too, via a
multiply-free sign-bit predicate (~4.9× stdlib); and
crc32 is the deliberate exception to the six-arch pattern
— arm64-only, since stdlib already hardware-accelerates IEEE crc32 elsewhere.
As elsewhere in the org, ppc64le, riscv64 and loong64 are now natively
measured on real silicon (GCC Compile Farm — POWER9, SpacemiT X60 RVV 1.0,
Loongson 3A5000); most repos are now natively measured on real IBM z15
(VXE2, 2026-07-03) — jsonvalidate and ascii85 are the two still pending a
follow-up z15 run — see the per-repo pages for the vector-facility speedups.
Read the methodology for the check-existing → go-asmgen →
llvm-mca → real-hardware → 100%-coverage pipeline every repo follows.
Source lives under github.com/go-simd. Assembly is generated by go-asmgen.