Skip to content

Add SSE2 backend#270

Merged
Shnatsel merged 11 commits into
linebender:mainfrom
Shnatsel:sse2-cleaned-up
Jul 18, 2026
Merged

Add SSE2 backend#270
Shnatsel merged 11 commits into
linebender:mainfrom
Shnatsel:sse2-cleaned-up

Conversation

@Shnatsel

@Shnatsel Shnatsel commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Fulfills #256

SSE2 is guaranteed to be present in the baseline on x86_64, and the Rust i686 targets also guarantee its presence. You need to use the tier-2 i586 target to opt out. So this replaces Fallback on x86 and does not bloat the binary, even on 32-bit targets.

Not having SSE4.2 is quite rare these days, but this is still useful in contexts where dynamic dispatch is expensive. For example, this unlocks access to explicit SIMD in the png crate which uses SSE2 with autovectorization without runtime dispatch, but autovectorization sometimes regresses on newer rustc versions, so explicit SIMD is desirable.

To reduce the maintenance burden, most operations on SSE2 level reuse either the SSE4.2 path or the scalar fallback. Only a few select operations get dedicated SSE2 paths. I feel those exceptions are justified because autovectorization is still quite fickle. For example, individual calls to min() and max() autovectorize into identical assembly, but without intrinsics this falls apart and turns from 8 instructions into 181 - I've even experimented with alternative formulations of the fallback level to no avail:

#[inline(always)]
fn minmax_u8<S: Simd>(
    simd: S,
    a: &[u8; 16],
    b: &[u8; 16],
    min_out: &mut [u8; 16],
    max_out: &mut [u8; 16],
) {
    let a = u8x16::from_slice(simd, a);
    let b = u8x16::from_slice(simd, b);
    a.min(b).store_slice(min_out);
    a.max(b).store_slice(max_out);
}

Shnatsel added 3 commits July 12, 2026 21:09
SSE2 is guaranteed as the baseline on x86_64, and the Rust i686 targets also guarantee its presence. You need to use the tier-2 i586 target to opt out. So this level replaces Fallback on x86 and does not bloat the binary.

To reduce the maintenance burden, most operations reuse either the SSE4.2 path or the scalar fallback. Only a few select operations get dedicated SSE2 paths.

Not having SSE4.2 is quite rare these days, but this is still useful in contexts where dynamic dispatch is expensive. For example, this immediately unlocks access to explicit SIMD in the `png` crate which uses SSE2 with autovectorization without runtime dispatch.
Comment thread CHANGELOG.md Outdated
Comment thread fearless_simd_gen/src/mk_x86.rs
@Shnatsel

Copy link
Copy Markdown
Contributor Author

I went back and forth on this a bunch, but eventually decided to add fxsr checks everywhere since it's part of the baseline for x86_64 and i686 targets, and there are some uses for those instructions inside kernel! functions.

The tier3 target is probably just misconfigured, so now we disable SIMD on it instead of making potentially unsound calls.

@LaurenzV LaurenzV left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once again mostly relying on our existing tests for correctness, but LGTM overall!

Comment thread fearless_simd_gen/src/mk_x86.rs Outdated

if *self == Self::Sse2
&& vec_ty.scalar == ScalarType::Float
&& matches!(method, "floor" | "ceil" | "round_ties_even" | "trunc")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like at some point we should introduce constants for the names... But also not for this PR.

Comment thread fearless_simd/src/generated/sse2.rs Outdated
@Shnatsel
Shnatsel enabled auto-merge July 18, 2026 14:24
@Shnatsel

Copy link
Copy Markdown
Contributor Author

The remarks are addressed, merging. I appreciate the in-depth review as always!

@Shnatsel
Shnatsel added this pull request to the merge queue Jul 18, 2026
Merged via the queue into linebender:main with commit 36adebb Jul 18, 2026
22 checks passed
@Shnatsel
Shnatsel deleted the sse2-cleaned-up branch July 18, 2026 14:31
Shnatsel added a commit to Shnatsel/fearless_simd that referenced this pull request Jul 18, 2026
Shnatsel added a commit to Shnatsel/fearless_simd that referenced this pull request Jul 18, 2026
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.

2 participants