Skip to content

Commit 640b567

Browse files
committed
Add SSSE3 SSE4.1 encode prototype
1 parent 56f42de commit 640b567

6 files changed

Lines changed: 134 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
feature-bundle compile check while keeping scalar as the only active backend.
1010
- Added SSSE3/SSE4.1 candidate reporting and reserved feature-bundle compile
1111
evidence for older x86 CPUs before any active SIMD admission.
12+
- Added an inactive SSSE3/SSE4.1 fixed-block encode prototype with
13+
scalar-equivalence tests while keeping runtime dispatch scalar-only.
1214
- Added reserved SIMD feature-bundle compile checks to the normal local
1315
`scripts/checks.sh` gate so day-to-day checks match release expectations.
1416

docs/PLAN.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ the zero-runtime-dependency stance.
354354
checks while keeping scalar as the only active backend.
355355
- Add SSSE3/SSE4.1 candidate reporting and reserved feature-bundle compile
356356
checks for older x86 CPUs before active SIMD admission.
357+
- Add an inactive SSSE3/SSE4.1 fixed-block encode prototype with scalar
358+
equivalence tests before any runtime admission.
357359
- Replace inactive SIMD encode prototypes with real AVX2, AVX-512, NEON,
358360
SSSE3/SSE4.1, and wasm `simd128` candidate implementations only when scalar
359361
differential tests, fuzz evidence, target-feature checks, unsafe inventory

docs/RELEASE_EVIDENCE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ scripts/check_backend_evidence.sh
155155
```
156156

157157
The script runs the runtime backend-report test and the gated SIMD prototype
158-
scalar-equivalence tests with `--nocapture`. On CPUs with AVX2 or the AVX-512
159-
candidate bundle, those prototype tests execute the inactive prototype body and
160-
compare it against scalar output.
158+
scalar-equivalence tests with `--nocapture`. On CPUs with SSSE3/SSE4.1, AVX2,
159+
or the AVX-512 candidate bundle, those prototype tests execute the inactive
160+
prototype body and compare it against scalar output.
161161

162162
The release gate also runs:
163163

docs/SIMD.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ weakening the scalar trust base.
3939
without parsing formatted strings.
4040
- SSSE3/SSE4.1 detection is reporting-only until an implementation has scalar
4141
differential tests, fuzz coverage, and benchmark evidence.
42+
- An inactive SSSE3/SSE4.1 fixed-block encode prototype exists behind the SIMD
43+
boundary and is tested against scalar output only when SSSE3/SSE4.1 is
44+
available.
4245
- An inactive AVX2 fixed-block encode prototype exists behind the SIMD boundary
4346
and is tested against scalar output only when AVX2 is available.
4447
- An inactive NEON fixed-block encode prototype exists behind the same boundary

docs/UNSAFE.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,38 @@ Safety argument:
122122
- The function is guarded by an AVX2 target-feature contract.
123123
- The prototype then overwrites the block with scalar-equivalent Base64 output.
124124

125+
### `encode_12_bytes_ssse3_sse41`
126+
127+
Location: `src/simd.rs`
128+
129+
Status: inactive prototype, not dispatchable.
130+
131+
Purpose:
132+
133+
- Exercise lower-tier x86 target-feature plumbing.
134+
- Validate the unsafe boundary.
135+
- Provide scalar-equivalence test coverage before any real vector path is
136+
admitted.
137+
138+
Preconditions:
139+
140+
- Caller must prove SSSE3 and SSE4.1 are available on the current CPU.
141+
- Input is exactly 12 bytes.
142+
- Output is exactly 16 bytes.
143+
144+
Unsafe operation:
145+
146+
- `_mm_storeu_si128` stores one 128-bit zero vector into the output buffer.
147+
148+
Safety argument:
149+
150+
- The output type is `&mut [u8; 16]`, so the store has enough initialized,
151+
writable memory.
152+
- The intrinsic is the unaligned store variant, so no stronger alignment is
153+
required.
154+
- The function is guarded by an SSSE3/SSE4.1 target-feature contract.
155+
- The prototype then overwrites the block with scalar-equivalent Base64 output.
156+
125157
### `encode_12_bytes_neon`
126158

127159
Location: `src/simd.rs`

src/simd.rs

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ use core::arch::aarch64::{uint8x16_t, vdupq_n_u8, vst1q_u8};
2424
use core::arch::arm::{uint8x16_t, vdupq_n_u8, vst1q_u8};
2525
#[cfg(target_arch = "x86")]
2626
use core::arch::x86::{
27-
__m256i, __m512i, _mm256_setzero_si256, _mm256_storeu_si256, _mm512_setzero_si512,
28-
_mm512_storeu_si512,
27+
__m128i, __m256i, __m512i, _mm_setzero_si128, _mm_storeu_si128, _mm256_setzero_si256,
28+
_mm256_storeu_si256, _mm512_setzero_si512, _mm512_storeu_si512,
2929
};
3030
#[cfg(target_arch = "x86_64")]
3131
use core::arch::x86_64::{
32-
__m256i, __m512i, _mm256_setzero_si256, _mm256_storeu_si256, _mm512_setzero_si512,
33-
_mm512_storeu_si512,
32+
__m128i, __m256i, __m512i, _mm_setzero_si128, _mm_storeu_si128, _mm256_setzero_si256,
33+
_mm256_storeu_si256, _mm512_setzero_si512, _mm512_storeu_si512,
3434
};
3535

3636
/// Backend currently allowed to execute.
@@ -249,6 +249,54 @@ where
249249
}
250250
}
251251

252+
/// Encodes one 12-byte block into 16 bytes through the inactive SSSE3/SSE4.1 prototype.
253+
///
254+
/// This is not an admitted fast path. It exists to exercise lower-tier x86
255+
/// target-feature plumbing, unsafe isolation, and scalar equivalence before a
256+
/// real vector encoder is allowed to participate in dispatch.
257+
///
258+
/// # Safety
259+
///
260+
/// The caller must execute this function only when SSSE3 and SSE4.1 are
261+
/// available on the current CPU. The input and output sizes are fixed by their
262+
/// array types.
263+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
264+
#[allow(dead_code, reason = "inactive prototype is not dispatchable yet")]
265+
#[expect(
266+
clippy::cast_ptr_alignment,
267+
reason = "_mm_storeu_si128 accepts unaligned pointers"
268+
)]
269+
#[target_feature(enable = "ssse3,sse4.1")]
270+
pub(super) unsafe fn encode_12_bytes_ssse3_sse41<A>(input: &[u8; 12], output: &mut [u8; 16])
271+
where
272+
A: Alphabet,
273+
{
274+
let zeros = _mm_setzero_si128();
275+
// SAFETY: `output` is a valid 16-byte mutable array. SSSE3/SSE4.1
276+
// availability is guaranteed by this function's target-feature
277+
// precondition, and the unaligned store does not require stronger pointer
278+
// alignment.
279+
unsafe {
280+
_mm_storeu_si128(output.as_mut_ptr().cast::<__m128i>(), zeros);
281+
}
282+
283+
let mut read = 0;
284+
let mut write = 0;
285+
while read < input.len() {
286+
let b0 = input[read];
287+
let b1 = input[read + 1];
288+
let b2 = input[read + 2];
289+
290+
output[write] = encode_base64_value::<A>(b0 >> 2);
291+
output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
292+
output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
293+
output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
294+
295+
read += 3;
296+
write += 4;
297+
}
298+
}
299+
252300
/// Encodes one 12-byte block into 16 bytes through the inactive NEON prototype.
253301
///
254302
/// This is not an admitted fast path. It exists to exercise ARM intrinsic
@@ -386,6 +434,46 @@ mod tests {
386434
}
387435
}
388436

437+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
438+
#[test]
439+
fn ssse3_sse41_encode_prototype_matches_scalar_when_available() {
440+
if !ssse3_sse41_available() {
441+
return;
442+
}
443+
444+
let mut input = [0; 12];
445+
for seed in 0..64 {
446+
fill_pattern(&mut input, seed);
447+
448+
let mut ssse3_standard = [0x55; 16];
449+
let mut scalar_standard = [0xaa; 16];
450+
// SAFETY: The feature check above uses runtime SSSE3/SSE4.1
451+
// detection on std builds and compile-time target-feature
452+
// detection otherwise.
453+
unsafe {
454+
encode_12_bytes_ssse3_sse41::<Standard>(&input, &mut ssse3_standard);
455+
}
456+
let scalar_len = Engine::<Standard, true>::new()
457+
.encode_slice(&input, &mut scalar_standard)
458+
.unwrap();
459+
assert_eq!(scalar_len, ssse3_standard.len());
460+
assert_eq!(ssse3_standard, scalar_standard);
461+
462+
let mut ssse3_url_safe = [0x55; 16];
463+
let mut scalar_url_safe = [0xaa; 16];
464+
// SAFETY: The feature check above proves SSSE3/SSE4.1
465+
// availability for this test invocation.
466+
unsafe {
467+
encode_12_bytes_ssse3_sse41::<UrlSafe>(&input, &mut ssse3_url_safe);
468+
}
469+
let scalar_len = Engine::<UrlSafe, true>::new()
470+
.encode_slice(&input, &mut scalar_url_safe)
471+
.unwrap();
472+
assert_eq!(scalar_len, ssse3_url_safe.len());
473+
assert_eq!(ssse3_url_safe, scalar_url_safe);
474+
}
475+
}
476+
389477
#[cfg(any(
390478
target_arch = "aarch64",
391479
all(target_arch = "arm", target_feature = "neon")

0 commit comments

Comments
 (0)