@@ -264,6 +264,85 @@ where
264264 ( encode[ 62 ] == b'+' && encode[ 63 ] == b'/' ) || ( encode[ 62 ] == b'-' && encode[ 63 ] == b'_' )
265265}
266266
267+ #[ cfg( all( test, target_arch = "aarch64" ) ) ]
268+ macro_rules! clear_neon_registers_for_test_prototype {
269+ ( ) => { {
270+ // SAFETY: This test-only cleanup is expanded directly inside the
271+ // prototype function after it stores its output. There is no separate
272+ // helper frame whose ABI save/restore can undo `v8..v15` clearing. The
273+ // explicit outputs tell the compiler every AArch64 vector register is
274+ // clobbered while the assembly clears it. This is retention reduction
275+ // for prototype evidence, not a formal microarchitectural proof.
276+ core:: arch:: asm!(
277+ "eor v0.16b, v0.16b, v0.16b" ,
278+ "eor v1.16b, v1.16b, v1.16b" ,
279+ "eor v2.16b, v2.16b, v2.16b" ,
280+ "eor v3.16b, v3.16b, v3.16b" ,
281+ "eor v4.16b, v4.16b, v4.16b" ,
282+ "eor v5.16b, v5.16b, v5.16b" ,
283+ "eor v6.16b, v6.16b, v6.16b" ,
284+ "eor v7.16b, v7.16b, v7.16b" ,
285+ "eor v8.16b, v8.16b, v8.16b" ,
286+ "eor v9.16b, v9.16b, v9.16b" ,
287+ "eor v10.16b, v10.16b, v10.16b" ,
288+ "eor v11.16b, v11.16b, v11.16b" ,
289+ "eor v12.16b, v12.16b, v12.16b" ,
290+ "eor v13.16b, v13.16b, v13.16b" ,
291+ "eor v14.16b, v14.16b, v14.16b" ,
292+ "eor v15.16b, v15.16b, v15.16b" ,
293+ "eor v16.16b, v16.16b, v16.16b" ,
294+ "eor v17.16b, v17.16b, v17.16b" ,
295+ "eor v18.16b, v18.16b, v18.16b" ,
296+ "eor v19.16b, v19.16b, v19.16b" ,
297+ "eor v20.16b, v20.16b, v20.16b" ,
298+ "eor v21.16b, v21.16b, v21.16b" ,
299+ "eor v22.16b, v22.16b, v22.16b" ,
300+ "eor v23.16b, v23.16b, v23.16b" ,
301+ "eor v24.16b, v24.16b, v24.16b" ,
302+ "eor v25.16b, v25.16b, v25.16b" ,
303+ "eor v26.16b, v26.16b, v26.16b" ,
304+ "eor v27.16b, v27.16b, v27.16b" ,
305+ "eor v28.16b, v28.16b, v28.16b" ,
306+ "eor v29.16b, v29.16b, v29.16b" ,
307+ "eor v30.16b, v30.16b, v30.16b" ,
308+ "eor v31.16b, v31.16b, v31.16b" ,
309+ out( "v0" ) _,
310+ out( "v1" ) _,
311+ out( "v2" ) _,
312+ out( "v3" ) _,
313+ out( "v4" ) _,
314+ out( "v5" ) _,
315+ out( "v6" ) _,
316+ out( "v7" ) _,
317+ out( "v8" ) _,
318+ out( "v9" ) _,
319+ out( "v10" ) _,
320+ out( "v11" ) _,
321+ out( "v12" ) _,
322+ out( "v13" ) _,
323+ out( "v14" ) _,
324+ out( "v15" ) _,
325+ out( "v16" ) _,
326+ out( "v17" ) _,
327+ out( "v18" ) _,
328+ out( "v19" ) _,
329+ out( "v20" ) _,
330+ out( "v21" ) _,
331+ out( "v22" ) _,
332+ out( "v23" ) _,
333+ out( "v24" ) _,
334+ out( "v25" ) _,
335+ out( "v26" ) _,
336+ out( "v27" ) _,
337+ out( "v28" ) _,
338+ out( "v29" ) _,
339+ out( "v30" ) _,
340+ out( "v31" ) _,
341+ options( nostack, preserves_flags)
342+ ) ;
343+ } } ;
344+ }
345+
267346#[ cfg( all( test, target_arch = "aarch64" ) ) ]
268347#[ target_feature( enable = "neon" ) ]
269348unsafe fn encode_12_bytes_neon_aarch64_standard_family < A > ( input : & [ u8 ; 12 ] , output : & mut [ u8 ; 16 ] )
@@ -296,7 +375,7 @@ where
296375
297376 let encoded = encode_standard_family_indices_neon :: < A > ( indices) ;
298377 vst1q_u8 ( output. as_mut_ptr ( ) , encoded) ;
299- clear_neon_registers_for_test_prototype ( ) ;
378+ clear_neon_registers_for_test_prototype ! ( ) ;
300379 }
301380 crate :: wipe_bytes ( & mut staged) ;
302381}
@@ -337,82 +416,5 @@ where
337416 vbslq_u8 ( slash, vdupq_n_u8 ( slash_char) , encoded)
338417}
339418
340- #[ cfg( all( test, target_arch = "aarch64" ) ) ]
341- unsafe fn clear_neon_registers_for_test_prototype ( ) {
342- // SAFETY: This test-only cleanup runs after the prototype stores its
343- // output. The explicit outputs tell the compiler every AArch64 vector
344- // register is clobbered while the assembly clears it. This is retention
345- // reduction for prototype evidence, not a formal microarchitectural proof.
346- unsafe {
347- core:: arch:: asm!(
348- "eor v0.16b, v0.16b, v0.16b" ,
349- "eor v1.16b, v1.16b, v1.16b" ,
350- "eor v2.16b, v2.16b, v2.16b" ,
351- "eor v3.16b, v3.16b, v3.16b" ,
352- "eor v4.16b, v4.16b, v4.16b" ,
353- "eor v5.16b, v5.16b, v5.16b" ,
354- "eor v6.16b, v6.16b, v6.16b" ,
355- "eor v7.16b, v7.16b, v7.16b" ,
356- "eor v8.16b, v8.16b, v8.16b" ,
357- "eor v9.16b, v9.16b, v9.16b" ,
358- "eor v10.16b, v10.16b, v10.16b" ,
359- "eor v11.16b, v11.16b, v11.16b" ,
360- "eor v12.16b, v12.16b, v12.16b" ,
361- "eor v13.16b, v13.16b, v13.16b" ,
362- "eor v14.16b, v14.16b, v14.16b" ,
363- "eor v15.16b, v15.16b, v15.16b" ,
364- "eor v16.16b, v16.16b, v16.16b" ,
365- "eor v17.16b, v17.16b, v17.16b" ,
366- "eor v18.16b, v18.16b, v18.16b" ,
367- "eor v19.16b, v19.16b, v19.16b" ,
368- "eor v20.16b, v20.16b, v20.16b" ,
369- "eor v21.16b, v21.16b, v21.16b" ,
370- "eor v22.16b, v22.16b, v22.16b" ,
371- "eor v23.16b, v23.16b, v23.16b" ,
372- "eor v24.16b, v24.16b, v24.16b" ,
373- "eor v25.16b, v25.16b, v25.16b" ,
374- "eor v26.16b, v26.16b, v26.16b" ,
375- "eor v27.16b, v27.16b, v27.16b" ,
376- "eor v28.16b, v28.16b, v28.16b" ,
377- "eor v29.16b, v29.16b, v29.16b" ,
378- "eor v30.16b, v30.16b, v30.16b" ,
379- "eor v31.16b, v31.16b, v31.16b" ,
380- out( "v0" ) _,
381- out( "v1" ) _,
382- out( "v2" ) _,
383- out( "v3" ) _,
384- out( "v4" ) _,
385- out( "v5" ) _,
386- out( "v6" ) _,
387- out( "v7" ) _,
388- out( "v8" ) _,
389- out( "v9" ) _,
390- out( "v10" ) _,
391- out( "v11" ) _,
392- out( "v12" ) _,
393- out( "v13" ) _,
394- out( "v14" ) _,
395- out( "v15" ) _,
396- out( "v16" ) _,
397- out( "v17" ) _,
398- out( "v18" ) _,
399- out( "v19" ) _,
400- out( "v20" ) _,
401- out( "v21" ) _,
402- out( "v22" ) _,
403- out( "v23" ) _,
404- out( "v24" ) _,
405- out( "v25" ) _,
406- out( "v26" ) _,
407- out( "v27" ) _,
408- out( "v28" ) _,
409- out( "v29" ) _,
410- out( "v30" ) _,
411- out( "v31" ) _,
412- options( nostack, preserves_flags)
413- ) ;
414- }
415- }
416-
417419#[ cfg( all( test, not( target_arch = "wasm32" ) ) ) ]
418420mod tests;
0 commit comments