@@ -597,6 +597,177 @@ uint32_t crc32c_hw(const uint8_t *data, size_t nbytes, uint32_t crc) {
597597 return crc32c_hw_portable (data, nbytes, crc);
598598}
599599
600+ // rk1 ~ rk20
601+ __attribute__ ((aligned(16 ), used))
602+ const static uint64_t rk[20] = {
603+ 0xdabe95afc7875f40 ,
604+ 0xe05dd497ca393ae4 ,
605+ 0xd7d86b2af73de740 ,
606+ 0x8757d71d4fcc1000 ,
607+ 0xdabe95afc7875f40 ,
608+ 0x0000000000000000 ,
609+ 0x9c3e466c172963d5 ,
610+ 0x92d8af2baf0e1e84 ,
611+ 0x947874de595052cb ,
612+ 0x9e735cb59b4724da ,
613+ 0xe4ce2cd55fea0037 ,
614+ 0x2fe3fd2920ce82ec ,
615+ 0x0e31d519421a63a5 ,
616+ 0x2e30203212cac325 ,
617+ 0x081f6054a7842df4 ,
618+ 0x6ae3efbb9dd441f3 ,
619+ 0x69a35d91c3730254 ,
620+ 0xb5ea1af9c013aca4 ,
621+ 0x3be653a30fe1af51 ,
622+ 0x60095b008a9efa44 ,
623+ };
624+
625+ #define RK (i ) &rk[i-1 ]
626+
627+ __attribute__ ((aligned(16 ), used))
628+ const static uint64_t mask[6] = {
629+ 0xFFFFFFFFFFFFFFFF , 0x0000000000000000 ,
630+ 0xFFFFFFFF00000000 , 0xFFFFFFFFFFFFFFFF ,
631+ 0x8080808080808080 , 0x8080808080808080 ,
632+ };
633+
634+ #define MASK (i ) ({auto p = &mask[((i)-1 )*2 ]; *(v128*)p;})
635+
636+ const static uint64_t pshufb_shf_table[4 ] = {
637+ 0x8786858483828100 , 0x8f8e8d8c8b8a8988 ,
638+ 0x0706050403020100 , 0x000e0d0c0b0a0908 };
639+
640+ inline void * get_shf_table (size_t i) {
641+ return (char *)pshufb_shf_table + i;
642+ }
643+
644+ #pragma GCC diagnostic ignored "-Wstrict-aliasing"
645+
646+ inline uint64_t mm_load_tail_tiny (const void * data, size_t n) {
647+ uint64_t x = 0 ;
648+ (char *&)data += n;
649+ if (n & 4 ) x = *--(const uint32_t *&)data;
650+ if (n & 2 ) x = (x<<16 ) | *--(const uint16_t *&)data ;
651+ if (n & 1 ) x = (x <<8 ) | *--(const uint8_t *&)data ;
652+ return x;
653+ }
654+
655+ #ifdef __x86_64__
656+ #include < immintrin.h>
657+ #elif defined(__aarch64__)
658+ #if !defined(__clang__) && defined(__GNUC__)
659+ #undef __GNUC__
660+ #define __GNUC__ 10
661+ #endif
662+ #define SSE2NEON_SUPPRESS_WARNINGS
663+ #include " sse2neon.h"
664+ #else
665+ #error "Unsupported architecture"
666+ #endif
667+
668+ struct SSE {
669+ public:
670+ typedef __m128i v128;
671+ static v128 loadu (const void * ptr) {
672+ return _mm_loadu_si128 ((v128*)ptr);
673+ }
674+ static v128 pshufb (v128& x, const v128& y) {
675+ return (v128)_mm_shuffle_epi8 ((__m128i&)x, (const __m128i&)y);
676+ }
677+ static v128 pblendvb (v128& x, v128& y, v128& z) {
678+ return (v128)_mm_blendv_epi8 ((__m128i&)x, (__m128i&)y, (__m128i&)z);
679+ }
680+ template <uint8_t imm>
681+ static v128 pclmulqdq (v128& x, const uint64_t * rk) {
682+ return _mm_clmulepi64_si128 (x, *(const v128*)rk, imm);
683+ }
684+ static v128 op (v128& x, const uint64_t * rk) {
685+ return pclmulqdq<0x10 >(x, rk) ^ pclmulqdq<0x01 >(x, rk);
686+ }
687+ static v128 load_small (const void * data, size_t n) {
688+ assert (n < 16 );
689+ long x = mm_load_tail_tiny (data, n);
690+ return (n & 8 ) ? v128{*(long *)data, x} : v128{x, 0 };
691+ }
692+ static v128 bsl8 (v128 x) {
693+ return _mm_bslli_si128 (x, 8 );
694+ }
695+ static v128 bsr8 (v128 x) {
696+ return _mm_bsrli_si128 (x, 8 );
697+ }
698+ };
699+
700+
701+ inline __attribute__ ((always_inline))
702+ uint64_t crc64ecma_hw_portable(const uint8_t *data, size_t nbytes, uint64_t crc) {
703+ if (unlikely (!nbytes || !data)) return crc;
704+ using SIMD = SSE ;
705+ using v128 = typename SIMD ::v128;
706+ v128 xmm7 = {(long )~crc};
707+ auto & ptr = (const v128*&)data;
708+ if (nbytes >= 256 ) {
709+ v128 xmm[8 ];
710+ assert (nbytes >= 256 );
711+ static_loop<0 , 7 , 1 >(BODY (i){ xmm[i] = SIMD::loadu (ptr+i); });
712+ xmm[0 ] ^= xmm7; ptr += 8 ; nbytes -= 128 ;
713+ do {
714+ static_loop<0 , 7 , 1 >(BODY (i) {
715+ xmm[i] = SIMD::op (xmm[i], RK (3 )) ^ SIMD::loadu (ptr+i);
716+ });
717+ ptr += 8 ; nbytes -= 128 ;
718+ } while (nbytes >= 128 );
719+ static_loop<0 , 6 , 1 >(BODY (i) {
720+ auto I = (i == 6 ) ? 1 : (9 + i * 2 );
721+ xmm[7 ] ^= SIMD::op (xmm[i], RK (I));
722+ });
723+ xmm7 = xmm[7 ];
724+ } else if (nbytes >= 16 ) {
725+ xmm7 ^= SIMD::loadu (ptr++);
726+ nbytes -= 16 ;
727+ } else /* 0 < nbytes < 16*/ {
728+ xmm7 ^= SIMD::load_small (data, nbytes);
729+ if (nbytes >= 8 ) {
730+ auto shf = SIMD::loadu (get_shf_table (nbytes));
731+ xmm7 = SIMD::pshufb (xmm7, shf);
732+ goto _128_done;
733+ } else {
734+ auto shf = SIMD::loadu (get_shf_table (nbytes + 8 ));
735+ xmm7 = SIMD::pshufb (xmm7, shf);
736+ goto _barrett;
737+ }
738+ }
739+
740+ while (nbytes >= 16 ) {
741+ xmm7 = SIMD::op (xmm7, RK (1 )) ^ SIMD::loadu (ptr++);
742+ nbytes -= 16 ;
743+ }
744+
745+ if (nbytes) {
746+ auto p = data + nbytes - 16 ;
747+ auto remainder = SIMD::loadu ((v128*)p);
748+ auto xmm0 = SIMD::loadu (get_shf_table (nbytes));
749+ auto xmm2 = xmm7;
750+ xmm7 = SIMD::pshufb (xmm7, xmm0);
751+ xmm0 ^= MASK (3 );
752+ xmm2 = SIMD::pshufb (xmm2, xmm0);
753+ xmm2 = SIMD::pblendvb (xmm2, remainder, xmm0);
754+ xmm7 = xmm2 ^ SIMD::op (xmm7, RK (1 ));
755+ }
756+ _128_done:
757+ xmm7 = SIMD ::pclmulqdq<0 >(xmm7, RK (5 )) ^ SIMD::bsr8 (xmm7);
758+ _barrett:
759+ auto t = SIMD ::pclmulqdq<0 >(xmm7, RK (7 ));
760+ xmm7 ^= SIMD ::pclmulqdq<0x10 >(t, RK (7 )) ^ SIMD::bsl8 (t);
761+ auto p = (uint64_t *)&xmm7;
762+ crc = ~p[1 ];
763+ return crc;
764+ }
765+
766+ uint64_t crc64ecma_hw (const uint8_t *buf, size_t len, uint64_t crc) {
767+ return crc64ecma_hw_portable (buf, len, crc);
768+ }
769+
770+
600771/*
601772 * Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved
602773 *
0 commit comments