base64¶
A drop-in fast path for standard base64 (StdEncoding, padded), byte- and
error-identical to encoding/base64. Both encode and decode run a SIMD kernel
generated by go-asmgen; the short tail +
padding (and, on decode, any block with an invalid byte) reuse the standard
library, so output and every CorruptInputError offset match exactly.
Repository →
API¶
s := base64.EncodeToString(data) // same bytes as encoding/base64.StdEncoding
b, err := base64.DecodeString(s) // same bytes + same error/offset as stdlib
| op | amd64 | arm64 | ppc64le | s390x | loong64 / riscv64 |
|---|---|---|---|---|---|
| encode | AVX2 + SSE2 (Lemire) | NEON (VLD3/VST4 deinterleaving I/O) |
VSX (shift-based) | vector facility (shift-based) | scalar (stdlib) |
| decode | AVX2 + SSE (Muła) | NEON (shift-based) | VSX (shift-based) | vector facility (shift-based) | scalar (stdlib) |
Algorithm¶
The encoder is Lemire's vectorised base64: a shuffle spreads the input across
24-bit lanes, two multiplies pull out the 6-bit indices, and a PSHUFB / TBL
offset-LUT maps each to its ASCII byte (constants via go-asmgen's
emit.File.Data). The amd64 path uses the multiply trick; arm64, ppc64le and
s390x use a shift-based variant (VSRW/VESRLF index extraction), since those
ISAs lack the integer vector multiply amd64 relies on. All six 64-bit targets are
covered: AVX2/SSE2 on amd64, NEON on arm64, VSX on ppc64le, the vector
facility on s390x (big-endian), and a scalar fallback on loong64/riscv64. On
s390x the VPERM control vectors use big-endian lane numbering (lane 0 =
lowest address) and were verified to produce byte-identical output. arm64 uses
the aklomp/emmansun deinterleaving-I/O design (VLD3.P / VST4.P), which needs
no integer vector multiply and so builds on released Go. Decode is now SIMD too
(amd64 Muła AVX2/SSE; NEON/VSX/vector-facility on arm64/ppc64le/s390x), with the
CorruptInputError offset of any invalid block matching encoding/base64 exactly.
Performance¶
Encode throughput, 1 MiB buffer, native amd64 (GitHub Actions, AMD EPYC
7763, GOAMD64=v1, -count=6, median MB/s — CI-measured because the dev box is
arm64):
| implementation | kind | MB/s | vs stdlib |
|---|---|---|---|
encoding/base64 (stdlib) |
scalar | ~1180 | 1.0× |
cristalhq/base64 |
pure-Go scalar | ~2650 | 2.2× |
emmansun/base64 |
pure-Go SIMD (AVX2) | ~19300 | ~16× |
| this package | pure-Go SIMD (AVX2) | ~20500 | ~17× |
This package leads emmansun/base64 by ~5–6% (confirmed across CI reruns) —
notable, since emmansun is the mature reference. The edge came from a
cycle-model-guided optimization: llvm-mca showed the kernel was
shuffle-port (Zn3FP1) bound; disassembling emmansun revealed a -4-offset
32-byte load that spreads with a single VPSHUFB (no cross-lane
VINSERTI128). Combining that load with this package's 2× unroll was predicted
at 2.15 cyc/block (vs emmansun's 2.20) and the benchmark confirmed it. (Block 0
keeps VINSERTI128 — a -4 load there would read before src.)
- arm64: NEON
VLD3/VST4deinterleaving-I/O encode kernel on released Go — ~8× stdlib, tiesemmansun/base64(~22 GB/s); decode is a NEON shift-based kernel. - ppc64le: VSX SIMD encode and decode, natively measured on real POWER9 (GCC Compile Farm, Go 1.26.4, 2026-06-26): encode ~2.1× stdlib (1613 vs 782 MB/s), decode ~2.0× (2090 vs 1057 MB/s; decode also beats emmansun).
- s390x: vector-facility SIMD encode+decode kernels, natively measured on
real IBM z15 (VXE2) (2026-07-03,
-count=6): ~3.7–4.2× stdlib on buffers ≥1 KiB; the scalar fallback wins at ≤16-byte small inputs (dispatch - non-vectorised tail dominate there).
- decode is now SIMD on amd64/arm64/ppc64le/s390x — beats emmansun decode on amd64 (~1.3×); scalar on loong64/riscv64.
- cgo wrappers of
aklomp/base64are faster still but need a C toolchain — excluded from this pure-Go comparison.
Coverage¶
100% of the Go code on every arch job (native amd64 + native arm64, plus QEMU
jobs for ppc64le, s390x and riscv64). The generated .s kernels are validated by
differential tests against encoding/base64 plus FuzzEncode — on a real AVX2
box for amd64/arm64, and under qemu-user for the VSX and big-endian
vector-facility kernels. BSD-3-Clause.