@@ -44,7 +44,6 @@ inline T do_crc(const uint8_t *data, size_t nbytes, T crc, F1 f1, F8 f8) {
4444 crc = f8 (crc, *(uint64_t *)(data + offset));
4545 offset += sizeof (uint64_t );
4646 }
47-
4847 // Process any bytes remaining after the last aligned 8-byte block.
4948 while (offset < nbytes) {
5049 crc = f1 (crc, data[offset]);
@@ -515,8 +514,8 @@ uint32_t crc32c_hw(const uint8_t *data, size_t nbytes, uint32_t crc) {
515514 return crc32c_hw_portable (data, nbytes, crc);
516515}
517516
518- // for 2nd size of 16, 32, ..., 2G bytes
519- const static uint32_t crc32c_combine_table[] = {
517+ const static uint32_t crc32c_lshift_table[] = {
518+ // by length of 16, 32, ..., 2G bytes
520519 0x493c7d27 , 0xba4fc28e , 0x9e4addf8 , 0x0d3b6092 ,
521520 0xb9e02b86 , 0xdd7e3b0c , 0x170076fa , 0xa51b6135 ,
522521 0x82f89c77 , 0x54a86326 , 0x1dc403cc , 0x5ae703ab ,
@@ -526,16 +525,20 @@ const static uint32_t crc32c_combine_table[] = {
526525 0xd610d67e , 0x6b086b3f , 0xd94f3c0b , 0xbf818109 ,
527526};
528527
529- static uint32_t crc32c_shift (uint32_t crc1, uint32_t len2,
528+ // virtually pad `len2` bytes of 0 to source
529+ // data, and return resulting crc value
530+ // `len2` must be >= 16
531+ static uint32_t crc32c_lshift_big (uint32_t crc1, uint32_t len2,
530532 uint32_t (*shift)(uint32_t crc1, uint32_t x)) {
531533 for (len2 >>= 4 ; len2; len2 &= len2 - 1 ) {
532- auto x = crc32c_combine_table [__builtin_ctz (len2)];
534+ auto x = crc32c_lshift_table [__builtin_ctz (len2)];
533535 crc1 = shift (crc1, x);
534536 }
535537 return crc1;
536538}
537539
538- static uint32_t crc32c_shift_hw (uint32_t crc1, uint32_t x) {
540+ // do lshift with SIMD instructions
541+ static uint32_t do_crc32c_lshift_hw (uint32_t crc1, uint32_t x) {
539542 uint64_t dat64;
540543 __m128i crc1x, cnstx;
541544 crc1x = _mm_setr_epi32 (crc1, 0 , 0 , 0 );
@@ -546,15 +549,15 @@ static uint32_t crc32c_shift_hw(uint32_t crc1, uint32_t x) {
546549}
547550
548551uint32_t crc32c_combine_hw (uint32_t crc1, uint32_t crc2, uint32_t len2) {
549- crc1 = crc32c_shift (crc1, len2, crc32c_shift_hw);
550- if (unlikely (len2 &= 16 - 1 )) {
551- // I don't know why this doesn't work, while it works for crc32c_combine_sw()
552- LOG_ERROR_RETURN (EINVAL , -1 , " len2 must be a multiple of 16" );
552+ if (unlikely (!crc1)) return crc2;
553+ if (unlikely (!len2)) return crc1;
554+ if (unlikely (len2 & 15 )) {
553555 if (unlikely (len2 & 8 )) crc1 = crc32c (crc1, (uint64_t )0 );
554556 if (unlikely (len2 & 4 )) crc1 = crc32c (crc1, (uint32_t )0 );
555557 if (unlikely (len2 & 2 )) crc1 = crc32c (crc1, (uint16_t )0 );
556558 if (unlikely (len2 & 1 )) crc1 = crc32c (crc1, (uint8_t )0 );
557559 }
560+ crc1 = crc32c_lshift_big (crc1, len2, do_crc32c_lshift_hw);
558561 return crc1 ^ crc2;
559562}
560563
@@ -575,26 +578,28 @@ static uint64_t bit_reverse32_64(uint32_t x) {
575578 return x64 << 32 ;
576579}
577580
578- static uint32_t crc32c_shift_sw (uint32_t crc1, uint32_t x) {
581+ // do lshift with traditional scalar instructions
582+ static uint32_t do_crc32c_lshift_sw (uint32_t crc1, uint32_t x) {
579583 uint64_t q = 0 , xrev = bit_reverse32_64 (x);
580584 for (int i = 0 ; i < 64 ; i++, xrev >>= 1 )
581585 q = (q << 1 ) | __builtin_parity (crc1 & xrev);
582586 return crc32c_sw ((uint8_t *)&q, 8 , 0 );
583587}
584588
589+ const static unsigned char zeros[32 ] = {0 };
585590uint32_t crc32c_combine_sw (uint32_t crc1, uint32_t crc2, uint32_t len2) {
586- crc1 = crc32c_shift (crc1, len2, crc32c_shift_sw);
587- if (unlikely (len2 &= 16 - 1 )) {
588- const static unsigned char zero[8 ] = {0 };
589- if (unlikely (len2 & 8 )) crc1 = crc32c_sw (zero, 8 , crc1);
590- if (unlikely (len2 & 4 )) crc1 = crc32c_sw (zero, 4 , crc1);
591- if (unlikely (len2 & 2 )) crc1 = crc32c_sw (zero, 2 , crc1);
592- if (unlikely (len2 & 1 )) crc1 = crc32c_sw (zero, 1 , crc1);
591+ if (unlikely (!crc1)) return crc2;
592+ if (unlikely (!len2)) return crc1;
593+ if (unlikely (len2 & 15 )) {
594+ crc1 = crc32c_sw (zeros, len2 & 15 , crc1);
593595 }
596+ crc1 = crc32c_lshift_big (crc1, len2, do_crc32c_lshift_sw);
594597 return crc1 ^ crc2;
595598}
596599
597- static uint32_t crc32_remove0 (uint32_t crc1, size_t len2) {
600+ // virtually remove `len2` bytes of trailing 0 from
601+ // source data, and return resulting crc value
602+ static uint32_t crc32c_rshift_sw (uint32_t crc1, size_t len2) {
598603 // remove the effect of the zeros added to crc1
599604 // If crc1 = crcA * x^len2 mod p(x), then crcA = crc1 * (x^len2)^(-1) mod p(x)
600605 // Based on crc32_combine_return_crcA0, but uses inverse matrix to remove zeros.
@@ -679,9 +684,9 @@ uint32_t crc32c_trim_sw(CRC32C_Component all, CRC32C_Component prefix, CRC32C_Co
679684 LOG_ERRNO_RETURN (EINVAL , 0 , " total size (`) is shorter than summed sizes of prefix (`) + suffix (`)" , all.size , prefix.size , suffix.size );
680685 auto crc = all.crc ;
681686 if (prefix.size )
682- crc ^= crc32c_shift (prefix.crc , all.size - prefix.size , crc32c_shift_hw );
687+ crc = crc32c_combine_sw (prefix.crc , crc, all.size - prefix.size );
683688 if (suffix.size )
684- crc = crc32_remove0 (crc ^ suffix.crc , suffix.size );
689+ crc = crc32c_rshift_sw (crc ^ suffix.crc , suffix.size );
685690 return crc;
686691}
687692
@@ -850,6 +855,64 @@ uint64_t crc64ecma_hw_sse128(const uint8_t *buf, size_t len, uint64_t crc) {
850855 return crc64ecma_hw_portable (buf, len, crc, crc64ecma_hw_big_sse);
851856}
852857
858+ __attribute__ ((aligned(16 ), used))
859+ const static uint64_t crc64ecma_lshift_table[] = {
860+ // by length of 32, 64, ..., 4G bytes
861+ 0xe05dd497ca393ae4 , 0xb5ea1af9c013aca4 , 0x9e735cb59b4724da , 0x2ecbc6dd0447c685 ,
862+ 0x15d325270d465dfe , 0x3f663335b446e329 , 0x68a971ffad4f1766 , 0xb7fd3098b8293475 ,
863+ 0x1b225daef15ff37d , 0xea0ddceb7273a052 , 0x620648e8f01b0134 , 0xfba68785783fd770 ,
864+ 0x4c0976fee55cc2f6 , 0x2b4d20a2ca417feb , 0xf8a6eaabee9c15b0 , 0x2068c6b926839fed ,
865+ 0xc8fef34a6a17f35a , 0x0de5614bc4140f08 , 0x724fd734d6b83fac , 0x710def1593c89dfa ,
866+ 0x337733943ec752b9 , 0x2a46a23b7286e04a , 0x5e7857ffbea8390a , 0xa2988a6572c32450 ,
867+ 0xdb67937ee00fcea3 , 0xb427cfd9f16baa88 , 0x465d86031d8426b3 , 0x56ebf2f895082092 ,
868+ };
869+
870+ // virtually pad `len2` bytes of 0 to source
871+ // data, and return resulting crc value
872+ // `len2` must be >= 32
873+ static uint64_t crc64ecma_lshift_big (uint64_t crc1, uint32_t len2,
874+ uint64_t (*shift)(uint64_t crc1, uint64_t x)) {
875+ for (len2 >>= 5 ; len2; len2 &= len2 - 1 ) {
876+ auto x = crc64ecma_lshift_table[__builtin_ctz (len2)];
877+ crc1 = shift (crc1, x);
878+ }
879+ return crc1;
880+ }
881+
882+ static uint64_t do_crc64ecma_lshift_hw (uint64_t crc, uint64_t x) {
883+ __m128i crc1x, crc2x, crc3x, constx;
884+ const __m128i rk5 = _mm_loadl_epi64 ((__m128i*)&rk[5 -1 ]);
885+ const __m128i rk7 = _mm_loadu_si128 ((__m128i*)&rk[7 -1 ]);
886+
887+ crc1x = _mm_cvtsi64_si128 (crc);
888+ constx = _mm_cvtsi64_si128 (x);
889+ crc1x = _mm_clmulepi64_si128 (crc1x, constx, 0x00 );
890+
891+ // Fold to 64b
892+ crc2x = _mm_clmulepi64_si128 (crc1x, rk5, 0x00 );
893+ crc3x = _mm_bsrli_si128 (crc1x, 8 );
894+ crc1x = _mm_xor_si128 (crc2x, crc3x);
895+
896+ // Reduce
897+ crc2x = _mm_clmulepi64_si128 (crc1x, rk7, 0x00 );
898+ crc3x = _mm_clmulepi64_si128 (crc2x, rk7, 0x10 );
899+ crc2x = _mm_bslli_si128 (crc2x, 8 );
900+ crc1x = _mm_xor_si128 (crc1x, crc2x);
901+ crc1x = _mm_xor_si128 (crc1x, crc3x);
902+ return _mm_extract_epi64 (crc1x, 1 );
903+ }
904+
905+ uint64_t crc64ecma_combine_hw (uint64_t crc1, uint64_t crc2, uint32_t len2) {
906+ if (unlikely (!crc1)) return crc2;
907+ if (unlikely (!len2)) return crc1;
908+ if (unlikely (len2 & 31 )) {
909+ crc1 = ~crc64ecma_hw (zeros, len2 & 31 , ~crc1);
910+ }
911+ crc1 = crc64ecma_lshift_big (crc1, len2, do_crc64ecma_lshift_hw);
912+ return crc1 ^ crc2;
913+ }
914+
915+
853916#ifdef __x86_64__
854917#ifdef __clang__
855918#pragma clang attribute pop
0 commit comments