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