1 /* 7zCrc.c -- CRC32 calculation and init
2 2024-03-01 : Igor Pavlov : Public domain */
3
4 #include "Precomp.h"
5
6 #include "7zCrc.h"
7 #include "CpuArch.h"
8
9 // for debug:
10 // #define __ARM_FEATURE_CRC32 1
11
12 #ifdef __ARM_FEATURE_CRC32
13 // #pragma message("__ARM_FEATURE_CRC32")
14 #define Z7_CRC_HW_FORCE
15 #endif
16
17 // #define Z7_CRC_DEBUG_BE
18 #ifdef Z7_CRC_DEBUG_BE
19 #undef MY_CPU_LE
20 #define MY_CPU_BE
21 #endif
22
23 #ifdef Z7_CRC_HW_FORCE
24 #define Z7_CRC_NUM_TABLES_USE 1
25 #else
26 #ifdef Z7_CRC_NUM_TABLES
27 #define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES
28 #else
29 #define Z7_CRC_NUM_TABLES_USE 12
30 #endif
31 #endif
32
33 #if Z7_CRC_NUM_TABLES_USE < 1
34 #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES
35 #endif
36
37 #if defined(MY_CPU_LE) || (Z7_CRC_NUM_TABLES_USE == 1)
38 #define Z7_CRC_NUM_TABLES_TOTAL Z7_CRC_NUM_TABLES_USE
39 #else
40 #define Z7_CRC_NUM_TABLES_TOTAL (Z7_CRC_NUM_TABLES_USE + 1)
41 #endif
42
43 #ifndef Z7_CRC_HW_FORCE
44
45 #if Z7_CRC_NUM_TABLES_USE == 1 \
46 || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
47 #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
48 #define Z7_CRC_UPDATE_T1_FUNC_NAME CrcUpdateGT1
Z7_CRC_UPDATE_T1_FUNC_NAME(UInt32 v,const void * data,size_t size)49 static UInt32 Z7_FASTCALL Z7_CRC_UPDATE_T1_FUNC_NAME(UInt32 v, const void *data, size_t size)
50 {
51 const UInt32 *table = g_CrcTable;
52 const Byte *p = (const Byte *)data;
53 const Byte *lim = p + size;
54 for (; p != lim; p++)
55 v = CRC_UPDATE_BYTE_2(v, *p);
56 return v;
57 }
58 #endif
59
60
61 #if Z7_CRC_NUM_TABLES_USE != 1
62 #ifndef MY_CPU_BE
63 #define FUNC_NAME_LE_2(s) CrcUpdateT ## s
64 #define FUNC_NAME_LE_1(s) FUNC_NAME_LE_2(s)
65 #define FUNC_NAME_LE FUNC_NAME_LE_1(Z7_CRC_NUM_TABLES_USE)
66 UInt32 Z7_FASTCALL FUNC_NAME_LE (UInt32 v, const void *data, size_t size, const UInt32 *table);
67 #endif
68 #ifndef MY_CPU_LE
69 #define FUNC_NAME_BE_2(s) CrcUpdateT1_BeT ## s
70 #define FUNC_NAME_BE_1(s) FUNC_NAME_BE_2(s)
71 #define FUNC_NAME_BE FUNC_NAME_BE_1(Z7_CRC_NUM_TABLES_USE)
72 UInt32 Z7_FASTCALL FUNC_NAME_BE (UInt32 v, const void *data, size_t size, const UInt32 *table);
73 #endif
74 #endif
75
76 #endif // Z7_CRC_HW_FORCE
77
78 /* ---------- hardware CRC ---------- */
79
80 #ifdef MY_CPU_LE
81
82 #if defined(MY_CPU_ARM_OR_ARM64)
83 // #pragma message("ARM*")
84
85 #if (defined(__clang__) && (__clang_major__ >= 3)) \
86 || defined(__GNUC__) && (__GNUC__ >= 6) && defined(MY_CPU_ARM64) \
87 || defined(__GNUC__) && (__GNUC__ >= 8)
88 #if !defined(__ARM_FEATURE_CRC32)
89 // #pragma message("!defined(__ARM_FEATURE_CRC32)")
90 Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
91 #define __ARM_FEATURE_CRC32 1
92 Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
93 #define Z7_ARM_FEATURE_CRC32_WAS_SET
94 #if defined(__clang__)
95 #if defined(MY_CPU_ARM64)
96 #define ATTRIB_CRC __attribute__((__target__("crc")))
97 #else
98 #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc")))
99 #endif
100 #else
101 #if defined(MY_CPU_ARM64)
102 #if !defined(Z7_GCC_VERSION) || (Z7_GCC_VERSION >= 60000)
103 #define ATTRIB_CRC __attribute__((__target__("+crc")))
104 #endif
105 #else
106 #if !defined(Z7_GCC_VERSION) || (__GNUC__ >= 8)
107 #if defined(__ARM_FP) && __GNUC__ >= 8
108 // for -mfloat-abi=hard: similar to <arm_acle.h>
109 #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc+simd")))
110 #else
111 #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc")))
112 #endif
113 #endif
114 #endif
115 #endif
116 #endif
117 #if defined(__ARM_FEATURE_CRC32)
118 // #pragma message("<arm_acle.h>")
119 /*
120 arm_acle.h (GGC):
121 before Nov 17, 2017:
122 #ifdef __ARM_FEATURE_CRC32
123
124 Nov 17, 2017: gcc10.0 (gcc 9.2.0) checked"
125 #if __ARM_ARCH >= 8
126 #pragma GCC target ("arch=armv8-a+crc")
127
128 Aug 22, 2019: GCC 8.4?, 9.2.1, 10.1:
129 #ifdef __ARM_FEATURE_CRC32
130 #ifdef __ARM_FP
131 #pragma GCC target ("arch=armv8-a+crc+simd")
132 #else
133 #pragma GCC target ("arch=armv8-a+crc")
134 #endif
135 */
136 #if defined(__ARM_ARCH) && __ARM_ARCH < 8
137 #if defined(Z7_GCC_VERSION) && (__GNUC__ == 8) && (Z7_GCC_VERSION < 80400) \
138 || defined(Z7_GCC_VERSION) && (__GNUC__ == 9) && (Z7_GCC_VERSION < 90201) \
139 || defined(Z7_GCC_VERSION) && (__GNUC__ == 10) && (Z7_GCC_VERSION < 100100)
140 Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
141 // #pragma message("#define __ARM_ARCH 8")
142 #undef __ARM_ARCH
143 #define __ARM_ARCH 8
144 Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
145 #endif
146 #endif
147 #define Z7_CRC_HW_USE
148 #include <arm_acle.h>
149 #endif
150 #elif defined(_MSC_VER)
151 #if defined(MY_CPU_ARM64)
152 #if (_MSC_VER >= 1910)
153 #ifdef __clang__
154 // #define Z7_CRC_HW_USE
155 // #include <arm_acle.h>
156 #else
157 #define Z7_CRC_HW_USE
158 #include <intrin.h>
159 #endif
160 #endif
161 #endif
162 #endif
163
164 #else // non-ARM*
165
166 // #define Z7_CRC_HW_USE // for debug : we can test HW-branch of code
167 #ifdef Z7_CRC_HW_USE
168 #include "7zCrcEmu.h"
169 #endif
170
171 #endif // non-ARM*
172
173
174
175 #if defined(Z7_CRC_HW_USE)
176
177 // #pragma message("USE ARM HW CRC")
178
179 #ifdef MY_CPU_64BIT
180 #define CRC_HW_WORD_TYPE UInt64
181 #define CRC_HW_WORD_FUNC __crc32d
182 #else
183 #define CRC_HW_WORD_TYPE UInt32
184 #define CRC_HW_WORD_FUNC __crc32w
185 #endif
186
187 #define CRC_HW_UNROLL_BYTES (sizeof(CRC_HW_WORD_TYPE) * 4)
188
189 #ifdef ATTRIB_CRC
190 ATTRIB_CRC
191 #endif
192 Z7_NO_INLINE
193 #ifdef Z7_CRC_HW_FORCE
CrcUpdate(UInt32 v,const void * data,size_t size)194 UInt32 Z7_FASTCALL CrcUpdate
195 #else
196 static UInt32 Z7_FASTCALL CrcUpdate_HW
197 #endif
198 (UInt32 v, const void *data, size_t size)
199 {
200 const Byte *p = (const Byte *)data;
201 for (; size != 0 && ((unsigned)(ptrdiff_t)p & (CRC_HW_UNROLL_BYTES - 1)) != 0; size--)
202 v = __crc32b(v, *p++);
203 if (size >= CRC_HW_UNROLL_BYTES)
204 {
205 const Byte *lim = p + size;
206 size &= CRC_HW_UNROLL_BYTES - 1;
207 lim -= size;
208 do
209 {
210 v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
211 v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
212 p += 2 * sizeof(CRC_HW_WORD_TYPE);
213 v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p));
214 v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE)));
215 p += 2 * sizeof(CRC_HW_WORD_TYPE);
216 }
217 while (p != lim);
218 }
219
220 for (; size != 0; size--)
221 v = __crc32b(v, *p++);
222
223 return v;
224 }
225
226 #ifdef Z7_ARM_FEATURE_CRC32_WAS_SET
227 Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
228 #undef __ARM_FEATURE_CRC32
229 Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
230 #undef Z7_ARM_FEATURE_CRC32_WAS_SET
231 #endif
232
233 #endif // defined(Z7_CRC_HW_USE)
234 #endif // MY_CPU_LE
235
236
237
238 #ifndef Z7_CRC_HW_FORCE
239
240 #if defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
241 /*
242 typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_WITH_TABLE_FUNC)
243 (UInt32 v, const void *data, size_t size, const UInt32 *table);
244 Z7_CRC_UPDATE_WITH_TABLE_FUNC g_CrcUpdate;
245 */
246 static unsigned g_Crc_Algo;
247 #if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
248 static unsigned g_Crc_Be;
249 #endif
250 #endif // defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
251
252
253
254 Z7_NO_INLINE
255 #ifdef Z7_CRC_HW_USE
CrcUpdate_Base(UInt32 crc,const void * data,size_t size)256 static UInt32 Z7_FASTCALL CrcUpdate_Base
257 #else
258 UInt32 Z7_FASTCALL CrcUpdate
259 #endif
260 (UInt32 crc, const void *data, size_t size)
261 {
262 #if Z7_CRC_NUM_TABLES_USE == 1
263 return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
264 #else // Z7_CRC_NUM_TABLES_USE != 1
265 #ifdef Z7_CRC_UPDATE_T1_FUNC_NAME
266 if (g_Crc_Algo == 1)
267 return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size);
268 #endif
269
270 #ifdef MY_CPU_LE
271 return FUNC_NAME_LE(crc, data, size, g_CrcTable);
272 #elif defined(MY_CPU_BE)
273 return FUNC_NAME_BE(crc, data, size, g_CrcTable);
274 #else
275 if (g_Crc_Be)
276 return FUNC_NAME_BE(crc, data, size, g_CrcTable);
277 else
278 return FUNC_NAME_LE(crc, data, size, g_CrcTable);
279 #endif
280 #endif // Z7_CRC_NUM_TABLES_USE != 1
281 }
282
283
284 #ifdef Z7_CRC_HW_USE
285 Z7_NO_INLINE
CrcUpdate(UInt32 crc,const void * data,size_t size)286 UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size)
287 {
288 if (g_Crc_Algo == 0)
289 return CrcUpdate_HW(crc, data, size);
290 return CrcUpdate_Base(crc, data, size);
291 }
292 #endif
293
294 #endif // !defined(Z7_CRC_HW_FORCE)
295
296
297
CrcCalc(const void * data,size_t size)298 UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
299 {
300 return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL;
301 }
302
303
304 MY_ALIGN(64)
305 UInt32 g_CrcTable[256 * Z7_CRC_NUM_TABLES_TOTAL];
306
307
CrcGenerateTable(void)308 void Z7_FASTCALL CrcGenerateTable(void)
309 {
310 UInt32 i;
311 for (i = 0; i < 256; i++)
312 {
313 #if defined(Z7_CRC_HW_FORCE)
314 g_CrcTable[i] = __crc32b(i, 0);
315 #else
316 #define kCrcPoly 0xEDB88320
317 UInt32 r = i;
318 unsigned j;
319 for (j = 0; j < 8; j++)
320 r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
321 g_CrcTable[i] = r;
322 #endif
323 }
324 for (i = 256; i < 256 * Z7_CRC_NUM_TABLES_USE; i++)
325 {
326 const UInt32 r = g_CrcTable[(size_t)i - 256];
327 g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
328 }
329
330 #if !defined(Z7_CRC_HW_FORCE) && \
331 (defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) || defined(MY_CPU_BE))
332
333 #if Z7_CRC_NUM_TABLES_USE <= 1
334 g_Crc_Algo = 1;
335 #else // Z7_CRC_NUM_TABLES_USE <= 1
336
337 #if defined(MY_CPU_LE)
338 g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
339 #else // !defined(MY_CPU_LE)
340 {
341 #ifndef MY_CPU_BE
342 UInt32 k = 0x01020304;
343 const Byte *p = (const Byte *)&k;
344 if (p[0] == 4 && p[1] == 3)
345 g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
346 else if (p[0] != 1 || p[1] != 2)
347 g_Crc_Algo = 1;
348 else
349 #endif // MY_CPU_BE
350 {
351 for (i = 256 * Z7_CRC_NUM_TABLES_TOTAL - 1; i >= 256; i--)
352 {
353 const UInt32 x = g_CrcTable[(size_t)i - 256];
354 g_CrcTable[i] = Z7_BSWAP32(x);
355 }
356 #if defined(Z7_CRC_UPDATE_T1_FUNC_NAME)
357 g_Crc_Algo = Z7_CRC_NUM_TABLES_USE;
358 #endif
359 #if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
360 g_Crc_Be = 1;
361 #endif
362 }
363 }
364 #endif // !defined(MY_CPU_LE)
365
366 #ifdef MY_CPU_LE
367 #ifdef Z7_CRC_HW_USE
368 if (CPU_IsSupported_CRC32())
369 g_Crc_Algo = 0;
370 #endif // Z7_CRC_HW_USE
371 #endif // MY_CPU_LE
372
373 #endif // Z7_CRC_NUM_TABLES_USE <= 1
374 #endif // g_Crc_Algo was declared
375 }
376
z7_GetFunc_CrcUpdate(unsigned algo)377 Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo)
378 {
379 if (algo == 0)
380 return &CrcUpdate;
381
382 #if defined(Z7_CRC_HW_USE)
383 if (algo == sizeof(CRC_HW_WORD_TYPE) * 8)
384 {
385 #ifdef Z7_CRC_HW_FORCE
386 return &CrcUpdate;
387 #else
388 if (g_Crc_Algo == 0)
389 return &CrcUpdate_HW;
390 #endif
391 }
392 #endif
393
394 #ifndef Z7_CRC_HW_FORCE
395 if (algo == Z7_CRC_NUM_TABLES_USE)
396 return
397 #ifdef Z7_CRC_HW_USE
398 &CrcUpdate_Base;
399 #else
400 &CrcUpdate;
401 #endif
402 #endif
403
404 return NULL;
405 }
406
407 #undef kCrcPoly
408 #undef Z7_CRC_NUM_TABLES_USE
409 #undef Z7_CRC_NUM_TABLES_TOTAL
410 #undef CRC_UPDATE_BYTE_2
411 #undef FUNC_NAME_LE_2
412 #undef FUNC_NAME_LE_1
413 #undef FUNC_NAME_LE
414 #undef FUNC_NAME_BE_2
415 #undef FUNC_NAME_BE_1
416 #undef FUNC_NAME_BE
417
418 #undef CRC_HW_UNROLL_BYTES
419 #undef CRC_HW_WORD_FUNC
420 #undef CRC_HW_WORD_TYPE
421