checksumcrc32simdimpl_p.h (3465B)
1 // This file is part of Blend2D project <https://blend2d.com> 2 // 3 // See blend2d.h or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #ifndef BLEND2D_COMPRESSION_CHECKSUMCRC32SIMDIMPL_P_H_INCLUDED 7 #define BLEND2D_COMPRESSION_CHECKSUMCRC32SIMDIMPL_P_H_INCLUDED 8 9 #include "../api-internal_p.h" 10 #include "../compression/checksum_p.h" 11 #include "../simd/simd_p.h" 12 13 //! \cond INTERNAL 14 15 namespace bl::Compression::Checksum { 16 namespace { 17 18 static constexpr uint64_t kConstK1 = 0x0154442BD4u; 19 static constexpr uint64_t kConstK2 = 0x01C6E41596u; 20 static constexpr uint64_t kConstK3 = 0x01751997D0u; 21 static constexpr uint64_t kConstK4 = 0x00CCAA009Eu; 22 static constexpr uint64_t kConstK5 = 0x0163CD6124u; 23 static constexpr uint64_t kConstP0 = 0x01DB710641u; 24 static constexpr uint64_t kConstP1 = 0x01F7011641u; 25 26 BL_INLINE uint32_t crc32_update_clmul128(uint32_t checksum, const uint8_t* data, size_t size) noexcept { 27 using namespace SIMD; 28 29 size_t n = bl_min<size_t>(IntOps::align_up_diff(uintptr_t(data), 16u), size); 30 size -= n; 31 32 BL_NOUNROLL 33 while (n) { 34 checksum = crc32_update_byte(checksum, *data++); 35 n--; 36 } 37 38 // Process 64-byte chunks. 39 if (size >= 64u) { 40 Vec2xU64 x1 = loada_128<Vec2xU64>(data + 0u) ^ cast_from_u32<Vec2xU64>(checksum); 41 Vec2xU64 x2 = loada_128<Vec2xU64>(data + 16u); 42 Vec2xU64 x3 = loada_128<Vec2xU64>(data + 32u); 43 Vec2xU64 x4 = loada_128<Vec2xU64>(data + 48u); 44 Vec2xU64 k2k1 = make128_u64(kConstK2, kConstK1); 45 46 data += 64u; 47 size -= 64u; 48 49 BL_NOUNROLL 50 while (size >= 64u) { 51 Vec2xU64 t1 = clmul_u128_ll(x1, k2k1); 52 Vec2xU64 t2 = clmul_u128_ll(x2, k2k1); 53 Vec2xU64 t3 = clmul_u128_ll(x3, k2k1); 54 Vec2xU64 t4 = clmul_u128_ll(x4, k2k1); 55 56 x1 = clmul_u128_hh(x1, k2k1) ^ t1; 57 x2 = clmul_u128_hh(x2, k2k1) ^ t2; 58 x3 = clmul_u128_hh(x3, k2k1) ^ t3; 59 x4 = clmul_u128_hh(x4, k2k1) ^ t4; 60 61 x1 ^= loada_128<Vec2xU64>(data + 0u); 62 x2 ^= loada_128<Vec2xU64>(data + 16u); 63 x3 ^= loada_128<Vec2xU64>(data + 32u); 64 x4 ^= loada_128<Vec2xU64>(data + 48u); 65 66 data += 64u; 67 size -= 64u; 68 } 69 70 // Fold 4x128 bits into 128 bits. 71 Vec2xU64 k4k3 = make128_u64(kConstK4, kConstK3); 72 Vec2xU64 t1; 73 74 t1 = clmul_u128_ll(x1, k4k3) ^ x2; 75 x1 = clmul_u128_hh(x1, k4k3) ^ t1; 76 77 t1 = clmul_u128_ll(x1, k4k3) ^ x3; 78 x1 = clmul_u128_hh(x1, k4k3) ^ t1; 79 80 t1 = clmul_u128_ll(x1, k4k3) ^ x4; 81 x1 = clmul_u128_hh(x1, k4k3) ^ t1; 82 83 // Process remaining 16-byte chunks. 84 BL_NOUNROLL 85 while (size >= 16u) { 86 t1 = clmul_u128_ll(x1, k4k3); 87 x1 = clmul_u128_hh(x1, k4k3) ^ t1; 88 x1 ^= loada_128<Vec2xU64>(data); 89 90 data += 16u; 91 size -= 16u; 92 } 93 94 // Fold 128 bits to 64 bits. 95 t1 = clmul_u128_lh(x1, k4k3); 96 x1 = srlb_u128<8>(x1) ^ t1; 97 98 Vec2xU64 k5 = make128_u64(kConstK5); 99 Vec2xU64 lo32 = make128_u64(0x00000000FFFFFFFFu); 100 101 t1 = srlb_u128<4>(x1); 102 x1 = clmul_u128_ll(x1 & lo32, k5) ^ t1; 103 104 // Reduce 64 bits to 32 bits. 105 Vec2xU64 poly = make128_u64(kConstP1, kConstP0); 106 t1 = clmul_u128_lh(x1 & lo32, poly); 107 x1 ^= clmul_u128_ll(t1 & lo32, poly); 108 109 checksum = extract_u32<1>(x1); 110 } 111 112 BL_NOUNROLL 113 while (size) { 114 checksum = crc32_update_byte(checksum, *data++); 115 size--; 116 } 117 118 return checksum; 119 } 120 121 } // {anonymous} 122 } // {bl::Compression::Checksum} 123 124 //! \endcond 125 126 #endif // BLEND2D_COMPRESSION_CHECKSUMCRC32SIMDIMPL_P_H_INCLUDED