LCOV - code coverage report
Current view: top level - ballet/blake3 - fd_blake3_avx2.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 483 485 99.6 %
Date: 2026-07-15 05:23:55 Functions: 6 6 100.0 %

          Line data    Source code
       1             : 
       2             : // Source originally from https://github.com/BLAKE3-team/BLAKE3
       3             : // From commit: 64747d48ffe9d1fbf4b71e94cabeb8a211461081
       4             : 
       5             : #include "fd_blake3.h"
       6             : #include "fd_blake3_private.h"
       7             : #include "../../util/simd/fd_avx.h"
       8             : 
       9  7872527376 : #define wu_rot16 wb_exch_adj_pair
      10             : 
      11             : static inline __attribute__((always_inline)) wu_t
      12  7872527376 : wu_rot12( wu_t x ) {
      13  7872527376 :   return wu_ror( x, 12 );
      14  7872527376 : }
      15             : 
      16             : static inline __attribute__((always_inline)) wu_t
      17  7872527376 : wu_rot8( wu_t x ) {
      18  7872527376 :   wb_t const mask =
      19  7872527376 :     wb( 1,2,3,0,  5,6,7,4,  9,10,11,8,  13,14,15,12,
      20  7872527376 :         1,2,3,0,  5,6,7,4,  9,10,11,8,  13,14,15,12 );
      21  7872527376 :   return _mm256_shuffle_epi8( x, mask );
      22  7872527376 : }
      23             : 
      24             : static inline __attribute__((always_inline)) wu_t
      25  7872527376 : wu_rot7( wu_t x ) {
      26  7872527376 :   return wu_ror( x, 7 );
      27  7872527376 : }
      28             : 
      29             : static inline __attribute__((always_inline)) void
      30             : round_fn8( wu_t  v[16],
      31             :            wu_t  m[16],
      32   984065922 :            ulong r ) {
      33   984065922 :   v[ 0] = wu_add(v[0], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][0]]);
      34   984065922 :   v[ 1] = wu_add(v[1], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][2]]);
      35   984065922 :   v[ 2] = wu_add(v[2], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][4]]);
      36   984065922 :   v[ 3] = wu_add(v[3], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][6]]);
      37   984065922 :   v[ 0] = wu_add(v[0], v[4]);
      38   984065922 :   v[ 1] = wu_add(v[1], v[5]);
      39   984065922 :   v[ 2] = wu_add(v[2], v[6]);
      40   984065922 :   v[ 3] = wu_add(v[3], v[7]);
      41   984065922 :   v[12] = wu_xor(v[12], v[0]);
      42   984065922 :   v[13] = wu_xor(v[13], v[1]);
      43   984065922 :   v[14] = wu_xor(v[14], v[2]);
      44   984065922 :   v[15] = wu_xor(v[15], v[3]);
      45   984065922 :   v[12] = wu_rot16(v[12]);
      46   984065922 :   v[13] = wu_rot16(v[13]);
      47   984065922 :   v[14] = wu_rot16(v[14]);
      48   984065922 :   v[15] = wu_rot16(v[15]);
      49   984065922 :   v[ 8] = wu_add(v[8], v[12]);
      50   984065922 :   v[ 9] = wu_add(v[9], v[13]);
      51   984065922 :   v[10] = wu_add(v[10], v[14]);
      52   984065922 :   v[11] = wu_add(v[11], v[15]);
      53   984065922 :   v[ 4] = wu_xor(v[4], v[8]);
      54   984065922 :   v[ 5] = wu_xor(v[5], v[9]);
      55   984065922 :   v[ 6] = wu_xor(v[6], v[10]);
      56   984065922 :   v[ 7] = wu_xor(v[7], v[11]);
      57   984065922 :   v[ 4] = wu_rot12(v[4]);
      58   984065922 :   v[ 5] = wu_rot12(v[5]);
      59   984065922 :   v[ 6] = wu_rot12(v[6]);
      60   984065922 :   v[ 7] = wu_rot12(v[7]);
      61   984065922 :   v[ 0] = wu_add(v[0], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][1]]);
      62   984065922 :   v[ 1] = wu_add(v[1], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][3]]);
      63   984065922 :   v[ 2] = wu_add(v[2], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][5]]);
      64   984065922 :   v[ 3] = wu_add(v[3], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][7]]);
      65   984065922 :   v[ 0] = wu_add(v[0], v[4]);
      66   984065922 :   v[ 1] = wu_add(v[1], v[5]);
      67   984065922 :   v[ 2] = wu_add(v[2], v[6]);
      68   984065922 :   v[ 3] = wu_add(v[3], v[7]);
      69   984065922 :   v[12] = wu_xor(v[12], v[0]);
      70   984065922 :   v[13] = wu_xor(v[13], v[1]);
      71   984065922 :   v[14] = wu_xor(v[14], v[2]);
      72   984065922 :   v[15] = wu_xor(v[15], v[3]);
      73   984065922 :   v[12] = wu_rot8(v[12]);
      74   984065922 :   v[13] = wu_rot8(v[13]);
      75   984065922 :   v[14] = wu_rot8(v[14]);
      76   984065922 :   v[15] = wu_rot8(v[15]);
      77   984065922 :   v[ 8] = wu_add(v[8], v[12]);
      78   984065922 :   v[ 9] = wu_add(v[9], v[13]);
      79   984065922 :   v[10] = wu_add(v[10], v[14]);
      80   984065922 :   v[11] = wu_add(v[11], v[15]);
      81   984065922 :   v[ 4] = wu_xor(v[4], v[8]);
      82   984065922 :   v[ 5] = wu_xor(v[5], v[9]);
      83   984065922 :   v[ 6] = wu_xor(v[6], v[10]);
      84   984065922 :   v[ 7] = wu_xor(v[7], v[11]);
      85   984065922 :   v[ 4] = wu_rot7(v[4]);
      86   984065922 :   v[ 5] = wu_rot7(v[5]);
      87   984065922 :   v[ 6] = wu_rot7(v[6]);
      88   984065922 :   v[ 7] = wu_rot7(v[7]);
      89             : 
      90   984065922 :   v[ 0] = wu_add(v[0], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][8]]);
      91   984065922 :   v[ 1] = wu_add(v[1], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][10]]);
      92   984065922 :   v[ 2] = wu_add(v[2], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][12]]);
      93   984065922 :   v[ 3] = wu_add(v[3], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][14]]);
      94   984065922 :   v[ 0] = wu_add(v[0], v[5]);
      95   984065922 :   v[ 1] = wu_add(v[1], v[6]);
      96   984065922 :   v[ 2] = wu_add(v[2], v[7]);
      97   984065922 :   v[ 3] = wu_add(v[3], v[4]);
      98   984065922 :   v[15] = wu_xor(v[15], v[0]);
      99   984065922 :   v[12] = wu_xor(v[12], v[1]);
     100   984065922 :   v[13] = wu_xor(v[13], v[2]);
     101   984065922 :   v[14] = wu_xor(v[14], v[3]);
     102   984065922 :   v[15] = wu_rot16(v[15]);
     103   984065922 :   v[12] = wu_rot16(v[12]);
     104   984065922 :   v[13] = wu_rot16(v[13]);
     105   984065922 :   v[14] = wu_rot16(v[14]);
     106   984065922 :   v[10] = wu_add(v[10], v[15]);
     107   984065922 :   v[11] = wu_add(v[11], v[12]);
     108   984065922 :   v[ 8] = wu_add(v[8], v[13]);
     109   984065922 :   v[ 9] = wu_add(v[9], v[14]);
     110   984065922 :   v[ 5] = wu_xor(v[5], v[10]);
     111   984065922 :   v[ 6] = wu_xor(v[6], v[11]);
     112   984065922 :   v[ 7] = wu_xor(v[7], v[8]);
     113   984065922 :   v[ 4] = wu_xor(v[4], v[9]);
     114   984065922 :   v[ 5] = wu_rot12(v[5]);
     115   984065922 :   v[ 6] = wu_rot12(v[6]);
     116   984065922 :   v[ 7] = wu_rot12(v[7]);
     117   984065922 :   v[ 4] = wu_rot12(v[4]);
     118   984065922 :   v[ 0] = wu_add(v[0], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][9]]);
     119   984065922 :   v[ 1] = wu_add(v[1], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][11]]);
     120   984065922 :   v[ 2] = wu_add(v[2], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][13]]);
     121   984065922 :   v[ 3] = wu_add(v[3], m[(ulong)FD_BLAKE3_MSG_SCHEDULE[r][15]]);
     122   984065922 :   v[ 0] = wu_add(v[0], v[5]);
     123   984065922 :   v[ 1] = wu_add(v[1], v[6]);
     124   984065922 :   v[ 2] = wu_add(v[2], v[7]);
     125   984065922 :   v[ 3] = wu_add(v[3], v[4]);
     126   984065922 :   v[15] = wu_xor(v[15], v[0]);
     127   984065922 :   v[12] = wu_xor(v[12], v[1]);
     128   984065922 :   v[13] = wu_xor(v[13], v[2]);
     129   984065922 :   v[14] = wu_xor(v[14], v[3]);
     130   984065922 :   v[15] = wu_rot8(v[15]);
     131   984065922 :   v[12] = wu_rot8(v[12]);
     132   984065922 :   v[13] = wu_rot8(v[13]);
     133   984065922 :   v[14] = wu_rot8(v[14]);
     134   984065922 :   v[10] = wu_add(v[10], v[15]);
     135   984065922 :   v[11] = wu_add(v[11], v[12]);
     136   984065922 :   v[ 8] = wu_add(v[8], v[13]);
     137   984065922 :   v[ 9] = wu_add(v[9], v[14]);
     138   984065922 :   v[ 5] = wu_xor(v[5], v[10]);
     139   984065922 :   v[ 6] = wu_xor(v[6], v[11]);
     140   984065922 :   v[ 7] = wu_xor(v[7], v[8]);
     141   984065922 :   v[ 4] = wu_xor(v[4], v[9]);
     142   984065922 :   v[ 5] = wu_rot7(v[5]);
     143   984065922 :   v[ 6] = wu_rot7(v[6]);
     144   984065922 :   v[ 7] = wu_rot7(v[7]);
     145   984065922 :   v[ 4] = wu_rot7(v[4]);
     146   984065922 : }
     147             : 
     148             : void
     149             : fd_blake3_avx_compress8( ulong                   batch_cnt,
     150             :                          void   const * restrict _batch_data,
     151             :                          uint   const * restrict batch_sz,
     152             :                          ulong  const * restrict ctr_vec,
     153             :                          uint   const * restrict batch_flags,
     154             :                          void * const * restrict _batch_hash,
     155             :                          ushort *       restrict lthash,
     156             :                          uint                    out_sz,
     157    27827250 :                          void const *   restrict batch_cv ) {
     158    27827250 :   if( FD_UNLIKELY( lthash && batch_cnt!=8 ) ) FD_LOG_ERR(( "Lane masking not supported for fd_blake3_avx_compress8 in LtHash mode" ));
     159    27827250 :   if( FD_UNLIKELY( batch_cnt==0 || batch_cnt>8 ) ) FD_LOG_ERR(( "Invalid batch_cnt %lu", batch_cnt ));
     160             : 
     161    27827250 :   ulong const * batch_data = (ulong const *)_batch_data;
     162             : 
     163    27827250 :   if( FD_UNLIKELY( batch_cnt==1 ) ) {
     164      380460 :     fd_blake3_sse_compress1( (uchar *)(_batch_hash[0]),
     165      380460 :                              (uchar const *)(batch_data[0]),
     166      380460 :                              batch_sz[0],
     167      380460 :                              ctr_vec[0],
     168      380460 :                              batch_flags[0],
     169      380460 :                              NULL,
     170      380460 :                              NULL );
     171      380460 :     return;
     172      380460 :   }
     173             : 
     174             : #if FD_BLAKE3_TRACING
     175             :   /* This log_line buffer is oversized by a fair bit (due to all the
     176             :      NULL terminators) but that's fine */
     177             :   char log_line[
     178             :       sizeof( "fd_blake3_avx_compress8" )+
     179             :       sizeof( "(batch_cnt=" )+21+
     180             :       sizeof( ",sz=["       )+(8*11)+sizeof( "]" )+
     181             :       sizeof( ",counter=["  )+(8*21)+sizeof( "]" )+
     182             :       sizeof( ",flags=["    )+(8* 2)+sizeof( "]" )+
     183             :       sizeof( ",custom_cv"  )+
     184             :       sizeof( ",lthash" )+
     185             :       sizeof( ")" ) ];
     186             : 
     187             :   char * p = fd_cstr_init( log_line );
     188             :   p = fd_cstr_append_text( p, "fd_blake3_avx_compress8(batch_cnt=", 34UL );
     189             :   p = fd_cstr_append_ulong_as_text( p, 0, 0, batch_cnt, fd_uchar_base10_dig_cnt( (uchar)batch_cnt ) );
     190             :   p = fd_cstr_append_text( p, ",sz=[", 5UL );
     191             :   for( ulong i=0UL; i<batch_cnt; i++ ) {
     192             :     p = fd_cstr_append_uint_as_text( p, ' ', 0, batch_sz[ i ], fd_uint_base10_dig_cnt( batch_sz[ i ] ) );
     193             :     if( i+1<batch_cnt ) p = fd_cstr_append_char( p, ',' );
     194             :   }
     195             :   p = fd_cstr_append_text( p, "],counter=[", 11UL );
     196             :   for( ulong i=0UL; i<batch_cnt; i++ ) {
     197             :     p = fd_cstr_append_ulong_as_text( p, ' ', 0, ctr_vec[ i ], fd_ulong_base10_dig_cnt( ctr_vec[ i ] ) );
     198             :     if( i+1<batch_cnt ) p = fd_cstr_append_char( p, ',' );
     199             :   }
     200             :   p = fd_cstr_append_text( p, "],flags=[", 9UL );
     201             :   for( ulong i=0UL; i<batch_cnt; i++ ) {
     202             :     static char const hex_lut[ 16 ] = {
     203             :       '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
     204             :     };
     205             :     p = fd_cstr_append_char( p, hex_lut[ batch_flags[ i ]&0xf ] );
     206             :     if( i+1<batch_cnt ) p = fd_cstr_append_char( p, ',' );
     207             :   }
     208             :   p = fd_cstr_append_char( p, ']' );
     209             :   if( batch_cv ) p = fd_cstr_append_text( p, ",custom_cv", 10UL );
     210             :   if( lthash   ) p = fd_cstr_append_text( p, ",lthash", 7UL );
     211             :   p = fd_cstr_append_char( p, ')' );
     212             :   ulong line_len = (ulong)( p-log_line );
     213             :   fd_cstr_fini( p );
     214             : 
     215             :   FD_BLAKE3_TRACE(( "%.*s", (int)line_len, log_line ));
     216             : #endif
     217             : 
     218             :   /* We can only process input blocks of 64 bytes, but message data size
     219             :      is not necessarily a multiple of 64.  We compute the tail block of
     220             :      each message here.  We then process complete blocks of the original
     221             :      message in place, switching to processing to these  tail blocks in
     222             :      the same pass toward the end. */
     223             : 
     224    27446790 :   ulong batch_tail_data[ 8 ] __attribute__((aligned(32)));
     225    27446790 :   ulong batch_tail_rem [ 8 ] __attribute__((aligned(32)));
     226             : 
     227    27446790 :   uchar scratch[ 8*FD_BLAKE3_BLOCK_SZ ] __attribute__((aligned(128)));
     228    27446790 :   do {
     229    27446790 :     ulong scratch_free = (ulong)scratch;
     230             : 
     231    27446790 :     wv_t zero = wv_zero();
     232             : 
     233   242448516 :     for( ulong batch_idx=0UL; batch_idx<batch_cnt; batch_idx++ ) {
     234             : 
     235             :       /* Allocate the tail blocks for this message */
     236             : 
     237   215001726 :       ulong data = batch_data[ batch_idx ];
     238   215001726 :       ulong sz   = batch_sz  [ batch_idx ];
     239             : 
     240   215001726 :       ulong tail_data     = scratch_free;
     241   215001726 :       ulong tail_data_sz  = sz & (FD_BLAKE3_BLOCK_SZ-1UL);
     242   215001726 :       ulong tail_data_off = fd_ulong_align_dn( sz, FD_BLAKE3_BLOCK_SZ );
     243             : 
     244   215001726 :       batch_tail_data[ batch_idx ] = tail_data;
     245   215001726 :       batch_tail_rem [ batch_idx ] = (ulong)( (!!tail_data_sz) ^ (!sz) );  /* (hash 1 tail block if 0 sz) */
     246             : 
     247   215001726 :       scratch_free += FD_BLAKE3_BLOCK_SZ;
     248             : 
     249             :       /* Populate the tail blocks.  We first clear the blocks.  Then we
     250             :          copy any straggler data bytes into the tail. */
     251             : 
     252   215001726 :       wv_st( (ulong *) tail_data,     zero );
     253   215001726 :       wv_st( (ulong *)(tail_data+32), zero );
     254             : 
     255   215001726 : #     if 1
     256             :       /* See fd_sha256_private_batch_avx */
     257   215001726 :       ulong src = (ulong)data + tail_data_off;
     258   215001726 :       ulong dst = tail_data;
     259   215001726 :       ulong rem = tail_data_sz;
     260   242101894 :       while( rem>=32UL ) { wv_st( (ulong *)dst, wv_ldu( (ulong const *)src ) ); dst += 32UL; src += 32UL; rem -= 32UL; }
     261   296221108 :       while( rem>= 8UL ) { *(ulong  *)dst = FD_LOAD( ulong,  src );             dst +=  8UL; src +=  8UL; rem -=  8UL; }
     262   215001726 :       if   ( rem>= 4UL ) { *(uint   *)dst = FD_LOAD( uint,   src );             dst +=  4UL; src +=  4UL; rem -=  4UL; }
     263   215001726 :       if   ( rem>= 2UL ) { *(ushort *)dst = FD_LOAD( ushort, src );             dst +=  2UL; src +=  2UL; rem -=  2UL; }
     264   215001726 :       if   ( rem       ) { *(uchar  *)dst = FD_LOAD( uchar,  src );             dst++;                                 }
     265             : #     else
     266             :       fd_memcpy( (void *)tail_data, (void const *)(data + tail_data_off), tail_data_sz );
     267             : #     endif
     268   215001726 :     }
     269    27446790 :   } while(0);
     270             : 
     271             : 
     272    27446790 :   wu_t const iv0 = wu_bcast( FD_BLAKE3_IV[0] );
     273    27446790 :   wu_t const iv1 = wu_bcast( FD_BLAKE3_IV[1] );
     274    27446790 :   wu_t const iv2 = wu_bcast( FD_BLAKE3_IV[2] );
     275    27446790 :   wu_t const iv3 = wu_bcast( FD_BLAKE3_IV[3] );
     276    27446790 :   wu_t const iv4 = wu_bcast( FD_BLAKE3_IV[4] );
     277    27446790 :   wu_t const iv5 = wu_bcast( FD_BLAKE3_IV[5] );
     278    27446790 :   wu_t const iv6 = wu_bcast( FD_BLAKE3_IV[6] );
     279    27446790 :   wu_t const iv7 = wu_bcast( FD_BLAKE3_IV[7] );
     280             : 
     281    27446790 :   wu_t h0=iv0; wu_t h1=iv1; wu_t h2=iv2; wu_t h3=iv3;
     282    27446790 :   wu_t h4=iv4; wu_t h5=iv5; wu_t h6=iv6; wu_t h7=iv7;
     283    27446790 :   if( FD_UNLIKELY( batch_cv ) ) {
     284             :     /* If the input chaining value is overridden, transpose the input to
     285             :        AVX representation (8x8 transpose). */
     286    24776984 :     __m256i const ** cv_vec = (__m256i const **)batch_cv;
     287    24776984 :     wu_t cv[8];
     288   222992856 :     for( ulong i=0UL; i<8UL; i++ ) cv[i] = _mm256_loadu_si256( cv_vec[ i ] );
     289    24776984 :     wu_transpose_8x8( cv[0], cv[1], cv[2], cv[3], cv[4], cv[5], cv[6], cv[7],
     290    24776984 :                       h0,    h1,    h2,    h3,    h4,    h5,    h6,    h7 );
     291    24776984 :   }
     292             : 
     293    27446790 :   wu_t ctr_lo = wu( ctr_vec[0],     ctr_vec[1],     ctr_vec[2],     ctr_vec[3],
     294    27446790 :                     ctr_vec[4],     ctr_vec[5],     ctr_vec[6],     ctr_vec[7] );
     295    27446790 :   wu_t ctr_hi = wu( ctr_vec[0]>>32, ctr_vec[1]>>32, ctr_vec[2]>>32, ctr_vec[3]>>32,
     296    27446790 :                     ctr_vec[4]>>32, ctr_vec[5]>>32, ctr_vec[6]>>32, ctr_vec[7]>>32 );
     297    27446790 :   wu_t flags = wu_ldu( batch_flags );
     298    27446790 :   wu_t off   = wu_zero();
     299    27446790 :   wu_t sz    = wu_ldu( batch_sz );
     300             : 
     301    27446790 :   wv_t wv_64        = wv_bcast( FD_BLAKE3_BLOCK_SZ );
     302    27446790 :   wv_t W_sentinel   = wv_bcast( (ulong)scratch );
     303    27446790 :   wc_t batch_lane   = wc_unpack( (1<<batch_cnt)-1 );
     304             : 
     305    27446790 :   wv_t tail_lo      = wv_ld( batch_tail_data   );
     306    27446790 :   wv_t tail_hi      = wv_ld( batch_tail_data+4 );
     307             : 
     308    27446790 :   wv_t tail_rem_lo  = wv_ld( batch_tail_rem    );
     309    27446790 :   wv_t tail_rem_hi  = wv_ld( batch_tail_rem+4  );
     310             : 
     311    27446790 :   wv_t W_lo         = wv_ld( batch_data        );
     312    27446790 :   wv_t W_hi         = wv_ld( batch_data+4      );
     313             : 
     314    27446790 :   wv_t batch_sz_lo  = _mm256_cvtepi32_epi64( _mm256_extractf128_si256( sz, 0 ) );
     315    27446790 :   wv_t batch_sz_hi  = _mm256_cvtepi32_epi64( _mm256_extractf128_si256( sz, 1 ) );
     316             : 
     317    27446790 :   wv_t block_rem_lo = wv_notczero( wc_expand( batch_lane, 0 ),
     318    27446790 :                         wv_add( wv_shr( batch_sz_lo, FD_BLAKE3_BLOCK_LG_SZ ), tail_rem_lo ) );
     319    27446790 :   wv_t block_rem_hi = wv_notczero( wc_expand( batch_lane, 1 ),
     320    27446790 :                         wv_add( wv_shr( batch_sz_hi, FD_BLAKE3_BLOCK_LG_SZ ), tail_rem_hi ) );
     321             : 
     322             :   /* Upper half of the compression function output.
     323             :      Usually thrown away, but kept in the final compression round if
     324             :      out_sz==64. */
     325    27446790 :   wu_t hu[8] = {0};
     326             : 
     327    27446790 :   ulong lthash_rem    = lthash ? 32 : 0; /* Number of LtHash (XOF) blocks remaining */
     328    27446790 :   int   compress_done = 0;
     329    61513180 :   for(;;) {
     330             :     /* Switch lanes that have hit the end of their in-place bulk
     331             :        processing to their out-of-place scratch tail regions as
     332             :        necessary. */
     333             : 
     334    61513180 :     W_lo = wv_if( wv_eq( block_rem_lo, tail_rem_lo ), tail_lo, W_lo );
     335    61513180 :     W_hi = wv_if( wv_eq( block_rem_hi, tail_rem_hi ), tail_hi, W_hi );
     336             : 
     337             :     /* Derive per-block flags and block sizes */
     338             : 
     339    61513180 :     wc_t block_first = wu_eq( off, wu_zero() );
     340    61513180 :     wc_t block_last  = wi_lt( sz,  wu_add( off, wu_bcast( FD_BLAKE3_BLOCK_SZ+1 ) ) );
     341             : 
     342             :     /* Suppress root flag unless last block */
     343             : 
     344    61513180 :     wu_t root_mask = wu_or( block_last, wu_bcast( ~FD_BLAKE3_FLAG_ROOT ) );
     345    61513180 :     wu_t block_flags = wu_and( flags, root_mask );
     346             : 
     347             :     /* LtHash mode ends compression one early */
     348             : 
     349    61513180 :     wc_t active_lane_lo;
     350    61513180 :     wc_t active_lane_hi;
     351    61513180 :     if( FD_UNLIKELY( lthash ) ) {
     352             :       /* Compress until root block */
     353     6648896 :       wu_t all_root = wu_bcast( FD_BLAKE3_FLAG_ROOT );
     354     6648896 :       wu_t not_root = wu_ne( wu_and( block_flags, all_root ), all_root );
     355     6648896 :       active_lane_lo = _mm256_cvtepi32_epi64( _mm256_extractf128_si256( not_root, 0 ) );
     356     6648896 :       active_lane_hi = _mm256_cvtepi32_epi64( _mm256_extractf128_si256( not_root, 1 ) );
     357    56331946 :     } else {
     358             :       /* Complete when there is no more input data */
     359    54864284 :       active_lane_lo = wv_to_wc( block_rem_lo );
     360    54864284 :       active_lane_hi = wv_to_wc( block_rem_hi );
     361    54864284 :     }
     362             : 
     363             :     /* Suppress CHUNK_{START,END} flags unless leaf node */
     364             : 
     365    61513180 :     wc_t is_parent = wu_shl( flags, 5 );  /* shift FLAG_PARENT into AVX condition bit */
     366    61513180 :     wu_t chunk_flags = wu_if( block_last,  wu_bcast( FD_BLAKE3_FLAG_CHUNK_END   ), wu_zero() );
     367    61513180 :     if( out_sz==32 ) {
     368             :       /* Hacky: out_sz==64 is only used for post-compress XOF hashing,
     369             :          so use that as a hint when to suppress the 'CHUNK_START' flag. */
     370    11959212 :       chunk_flags = wu_or( chunk_flags, wu_if( block_first, wu_bcast( FD_BLAKE3_FLAG_CHUNK_START ), wu_zero() ) );
     371    11959212 :     }
     372    61513180 :     wu_t block_sz = wu_min( wu_sub( sz, off ), wu_bcast( FD_BLAKE3_BLOCK_SZ ) );
     373    61513180 :     block_flags = wu_or( block_flags, wu_if( is_parent, wu_zero(), chunk_flags ) );
     374             : 
     375             :     /* Check if we are done compressing */
     376             : 
     377    61513180 :     compress_done |= !wc_any( wc_or( active_lane_lo, active_lane_hi ) );
     378    61513180 :     if( FD_UNLIKELY( compress_done ) ) {
     379    27446790 :       if( FD_UNLIKELY( !lthash_rem ) ) break;
     380     1378478 :       active_lane_lo = wc_bcast( INT_MAX );
     381     1378478 :       active_lane_hi = wc_bcast( INT_MAX );
     382             :       /* Load the next message block and fall through to XOF expansion */
     383     1378478 :     }
     384             : 
     385             :     /* At this point, we have at least 1 block in this message segment
     386             :        pass that has not been processed.  Load the next 64 bytes of
     387             :        each unprocessed block.  Inactive lanes (e.g. message segments
     388             :        in this pass for which we've already processed all the blocks)
     389             :        will load garbage from a sentinel location (and the result of
     390             :        the state computations for the inactive lane will be ignored). */
     391             : 
     392    35444868 :     wv_t W03 = wv_if( active_lane_lo, W_lo, W_sentinel );
     393    35444868 :     uchar const * W0 = (uchar const *)wv_extract( W03, 0 );
     394    35444868 :     uchar const * W1 = (uchar const *)wv_extract( W03, 1 );
     395    35444868 :     uchar const * W2 = (uchar const *)wv_extract( W03, 2 );
     396    35444868 :     uchar const * W3 = (uchar const *)wv_extract( W03, 3 );
     397             : 
     398    35444868 :     wv_t W47 = wv_if( active_lane_hi, W_hi, W_sentinel );
     399    35444868 :     uchar const * W4 = (uchar const *)wv_extract( W47, 0 );
     400    35444868 :     uchar const * W5 = (uchar const *)wv_extract( W47, 1 );
     401    35444868 :     uchar const * W6 = (uchar const *)wv_extract( W47, 2 );
     402    35444868 :     uchar const * W7 = (uchar const *)wv_extract( W47, 3 );
     403             : 
     404    35444868 :     wu_t m[16] = { wu_ldu( W0    ), wu_ldu( W1    ), wu_ldu( W2    ), wu_ldu( W3    ),
     405    35444868 :                    wu_ldu( W4    ), wu_ldu( W5    ), wu_ldu( W6    ), wu_ldu( W7    ),
     406    35444868 :                    wu_ldu( W0+32 ), wu_ldu( W1+32 ), wu_ldu( W2+32 ), wu_ldu( W3+32 ),
     407    35444868 :                    wu_ldu( W4+32 ), wu_ldu( W5+32 ), wu_ldu( W6+32 ), wu_ldu( W7+32 ) };
     408             : 
     409    35444868 :     wu_transpose_8x8( m[0x0], m[0x1], m[0x2], m[0x3], m[0x4], m[0x5], m[0x6], m[0x7],
     410    35444868 :                       m[0x0], m[0x1], m[0x2], m[0x3], m[0x4], m[0x5], m[0x6], m[0x7] );
     411    35444868 :     wu_transpose_8x8( m[0x8], m[0x9], m[0xa], m[0xb], m[0xc], m[0xd], m[0xe], m[0xf],
     412    35444868 :                       m[0x8], m[0x9], m[0xa], m[0xb], m[0xc], m[0xd], m[0xe], m[0xf] );
     413             : 
     414             :     /* Compute the BLAKE3 compression function updates */
     415             : 
     416    78177686 : compress: (void)0;
     417    78177686 :     wu_t v[16] = {
     418    78177686 :         h0,     h1,     h2,       h3,
     419    78177686 :         h4,     h5,     h6,       h7,
     420    78177686 :         iv0,    iv1,    iv2,      iv3,
     421    78177686 :         ctr_lo, ctr_hi, block_sz, block_flags,
     422    78177686 :     };
     423             : 
     424             :     /* Debug utility */
     425    78177686 : #define STATE_FMT         "state[%u] =\n  %08x %08x %08x %08x\n  %08x %08x %08x %08x\n  %08x %08x %08x %08x\n  %08x %08x %08x %08x"
     426    78177686 : #define STATE_FMT_ARGS(v,i) (uint)i,\
     427    78177686 :         fd_uint_bswap(wu_extract(v[0x0],i)),fd_uint_bswap(wu_extract(v[0x1],i)),fd_uint_bswap(wu_extract(v[0x2],i)),fd_uint_bswap(wu_extract(v[0x3],i)),\
     428    78177686 :         fd_uint_bswap(wu_extract(v[0x4],i)),fd_uint_bswap(wu_extract(v[0x5],i)),fd_uint_bswap(wu_extract(v[0x6],i)),fd_uint_bswap(wu_extract(v[0x7],i)),\
     429    78177686 :         fd_uint_bswap(wu_extract(v[0x8],i)),fd_uint_bswap(wu_extract(v[0x9],i)),fd_uint_bswap(wu_extract(v[0xa],i)),fd_uint_bswap(wu_extract(v[0xb],i)),\
     430    78177686 :         fd_uint_bswap(wu_extract(v[0xc],i)),fd_uint_bswap(wu_extract(v[0xd],i)),fd_uint_bswap(wu_extract(v[0xe],i)),fd_uint_bswap(wu_extract(v[0xf],i))
     431             : 
     432             :     // FD_LOG_NOTICE(( STATE_FMT, STATE_FMT_ARGS(v,0) ));
     433    78177686 :     round_fn8( v, m, 0 );
     434    78177686 :     round_fn8( v, m, 1 );
     435    78177686 :     round_fn8( v, m, 2 );
     436    78177686 :     round_fn8( v, m, 3 );
     437    78177686 :     round_fn8( v, m, 4 );
     438    78177686 :     round_fn8( v, m, 5 );
     439    78177686 :     round_fn8( v, m, 6 );
     440             :     // FD_LOG_NOTICE(( STATE_FMT, STATE_FMT_ARGS(v,0) ));
     441             : 
     442    78177686 :     wu_t d[8] = {
     443    78177686 :       wu_xor( v[ 0], v[ 8] ), wu_xor( v[ 1], v[ 9] ),
     444    78177686 :       wu_xor( v[ 2], v[10] ), wu_xor( v[ 3], v[11] ),
     445    78177686 :       wu_xor( v[ 4], v[12] ), wu_xor( v[ 5], v[13] ),
     446    78177686 :       wu_xor( v[ 6], v[14] ), wu_xor( v[ 7], v[15] )
     447    78177686 :     };
     448             : 
     449    78177686 :     if( FD_LIKELY( !compress_done ) ) {
     450             : 
     451             :       /* Apply the state updates to the active lanes */
     452             : 
     453    34066390 :       wc_t active_lane = wc_narrow( active_lane_lo, active_lane_hi );
     454    34066390 :       if( FD_UNLIKELY( out_sz==64 ) ) {
     455             :         /* FIXME only export in the last iteration */
     456    24776984 :         hu[0] = wu_if( active_lane, wu_xor( h0, v[ 8] ), hu[0] );
     457    24776984 :         hu[1] = wu_if( active_lane, wu_xor( h1, v[ 9] ), hu[1] );
     458    24776984 :         hu[2] = wu_if( active_lane, wu_xor( h2, v[10] ), hu[2] );
     459    24776984 :         hu[3] = wu_if( active_lane, wu_xor( h3, v[11] ), hu[3] );
     460    24776984 :         hu[4] = wu_if( active_lane, wu_xor( h4, v[12] ), hu[4] );
     461    24776984 :         hu[5] = wu_if( active_lane, wu_xor( h5, v[13] ), hu[5] );
     462    24776984 :         hu[6] = wu_if( active_lane, wu_xor( h6, v[14] ), hu[6] );
     463    24776984 :         hu[7] = wu_if( active_lane, wu_xor( h7, v[15] ), hu[7] );
     464    24776984 :       }
     465    34066390 :       h0 = wu_if( active_lane, d[0], h0 );
     466    34066390 :       h1 = wu_if( active_lane, d[1], h1 );
     467    34066390 :       h2 = wu_if( active_lane, d[2], h2 );
     468    34066390 :       h3 = wu_if( active_lane, d[3], h3 );
     469    34066390 :       h4 = wu_if( active_lane, d[4], h4 );
     470    34066390 :       h5 = wu_if( active_lane, d[5], h5 );
     471    34066390 :       h6 = wu_if( active_lane, d[6], h6 );
     472    34066390 :       h7 = wu_if( active_lane, d[7], h7 );
     473             : 
     474             :       /* Advance to the next message segment blocks.  In pseudo code,
     475             :          the below is:
     476             : 
     477             :            W += 64; if( block_rem ) block_rem--;
     478             : 
     479             :          Since wc_to_wv_raw(false/true) is 0UL/~0UL, we can use wv_add /
     480             :          wc_to_wv_raw instead of wv_sub / wc_to_wv to save some ops.
     481             :          (Consider conditional increment / decrement operations?)
     482             : 
     483             :          Also since we do not load anything at W(lane) above unless
     484             :          block_rem(lane) is non-zero, we can omit vector conditional
     485             :          operations for W(lane) below to save some additional ops. */
     486             : 
     487    34066390 :       W_lo = wv_add( W_lo, wv_if( active_lane_lo, wv_64, wv_zero() ) );
     488    34066390 :       W_hi = wv_add( W_hi, wv_if( active_lane_hi, wv_64, wv_zero() ) );
     489    34066390 :       off  = wu_add( off,  wu_if( active_lane, wu_bcast( FD_BLAKE3_BLOCK_SZ ), wv_zero() ) );
     490             : 
     491    34066390 :       block_rem_lo = wv_add( block_rem_lo, wv_if( active_lane_lo, wc_to_wv_raw( active_lane_lo ), wv_zero() ) );
     492    34066390 :       block_rem_hi = wv_add( block_rem_hi, wv_if( active_lane_hi, wc_to_wv_raw( active_lane_hi ), wv_zero() ) );
     493             : 
     494    44111296 :     } else { /* LtHash mode */
     495             : 
     496             :       /* d[i] contains output_off+(i*4) 32-bit words across output[0..8] */
     497    44111296 :       wu_t dh[ 8 ] = {
     498    44111296 :         wu_xor( h0, v[0x8] ),
     499    44111296 :         wu_xor( h1, v[0x9] ),
     500    44111296 :         wu_xor( h2, v[0xa] ),
     501    44111296 :         wu_xor( h3, v[0xb] ),
     502    44111296 :         wu_xor( h4, v[0xc] ),
     503    44111296 :         wu_xor( h5, v[0xd] ),
     504    44111296 :         wu_xor( h6, v[0xe] ),
     505    44111296 :         wu_xor( h7, v[0xf] )
     506    44111296 :       };
     507             : 
     508             :       /* Transpose outer 8x8 blocks */
     509    44111296 :       wu_transpose_8x8( d [0],d [1],d [2],d [3],d [4],d [5],d [6],d [7],
     510    44111296 :                         d [0],d [1],d [2],d [3],d [4],d [5],d [6],d [7] );
     511    44111296 :       wu_transpose_8x8( dh[0],dh[1],dh[2],dh[3],dh[4],dh[5],dh[6],dh[7],
     512    44111296 :                         dh[0],dh[1],dh[2],dh[3],dh[4],dh[5],dh[6],dh[7] );
     513             : 
     514             :       /* d[i] contains output[i]+out_off */
     515             : 
     516             :       /* Reduce-add into d[0] */
     517    44111296 :       d [0] = wh_add( d [0], d [1] ); /* sum(l[0 1]) */
     518    44111296 :       dh[0] = wh_add( dh[0], dh[1] ); /* sum(h[0 1]) */
     519    44111296 :       d [2] = wh_add( d [2], d [3] ); /* sum(l[2 3]) */
     520    44111296 :       dh[2] = wh_add( dh[2], dh[3] ); /* sum(h[2 3]) */
     521    44111296 :       d [4] = wh_add( d [4], d [5] ); /* sum(l[4 5])*/
     522    44111296 :       dh[4] = wh_add( dh[4], dh[5] ); /* sum(h[4 5]) */
     523    44111296 :       d [6] = wh_add( d [6], d [7] ); /* sum(l[6 7]) */
     524    44111296 :       dh[6] = wh_add( dh[6], dh[7] ); /* sum(h[6 7]) */
     525    44111296 :       d [0] = wh_add( d [0], d [2] ); /* sum(l[0 1 2 3]) */
     526    44111296 :       dh[0] = wh_add( dh[0], dh[2] ); /* sum(h[0 1 2 3]) */
     527    44111296 :       d [4] = wh_add( d [4], d [6] ); /* sum(l[4 5 6 7]) */
     528    44111296 :       dh[4] = wh_add( dh[4], dh[6] ); /* sum(h[4 5 6 7]) */
     529    44111296 :       d [0] = wh_add( d [0], d [4] ); /* sum(l[0 1 2 3 4 5 6 7]) */
     530    44111296 :       dh[0] = wh_add( dh[0], dh[4] ); /* sum(h[0 1 2 3 4 5 6 7]) */
     531    44111296 :       wh_st( lthash,    d [0] );
     532    44111296 :       wh_st( lthash+16, dh[0] );
     533             : 
     534             :       /* Wind up for next iteration */
     535    44111296 :       lthash += 32;
     536    44111296 :       lthash_rem--;
     537    44111296 :       wu_t ctr_add   = wu_bcast( 1 );
     538    44111296 :       /**/ ctr_lo    = wu_add( ctr_lo, ctr_add );
     539    44111296 :       wu_t ctr_carry = wi_gt ( wu_xor( ctr_add, wu_bcast( 0x80000000 ) ),
     540    44111296 :                                wu_xor( ctr_lo,  wu_bcast( 0x80000000 ) ) );
     541    44111296 :       /**/ ctr_hi    = wu_sub( ctr_hi, ctr_carry );
     542    44111296 :       if( FD_UNLIKELY( !lthash_rem ) ) {
     543     1378478 :         FD_BLAKE3_TRACE(( "fd_blake3_avx_compress8: done (lthash para)" ));
     544     1378478 :         return;
     545     1378478 :       }
     546    42732818 :       goto compress;
     547             : 
     548    44111296 : #   undef STATE_FMT
     549    44111296 : #   undef STATE_FMT_ARGS
     550    44111296 :     }
     551    78177686 :   }
     552             : 
     553             :   /* Store the results */
     554             : 
     555    26068312 :   wu_transpose_8x8( h0, h1, h2, h3, h4, h5, h6, h7,
     556    26068312 :                     h0, h1, h2, h3, h4, h5, h6, h7 );
     557             : 
     558    26068312 :   uint * const * batch_hash = (uint * const *)__builtin_assume_aligned( _batch_hash, 32 );
     559    26068312 :   if( FD_LIKELY( out_sz==32 ) ) {
     560     1291328 :     switch( batch_cnt ) { /* application dependent prob */
     561      176218 :     case 8UL: wu_st( batch_hash[7], h7 ); __attribute__((fallthrough));
     562      309838 :     case 7UL: wu_st( batch_hash[6], h6 ); __attribute__((fallthrough));
     563      443878 :     case 6UL: wu_st( batch_hash[5], h5 ); __attribute__((fallthrough));
     564      593404 :     case 5UL: wu_st( batch_hash[4], h4 ); __attribute__((fallthrough));
     565      731972 :     case 4UL: wu_st( batch_hash[3], h3 ); __attribute__((fallthrough));
     566      920064 :     case 3UL: wu_st( batch_hash[2], h2 ); __attribute__((fallthrough));
     567     1291328 :     case 2UL: wu_st( batch_hash[1], h1 ); __attribute__((fallthrough));
     568     1291328 :     case 1UL: wu_st( batch_hash[0], h0 ); __attribute__((fallthrough));
     569     1291328 :     default: break;
     570     1291328 :     }
     571    24776984 :   } else if( out_sz==64 ) {
     572    24776984 :     wu_transpose_8x8( hu[0], hu[1], hu[2], hu[3], hu[4], hu[5], hu[6], hu[7],
     573    24776984 :                       hu[0], hu[1], hu[2], hu[3], hu[4], hu[5], hu[6], hu[7] );
     574    24776984 :     switch( batch_cnt ) { /* application dependent prob */
     575    24776984 :     case 8UL: wu_st( batch_hash[7],   h7    );
     576    24776984 :               wu_st( batch_hash[7]+8, hu[7] ); __attribute__((fallthrough));
     577    24776984 :     case 7UL: wu_st( batch_hash[6],   h6    );
     578    24776984 :               wu_st( batch_hash[6]+8, hu[6] ); __attribute__((fallthrough));
     579    24776984 :     case 6UL: wu_st( batch_hash[5],   h5    );
     580    24776984 :               wu_st( batch_hash[5]+8, hu[5] ); __attribute__((fallthrough));
     581    24776984 :     case 5UL: wu_st( batch_hash[4],   h4    );
     582    24776984 :               wu_st( batch_hash[4]+8, hu[4] ); __attribute__((fallthrough));
     583    24776984 :     case 4UL: wu_st( batch_hash[3],   h3    );
     584    24776984 :               wu_st( batch_hash[3]+8, hu[3] ); __attribute__((fallthrough));
     585    24776984 :     case 3UL: wu_st( batch_hash[2],   h2    );
     586    24776984 :               wu_st( batch_hash[2]+8, hu[2] ); __attribute__((fallthrough));
     587    24776984 :     case 2UL: wu_st( batch_hash[1],   h1    );
     588    24776984 :               wu_st( batch_hash[1]+8, hu[1] ); __attribute__((fallthrough));
     589    24776984 :     case 1UL: wu_st( batch_hash[0],   h0    );
     590    24776984 :               wu_st( batch_hash[0]+8, hu[0] ); __attribute__((fallthrough));
     591    24776984 :     default: break;
     592    24776984 :     }
     593    24776984 :   } else {
     594           0 :     FD_LOG_ERR(( "Invalid out_sz %u", out_sz ));
     595           0 :   }
     596    26068312 : }
     597             : 
     598             : void
     599             : fd_blake3_avx_compress8_fast( uchar const * restrict msg,
     600             :                               uchar       * restrict _out,
     601             :                               ulong                  counter,
     602     6825580 :                               uchar                  flags ) {
     603     6825580 :   FD_BLAKE3_TRACE(( "fd_blake3_avx_compress8_fast(msg=%p,out=%p,counter=%lu,flags=%02x)", (void *)msg, (void *)_out, counter, flags ));
     604             : 
     605     6825580 :   uchar * restrict out = __builtin_assume_aligned( _out, 32 );
     606             : 
     607     6825580 :   int   parent = flags & FD_BLAKE3_FLAG_PARENT;
     608     6825580 :   int   lg_sz  = fd_int_if( parent, FD_BLAKE3_OUTCHAIN_LG_SZ+1, FD_BLAKE3_CHUNK_LG_SZ );
     609     6825580 :   ulong sz     = 1UL<<lg_sz;
     610             : 
     611             :   /* counters stay the same for each block.  Across chunks, they
     612             :      increment if we are hashing leaves.  Otherwise, they are zero. */
     613             : 
     614     6825580 :   wu_t ctr_add   = wu_and( wu_bcast( parent ? 0 : UINT_MAX ),
     615     6825580 :                            wu( 0, 1, 2, 3, 4, 5, 6, 7 ) );
     616     6825580 :   wu_t ctr_lo    = wu_add( wu_bcast( counter ), ctr_add );
     617     6825580 :   wu_t ctr_carry = wi_gt ( wu_xor( ctr_add, wu_bcast( 0x80000000 ) ),
     618     6825580 :                            wu_xor( ctr_lo,  wu_bcast( 0x80000000 ) ) );
     619     6825580 :   wu_t ctr_hi    = wu_sub( wu_bcast( counter>>32 ), ctr_carry );
     620     6825580 :   wu_t sz_vec    = wu_bcast( FD_BLAKE3_BLOCK_SZ );
     621             : 
     622     6825580 :   wu_t const iv0 = wu_bcast( FD_BLAKE3_IV[0] );
     623     6825580 :   wu_t const iv1 = wu_bcast( FD_BLAKE3_IV[1] );
     624     6825580 :   wu_t const iv2 = wu_bcast( FD_BLAKE3_IV[2] );
     625     6825580 :   wu_t const iv3 = wu_bcast( FD_BLAKE3_IV[3] );
     626     6825580 :   wu_t const iv4 = wu_bcast( FD_BLAKE3_IV[4] );
     627     6825580 :   wu_t const iv5 = wu_bcast( FD_BLAKE3_IV[5] );
     628     6825580 :   wu_t const iv6 = wu_bcast( FD_BLAKE3_IV[6] );
     629     6825580 :   wu_t const iv7 = wu_bcast( FD_BLAKE3_IV[7] );
     630             : 
     631     6825580 :   wu_t h0=iv0; wu_t h1=iv1; wu_t h2=iv2; wu_t h3=iv3;
     632     6825580 :   wu_t h4=iv4; wu_t h5=iv5; wu_t h6=iv6; wu_t h7=iv7;
     633             : 
     634     6825580 :   ulong off = 0UL;
     635    62403160 :   do {
     636    62403160 :     ulong const off_next = off+FD_BLAKE3_BLOCK_SZ;
     637    62403160 :     uint chunk_flags =
     638    62403160 :         ( off     ==0UL ? FD_BLAKE3_FLAG_CHUNK_START : 0u ) |
     639    62403160 :         ( off_next==sz  ? FD_BLAKE3_FLAG_CHUNK_END   : 0u );
     640    62403160 :     uint flags_ = flags | fd_uint_if( parent, 0, chunk_flags );
     641    62403160 :     wu_t flags_vec = wu_bcast( flags_ );
     642             : 
     643    62403160 :     wu_t m[16];
     644    62403160 :     m[ 0] = wu_ldu( msg + (0<<lg_sz) + off      );
     645    62403160 :     m[ 1] = wu_ldu( msg + (1<<lg_sz) + off      );
     646    62403160 :     m[ 2] = wu_ldu( msg + (2<<lg_sz) + off      );
     647    62403160 :     m[ 3] = wu_ldu( msg + (3<<lg_sz) + off      );
     648    62403160 :     m[ 4] = wu_ldu( msg + (4<<lg_sz) + off      );
     649    62403160 :     m[ 5] = wu_ldu( msg + (5<<lg_sz) + off      );
     650    62403160 :     m[ 6] = wu_ldu( msg + (6<<lg_sz) + off      );
     651    62403160 :     m[ 7] = wu_ldu( msg + (7<<lg_sz) + off      );
     652    62403160 :     m[ 8] = wu_ldu( msg + (0<<lg_sz) + off + 32 );
     653    62403160 :     m[ 9] = wu_ldu( msg + (1<<lg_sz) + off + 32 );
     654    62403160 :     m[10] = wu_ldu( msg + (2<<lg_sz) + off + 32 );
     655    62403160 :     m[11] = wu_ldu( msg + (3<<lg_sz) + off + 32 );
     656    62403160 :     m[12] = wu_ldu( msg + (4<<lg_sz) + off + 32 );
     657    62403160 :     m[13] = wu_ldu( msg + (5<<lg_sz) + off + 32 );
     658    62403160 :     m[14] = wu_ldu( msg + (6<<lg_sz) + off + 32 );
     659    62403160 :     m[15] = wu_ldu( msg + (7<<lg_sz) + off + 32 );
     660             : 
     661    62403160 :     wu_transpose_8x8( m[0x0], m[0x1], m[0x2], m[0x3], m[0x4], m[0x5], m[0x6], m[0x7],
     662    62403160 :                       m[0x0], m[0x1], m[0x2], m[0x3], m[0x4], m[0x5], m[0x6], m[0x7] );
     663    62403160 :     wu_transpose_8x8( m[0x8], m[0x9], m[0xa], m[0xb], m[0xc], m[0xd], m[0xe], m[0xf],
     664    62403160 :                       m[0x8], m[0x9], m[0xa], m[0xb], m[0xc], m[0xd], m[0xe], m[0xf] );
     665             : 
     666    62403160 :     wu_t v[16] = {
     667    62403160 :         h0,     h1,     h2,     h3,
     668    62403160 :         h4,     h5,     h6,     h7,
     669    62403160 :         iv0,    iv1,    iv2,    iv3,
     670    62403160 :         ctr_lo, ctr_hi, sz_vec, flags_vec,
     671    62403160 :     };
     672             : 
     673    62403160 :     round_fn8( v, m, 0 );
     674    62403160 :     round_fn8( v, m, 1 );
     675    62403160 :     round_fn8( v, m, 2 );
     676    62403160 :     round_fn8( v, m, 3 );
     677    62403160 :     round_fn8( v, m, 4 );
     678    62403160 :     round_fn8( v, m, 5 );
     679    62403160 :     round_fn8( v, m, 6 );
     680             : 
     681    62403160 :     h0 = wu_xor( v[ 0], v[ 8] );
     682    62403160 :     h1 = wu_xor( v[ 1], v[ 9] );
     683    62403160 :     h2 = wu_xor( v[ 2], v[10] );
     684    62403160 :     h3 = wu_xor( v[ 3], v[11] );
     685    62403160 :     h4 = wu_xor( v[ 4], v[12] );
     686    62403160 :     h5 = wu_xor( v[ 5], v[13] );
     687    62403160 :     h6 = wu_xor( v[ 6], v[14] );
     688    62403160 :     h7 = wu_xor( v[ 7], v[15] );
     689             : 
     690    62403160 :     off = off_next;
     691    62403160 :   } while( off!=sz );
     692             : 
     693     6825580 :   wu_transpose_8x8( h0, h1, h2, h3, h4, h5, h6, h7,
     694     6825580 :                     h0, h1, h2, h3, h4, h5, h6, h7 );
     695             : 
     696     6825580 :   wu_st( (uint *)( out + (0UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h0 );
     697     6825580 :   wu_st( (uint *)( out + (1UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h1 );
     698     6825580 :   wu_st( (uint *)( out + (2UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h2 );
     699     6825580 :   wu_st( (uint *)( out + (3UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h3 );
     700     6825580 :   wu_st( (uint *)( out + (4UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h4 );
     701     6825580 :   wu_st( (uint *)( out + (5UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h5 );
     702     6825580 :   wu_st( (uint *)( out + (6UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h6 );
     703     6825580 :   wu_st( (uint *)( out + (7UL<<FD_BLAKE3_OUTCHAIN_LG_SZ) ), h7 );
     704     6825580 : }

Generated by: LCOV version 1.14