• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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