• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* CpuArch.h -- CPU specific code
2 2021-07-13 : Igor Pavlov : Public domain */
3 
4 #ifndef __CPU_ARCH_H
5 #define __CPU_ARCH_H
6 
7 #include "7zTypes.h"
8 
9 EXTERN_C_BEGIN
10 
11 /*
12 MY_CPU_LE means that CPU is LITTLE ENDIAN.
13 MY_CPU_BE means that CPU is BIG ENDIAN.
14 If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
15 
16 MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
17 
18 MY_CPU_64BIT means that processor can work with 64-bit registers.
19   MY_CPU_64BIT can be used to select fast code branch
20   MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8)
21 */
22 
23 #if  defined(_M_X64) \
24   || defined(_M_AMD64) \
25   || defined(__x86_64__) \
26   || defined(__AMD64__) \
27   || defined(__amd64__)
28   #define MY_CPU_AMD64
29   #ifdef __ILP32__
30     #define MY_CPU_NAME "x32"
31     #define MY_CPU_SIZEOF_POINTER 4
32   #else
33     #define MY_CPU_NAME "x64"
34     #define MY_CPU_SIZEOF_POINTER 8
35   #endif
36   #define MY_CPU_64BIT
37 #endif
38 
39 
40 #if  defined(_M_IX86) \
41   || defined(__i386__)
42   #define MY_CPU_X86
43   #define MY_CPU_NAME "x86"
44   /* #define MY_CPU_32BIT */
45   #define MY_CPU_SIZEOF_POINTER 4
46 #endif
47 
48 
49 #if  defined(_M_ARM64) \
50   || defined(__AARCH64EL__) \
51   || defined(__AARCH64EB__) \
52   || defined(__aarch64__)
53   #define MY_CPU_ARM64
54   #define MY_CPU_NAME "arm64"
55   #define MY_CPU_64BIT
56 #endif
57 
58 
59 #if  defined(_M_ARM) \
60   || defined(_M_ARM_NT) \
61   || defined(_M_ARMT) \
62   || defined(__arm__) \
63   || defined(__thumb__) \
64   || defined(__ARMEL__) \
65   || defined(__ARMEB__) \
66   || defined(__THUMBEL__) \
67   || defined(__THUMBEB__)
68   #define MY_CPU_ARM
69 
70   #if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT)
71     #define MY_CPU_NAME "armt"
72   #else
73     #define MY_CPU_NAME "arm"
74   #endif
75   /* #define MY_CPU_32BIT */
76   #define MY_CPU_SIZEOF_POINTER 4
77 #endif
78 
79 
80 #if  defined(_M_IA64) \
81   || defined(__ia64__)
82   #define MY_CPU_IA64
83   #define MY_CPU_NAME "ia64"
84   #define MY_CPU_64BIT
85 #endif
86 
87 
88 #if  defined(__mips64) \
89   || defined(__mips64__) \
90   || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
91   #define MY_CPU_NAME "mips64"
92   #define MY_CPU_64BIT
93 #elif defined(__mips__)
94   #define MY_CPU_NAME "mips"
95   /* #define MY_CPU_32BIT */
96 #endif
97 
98 
99 #if  defined(__ppc64__) \
100   || defined(__powerpc64__) \
101   || defined(__ppc__) \
102   || defined(__powerpc__) \
103   || defined(__PPC__) \
104   || defined(_POWER)
105 
106 #if  defined(__ppc64__) \
107   || defined(__powerpc64__) \
108   || defined(_LP64) \
109   || defined(__64BIT__)
110   #ifdef __ILP32__
111     #define MY_CPU_NAME "ppc64-32"
112     #define MY_CPU_SIZEOF_POINTER 4
113   #else
114     #define MY_CPU_NAME "ppc64"
115     #define MY_CPU_SIZEOF_POINTER 8
116   #endif
117   #define MY_CPU_64BIT
118 #else
119   #define MY_CPU_NAME "ppc"
120   #define MY_CPU_SIZEOF_POINTER 4
121   /* #define MY_CPU_32BIT */
122 #endif
123 #endif
124 
125 
126 #if  defined(__sparc64__)
127   #define MY_CPU_NAME "sparc64"
128   #define MY_CPU_64BIT
129 #elif defined(__sparc__)
130   #define MY_CPU_NAME "sparc"
131   /* #define MY_CPU_32BIT */
132 #endif
133 
134 
135 #if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
136 #define MY_CPU_X86_OR_AMD64
137 #endif
138 
139 #if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64)
140 #define MY_CPU_ARM_OR_ARM64
141 #endif
142 
143 
144 #ifdef _WIN32
145 
146   #ifdef MY_CPU_ARM
147   #define MY_CPU_ARM_LE
148   #endif
149 
150   #ifdef MY_CPU_ARM64
151   #define MY_CPU_ARM64_LE
152   #endif
153 
154   #ifdef _M_IA64
155   #define MY_CPU_IA64_LE
156   #endif
157 
158 #endif
159 
160 
161 #if defined(MY_CPU_X86_OR_AMD64) \
162     || defined(MY_CPU_ARM_LE) \
163     || defined(MY_CPU_ARM64_LE) \
164     || defined(MY_CPU_IA64_LE) \
165     || defined(__LITTLE_ENDIAN__) \
166     || defined(__ARMEL__) \
167     || defined(__THUMBEL__) \
168     || defined(__AARCH64EL__) \
169     || defined(__MIPSEL__) \
170     || defined(__MIPSEL) \
171     || defined(_MIPSEL) \
172     || defined(__BFIN__) \
173     || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
174   #define MY_CPU_LE
175 #endif
176 
177 #if defined(__BIG_ENDIAN__) \
178     || defined(__ARMEB__) \
179     || defined(__THUMBEB__) \
180     || defined(__AARCH64EB__) \
181     || defined(__MIPSEB__) \
182     || defined(__MIPSEB) \
183     || defined(_MIPSEB) \
184     || defined(__m68k__) \
185     || defined(__s390__) \
186     || defined(__s390x__) \
187     || defined(__zarch__) \
188     || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
189   #define MY_CPU_BE
190 #endif
191 
192 
193 #if defined(MY_CPU_LE) && defined(MY_CPU_BE)
194   #error Stop_Compiling_Bad_Endian
195 #endif
196 
197 
198 #if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
199   #error Stop_Compiling_Bad_32_64_BIT
200 #endif
201 
202 #ifdef __SIZEOF_POINTER__
203   #ifdef MY_CPU_SIZEOF_POINTER
204     #if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__
205       #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
206     #endif
207   #else
208     #define MY_CPU_SIZEOF_POINTER  __SIZEOF_POINTER__
209   #endif
210 #endif
211 
212 #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
213 #if defined (_LP64)
214       #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
215 #endif
216 #endif
217 
218 #ifdef _MSC_VER
219   #if _MSC_VER >= 1300
220     #define MY_CPU_pragma_pack_push_1   __pragma(pack(push, 1))
221     #define MY_CPU_pragma_pop           __pragma(pack(pop))
222   #else
223     #define MY_CPU_pragma_pack_push_1
224     #define MY_CPU_pragma_pop
225   #endif
226 #else
227   #ifdef __xlC__
228     #define MY_CPU_pragma_pack_push_1   _Pragma("pack(1)")
229     #define MY_CPU_pragma_pop           _Pragma("pack()")
230   #else
231     #define MY_CPU_pragma_pack_push_1   _Pragma("pack(push, 1)")
232     #define MY_CPU_pragma_pop           _Pragma("pack(pop)")
233   #endif
234 #endif
235 
236 
237 #ifndef MY_CPU_NAME
238   #ifdef MY_CPU_LE
239     #define MY_CPU_NAME "LE"
240   #elif defined(MY_CPU_BE)
241     #define MY_CPU_NAME "BE"
242   #else
243     /*
244     #define MY_CPU_NAME ""
245     */
246   #endif
247 #endif
248 
249 
250 
251 
252 
253 #ifdef MY_CPU_LE
254   #if defined(MY_CPU_X86_OR_AMD64) \
255       || defined(MY_CPU_ARM64)
256     #define MY_CPU_LE_UNALIGN
257     #define MY_CPU_LE_UNALIGN_64
258   #elif defined(__ARM_FEATURE_UNALIGNED)
259     /* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment.
260        So we can't use unaligned 64-bit operations. */
261     #define MY_CPU_LE_UNALIGN
262   #endif
263 #endif
264 
265 
266 #ifdef MY_CPU_LE_UNALIGN
267 
268 #define GetUi16(p) (*(const UInt16 *)(const void *)(p))
269 #define GetUi32(p) (*(const UInt32 *)(const void *)(p))
270 #ifdef MY_CPU_LE_UNALIGN_64
271 #define GetUi64(p) (*(const UInt64 *)(const void *)(p))
272 #endif
273 
274 #define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); }
275 #define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); }
276 #ifdef MY_CPU_LE_UNALIGN_64
277 #define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); }
278 #endif
279 
280 #else
281 
282 #define GetUi16(p) ( (UInt16) ( \
283              ((const Byte *)(p))[0] | \
284     ((UInt16)((const Byte *)(p))[1] << 8) ))
285 
286 #define GetUi32(p) ( \
287              ((const Byte *)(p))[0]        | \
288     ((UInt32)((const Byte *)(p))[1] <<  8) | \
289     ((UInt32)((const Byte *)(p))[2] << 16) | \
290     ((UInt32)((const Byte *)(p))[3] << 24))
291 
292 #define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
293     _ppp_[0] = (Byte)_vvv_; \
294     _ppp_[1] = (Byte)(_vvv_ >> 8); }
295 
296 #define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
297     _ppp_[0] = (Byte)_vvv_; \
298     _ppp_[1] = (Byte)(_vvv_ >> 8); \
299     _ppp_[2] = (Byte)(_vvv_ >> 16); \
300     _ppp_[3] = (Byte)(_vvv_ >> 24); }
301 
302 #endif
303 
304 
305 #ifndef MY_CPU_LE_UNALIGN_64
306 
307 #define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
308 
309 #define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
310     SetUi32(_ppp2_    , (UInt32)_vvv2_); \
311     SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
312 
313 #endif
314 
315 
316 
317 
318 #ifdef __has_builtin
319   #define MY__has_builtin(x) __has_builtin(x)
320 #else
321   #define MY__has_builtin(x) 0
322 #endif
323 
324 #if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ defined(_MSC_VER) && (_MSC_VER >= 1300)
325 
326 /* Note: we use bswap instruction, that is unsupported in 386 cpu */
327 
328 #include <stdlib.h>
329 
330 #pragma intrinsic(_byteswap_ushort)
331 #pragma intrinsic(_byteswap_ulong)
332 #pragma intrinsic(_byteswap_uint64)
333 
334 /* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */
335 #define GetBe32(p) _byteswap_ulong (*(const UInt32 *)(const void *)(p))
336 #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const void *)(p))
337 
338 #define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
339 
340 #elif defined(MY_CPU_LE_UNALIGN) && ( \
341        (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
342     || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )
343 
344 /* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const void *)(p)) */
345 #define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const void *)(p))
346 #define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const void *)(p))
347 
348 #define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
349 
350 #else
351 
352 #define GetBe32(p) ( \
353     ((UInt32)((const Byte *)(p))[0] << 24) | \
354     ((UInt32)((const Byte *)(p))[1] << 16) | \
355     ((UInt32)((const Byte *)(p))[2] <<  8) | \
356              ((const Byte *)(p))[3] )
357 
358 #define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
359 
360 #define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
361     _ppp_[0] = (Byte)(_vvv_ >> 24); \
362     _ppp_[1] = (Byte)(_vvv_ >> 16); \
363     _ppp_[2] = (Byte)(_vvv_ >> 8); \
364     _ppp_[3] = (Byte)_vvv_; }
365 
366 #endif
367 
368 
369 #ifndef GetBe16
370 
371 #define GetBe16(p) ( (UInt16) ( \
372     ((UInt16)((const Byte *)(p))[0] << 8) | \
373              ((const Byte *)(p))[1] ))
374 
375 #endif
376 
377 
378 
379 #ifdef MY_CPU_X86_OR_AMD64
380 
381 typedef struct
382 {
383   UInt32 maxFunc;
384   UInt32 vendor[3];
385   UInt32 ver;
386   UInt32 b;
387   UInt32 c;
388   UInt32 d;
389 } Cx86cpuid;
390 
391 enum
392 {
393   CPU_FIRM_INTEL,
394   CPU_FIRM_AMD,
395   CPU_FIRM_VIA
396 };
397 
398 void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
399 
400 BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);
401 int x86cpuid_GetFirm(const Cx86cpuid *p);
402 
403 #define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
404 #define x86cpuid_GetModel(ver)  (((ver >> 12) &  0xF0) | ((ver >> 4) & 0xF))
405 #define x86cpuid_GetStepping(ver) (ver & 0xF)
406 
407 BoolInt CPU_Is_InOrder(void);
408 
409 BoolInt CPU_IsSupported_AES(void);
410 BoolInt CPU_IsSupported_AVX2(void);
411 BoolInt CPU_IsSupported_VAES_AVX2(void);
412 BoolInt CPU_IsSupported_SSSE3(void);
413 BoolInt CPU_IsSupported_SSE41(void);
414 BoolInt CPU_IsSupported_SHA(void);
415 BoolInt CPU_IsSupported_PageGB(void);
416 
417 #elif defined(MY_CPU_ARM_OR_ARM64)
418 
419 BoolInt CPU_IsSupported_CRC32(void);
420 BoolInt CPU_IsSupported_NEON(void);
421 
422 #if defined(_WIN32)
423 BoolInt CPU_IsSupported_CRYPTO(void);
424 #define CPU_IsSupported_SHA1  CPU_IsSupported_CRYPTO
425 #define CPU_IsSupported_SHA2  CPU_IsSupported_CRYPTO
426 #define CPU_IsSupported_AES   CPU_IsSupported_CRYPTO
427 #else
428 BoolInt CPU_IsSupported_SHA1(void);
429 BoolInt CPU_IsSupported_SHA2(void);
430 BoolInt CPU_IsSupported_AES(void);
431 #endif
432 
433 #endif
434 
435 #if defined(__APPLE__)
436 int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize);
437 int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val);
438 #endif
439 
440 EXTERN_C_END
441 
442 #endif
443