From 17ebb38ebd91d4594e578232c5478add1e4fa5e3 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 15 Sep 2026 14:21:08 -0700 Subject: [PATCH] FEXCore/Utils: Make crc32 match between architectures I forgot that we actually need this to match arm64 behaviour on x86. Implement the pseudocodefor the instruction. --- FEXCore/Source/Utils/crc32.h | 51 +++++++++++++++++----------- FEXCore/unittests/APITests/crc32.cpp | 5 --- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/FEXCore/Source/Utils/crc32.h b/FEXCore/Source/Utils/crc32.h index 5af0e7cc4..f9fc7b114 100644 --- a/FEXCore/Source/Utils/crc32.h +++ b/FEXCore/Source/Utils/crc32.h @@ -4,8 +4,6 @@ #include #if defined(ARCHITECTURE_arm64) #include -#elif defined(ARCHITECTURE_x86_64) -#include #endif namespace FEXCore::Utils { @@ -23,24 +21,39 @@ static inline uint32_t crc32(const T* Ptr, size_t Size) { do_crc(uint32_t, w); do_crc(uint16_t, h); do_crc(uint8_t, b); - -#elif defined(ARCHITECTURE_x86_64) -#define do_crc(type, intrinsic) \ - while (Size >= sizeof(type)) { \ - Result = intrinsic(Result, *reinterpret_cast(Ptr)); \ - Ptr += sizeof(type); \ - Size -= sizeof(type); \ - } - - do_crc(uint64_t, _mm_crc32_u64); - do_crc(uint32_t, _mm_crc32_u32); - do_crc(uint16_t, _mm_crc32_u16); - do_crc(uint8_t, _mm_crc32_u8); -#else - // Unsupported on non-arm. - return 0; -#endif #undef do_crc +#else + // Emulate arm64 crc32. + // This is basically just the pseudo-code for crc32b. + // Doesn't need to be fast, just needs to match. + auto reverse_bits = [](auto bits) { + decltype(bits) Result {}; + for (size_t i = 0; i < (sizeof(decltype(bits)) * 8); ++i) { + Result = (Result << 1) | ((bits >> i) & 1); + } + return Result; + }; + + auto Poly32Mod2 = [](uint64_t data) -> uint32_t { + constexpr static size_t bits = 40; + constexpr static uint64_t poly = 0x04C11DB7U; + for (size_t i = (bits - 1); i >= 32; --i) { + if (((data >> i) & 1) != 0) { + const uint64_t poly_shift = poly << (i - 32); + const uint64_t data_mask = (1ULL << i) - 1; + data = (data & data_mask) ^ poly_shift; + } + } + + return data; + }; + + for (size_t i = 0; i < Size; ++i) { + uint64_t TempAcc = static_cast(reverse_bits(Result)) << 8; + uint64_t TempVal = static_cast(reverse_bits(reinterpret_cast(Ptr)[i])) << 32; + Result = reverse_bits(Poly32Mod2(TempAcc ^ TempVal)); + } +#endif return Result; } } // namespace FEXCore::Utils diff --git a/FEXCore/unittests/APITests/crc32.cpp b/FEXCore/unittests/APITests/crc32.cpp index eadb6adc0..7ec76b83d 100644 --- a/FEXCore/unittests/APITests/crc32.cpp +++ b/FEXCore/unittests/APITests/crc32.cpp @@ -5,10 +5,5 @@ TEST_CASE("Simple") { uint32_t data = 0x41424344U; - // Arm and x86 use different polynomials by default. -#if defined(ARCHITECTURE_arm64) CHECK(FEXCore::Utils::crc32(&data, sizeof(data)) == 0xa53ea072); -#elif defined(ARCHITECTURE_x86_64) - CHECK(FEXCore::Utils::crc32(&data, sizeof(data)) == 0x968d46eb); -#endif }