diff --git a/crc32.c b/crc32.c index dbdecd3..3bd0339 100644 --- a/crc32.c +++ b/crc32.c @@ -61,21 +61,27 @@ AARU_EXPORT int AARU_CALL crc32_update(crc32_ctx* ctx, const uint8_t* data, uint } #endif + crc32_slicing(&ctx->crc, data, len); + return 0; +} + +void crc32_slicing(uint32_t* crc, const unsigned char* data, long len) +{ // Unroll according to Intel slicing by uint8_t // http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf // http://sourceforge.net/projects/slicing-by-8/ - uint32_t crc; + uint32_t c; const uint32_t* current; const uint8_t* current_char = (const uint8_t*)data; const size_t unroll = 4; const size_t bytes_at_once = 8 * unroll; uintptr_t unaligned_length = (4 - (((uintptr_t)current_char) & 3)) & 3; - crc = ctx->crc; + c = *crc; while((len != 0) && (unaligned_length != 0)) { - crc = (crc >> 8) ^ crc32_table[0][(crc & 0xFF) ^ *current_char++]; + c = (c >> 8) ^ crc32_table[0][(c & 0xFF) ^ *current_char++]; len--; unaligned_length--; } @@ -87,12 +93,12 @@ AARU_EXPORT int AARU_CALL crc32_update(crc32_ctx* ctx, const uint8_t* data, uint size_t unrolling; for(unrolling = 0; unrolling < unroll; unrolling++) { - uint32_t one = *current++ ^ crc; + uint32_t one = *current++ ^ c; uint32_t two = *current++; // TODO: Big endian! - crc = crc32_table[0][(two >> 24) & 0xFF] ^ crc32_table[1][(two >> 16) & 0xFF] ^ - crc32_table[2][(two >> 8) & 0xFF] ^ crc32_table[3][two & 0xFF] ^ crc32_table[4][(one >> 24) & 0xFF] ^ - crc32_table[5][(one >> 16) & 0xFF] ^ crc32_table[6][(one >> 8) & 0xFF] ^ crc32_table[7][one & 0xFF]; + c = crc32_table[0][(two >> 24) & 0xFF] ^ crc32_table[1][(two >> 16) & 0xFF] ^ + crc32_table[2][(two >> 8) & 0xFF] ^ crc32_table[3][two & 0xFF] ^ crc32_table[4][(one >> 24) & 0xFF] ^ + crc32_table[5][(one >> 16) & 0xFF] ^ crc32_table[6][(one >> 8) & 0xFF] ^ crc32_table[7][one & 0xFF]; } len -= bytes_at_once; @@ -100,10 +106,9 @@ AARU_EXPORT int AARU_CALL crc32_update(crc32_ctx* ctx, const uint8_t* data, uint current_char = (const uint8_t*)current; - while(len-- != 0) crc = (crc >> 8) ^ crc32_table[0][(crc & 0xFF) ^ *current_char++]; + while(len-- != 0) c = (c >> 8) ^ crc32_table[0][(c & 0xFF) ^ *current_char++]; - ctx->crc = crc; - return 0; + *crc = c; } AARU_EXPORT int AARU_CALL crc32_final(crc32_ctx* ctx, uint32_t* crc) diff --git a/crc32.h b/crc32.h index d360d80..56d5448 100644 --- a/crc32.h +++ b/crc32.h @@ -263,13 +263,16 @@ AARU_EXPORT crc32_ctx* AARU_CALL crc32_init(); AARU_EXPORT int AARU_CALL crc32_update(crc32_ctx* ctx, const uint8_t* data, uint32_t len); AARU_EXPORT int AARU_CALL crc32_final(crc32_ctx* ctx, uint32_t* crc); AARU_EXPORT void AARU_CALL crc32_free(crc32_ctx* ctx); +AARU_EXPORT void AARU_CALL crc32_slicing(uint32_t* crc, const unsigned char* data, long len); #if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || defined(__I386__) || \ defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86) -CLMUL uint32_t crc32_clmul(const uint8_t* src, long len, uint32_t initial_crc); +AARU_EXPORT CLMUL uint32_t AARU_CALL crc32_clmul(const uint8_t* src, long len, uint32_t initial_crc); #endif #if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM) -TARGET_ARMV8_WITH_CRC uint32_t armv8_crc32_little(uint32_t crc, const unsigned char* buf, uint32_t len); -TARGET_WITH_SIMD uint32_t crc32_vmull(const uint8_t* src, long len, uint32_t initial_crc); +AARU_EXPORT TARGET_ARMV8_WITH_CRC uint32_t AARU_CALL armv8_crc32_little(uint32_t crc, + const unsigned char* buf, + uint32_t len); +AARU_EXPORT TARGET_WITH_SIMD uint32_t AARU_CALL crc32_vmull(const uint8_t* src, long len, uint32_t initial_crc); #endif \ No newline at end of file diff --git a/tests/crc32.cpp b/tests/crc32.cpp index 85950a3..dbb3076 100644 --- a/tests/crc32.cpp +++ b/tests/crc32.cpp @@ -52,3 +52,58 @@ TEST_F(crc32Fixture, crc32_auto) EXPECT_EQ(crc, EXPECTED_CRC32); } + +TEST_F(crc32Fixture, crc32_slicing) +{ + uint32_t crc = CRC32_ISO_SEED; + + crc32_slicing(&crc, buffer, 1048576); + + crc ^= CRC32_ISO_SEED; + + EXPECT_EQ(crc, EXPECTED_CRC32); +} + +#if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || defined(__I386__) || \ + defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86) +TEST_F(crc32Fixture, crc32_clmul) +{ + if(!have_clmul()) return; + + uint32_t crc = CRC32_ISO_SEED; + + crc = ~crc32_clmul(buffer, 1048576, ~crc); + + crc ^= CRC32_ISO_SEED; + + EXPECT_EQ(crc, EXPECTED_CRC32); +} +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM) +TEST_F(crc32Fixture, crc32_arm_crc32) +{ + if(!have_arm_crc32()) return; + + uint32_t crc = CRC32_ISO_SEED; + + crc = armv8_crc32_little(crc, buffer, 1048576); + + crc ^= CRC32_ISO_SEED; + + EXPECT_EQ(crc, EXPECTED_CRC32); +} + +TEST_F(crc32Fixture, crc32_vmull) +{ + if(!have_neon()) return; + + uint32_t crc = CRC32_ISO_SEED; + + crc = ~crc32_vmull(buffer, 1048576, ~crc); + + crc ^= CRC32_ISO_SEED; + + EXPECT_EQ(crc, EXPECTED_CRC32); +} +#endif