1/* 7zCrc.c -- CRC32 calculation and init 22023-04-02 : Igor Pavlov : Public domain */ 3 4#include "Precomp.h" 5 6#include "7zCrc.h" 7#include "CpuArch.h" 8 9#define kCrcPoly 0xEDB88320 10 11#ifdef MY_CPU_LE 12 #define CRC_NUM_TABLES 8 13#else 14 #define CRC_NUM_TABLES 9 15 16 UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); 17 UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); 18#endif 19 20#ifndef MY_CPU_BE 21 UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); 22 UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); 23#endif 24 25/* 26extern 27CRC_FUNC g_CrcUpdateT4; 28CRC_FUNC g_CrcUpdateT4; 29*/ 30extern 31CRC_FUNC g_CrcUpdateT8; 32CRC_FUNC g_CrcUpdateT8; 33extern 34CRC_FUNC g_CrcUpdateT0_32; 35CRC_FUNC g_CrcUpdateT0_32; 36extern 37CRC_FUNC g_CrcUpdateT0_64; 38CRC_FUNC g_CrcUpdateT0_64; 39extern 40CRC_FUNC g_CrcUpdate; 41CRC_FUNC g_CrcUpdate; 42 43UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; 44 45UInt32 Z7_FASTCALL CrcUpdate(UInt32 v, const void *data, size_t size) 46{ 47 return g_CrcUpdate(v, data, size, g_CrcTable); 48} 49 50UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size) 51{ 52 return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; 53} 54 55#if CRC_NUM_TABLES < 4 \ 56 || (CRC_NUM_TABLES == 4 && defined(MY_CPU_BE)) \ 57 || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) 58#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) 59UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); 60UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) 61{ 62 const Byte *p = (const Byte *)data; 63 const Byte *pEnd = p + size; 64 for (; p != pEnd; p++) 65 v = CRC_UPDATE_BYTE_2(v, *p); 66 return v; 67} 68#endif 69 70/* ---------- hardware CRC ---------- */ 71 72#ifdef MY_CPU_LE 73 74#if defined(MY_CPU_ARM_OR_ARM64) 75 76// #pragma message("ARM*") 77 78 #if defined(_MSC_VER) 79 #if defined(MY_CPU_ARM64) 80 #if (_MSC_VER >= 1910) 81 #ifndef __clang__ 82 #define USE_ARM64_CRC 83 #include <intrin.h> 84 #endif 85 #endif 86 #endif 87 #elif (defined(__clang__) && (__clang_major__ >= 3)) \ 88 || (defined(__GNUC__) && (__GNUC__ > 4)) 89 #if !defined(__ARM_FEATURE_CRC32) 90 #define __ARM_FEATURE_CRC32 1 91 #if defined(__clang__) 92 #if defined(MY_CPU_ARM64) 93 #define ATTRIB_CRC __attribute__((__target__("crc"))) 94 #else 95 #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc"))) 96 #endif 97 #else 98 #if defined(MY_CPU_ARM64) 99 #define ATTRIB_CRC __attribute__((__target__("+crc"))) 100 #else 101 #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc"))) 102 #endif 103 #endif 104 #endif 105 #if defined(__ARM_FEATURE_CRC32) 106 #define USE_ARM64_CRC 107 #include <arm_acle.h> 108 #endif 109 #endif 110 111#else 112 113// no hardware CRC 114 115// #define USE_CRC_EMU 116 117#ifdef USE_CRC_EMU 118 119#pragma message("ARM64 CRC emulation") 120 121Z7_FORCE_INLINE 122UInt32 __crc32b(UInt32 v, UInt32 data) 123{ 124 const UInt32 *table = g_CrcTable; 125 v = CRC_UPDATE_BYTE_2(v, (Byte)data); 126 return v; 127} 128 129Z7_FORCE_INLINE 130UInt32 __crc32w(UInt32 v, UInt32 data) 131{ 132 const UInt32 *table = g_CrcTable; 133 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 134 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 135 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 136 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 137 return v; 138} 139 140Z7_FORCE_INLINE 141UInt32 __crc32d(UInt32 v, UInt64 data) 142{ 143 const UInt32 *table = g_CrcTable; 144 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 145 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 146 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 147 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 148 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 149 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 150 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 151 v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8; 152 return v; 153} 154 155#endif // USE_CRC_EMU 156 157#endif // defined(MY_CPU_ARM64) && defined(MY_CPU_LE) 158 159 160 161#if defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) 162 163#define T0_32_UNROLL_BYTES (4 * 4) 164#define T0_64_UNROLL_BYTES (4 * 8) 165 166#ifndef ATTRIB_CRC 167#define ATTRIB_CRC 168#endif 169// #pragma message("USE ARM HW CRC") 170 171ATTRIB_CRC 172UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table); 173ATTRIB_CRC 174UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table) 175{ 176 const Byte *p = (const Byte *)data; 177 UNUSED_VAR(table); 178 179 for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_32_UNROLL_BYTES - 1)) != 0; size--) 180 v = __crc32b(v, *p++); 181 182 if (size >= T0_32_UNROLL_BYTES) 183 { 184 const Byte *lim = p + size; 185 size &= (T0_32_UNROLL_BYTES - 1); 186 lim -= size; 187 do 188 { 189 v = __crc32w(v, *(const UInt32 *)(const void *)(p)); 190 v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; 191 v = __crc32w(v, *(const UInt32 *)(const void *)(p)); 192 v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4; 193 } 194 while (p != lim); 195 } 196 197 for (; size != 0; size--) 198 v = __crc32b(v, *p++); 199 200 return v; 201} 202 203ATTRIB_CRC 204UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table); 205ATTRIB_CRC 206UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table) 207{ 208 const Byte *p = (const Byte *)data; 209 UNUSED_VAR(table); 210 211 for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_64_UNROLL_BYTES - 1)) != 0; size--) 212 v = __crc32b(v, *p++); 213 214 if (size >= T0_64_UNROLL_BYTES) 215 { 216 const Byte *lim = p + size; 217 size &= (T0_64_UNROLL_BYTES - 1); 218 lim -= size; 219 do 220 { 221 v = __crc32d(v, *(const UInt64 *)(const void *)(p)); 222 v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; 223 v = __crc32d(v, *(const UInt64 *)(const void *)(p)); 224 v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8; 225 } 226 while (p != lim); 227 } 228 229 for (; size != 0; size--) 230 v = __crc32b(v, *p++); 231 232 return v; 233} 234 235#undef T0_32_UNROLL_BYTES 236#undef T0_64_UNROLL_BYTES 237 238#endif // defined(USE_ARM64_CRC) || defined(USE_CRC_EMU) 239 240#endif // MY_CPU_LE 241 242 243 244 245void Z7_FASTCALL CrcGenerateTable(void) 246{ 247 UInt32 i; 248 for (i = 0; i < 256; i++) 249 { 250 UInt32 r = i; 251 unsigned j; 252 for (j = 0; j < 8; j++) 253 r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); 254 g_CrcTable[i] = r; 255 } 256 for (i = 256; i < 256 * CRC_NUM_TABLES; i++) 257 { 258 const UInt32 r = g_CrcTable[(size_t)i - 256]; 259 g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); 260 } 261 262 #if CRC_NUM_TABLES < 4 263 g_CrcUpdate = CrcUpdateT1; 264 #elif defined(MY_CPU_LE) 265 // g_CrcUpdateT4 = CrcUpdateT4; 266 #if CRC_NUM_TABLES < 8 267 g_CrcUpdate = CrcUpdateT4; 268 #else // CRC_NUM_TABLES >= 8 269 g_CrcUpdateT8 = CrcUpdateT8; 270 /* 271 #ifdef MY_CPU_X86_OR_AMD64 272 if (!CPU_Is_InOrder()) 273 #endif 274 */ 275 g_CrcUpdate = CrcUpdateT8; 276 #endif 277 #else 278 { 279 #ifndef MY_CPU_BE 280 UInt32 k = 0x01020304; 281 const Byte *p = (const Byte *)&k; 282 if (p[0] == 4 && p[1] == 3) 283 { 284 #if CRC_NUM_TABLES < 8 285 // g_CrcUpdateT4 = CrcUpdateT4; 286 g_CrcUpdate = CrcUpdateT4; 287 #else // CRC_NUM_TABLES >= 8 288 g_CrcUpdateT8 = CrcUpdateT8; 289 g_CrcUpdate = CrcUpdateT8; 290 #endif 291 } 292 else if (p[0] != 1 || p[1] != 2) 293 g_CrcUpdate = CrcUpdateT1; 294 else 295 #endif // MY_CPU_BE 296 { 297 for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--) 298 { 299 const UInt32 x = g_CrcTable[(size_t)i - 256]; 300 g_CrcTable[i] = Z7_BSWAP32(x); 301 } 302 #if CRC_NUM_TABLES <= 4 303 g_CrcUpdate = CrcUpdateT1; 304 #elif CRC_NUM_TABLES <= 8 305 // g_CrcUpdateT4 = CrcUpdateT1_BeT4; 306 g_CrcUpdate = CrcUpdateT1_BeT4; 307 #else // CRC_NUM_TABLES > 8 308 g_CrcUpdateT8 = CrcUpdateT1_BeT8; 309 g_CrcUpdate = CrcUpdateT1_BeT8; 310 #endif 311 } 312 } 313 #endif // CRC_NUM_TABLES < 4 314 315 #ifdef MY_CPU_LE 316 #ifdef USE_ARM64_CRC 317 if (CPU_IsSupported_CRC32()) 318 { 319 g_CrcUpdateT0_32 = CrcUpdateT0_32; 320 g_CrcUpdateT0_64 = CrcUpdateT0_64; 321 g_CrcUpdate = 322 #if defined(MY_CPU_ARM) 323 CrcUpdateT0_32; 324 #else 325 CrcUpdateT0_64; 326 #endif 327 } 328 #endif 329 330 #ifdef USE_CRC_EMU 331 g_CrcUpdateT0_32 = CrcUpdateT0_32; 332 g_CrcUpdateT0_64 = CrcUpdateT0_64; 333 g_CrcUpdate = CrcUpdateT0_64; 334 #endif 335 #endif 336} 337 338#undef kCrcPoly 339#undef CRC64_NUM_TABLES 340#undef CRC_UPDATE_BYTE_2 341