1370b324cSopenharmony_ci/* 7zCrc.c -- CRC32 calculation and init 2370b324cSopenharmony_ci2023-04-02 : Igor Pavlov : Public domain */ 3370b324cSopenharmony_ci 4370b324cSopenharmony_ci#include "Precomp.h" 5370b324cSopenharmony_ci 6370b324cSopenharmony_ci#include "7zCrc.h" 7370b324cSopenharmony_ci#include "CpuArch.h" 8370b324cSopenharmony_ci 9370b324cSopenharmony_ci#define kCrcPoly 0xEDB88320 10370b324cSopenharmony_ci 11370b324cSopenharmony_ci#ifdef MY_CPU_LE 12370b324cSopenharmony_ci #define CRC_NUM_TABLES 8 13370b324cSopenharmony_ci#else 14370b324cSopenharmony_ci #define CRC_NUM_TABLES 9 15370b324cSopenharmony_ci 16370b324cSopenharmony_ci UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); 17370b324cSopenharmony_ci UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); 18370b324cSopenharmony_ci#endif 19370b324cSopenharmony_ci 20370b324cSopenharmony_ci#ifndef MY_CPU_BE 21370b324cSopenharmony_ci UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); 22370b324cSopenharmony_ci UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); 23370b324cSopenharmony_ci#endif 24370b324cSopenharmony_ci 25370b324cSopenharmony_ci/* 26370b324cSopenharmony_ciextern 27370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT4; 28370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT4; 29370b324cSopenharmony_ci*/ 30370b324cSopenharmony_ciextern 31370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT8; 32370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT8; 33370b324cSopenharmony_ciextern 34370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT0_32; 35370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT0_32; 36370b324cSopenharmony_ciextern 37370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT0_64; 38370b324cSopenharmony_ciCRC_FUNC g_CrcUpdateT0_64; 39370b324cSopenharmony_ciextern 40370b324cSopenharmony_ciCRC_FUNC g_CrcUpdate; 41370b324cSopenharmony_ciCRC_FUNC g_CrcUpdate; 42370b324cSopenharmony_ci 43370b324cSopenharmony_ciUInt32 g_CrcTable[256 * CRC_NUM_TABLES]; 44370b324cSopenharmony_ci 45370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcUpdate(UInt32 v, const void *data, size_t size) 46370b324cSopenharmony_ci{ 47370b324cSopenharmony_ci return g_CrcUpdate(v, data, size, g_CrcTable); 48370b324cSopenharmony_ci} 49370b324cSopenharmony_ci 50370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size) 51370b324cSopenharmony_ci{ 52370b324cSopenharmony_ci return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; 53370b324cSopenharmony_ci} 54370b324cSopenharmony_ci 55370b324cSopenharmony_ci#if CRC_NUM_TABLES < 4 \ 56370b324cSopenharmony_ci || (CRC_NUM_TABLES == 4 && defined(MY_CPU_BE)) \ 57370b324cSopenharmony_ci || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) 58370b324cSopenharmony_ci#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) 59370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); 60370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) 61370b324cSopenharmony_ci{ 62370b324cSopenharmony_ci const Byte *p = (const Byte *)data; 63370b324cSopenharmony_ci const Byte *pEnd = p + size; 64370b324cSopenharmony_ci for (; p != pEnd; p++) 65370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, *p); 66370b324cSopenharmony_ci return v; 67370b324cSopenharmony_ci} 68370b324cSopenharmony_ci#endif 69370b324cSopenharmony_ci 70370b324cSopenharmony_ci/* ---------- hardware CRC ---------- */ 71370b324cSopenharmony_ci 72370b324cSopenharmony_ci#ifdef MY_CPU_LE 73370b324cSopenharmony_ci 74370b324cSopenharmony_ci#if defined(MY_CPU_ARM_OR_ARM64) 75370b324cSopenharmony_ci 76370b324cSopenharmony_ci// #pragma message("ARM*") 77370b324cSopenharmony_ci 78370b324cSopenharmony_ci #if defined(_MSC_VER) 79370b324cSopenharmony_ci #if defined(MY_CPU_ARM64) 80370b324cSopenharmony_ci #if (_MSC_VER >= 1910) 81370b324cSopenharmony_ci #ifndef __clang__ 82370b324cSopenharmony_ci #define USE_ARM64_CRC 83370b324cSopenharmony_ci #include <intrin.h> 84370b324cSopenharmony_ci #endif 85370b324cSopenharmony_ci #endif 86370b324cSopenharmony_ci #endif 87370b324cSopenharmony_ci #elif (defined(__clang__) && (__clang_major__ >= 3)) \ 88370b324cSopenharmony_ci || (defined(__GNUC__) && (__GNUC__ > 4)) 89370b324cSopenharmony_ci #if !defined(__ARM_FEATURE_CRC32) 90370b324cSopenharmony_ci #define __ARM_FEATURE_CRC32 1 91370b324cSopenharmony_ci #if defined(__clang__) 92370b324cSopenharmony_ci #if defined(MY_CPU_ARM64) 93370b324cSopenharmony_ci #define ATTRIB_CRC __attribute__((__target__("crc"))) 94370b324cSopenharmony_ci #else 95370b324cSopenharmony_ci #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc"))) 96370b324cSopenharmony_ci #endif 97370b324cSopenharmony_ci #else 98370b324cSopenharmony_ci #if defined(MY_CPU_ARM64) 99370b324cSopenharmony_ci #define ATTRIB_CRC __attribute__((__target__("+crc"))) 100370b324cSopenharmony_ci #else 101370b324cSopenharmony_ci #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc"))) 102370b324cSopenharmony_ci #endif 103370b324cSopenharmony_ci #endif 104370b324cSopenharmony_ci #endif 105370b324cSopenharmony_ci #if defined(__ARM_FEATURE_CRC32) 106370b324cSopenharmony_ci #define USE_ARM64_CRC 107370b324cSopenharmony_ci #include <arm_acle.h> 108370b324cSopenharmony_ci #endif 109370b324cSopenharmony_ci #endif 110370b324cSopenharmony_ci 111370b324cSopenharmony_ci#else 112370b324cSopenharmony_ci 113370b324cSopenharmony_ci// no hardware CRC 114370b324cSopenharmony_ci 115370b324cSopenharmony_ci// #define USE_CRC_EMU 116370b324cSopenharmony_ci 117370b324cSopenharmony_ci#ifdef USE_CRC_EMU 118370b324cSopenharmony_ci 119370b324cSopenharmony_ci#pragma message("ARM64 CRC emulation") 120370b324cSopenharmony_ci 121370b324cSopenharmony_ciZ7_FORCE_INLINE 122370b324cSopenharmony_ciUInt32 __crc32b(UInt32 v, UInt32 data) 123370b324cSopenharmony_ci{ 124370b324cSopenharmony_ci const UInt32 *table = g_CrcTable; 125370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); 126370b324cSopenharmony_ci return v; 127370b324cSopenharmony_ci} 128370b324cSopenharmony_ci 129370b324cSopenharmony_ciZ7_FORCE_INLINE 130370b324cSopenharmony_ciUInt32 __crc32w(UInt32 v, UInt32 data) 131370b324cSopenharmony_ci{ 132370b324cSopenharmony_ci const UInt32 *table = g_CrcTable; 133370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 134370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 135370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 136370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 137370b324cSopenharmony_ci return v; 138370b324cSopenharmony_ci} 139370b324cSopenharmony_ci 140370b324cSopenharmony_ciZ7_FORCE_INLINE 141370b324cSopenharmony_ciUInt32 __crc32d(UInt32 v, UInt64 data) 142370b324cSopenharmony_ci{ 143370b324cSopenharmony_ci const UInt32 *table = g_CrcTable; 144370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 145370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 146370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 147370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 148370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 149370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 150370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 151370b324cSopenharmony_ci v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 152370b324cSopenharmony_ci return v; 153370b324cSopenharmony_ci} 154370b324cSopenharmony_ci 155370b324cSopenharmony_ci#endif // USE_CRC_EMU 156370b324cSopenharmony_ci 157370b324cSopenharmony_ci#endif // defined(MY_CPU_ARM64) && defined(MY_CPU_LE) 158370b324cSopenharmony_ci 159370b324cSopenharmony_ci 160370b324cSopenharmony_ci 161370b324cSopenharmony_ci#if defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) 162370b324cSopenharmony_ci 163370b324cSopenharmony_ci#define T0_32_UNROLL_BYTES (4 * 4) 164370b324cSopenharmony_ci#define T0_64_UNROLL_BYTES (4 * 8) 165370b324cSopenharmony_ci 166370b324cSopenharmony_ci#ifndef ATTRIB_CRC 167370b324cSopenharmony_ci#define ATTRIB_CRC 168370b324cSopenharmony_ci#endif 169370b324cSopenharmony_ci// #pragma message("USE ARM HW CRC") 170370b324cSopenharmony_ci 171370b324cSopenharmony_ciATTRIB_CRC 172370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table); 173370b324cSopenharmony_ciATTRIB_CRC 174370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table) 175370b324cSopenharmony_ci{ 176370b324cSopenharmony_ci const Byte *p = (const Byte *)data; 177370b324cSopenharmony_ci UNUSED_VAR(table); 178370b324cSopenharmony_ci 179370b324cSopenharmony_ci for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_32_UNROLL_BYTES - 1)) != 0; size--) 180370b324cSopenharmony_ci v = __crc32b(v, *p++); 181370b324cSopenharmony_ci 182370b324cSopenharmony_ci if (size >= T0_32_UNROLL_BYTES) 183370b324cSopenharmony_ci { 184370b324cSopenharmony_ci const Byte *lim = p + size; 185370b324cSopenharmony_ci size &= (T0_32_UNROLL_BYTES - 1); 186370b324cSopenharmony_ci lim -= size; 187370b324cSopenharmony_ci do 188370b324cSopenharmony_ci { 189370b324cSopenharmony_ci v = __crc32w(v, *(const UInt32 *)(const void *)(p)); 190370b324cSopenharmony_ci v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; 191370b324cSopenharmony_ci v = __crc32w(v, *(const UInt32 *)(const void *)(p)); 192370b324cSopenharmony_ci v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; 193370b324cSopenharmony_ci } 194370b324cSopenharmony_ci while (p != lim); 195370b324cSopenharmony_ci } 196370b324cSopenharmony_ci 197370b324cSopenharmony_ci for (; size != 0; size--) 198370b324cSopenharmony_ci v = __crc32b(v, *p++); 199370b324cSopenharmony_ci 200370b324cSopenharmony_ci return v; 201370b324cSopenharmony_ci} 202370b324cSopenharmony_ci 203370b324cSopenharmony_ciATTRIB_CRC 204370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table); 205370b324cSopenharmony_ciATTRIB_CRC 206370b324cSopenharmony_ciUInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table) 207370b324cSopenharmony_ci{ 208370b324cSopenharmony_ci const Byte *p = (const Byte *)data; 209370b324cSopenharmony_ci UNUSED_VAR(table); 210370b324cSopenharmony_ci 211370b324cSopenharmony_ci for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_64_UNROLL_BYTES - 1)) != 0; size--) 212370b324cSopenharmony_ci v = __crc32b(v, *p++); 213370b324cSopenharmony_ci 214370b324cSopenharmony_ci if (size >= T0_64_UNROLL_BYTES) 215370b324cSopenharmony_ci { 216370b324cSopenharmony_ci const Byte *lim = p + size; 217370b324cSopenharmony_ci size &= (T0_64_UNROLL_BYTES - 1); 218370b324cSopenharmony_ci lim -= size; 219370b324cSopenharmony_ci do 220370b324cSopenharmony_ci { 221370b324cSopenharmony_ci v = __crc32d(v, *(const UInt64 *)(const void *)(p)); 222370b324cSopenharmony_ci v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; 223370b324cSopenharmony_ci v = __crc32d(v, *(const UInt64 *)(const void *)(p)); 224370b324cSopenharmony_ci v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; 225370b324cSopenharmony_ci } 226370b324cSopenharmony_ci while (p != lim); 227370b324cSopenharmony_ci } 228370b324cSopenharmony_ci 229370b324cSopenharmony_ci for (; size != 0; size--) 230370b324cSopenharmony_ci v = __crc32b(v, *p++); 231370b324cSopenharmony_ci 232370b324cSopenharmony_ci return v; 233370b324cSopenharmony_ci} 234370b324cSopenharmony_ci 235370b324cSopenharmony_ci#undef T0_32_UNROLL_BYTES 236370b324cSopenharmony_ci#undef T0_64_UNROLL_BYTES 237370b324cSopenharmony_ci 238370b324cSopenharmony_ci#endif // defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) 239370b324cSopenharmony_ci 240370b324cSopenharmony_ci#endif // MY_CPU_LE 241370b324cSopenharmony_ci 242370b324cSopenharmony_ci 243370b324cSopenharmony_ci 244370b324cSopenharmony_ci 245370b324cSopenharmony_civoid Z7_FASTCALL CrcGenerateTable(void) 246370b324cSopenharmony_ci{ 247370b324cSopenharmony_ci UInt32 i; 248370b324cSopenharmony_ci for (i = 0; i < 256; i++) 249370b324cSopenharmony_ci { 250370b324cSopenharmony_ci UInt32 r = i; 251370b324cSopenharmony_ci unsigned j; 252370b324cSopenharmony_ci for (j = 0; j < 8; j++) 253370b324cSopenharmony_ci r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); 254370b324cSopenharmony_ci g_CrcTable[i] = r; 255370b324cSopenharmony_ci } 256370b324cSopenharmony_ci for (i = 256; i < 256 * CRC_NUM_TABLES; i++) 257370b324cSopenharmony_ci { 258370b324cSopenharmony_ci const UInt32 r = g_CrcTable[(size_t)i - 256]; 259370b324cSopenharmony_ci g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); 260370b324cSopenharmony_ci } 261370b324cSopenharmony_ci 262370b324cSopenharmony_ci #if CRC_NUM_TABLES < 4 263370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT1; 264370b324cSopenharmony_ci #elif defined(MY_CPU_LE) 265370b324cSopenharmony_ci // g_CrcUpdateT4 = CrcUpdateT4; 266370b324cSopenharmony_ci #if CRC_NUM_TABLES < 8 267370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT4; 268370b324cSopenharmony_ci #else // CRC_NUM_TABLES >= 8 269370b324cSopenharmony_ci g_CrcUpdateT8 = CrcUpdateT8; 270370b324cSopenharmony_ci /* 271370b324cSopenharmony_ci #ifdef MY_CPU_X86_OR_AMD64 272370b324cSopenharmony_ci if (!CPU_Is_InOrder()) 273370b324cSopenharmony_ci #endif 274370b324cSopenharmony_ci */ 275370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT8; 276370b324cSopenharmony_ci #endif 277370b324cSopenharmony_ci #else 278370b324cSopenharmony_ci { 279370b324cSopenharmony_ci #ifndef MY_CPU_BE 280370b324cSopenharmony_ci UInt32 k = 0x01020304; 281370b324cSopenharmony_ci const Byte *p = (const Byte *)&k; 282370b324cSopenharmony_ci if (p[0] == 4 && p[1] == 3) 283370b324cSopenharmony_ci { 284370b324cSopenharmony_ci #if CRC_NUM_TABLES < 8 285370b324cSopenharmony_ci // g_CrcUpdateT4 = CrcUpdateT4; 286370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT4; 287370b324cSopenharmony_ci #else // CRC_NUM_TABLES >= 8 288370b324cSopenharmony_ci g_CrcUpdateT8 = CrcUpdateT8; 289370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT8; 290370b324cSopenharmony_ci #endif 291370b324cSopenharmony_ci } 292370b324cSopenharmony_ci else if (p[0] != 1 || p[1] != 2) 293370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT1; 294370b324cSopenharmony_ci else 295370b324cSopenharmony_ci #endif // MY_CPU_BE 296370b324cSopenharmony_ci { 297370b324cSopenharmony_ci for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) 298370b324cSopenharmony_ci { 299370b324cSopenharmony_ci const UInt32 x = g_CrcTable[(size_t)i - 256]; 300370b324cSopenharmony_ci g_CrcTable[i] = Z7_BSWAP32(x); 301370b324cSopenharmony_ci } 302370b324cSopenharmony_ci #if CRC_NUM_TABLES <= 4 303370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT1; 304370b324cSopenharmony_ci #elif CRC_NUM_TABLES <= 8 305370b324cSopenharmony_ci // g_CrcUpdateT4 = CrcUpdateT1_BeT4; 306370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT1_BeT4; 307370b324cSopenharmony_ci #else // CRC_NUM_TABLES > 8 308370b324cSopenharmony_ci g_CrcUpdateT8 = CrcUpdateT1_BeT8; 309370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT1_BeT8; 310370b324cSopenharmony_ci #endif 311370b324cSopenharmony_ci } 312370b324cSopenharmony_ci } 313370b324cSopenharmony_ci #endif // CRC_NUM_TABLES < 4 314370b324cSopenharmony_ci 315370b324cSopenharmony_ci #ifdef MY_CPU_LE 316370b324cSopenharmony_ci #ifdef USE_ARM64_CRC 317370b324cSopenharmony_ci if (CPU_IsSupported_CRC32()) 318370b324cSopenharmony_ci { 319370b324cSopenharmony_ci g_CrcUpdateT0_32 = CrcUpdateT0_32; 320370b324cSopenharmony_ci g_CrcUpdateT0_64 = CrcUpdateT0_64; 321370b324cSopenharmony_ci g_CrcUpdate = 322370b324cSopenharmony_ci #if defined(MY_CPU_ARM) 323370b324cSopenharmony_ci CrcUpdateT0_32; 324370b324cSopenharmony_ci #else 325370b324cSopenharmony_ci CrcUpdateT0_64; 326370b324cSopenharmony_ci #endif 327370b324cSopenharmony_ci } 328370b324cSopenharmony_ci #endif 329370b324cSopenharmony_ci 330370b324cSopenharmony_ci #ifdef USE_CRC_EMU 331370b324cSopenharmony_ci g_CrcUpdateT0_32 = CrcUpdateT0_32; 332370b324cSopenharmony_ci g_CrcUpdateT0_64 = CrcUpdateT0_64; 333370b324cSopenharmony_ci g_CrcUpdate = CrcUpdateT0_64; 334370b324cSopenharmony_ci #endif 335370b324cSopenharmony_ci #endif 336370b324cSopenharmony_ci} 337370b324cSopenharmony_ci 338370b324cSopenharmony_ci#undef kCrcPoly 339370b324cSopenharmony_ci#undef CRC64_NUM_TABLES 340370b324cSopenharmony_ci#undef CRC_UPDATE_BYTE_2 341