Skip to content

Port SIMD from wide to fearless_simd for better performance, less unsafe - #41

Draft
Shnatsel wants to merge 13 commits into
vstroebel:mainfrom
Shnatsel:fearless-simd
Draft

Shnatsel wants to merge 13 commits into
vstroebel:mainfrom
Shnatsel:fearless-simd

Conversation

@Shnatsel

@Shnatsel Shnatsel commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Replace portable SIMD code derived from scalar code using wide with portable SIMD code derived from existing AVX2 codepaths using fearless_simd.

Add portable SIMD YCbCr conversions.

Motivation

  • Safety (fearless_simd is very light on unsafe, an order of magnitude less than other crates)
  • Performance (see below)
  • Unifying image around a single SIMD library, right now it pulls in every SIMD crate under the sun

Safety

~10x reduction in unsafe with --all-features (no_std support), ~20x reduction with std and use_wide features:

cargo-geiger outputs

jpeg-encoder (main)> cargo geiger --all-features

Metric output format: x/y
    x = unsafe code used by the build
    y = total unsafe code found in the crate

Symbols:
    🔒  = No `unsafe` usage found, declares #![forbid(unsafe_code)]
    ❓  = No `unsafe` usage found, missing #![forbid(unsafe_code)]
    ☢️   = `unsafe` usage found


Functions  Expressions  Impls  Traits  Methods  Dependency

0/0        7/7          0/0    0/0     0/0      ☢️  jpeg-encoder 0.8.0
18/18      356/434      153/156 9/9     0/1      ☢️  ├── bytemuck 1.25.2
0/0        0/0          0/0    0/0     0/0      ❓ └── wide 1.7.1
18/18      356/434      153/156 9/9     0/1      ☢️      ├── bytemuck 1.25.2
0/0        835/2861     27/27  0/0     0/0      ☢️      └── safe_arch 1.2.0
18/18      356/434      153/156 9/9     0/1      ☢️          └── bytemuck 1.25.2

18/18      1198/3302    180/183 9/9     0/1
jpeg-encoder (fearless_simd)> cargo geiger --all-features

Metric output format: x/y
    x = unsafe code used by the build
    y = total unsafe code found in the crate

Symbols:
    🔒  = No `unsafe` usage found, declares #![forbid(unsafe_code)]
    ❓  = No `unsafe` usage found, missing #![forbid(unsafe_code)]
    ☢️   = `unsafe` usage found


Functions  Expressions  Impls  Traits  Methods  Dependency

0/0        7/7          0/0    0/0     0/0      ☢️  jpeg-encoder 0.8.0
0/0        49/100       51/51  1/1     0/0      ☢️  └── fearless_simd 1.1.0
5/5        69/69        0/0    0/0     0/0      ☢️      └── libm 0.2.16

5/5        125/176      51/51  1/1     0/0

Performance

FDCT:

  • portable AVX2 is on par with handwritten AVX2.
  • AVX-512 is 20% faster (higher throughput) than handwritten AVX2. Making full use of the extra width will require processing two blocks at once which is not done in this PR
  • SSE4.2 and SSE2 improve throughput by 37%
  • ARM NEON improves throughput by 20%

YCbCr:

  • portable AVX2 is 2x faster than handwritten AVX2 thanks to SIMD swizzles that can be conveniently expressed in portable SIMD. Handwritten AVX2 uses scalar loads.
  • AVX-512 is ~4x faster than handwritten AVX2 thanks to a dedicated wider codepath and better swizzle instructions.
  • SSE4.2 is 2x to 2.5x faster than before
  • ARM NEON is unchanged for RGB (already autovectorized well), but 1.8x improvement for RGBA

Fearless SIMD uses AVX-512 only on machines where it doesn't cause performance issues (downclocking), so there should be no drawback to enabling it. If jpeg_encoder users have to disable certain instruction sets for their build for any reason, Fearless SIMD supports that.

Correctness

This was verified on random inputs against the scalar reference. The same testing found a bug in handwritten AVX2 code: #40

Stability

I remember stability was a concern when adopting wide. Fearless SIMD is v1.0 and has an explicit security backport policy, so it should be as good as or better than wide in this regard.

Status

I believe this is complete, but I am marking it as draft until linebender/fearless_simd#415 lands and ships in a stable release.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant