Skip to content

perf(decoding): SIMD HUF decode kernels with runtime CPU dispatch #66

Description

@polaz

Problem

Our Huffman decode path in zstd/src/huff0/huff0_decoder.rs and zstd/src/decoding/literals_section_decoder.rs is scalar/table-driven only. The donor uses specialized decode loops and arch dispatch in lib/decompress/huf_decompress.c and lib/decompress/huf_decompress_amd64.S to reduce branch and memory stalls.

This leaves a material decode-speed gap on literal-heavy corpora.

Goal

Add architecture-specialized Huffman decode kernels with runtime CPU dispatch, covering x86-64 and ARM targets, while preserving the current safe scalar fallback.

Implementation plan

Core abstraction

  1. Introduce internal decode-kernel abstraction (scalar, x86 BMI2, x86 SIMD, ARM NEON).
  2. Add runtime selection once per decoder initialization via `std::arch::is_x86_feature_detected!` / `std::arch::is_aarch64_feature_detected!`.
  3. Keep exact bitstream semantics and error behavior parity with the scalar path.

x86-64 kernels

  1. BMI2 kernel: `bzhi`/`pext` for bit extraction in Huffman symbol decode loop.
  2. AVX2 kernel: Vectorized 4-stream interleaved decode — process 4×8 symbols per iteration with gather/scatter table lookups.
  3. AVX-512 VBMI2 kernel (Ice Lake+): Use `vpcompressb`/`vpexpandb` for variable-length bit extraction on 64 symbols in parallel. This is the highest-impact x86 optimization — C zstd v1.5.6+ shows 4-8x Huffman throughput gain with VBMI2 on literal-heavy blocks.

ARM kernels

  1. NEON kernel: `vld1q_u8` + table lookup via `vqtbl1q_u8` for 16 symbols per iteration. NEON is baseline on all AArch64, so this becomes the default ARM fast path.
  2. SVE/SVE2 kernel (Graviton 3+, Apple M4+): Scalable vector width (128-2048 bit) enables processing variable numbers of symbols per iteration with predicated loads. Lower priority — NEON covers most ARM hardware.

Testing & benchmarks

  1. Add corpus benchmarks focused on literals-heavy blocks and mixed blocks, per-kernel.
  2. Gate unsafe/SIMD code behind feature/cfg checks with deterministic fallback.
  3. Cross-validate byte-exact output across all kernels.

Acceptance criteria

  • x86_64 builds use specialized HUF decode kernel when CPU features are available (BMI2 → AVX2 → VBMI2 cascade).
  • AArch64 builds use NEON kernel by default.
  • Byte-exact output parity with scalar path and C zstd on existing interop suites.
  • No regressions on non-x86/non-ARM targets (scalar fallback remains default).
  • Benchmarks show measurable decode throughput gain on literals-heavy workloads.
  • Runtime dispatch adds zero overhead to per-symbol decode (resolved once at init).

Performance expectations

  • BMI2 kernel: ~1.3-1.5x over scalar
  • AVX2 kernel: ~2-3x over scalar
  • VBMI2 kernel: ~4-8x over scalar (on Ice Lake+)
  • NEON kernel: ~1.5-2x over scalar

Dependencies

Estimate

4d (BMI2 + AVX2 + NEON: 2d 4h, VBMI2 + SVE: 1d 4h)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2-mediumMedium priority — important improvementenhancementNew feature or requestperformancePerformance optimization

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions