@@ -24,13 +24,13 @@ use core::arch::aarch64::{uint8x16_t, vdupq_n_u8, vst1q_u8};
2424use core:: arch:: arm:: { uint8x16_t, vdupq_n_u8, vst1q_u8} ;
2525#[ cfg( target_arch = "x86" ) ]
2626use 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" ) ]
3131use 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