1 /* 7zCrc.c -- CRC32 calculation and init
2 2023-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 /*
26 extern
27 CRC_FUNC g_CrcUpdateT4;
28 CRC_FUNC g_CrcUpdateT4;
29 */
30 extern
31 CRC_FUNC g_CrcUpdateT8;
32 CRC_FUNC g_CrcUpdateT8;
33 extern
34 CRC_FUNC g_CrcUpdateT0_32;
35 CRC_FUNC g_CrcUpdateT0_32;
36 extern
37 CRC_FUNC g_CrcUpdateT0_64;
38 CRC_FUNC g_CrcUpdateT0_64;
39 extern
40 CRC_FUNC g_CrcUpdate;
41 CRC_FUNC g_CrcUpdate;
42
43 UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
44
CrcUpdate(UInt32 v,const void * data,size_t size)45 UInt32 Z7_FASTCALL CrcUpdate(UInt32 v, const void *data, size_t size)
46 {
47 return g_CrcUpdate(v, data, size, g_CrcTable);
48 }
49
CrcCalc(const void * data,size_t size)50 UInt32 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))
59 UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
CrcUpdateT1(UInt32 v,const void * data,size_t size,const UInt32 * table)60 UInt32 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
121 Z7_FORCE_INLINE
__crc32b(UInt32 v,UInt32 data)122 UInt32 __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
129 Z7_FORCE_INLINE
__crc32w(UInt32 v,UInt32 data)130 UInt32 __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
140 Z7_FORCE_INLINE
__crc32d(UInt32 v,UInt64 data)141 UInt32 __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
171 ATTRIB_CRC
172 UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table);
173 ATTRIB_CRC
CrcUpdateT0_32(UInt32 v,const void * data,size_t size,const UInt32 * table)174 UInt32 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
203 ATTRIB_CRC
204 UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table);
205 ATTRIB_CRC
CrcUpdateT0_64(UInt32 v,const void * data,size_t size,const UInt32 * table)206 UInt32 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
CrcGenerateTable(void)245 void 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