1 //===-- cpu_model/x86.c - Support for __cpu_model builtin --------*- C -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is based on LLVM's lib/Support/Host.cpp. 10 // It implements the operating system Host concept and builtin 11 // __cpu_model for the compiler_rt library for x86. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "cpu_model.h" 16 17 #if !(defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \ 18 defined(_M_X64)) 19 #error This file is intended only for x86-based targets 20 #endif 21 22 #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) 23 24 #include <assert.h> 25 26 #if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER) 27 #include <cpuid.h> 28 #endif 29 30 #ifdef _MSC_VER 31 #include <intrin.h> 32 #endif 33 34 enum VendorSignatures { 35 SIG_INTEL = 0x756e6547, // Genu 36 SIG_AMD = 0x68747541, // Auth 37 }; 38 39 enum ProcessorVendors { 40 VENDOR_INTEL = 1, 41 VENDOR_AMD, 42 VENDOR_OTHER, 43 VENDOR_MAX 44 }; 45 46 enum ProcessorTypes { 47 INTEL_BONNELL = 1, 48 INTEL_CORE2, 49 INTEL_COREI7, 50 AMDFAM10H, 51 AMDFAM15H, 52 INTEL_SILVERMONT, 53 INTEL_KNL, 54 AMD_BTVER1, 55 AMD_BTVER2, 56 AMDFAM17H, 57 INTEL_KNM, 58 INTEL_GOLDMONT, 59 INTEL_GOLDMONT_PLUS, 60 INTEL_TREMONT, 61 AMDFAM19H, 62 ZHAOXIN_FAM7H, 63 INTEL_SIERRAFOREST, 64 INTEL_GRANDRIDGE, 65 INTEL_CLEARWATERFOREST, 66 AMDFAM1AH, 67 CPU_TYPE_MAX 68 }; 69 70 enum ProcessorSubtypes { 71 INTEL_COREI7_NEHALEM = 1, 72 INTEL_COREI7_WESTMERE, 73 INTEL_COREI7_SANDYBRIDGE, 74 AMDFAM10H_BARCELONA, 75 AMDFAM10H_SHANGHAI, 76 AMDFAM10H_ISTANBUL, 77 AMDFAM15H_BDVER1, 78 AMDFAM15H_BDVER2, 79 AMDFAM15H_BDVER3, 80 AMDFAM15H_BDVER4, 81 AMDFAM17H_ZNVER1, 82 INTEL_COREI7_IVYBRIDGE, 83 INTEL_COREI7_HASWELL, 84 INTEL_COREI7_BROADWELL, 85 INTEL_COREI7_SKYLAKE, 86 INTEL_COREI7_SKYLAKE_AVX512, 87 INTEL_COREI7_CANNONLAKE, 88 INTEL_COREI7_ICELAKE_CLIENT, 89 INTEL_COREI7_ICELAKE_SERVER, 90 AMDFAM17H_ZNVER2, 91 INTEL_COREI7_CASCADELAKE, 92 INTEL_COREI7_TIGERLAKE, 93 INTEL_COREI7_COOPERLAKE, 94 INTEL_COREI7_SAPPHIRERAPIDS, 95 INTEL_COREI7_ALDERLAKE, 96 AMDFAM19H_ZNVER3, 97 INTEL_COREI7_ROCKETLAKE, 98 ZHAOXIN_FAM7H_LUJIAZUI, 99 AMDFAM19H_ZNVER4, 100 INTEL_COREI7_GRANITERAPIDS, 101 INTEL_COREI7_GRANITERAPIDS_D, 102 INTEL_COREI7_ARROWLAKE, 103 INTEL_COREI7_ARROWLAKE_S, 104 INTEL_COREI7_PANTHERLAKE, 105 AMDFAM1AH_ZNVER5, 106 INTEL_COREI7_DIAMONDRAPIDS, 107 CPU_SUBTYPE_MAX 108 }; 109 110 enum ProcessorFeatures { 111 FEATURE_CMOV = 0, 112 FEATURE_MMX, 113 FEATURE_POPCNT, 114 FEATURE_SSE, 115 FEATURE_SSE2, 116 FEATURE_SSE3, 117 FEATURE_SSSE3, 118 FEATURE_SSE4_1, 119 FEATURE_SSE4_2, 120 FEATURE_AVX, 121 FEATURE_AVX2, 122 FEATURE_SSE4_A, 123 FEATURE_FMA4, 124 FEATURE_XOP, 125 FEATURE_FMA, 126 FEATURE_AVX512F, 127 FEATURE_BMI, 128 FEATURE_BMI2, 129 FEATURE_AES, 130 FEATURE_PCLMUL, 131 FEATURE_AVX512VL, 132 FEATURE_AVX512BW, 133 FEATURE_AVX512DQ, 134 FEATURE_AVX512CD, 135 FEATURE_AVX512ER, 136 FEATURE_AVX512PF, 137 FEATURE_AVX512VBMI, 138 FEATURE_AVX512IFMA, 139 FEATURE_AVX5124VNNIW, 140 FEATURE_AVX5124FMAPS, 141 FEATURE_AVX512VPOPCNTDQ, 142 FEATURE_AVX512VBMI2, 143 FEATURE_GFNI, 144 FEATURE_VPCLMULQDQ, 145 FEATURE_AVX512VNNI, 146 FEATURE_AVX512BITALG, 147 FEATURE_AVX512BF16, 148 FEATURE_AVX512VP2INTERSECT, 149 // FIXME: Below Features has some missings comparing to gcc, it's because gcc 150 // has some not one-to-one mapped in llvm. 151 // FEATURE_3DNOW, 152 // FEATURE_3DNOWP, 153 FEATURE_ADX = 40, 154 // FEATURE_ABM, 155 FEATURE_CLDEMOTE = 42, 156 FEATURE_CLFLUSHOPT, 157 FEATURE_CLWB, 158 FEATURE_CLZERO, 159 FEATURE_CMPXCHG16B, 160 // FIXME: Not adding FEATURE_CMPXCHG8B is a workaround to make 'generic' as 161 // a cpu string with no X86_FEATURE_COMPAT features, which is required in 162 // current implementantion of cpu_specific/cpu_dispatch FMV feature. 163 // FEATURE_CMPXCHG8B, 164 FEATURE_ENQCMD = 48, 165 FEATURE_F16C, 166 FEATURE_FSGSBASE, 167 // FEATURE_FXSAVE, 168 // FEATURE_HLE, 169 // FEATURE_IBT, 170 FEATURE_LAHF_LM = 54, 171 FEATURE_LM, 172 FEATURE_LWP, 173 FEATURE_LZCNT, 174 FEATURE_MOVBE, 175 FEATURE_MOVDIR64B, 176 FEATURE_MOVDIRI, 177 FEATURE_MWAITX, 178 // FEATURE_OSXSAVE, 179 FEATURE_PCONFIG = 63, 180 FEATURE_PKU, 181 FEATURE_PREFETCHWT1, 182 FEATURE_PRFCHW, 183 FEATURE_PTWRITE, 184 FEATURE_RDPID, 185 FEATURE_RDRND, 186 FEATURE_RDSEED, 187 FEATURE_RTM, 188 FEATURE_SERIALIZE, 189 FEATURE_SGX, 190 FEATURE_SHA, 191 FEATURE_SHSTK, 192 FEATURE_TBM, 193 FEATURE_TSXLDTRK, 194 FEATURE_VAES, 195 FEATURE_WAITPKG, 196 FEATURE_WBNOINVD, 197 FEATURE_XSAVE, 198 FEATURE_XSAVEC, 199 FEATURE_XSAVEOPT, 200 FEATURE_XSAVES, 201 FEATURE_AMX_TILE, 202 FEATURE_AMX_INT8, 203 FEATURE_AMX_BF16, 204 FEATURE_UINTR, 205 FEATURE_HRESET, 206 FEATURE_KL, 207 // FEATURE_AESKLE, 208 FEATURE_WIDEKL = 92, 209 FEATURE_AVXVNNI, 210 FEATURE_AVX512FP16, 211 FEATURE_X86_64_BASELINE, 212 FEATURE_X86_64_V2, 213 FEATURE_X86_64_V3, 214 FEATURE_X86_64_V4, 215 FEATURE_AVXIFMA, 216 FEATURE_AVXVNNIINT8, 217 FEATURE_AVXNECONVERT, 218 FEATURE_CMPCCXADD, 219 FEATURE_AMX_FP16, 220 FEATURE_PREFETCHI, 221 FEATURE_RAOINT, 222 FEATURE_AMX_COMPLEX, 223 FEATURE_AVXVNNIINT16, 224 FEATURE_SM3, 225 FEATURE_SHA512, 226 FEATURE_SM4, 227 FEATURE_APXF, 228 FEATURE_USERMSR, 229 FEATURE_AVX10_1_256, 230 FEATURE_AVX10_1_512, 231 FEATURE_AVX10_2_256, 232 FEATURE_AVX10_2_512, 233 FEATURE_MOVRS, 234 CPU_FEATURE_MAX 235 }; 236 237 // This code is copied from lib/Support/Host.cpp. 238 // Changes to either file should be mirrored in the other. 239 240 /// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in 241 /// the specified arguments. If we can't run cpuid on the host, return true. 242 static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, 243 unsigned *rECX, unsigned *rEDX) { 244 #if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER) 245 return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX); 246 #elif defined(_MSC_VER) 247 // The MSVC intrinsic is portable across x86 and x64. 248 int registers[4]; 249 __cpuid(registers, value); 250 *rEAX = registers[0]; 251 *rEBX = registers[1]; 252 *rECX = registers[2]; 253 *rEDX = registers[3]; 254 return false; 255 #else 256 return true; 257 #endif 258 } 259 260 /// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return 261 /// the 4 values in the specified arguments. If we can't run cpuid on the host, 262 /// return true. 263 static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, 264 unsigned *rEAX, unsigned *rEBX, unsigned *rECX, 265 unsigned *rEDX) { 266 // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang 267 // are such that __cpuidex is defined within cpuid.h for both, we can remove 268 // the __get_cpuid_count function and share the MSVC implementation between 269 // all three. 270 #if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER) 271 return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX); 272 #elif defined(_MSC_VER) 273 int registers[4]; 274 __cpuidex(registers, value, subleaf); 275 *rEAX = registers[0]; 276 *rEBX = registers[1]; 277 *rECX = registers[2]; 278 *rEDX = registers[3]; 279 return false; 280 #else 281 return true; 282 #endif 283 } 284 285 // Read control register 0 (XCR0). Used to detect features such as AVX. 286 static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { 287 // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang 288 // are such that _xgetbv is supported by both, we can unify the implementation 289 // with MSVC and remove all inline assembly. 290 #if defined(__GNUC__) || defined(__clang__) 291 // Check xgetbv; this uses a .byte sequence instead of the instruction 292 // directly because older assemblers do not include support for xgetbv and 293 // there is no easy way to conditionally compile based on the assembler used. 294 __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); 295 return false; 296 #elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) 297 unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); 298 *rEAX = Result; 299 *rEDX = Result >> 32; 300 return false; 301 #else 302 return true; 303 #endif 304 } 305 306 static void detectX86FamilyModel(unsigned EAX, unsigned *Family, 307 unsigned *Model) { 308 *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 309 *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 310 if (*Family == 6 || *Family == 0xf) { 311 if (*Family == 0xf) 312 // Examine extended family ID if family ID is F. 313 *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 314 // Examine extended model ID if family ID is 6 or F. 315 *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 316 } 317 } 318 319 #define testFeature(F) (Features[F / 32] & (1 << (F % 32))) != 0 320 321 static const char *getIntelProcessorTypeAndSubtype(unsigned Family, 322 unsigned Model, 323 const unsigned *Features, 324 unsigned *Type, 325 unsigned *Subtype) { 326 // We select CPU strings to match the code in Host.cpp, but we don't use them 327 // in compiler-rt. 328 const char *CPU = 0; 329 330 switch (Family) { 331 case 6: 332 switch (Model) { 333 case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile 334 // processor, Intel Core 2 Quad processor, Intel Core 2 Quad 335 // mobile processor, Intel Core 2 Extreme processor, Intel 336 // Pentium Dual-Core processor, Intel Xeon processor, model 337 // 0Fh. All processors are manufactured using the 65 nm process. 338 case 0x16: // Intel Celeron processor model 16h. All processors are 339 // manufactured using the 65 nm process 340 CPU = "core2"; 341 *Type = INTEL_CORE2; 342 break; 343 case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model 344 // 17h. All processors are manufactured using the 45 nm process. 345 // 346 // 45nm: Penryn , Wolfdale, Yorkfield (XE) 347 case 0x1d: // Intel Xeon processor MP. All processors are manufactured using 348 // the 45 nm process. 349 CPU = "penryn"; 350 *Type = INTEL_CORE2; 351 break; 352 case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All 353 // processors are manufactured using the 45 nm process. 354 case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. 355 // As found in a Summer 2010 model iMac. 356 case 0x1f: 357 case 0x2e: // Nehalem EX 358 CPU = "nehalem"; 359 *Type = INTEL_COREI7; 360 *Subtype = INTEL_COREI7_NEHALEM; 361 break; 362 case 0x25: // Intel Core i7, laptop version. 363 case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All 364 // processors are manufactured using the 32 nm process. 365 case 0x2f: // Westmere EX 366 CPU = "westmere"; 367 *Type = INTEL_COREI7; 368 *Subtype = INTEL_COREI7_WESTMERE; 369 break; 370 case 0x2a: // Intel Core i7 processor. All processors are manufactured 371 // using the 32 nm process. 372 case 0x2d: 373 CPU = "sandybridge"; 374 *Type = INTEL_COREI7; 375 *Subtype = INTEL_COREI7_SANDYBRIDGE; 376 break; 377 case 0x3a: 378 case 0x3e: // Ivy Bridge EP 379 CPU = "ivybridge"; 380 *Type = INTEL_COREI7; 381 *Subtype = INTEL_COREI7_IVYBRIDGE; 382 break; 383 384 // Haswell: 385 case 0x3c: 386 case 0x3f: 387 case 0x45: 388 case 0x46: 389 CPU = "haswell"; 390 *Type = INTEL_COREI7; 391 *Subtype = INTEL_COREI7_HASWELL; 392 break; 393 394 // Broadwell: 395 case 0x3d: 396 case 0x47: 397 case 0x4f: 398 case 0x56: 399 CPU = "broadwell"; 400 *Type = INTEL_COREI7; 401 *Subtype = INTEL_COREI7_BROADWELL; 402 break; 403 404 // Skylake: 405 case 0x4e: // Skylake mobile 406 case 0x5e: // Skylake desktop 407 case 0x8e: // Kaby Lake mobile 408 case 0x9e: // Kaby Lake desktop 409 case 0xa5: // Comet Lake-H/S 410 case 0xa6: // Comet Lake-U 411 CPU = "skylake"; 412 *Type = INTEL_COREI7; 413 *Subtype = INTEL_COREI7_SKYLAKE; 414 break; 415 416 // Rocketlake: 417 case 0xa7: 418 CPU = "rocketlake"; 419 *Type = INTEL_COREI7; 420 *Subtype = INTEL_COREI7_ROCKETLAKE; 421 break; 422 423 // Skylake Xeon: 424 case 0x55: 425 *Type = INTEL_COREI7; 426 if (testFeature(FEATURE_AVX512BF16)) { 427 CPU = "cooperlake"; 428 *Subtype = INTEL_COREI7_COOPERLAKE; 429 } else if (testFeature(FEATURE_AVX512VNNI)) { 430 CPU = "cascadelake"; 431 *Subtype = INTEL_COREI7_CASCADELAKE; 432 } else { 433 CPU = "skylake-avx512"; 434 *Subtype = INTEL_COREI7_SKYLAKE_AVX512; 435 } 436 break; 437 438 // Cannonlake: 439 case 0x66: 440 CPU = "cannonlake"; 441 *Type = INTEL_COREI7; 442 *Subtype = INTEL_COREI7_CANNONLAKE; 443 break; 444 445 // Icelake: 446 case 0x7d: 447 case 0x7e: 448 CPU = "icelake-client"; 449 *Type = INTEL_COREI7; 450 *Subtype = INTEL_COREI7_ICELAKE_CLIENT; 451 break; 452 453 // Tigerlake: 454 case 0x8c: 455 case 0x8d: 456 CPU = "tigerlake"; 457 *Type = INTEL_COREI7; 458 *Subtype = INTEL_COREI7_TIGERLAKE; 459 break; 460 461 // Alderlake: 462 case 0x97: 463 case 0x9a: 464 CPU = "alderlake"; 465 *Type = INTEL_COREI7; 466 *Subtype = INTEL_COREI7_ALDERLAKE; 467 break; 468 469 // Raptorlake: 470 case 0xb7: 471 case 0xba: 472 case 0xbf: 473 CPU = "raptorlake"; 474 *Type = INTEL_COREI7; 475 *Subtype = INTEL_COREI7_ALDERLAKE; 476 break; 477 478 // Meteorlake: 479 case 0xaa: 480 case 0xac: 481 CPU = "meteorlake"; 482 *Type = INTEL_COREI7; 483 *Subtype = INTEL_COREI7_ALDERLAKE; 484 break; 485 486 // Gracemont: 487 case 0xbe: 488 CPU = "gracemont"; 489 *Type = INTEL_COREI7; 490 *Subtype = INTEL_COREI7_ALDERLAKE; 491 break; 492 493 // Arrowlake: 494 case 0xc5: 495 // Arrowlake U: 496 case 0xb5: 497 CPU = "arrowlake"; 498 *Type = INTEL_COREI7; 499 *Subtype = INTEL_COREI7_ARROWLAKE; 500 break; 501 502 // Arrowlake S: 503 case 0xc6: 504 CPU = "arrowlake-s"; 505 *Type = INTEL_COREI7; 506 *Subtype = INTEL_COREI7_ARROWLAKE_S; 507 break; 508 509 // Lunarlake: 510 case 0xbd: 511 CPU = "lunarlake"; 512 *Type = INTEL_COREI7; 513 *Subtype = INTEL_COREI7_ARROWLAKE_S; 514 break; 515 516 // Pantherlake: 517 case 0xcc: 518 CPU = "pantherlake"; 519 *Type = INTEL_COREI7; 520 *Subtype = INTEL_COREI7_PANTHERLAKE; 521 break; 522 523 // Icelake Xeon: 524 case 0x6a: 525 case 0x6c: 526 CPU = "icelake-server"; 527 *Type = INTEL_COREI7; 528 *Subtype = INTEL_COREI7_ICELAKE_SERVER; 529 break; 530 531 // Emerald Rapids: 532 case 0xcf: 533 CPU = "emeraldrapids"; 534 *Type = INTEL_COREI7; 535 *Subtype = INTEL_COREI7_SAPPHIRERAPIDS; 536 break; 537 538 // Sapphire Rapids: 539 case 0x8f: 540 CPU = "sapphirerapids"; 541 *Type = INTEL_COREI7; 542 *Subtype = INTEL_COREI7_SAPPHIRERAPIDS; 543 break; 544 545 // Granite Rapids: 546 case 0xad: 547 CPU = "graniterapids"; 548 *Type = INTEL_COREI7; 549 *Subtype = INTEL_COREI7_GRANITERAPIDS; 550 break; 551 552 // Granite Rapids D: 553 case 0xae: 554 CPU = "graniterapids-d"; 555 *Type = INTEL_COREI7; 556 *Subtype = INTEL_COREI7_GRANITERAPIDS_D; 557 break; 558 559 case 0x1c: // Most 45 nm Intel Atom processors 560 case 0x26: // 45 nm Atom Lincroft 561 case 0x27: // 32 nm Atom Medfield 562 case 0x35: // 32 nm Atom Midview 563 case 0x36: // 32 nm Atom Midview 564 CPU = "bonnell"; 565 *Type = INTEL_BONNELL; 566 break; 567 568 // Atom Silvermont codes from the Intel software optimization guide. 569 case 0x37: 570 case 0x4a: 571 case 0x4d: 572 case 0x5a: 573 case 0x5d: 574 case 0x4c: // really airmont 575 CPU = "silvermont"; 576 *Type = INTEL_SILVERMONT; 577 break; 578 // Goldmont: 579 case 0x5c: // Apollo Lake 580 case 0x5f: // Denverton 581 CPU = "goldmont"; 582 *Type = INTEL_GOLDMONT; 583 break; // "goldmont" 584 case 0x7a: 585 CPU = "goldmont-plus"; 586 *Type = INTEL_GOLDMONT_PLUS; 587 break; 588 case 0x86: 589 case 0x8a: // Lakefield 590 case 0x96: // Elkhart Lake 591 case 0x9c: // Jasper Lake 592 CPU = "tremont"; 593 *Type = INTEL_TREMONT; 594 break; 595 596 // Sierraforest: 597 case 0xaf: 598 CPU = "sierraforest"; 599 *Type = INTEL_SIERRAFOREST; 600 break; 601 602 // Grandridge: 603 case 0xb6: 604 CPU = "grandridge"; 605 *Type = INTEL_GRANDRIDGE; 606 break; 607 608 // Clearwaterforest: 609 case 0xdd: 610 CPU = "clearwaterforest"; 611 *Type = INTEL_COREI7; 612 *Subtype = INTEL_CLEARWATERFOREST; 613 break; 614 615 case 0x57: 616 CPU = "knl"; 617 *Type = INTEL_KNL; 618 break; 619 620 case 0x85: 621 CPU = "knm"; 622 *Type = INTEL_KNM; 623 break; 624 625 default: // Unknown family 6 CPU. 626 break; 627 } 628 break; 629 case 19: 630 switch (Model) { 631 // Diamond Rapids: 632 case 0x01: 633 CPU = "diamondrapids"; 634 *Type = INTEL_COREI7; 635 *Subtype = INTEL_COREI7_DIAMONDRAPIDS; 636 break; 637 638 default: // Unknown family 19 CPU. 639 break; 640 } 641 break; 642 default: 643 break; // Unknown. 644 } 645 646 return CPU; 647 } 648 649 static const char *getAMDProcessorTypeAndSubtype(unsigned Family, 650 unsigned Model, 651 const unsigned *Features, 652 unsigned *Type, 653 unsigned *Subtype) { 654 const char *CPU = 0; 655 656 switch (Family) { 657 case 4: 658 CPU = "i486"; 659 break; 660 case 5: 661 CPU = "pentium"; 662 switch (Model) { 663 case 6: 664 case 7: 665 CPU = "k6"; 666 break; 667 case 8: 668 CPU = "k6-2"; 669 break; 670 case 9: 671 case 13: 672 CPU = "k6-3"; 673 break; 674 case 10: 675 CPU = "geode"; 676 break; 677 } 678 break; 679 case 6: 680 if (testFeature(FEATURE_SSE)) { 681 CPU = "athlon-xp"; 682 break; 683 } 684 CPU = "athlon"; 685 break; 686 case 15: 687 if (testFeature(FEATURE_SSE3)) { 688 CPU = "k8-sse3"; 689 break; 690 } 691 CPU = "k8"; 692 break; 693 case 16: 694 case 18: 695 CPU = "amdfam10"; 696 *Type = AMDFAM10H; // "amdfam10" 697 switch (Model) { 698 case 2: 699 *Subtype = AMDFAM10H_BARCELONA; 700 break; 701 case 4: 702 *Subtype = AMDFAM10H_SHANGHAI; 703 break; 704 case 8: 705 *Subtype = AMDFAM10H_ISTANBUL; 706 break; 707 } 708 break; 709 case 20: 710 CPU = "btver1"; 711 *Type = AMD_BTVER1; 712 break; 713 case 21: 714 CPU = "bdver1"; 715 *Type = AMDFAM15H; 716 if (Model >= 0x60 && Model <= 0x7f) { 717 CPU = "bdver4"; 718 *Subtype = AMDFAM15H_BDVER4; 719 break; // 60h-7Fh: Excavator 720 } 721 if (Model >= 0x30 && Model <= 0x3f) { 722 CPU = "bdver3"; 723 *Subtype = AMDFAM15H_BDVER3; 724 break; // 30h-3Fh: Steamroller 725 } 726 if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { 727 CPU = "bdver2"; 728 *Subtype = AMDFAM15H_BDVER2; 729 break; // 02h, 10h-1Fh: Piledriver 730 } 731 if (Model <= 0x0f) { 732 *Subtype = AMDFAM15H_BDVER1; 733 break; // 00h-0Fh: Bulldozer 734 } 735 break; 736 case 22: 737 CPU = "btver2"; 738 *Type = AMD_BTVER2; 739 break; 740 case 23: 741 CPU = "znver1"; 742 *Type = AMDFAM17H; 743 if ((Model >= 0x30 && Model <= 0x3f) || (Model == 0x47) || 744 (Model >= 0x60 && Model <= 0x67) || (Model >= 0x68 && Model <= 0x6f) || 745 (Model >= 0x70 && Model <= 0x7f) || (Model >= 0x84 && Model <= 0x87) || 746 (Model >= 0x90 && Model <= 0x97) || (Model >= 0x98 && Model <= 0x9f) || 747 (Model >= 0xa0 && Model <= 0xaf)) { 748 // Family 17h Models 30h-3Fh (Starship) Zen 2 749 // Family 17h Models 47h (Cardinal) Zen 2 750 // Family 17h Models 60h-67h (Renoir) Zen 2 751 // Family 17h Models 68h-6Fh (Lucienne) Zen 2 752 // Family 17h Models 70h-7Fh (Matisse) Zen 2 753 // Family 17h Models 84h-87h (ProjectX) Zen 2 754 // Family 17h Models 90h-97h (VanGogh) Zen 2 755 // Family 17h Models 98h-9Fh (Mero) Zen 2 756 // Family 17h Models A0h-AFh (Mendocino) Zen 2 757 CPU = "znver2"; 758 *Subtype = AMDFAM17H_ZNVER2; 759 break; 760 } 761 if ((Model >= 0x10 && Model <= 0x1f) || (Model >= 0x20 && Model <= 0x2f)) { 762 // Family 17h Models 10h-1Fh (Raven1) Zen 763 // Family 17h Models 10h-1Fh (Picasso) Zen+ 764 // Family 17h Models 20h-2Fh (Raven2 x86) Zen 765 *Subtype = AMDFAM17H_ZNVER1; 766 break; 767 } 768 break; 769 case 25: 770 CPU = "znver3"; 771 *Type = AMDFAM19H; 772 if (Model <= 0x0f || (Model >= 0x20 && Model <= 0x2f) || 773 (Model >= 0x30 && Model <= 0x3f) || (Model >= 0x40 && Model <= 0x4f) || 774 (Model >= 0x50 && Model <= 0x5f)) { 775 // Family 19h Models 00h-0Fh (Genesis, Chagall) Zen 3 776 // Family 19h Models 20h-2Fh (Vermeer) Zen 3 777 // Family 19h Models 30h-3Fh (Badami) Zen 3 778 // Family 19h Models 40h-4Fh (Rembrandt) Zen 3+ 779 // Family 19h Models 50h-5Fh (Cezanne) Zen 3 780 *Subtype = AMDFAM19H_ZNVER3; 781 break; 782 } 783 if ((Model >= 0x10 && Model <= 0x1f) || (Model >= 0x60 && Model <= 0x6f) || 784 (Model >= 0x70 && Model <= 0x77) || (Model >= 0x78 && Model <= 0x7f) || 785 (Model >= 0xa0 && Model <= 0xaf)) { 786 // Family 19h Models 10h-1Fh (Stones; Storm Peak) Zen 4 787 // Family 19h Models 60h-6Fh (Raphael) Zen 4 788 // Family 19h Models 70h-77h (Phoenix, Hawkpoint1) Zen 4 789 // Family 19h Models 78h-7Fh (Phoenix 2, Hawkpoint2) Zen 4 790 // Family 19h Models A0h-AFh (Stones-Dense) Zen 4 791 CPU = "znver4"; 792 *Subtype = AMDFAM19H_ZNVER4; 793 break; // "znver4" 794 } 795 break; // family 19h 796 case 26: 797 CPU = "znver5"; 798 *Type = AMDFAM1AH; 799 if (Model <= 0x77) { 800 // Models 00h-0Fh (Breithorn). 801 // Models 10h-1Fh (Breithorn-Dense). 802 // Models 20h-2Fh (Strix 1). 803 // Models 30h-37h (Strix 2). 804 // Models 38h-3Fh (Strix 3). 805 // Models 40h-4Fh (Granite Ridge). 806 // Models 50h-5Fh (Weisshorn). 807 // Models 60h-6Fh (Krackan1). 808 // Models 70h-77h (Sarlak). 809 CPU = "znver5"; 810 *Subtype = AMDFAM1AH_ZNVER5; 811 break; // "znver5" 812 } 813 break; 814 default: 815 break; // Unknown AMD CPU. 816 } 817 818 return CPU; 819 } 820 821 #undef testFeature 822 823 static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, 824 unsigned *Features) { 825 unsigned EAX = 0, EBX = 0; 826 827 #define hasFeature(F) ((Features[F / 32] >> (F % 32)) & 1) 828 #define setFeature(F) Features[F / 32] |= 1U << (F % 32) 829 830 if ((EDX >> 15) & 1) 831 setFeature(FEATURE_CMOV); 832 if ((EDX >> 23) & 1) 833 setFeature(FEATURE_MMX); 834 if ((EDX >> 25) & 1) 835 setFeature(FEATURE_SSE); 836 if ((EDX >> 26) & 1) 837 setFeature(FEATURE_SSE2); 838 839 if ((ECX >> 0) & 1) 840 setFeature(FEATURE_SSE3); 841 if ((ECX >> 1) & 1) 842 setFeature(FEATURE_PCLMUL); 843 if ((ECX >> 9) & 1) 844 setFeature(FEATURE_SSSE3); 845 if ((ECX >> 12) & 1) 846 setFeature(FEATURE_FMA); 847 if ((ECX >> 13) & 1) 848 setFeature(FEATURE_CMPXCHG16B); 849 if ((ECX >> 19) & 1) 850 setFeature(FEATURE_SSE4_1); 851 if ((ECX >> 20) & 1) 852 setFeature(FEATURE_SSE4_2); 853 if ((ECX >> 22) & 1) 854 setFeature(FEATURE_MOVBE); 855 if ((ECX >> 23) & 1) 856 setFeature(FEATURE_POPCNT); 857 if ((ECX >> 25) & 1) 858 setFeature(FEATURE_AES); 859 if ((ECX >> 29) & 1) 860 setFeature(FEATURE_F16C); 861 if ((ECX >> 30) & 1) 862 setFeature(FEATURE_RDRND); 863 864 // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV 865 // indicates that the AVX registers will be saved and restored on context 866 // switch, then we have full AVX support. 867 const unsigned AVXBits = (1 << 27) | (1 << 28); 868 bool HasAVXSave = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && 869 ((EAX & 0x6) == 0x6); 870 #if defined(__APPLE__) 871 // Darwin lazily saves the AVX512 context on first use: trust that the OS will 872 // save the AVX512 context if we use AVX512 instructions, even the bit is not 873 // set right now. 874 bool HasAVX512Save = true; 875 #else 876 // AVX512 requires additional context to be saved by the OS. 877 bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0); 878 #endif 879 // AMX requires additional context to be saved by the OS. 880 const unsigned AMXBits = (1 << 17) | (1 << 18); 881 bool HasXSave = ((ECX >> 27) & 1) && !getX86XCR0(&EAX, &EDX); 882 bool HasAMXSave = HasXSave && ((EAX & AMXBits) == AMXBits); 883 884 if (HasAVXSave) 885 setFeature(FEATURE_AVX); 886 887 if (((ECX >> 26) & 1) && HasAVXSave) 888 setFeature(FEATURE_XSAVE); 889 890 bool HasLeaf7 = 891 MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); 892 893 if (HasLeaf7 && ((EBX >> 0) & 1)) 894 setFeature(FEATURE_FSGSBASE); 895 if (HasLeaf7 && ((EBX >> 2) & 1)) 896 setFeature(FEATURE_SGX); 897 if (HasLeaf7 && ((EBX >> 3) & 1)) 898 setFeature(FEATURE_BMI); 899 if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave) 900 setFeature(FEATURE_AVX2); 901 if (HasLeaf7 && ((EBX >> 8) & 1)) 902 setFeature(FEATURE_BMI2); 903 if (HasLeaf7 && ((EBX >> 11) & 1)) 904 setFeature(FEATURE_RTM); 905 if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) 906 setFeature(FEATURE_AVX512F); 907 if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) 908 setFeature(FEATURE_AVX512DQ); 909 if (HasLeaf7 && ((EBX >> 18) & 1)) 910 setFeature(FEATURE_RDSEED); 911 if (HasLeaf7 && ((EBX >> 19) & 1)) 912 setFeature(FEATURE_ADX); 913 if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) 914 setFeature(FEATURE_AVX512IFMA); 915 if (HasLeaf7 && ((EBX >> 24) & 1)) 916 setFeature(FEATURE_CLWB); 917 if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) 918 setFeature(FEATURE_AVX512PF); 919 if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) 920 setFeature(FEATURE_AVX512ER); 921 if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) 922 setFeature(FEATURE_AVX512CD); 923 if (HasLeaf7 && ((EBX >> 29) & 1)) 924 setFeature(FEATURE_SHA); 925 if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) 926 setFeature(FEATURE_AVX512BW); 927 if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) 928 setFeature(FEATURE_AVX512VL); 929 930 if (HasLeaf7 && ((ECX >> 0) & 1)) 931 setFeature(FEATURE_PREFETCHWT1); 932 if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) 933 setFeature(FEATURE_AVX512VBMI); 934 if (HasLeaf7 && ((ECX >> 4) & 1)) 935 setFeature(FEATURE_PKU); 936 if (HasLeaf7 && ((ECX >> 5) & 1)) 937 setFeature(FEATURE_WAITPKG); 938 if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save) 939 setFeature(FEATURE_AVX512VBMI2); 940 if (HasLeaf7 && ((ECX >> 7) & 1)) 941 setFeature(FEATURE_SHSTK); 942 if (HasLeaf7 && ((ECX >> 8) & 1)) 943 setFeature(FEATURE_GFNI); 944 if (HasLeaf7 && ((ECX >> 9) & 1) && HasAVXSave) 945 setFeature(FEATURE_VAES); 946 if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVXSave) 947 setFeature(FEATURE_VPCLMULQDQ); 948 if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save) 949 setFeature(FEATURE_AVX512VNNI); 950 if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save) 951 setFeature(FEATURE_AVX512BITALG); 952 if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) 953 setFeature(FEATURE_AVX512VPOPCNTDQ); 954 if (HasLeaf7 && ((ECX >> 22) & 1)) 955 setFeature(FEATURE_RDPID); 956 if (HasLeaf7 && ((ECX >> 23) & 1)) 957 setFeature(FEATURE_KL); 958 if (HasLeaf7 && ((ECX >> 25) & 1)) 959 setFeature(FEATURE_CLDEMOTE); 960 if (HasLeaf7 && ((ECX >> 27) & 1)) 961 setFeature(FEATURE_MOVDIRI); 962 if (HasLeaf7 && ((ECX >> 28) & 1)) 963 setFeature(FEATURE_MOVDIR64B); 964 if (HasLeaf7 && ((ECX >> 29) & 1)) 965 setFeature(FEATURE_ENQCMD); 966 967 if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) 968 setFeature(FEATURE_AVX5124VNNIW); 969 if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) 970 setFeature(FEATURE_AVX5124FMAPS); 971 if (HasLeaf7 && ((EDX >> 5) & 1)) 972 setFeature(FEATURE_UINTR); 973 if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save) 974 setFeature(FEATURE_AVX512VP2INTERSECT); 975 if (HasLeaf7 && ((EDX >> 14) & 1)) 976 setFeature(FEATURE_SERIALIZE); 977 if (HasLeaf7 && ((EDX >> 16) & 1)) 978 setFeature(FEATURE_TSXLDTRK); 979 if (HasLeaf7 && ((EDX >> 18) & 1)) 980 setFeature(FEATURE_PCONFIG); 981 if (HasLeaf7 && ((EDX >> 22) & 1) && HasAMXSave) 982 setFeature(FEATURE_AMX_BF16); 983 if (HasLeaf7 && ((EDX >> 23) & 1) && HasAVX512Save) 984 setFeature(FEATURE_AVX512FP16); 985 if (HasLeaf7 && ((EDX >> 24) & 1) && HasAMXSave) 986 setFeature(FEATURE_AMX_TILE); 987 if (HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave) 988 setFeature(FEATURE_AMX_INT8); 989 990 // EAX from subleaf 0 is the maximum subleaf supported. Some CPUs don't 991 // return all 0s for invalid subleaves so check the limit. 992 bool HasLeaf7Subleaf1 = 993 HasLeaf7 && EAX >= 1 && 994 !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); 995 if (HasLeaf7Subleaf1 && ((EAX >> 0) & 1)) 996 setFeature(FEATURE_SHA512); 997 if (HasLeaf7Subleaf1 && ((EAX >> 1) & 1)) 998 setFeature(FEATURE_SM3); 999 if (HasLeaf7Subleaf1 && ((EAX >> 2) & 1)) 1000 setFeature(FEATURE_SM4); 1001 if (HasLeaf7Subleaf1 && ((EAX >> 3) & 1)) 1002 setFeature(FEATURE_RAOINT); 1003 if (HasLeaf7Subleaf1 && ((EAX >> 4) & 1) && HasAVXSave) 1004 setFeature(FEATURE_AVXVNNI); 1005 if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save) 1006 setFeature(FEATURE_AVX512BF16); 1007 if (HasLeaf7Subleaf1 && ((EAX >> 7) & 1)) 1008 setFeature(FEATURE_CMPCCXADD); 1009 if (HasLeaf7Subleaf1 && ((EAX >> 21) & 1) && HasAMXSave) 1010 setFeature(FEATURE_AMX_FP16); 1011 if (HasLeaf7Subleaf1 && ((EAX >> 22) & 1)) 1012 setFeature(FEATURE_HRESET); 1013 if (HasLeaf7Subleaf1 && ((EAX >> 23) & 1) && HasAVXSave) 1014 setFeature(FEATURE_AVXIFMA); 1015 if (HasLeaf7Subleaf1 && ((EAX >> 31) & 1)) 1016 setFeature(FEATURE_MOVRS); 1017 1018 if (HasLeaf7Subleaf1 && ((EDX >> 4) & 1) && HasAVXSave) 1019 setFeature(FEATURE_AVXVNNIINT8); 1020 if (HasLeaf7Subleaf1 && ((EDX >> 5) & 1) && HasAVXSave) 1021 setFeature(FEATURE_AVXNECONVERT); 1022 if (HasLeaf7Subleaf1 && ((EDX >> 8) & 1) && HasAMXSave) 1023 setFeature(FEATURE_AMX_COMPLEX); 1024 if (HasLeaf7Subleaf1 && ((EDX >> 10) & 1) && HasAVXSave) 1025 setFeature(FEATURE_AVXVNNIINT16); 1026 if (HasLeaf7Subleaf1 && ((EDX >> 14) & 1)) 1027 setFeature(FEATURE_PREFETCHI); 1028 if (HasLeaf7Subleaf1 && ((EDX >> 15) & 1)) 1029 setFeature(FEATURE_USERMSR); 1030 if (HasLeaf7Subleaf1 && ((EDX >> 21) & 1)) 1031 setFeature(FEATURE_APXF); 1032 1033 unsigned MaxLevel = 0; 1034 getX86CpuIDAndInfo(0, &MaxLevel, &EBX, &ECX, &EDX); 1035 bool HasLeafD = MaxLevel >= 0xd && 1036 !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); 1037 if (HasLeafD && ((EAX >> 0) & 1) && HasAVXSave) 1038 setFeature(FEATURE_XSAVEOPT); 1039 if (HasLeafD && ((EAX >> 1) & 1) && HasAVXSave) 1040 setFeature(FEATURE_XSAVEC); 1041 if (HasLeafD && ((EAX >> 3) & 1) && HasAVXSave) 1042 setFeature(FEATURE_XSAVES); 1043 1044 bool HasLeaf24 = 1045 MaxLevel >= 0x24 && !getX86CpuIDAndInfo(0x24, &EAX, &EBX, &ECX, &EDX); 1046 if (HasLeaf7Subleaf1 && ((EDX >> 19) & 1) && HasLeaf24) { 1047 bool Has512Len = (EBX >> 18) & 1; 1048 int AVX10Ver = EBX & 0xff; 1049 if (AVX10Ver >= 2) { 1050 setFeature(FEATURE_AVX10_2_256); 1051 if (Has512Len) 1052 setFeature(FEATURE_AVX10_2_512); 1053 } 1054 if (AVX10Ver >= 1) { 1055 setFeature(FEATURE_AVX10_1_256); 1056 if (Has512Len) 1057 setFeature(FEATURE_AVX10_1_512); 1058 } 1059 } 1060 1061 unsigned MaxExtLevel = 0; 1062 getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); 1063 1064 bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && 1065 !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); 1066 if (HasExtLeaf1) { 1067 if (ECX & 1) 1068 setFeature(FEATURE_LAHF_LM); 1069 if ((ECX >> 5) & 1) 1070 setFeature(FEATURE_LZCNT); 1071 if (((ECX >> 6) & 1)) 1072 setFeature(FEATURE_SSE4_A); 1073 if (((ECX >> 8) & 1)) 1074 setFeature(FEATURE_PRFCHW); 1075 if (((ECX >> 11) & 1)) 1076 setFeature(FEATURE_XOP); 1077 if (((ECX >> 15) & 1)) 1078 setFeature(FEATURE_LWP); 1079 if (((ECX >> 16) & 1)) 1080 setFeature(FEATURE_FMA4); 1081 if (((ECX >> 21) & 1)) 1082 setFeature(FEATURE_TBM); 1083 if (((ECX >> 29) & 1)) 1084 setFeature(FEATURE_MWAITX); 1085 1086 if (((EDX >> 29) & 1)) 1087 setFeature(FEATURE_LM); 1088 } 1089 1090 bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && 1091 !getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX); 1092 if (HasExtLeaf8 && ((EBX >> 0) & 1)) 1093 setFeature(FEATURE_CLZERO); 1094 if (HasExtLeaf8 && ((EBX >> 9) & 1)) 1095 setFeature(FEATURE_WBNOINVD); 1096 1097 bool HasLeaf14 = MaxLevel >= 0x14 && 1098 !getX86CpuIDAndInfoEx(0x14, 0x0, &EAX, &EBX, &ECX, &EDX); 1099 if (HasLeaf14 && ((EBX >> 4) & 1)) 1100 setFeature(FEATURE_PTWRITE); 1101 1102 bool HasLeaf19 = 1103 MaxLevel >= 0x19 && !getX86CpuIDAndInfo(0x19, &EAX, &EBX, &ECX, &EDX); 1104 if (HasLeaf7 && HasLeaf19 && ((EBX >> 2) & 1)) 1105 setFeature(FEATURE_WIDEKL); 1106 1107 if (hasFeature(FEATURE_LM) && hasFeature(FEATURE_SSE2)) { 1108 setFeature(FEATURE_X86_64_BASELINE); 1109 if (hasFeature(FEATURE_CMPXCHG16B) && hasFeature(FEATURE_POPCNT) && 1110 hasFeature(FEATURE_LAHF_LM) && hasFeature(FEATURE_SSE4_2)) { 1111 setFeature(FEATURE_X86_64_V2); 1112 if (hasFeature(FEATURE_AVX2) && hasFeature(FEATURE_BMI) && 1113 hasFeature(FEATURE_BMI2) && hasFeature(FEATURE_F16C) && 1114 hasFeature(FEATURE_FMA) && hasFeature(FEATURE_LZCNT) && 1115 hasFeature(FEATURE_MOVBE)) { 1116 setFeature(FEATURE_X86_64_V3); 1117 if (hasFeature(FEATURE_AVX512BW) && hasFeature(FEATURE_AVX512CD) && 1118 hasFeature(FEATURE_AVX512DQ) && hasFeature(FEATURE_AVX512VL)) 1119 setFeature(FEATURE_X86_64_V4); 1120 } 1121 } 1122 } 1123 1124 #undef hasFeature 1125 #undef setFeature 1126 } 1127 1128 #ifndef _WIN32 1129 __attribute__((visibility("hidden"))) 1130 #endif 1131 int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE; 1132 1133 #ifndef _WIN32 1134 __attribute__((visibility("hidden"))) 1135 #endif 1136 struct __processor_model { 1137 unsigned int __cpu_vendor; 1138 unsigned int __cpu_type; 1139 unsigned int __cpu_subtype; 1140 unsigned int __cpu_features[1]; 1141 } __cpu_model = {0, 0, 0, {0}}; 1142 1143 #ifndef _WIN32 1144 __attribute__((visibility("hidden"))) 1145 #endif 1146 unsigned __cpu_features2[(CPU_FEATURE_MAX - 1) / 32]; 1147 1148 // A constructor function that is sets __cpu_model and __cpu_features2 with 1149 // the right values. This needs to run only once. This constructor is 1150 // given the highest priority and it should run before constructors without 1151 // the priority set. However, it still runs after ifunc initializers and 1152 // needs to be called explicitly there. 1153 1154 int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { 1155 unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; 1156 unsigned MaxLeaf = 5; 1157 unsigned Vendor; 1158 unsigned Model, Family; 1159 unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0}; 1160 static_assert(sizeof(Features) / sizeof(Features[0]) == 4, ""); 1161 static_assert(sizeof(__cpu_features2) / sizeof(__cpu_features2[0]) == 3, ""); 1162 1163 // This function needs to run just once. 1164 if (__cpu_model.__cpu_vendor) 1165 return 0; 1166 1167 if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { 1168 __cpu_model.__cpu_vendor = VENDOR_OTHER; 1169 return -1; 1170 } 1171 1172 getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); 1173 detectX86FamilyModel(EAX, &Family, &Model); 1174 1175 // Find available features. 1176 getAvailableFeatures(ECX, EDX, MaxLeaf, &Features[0]); 1177 1178 __cpu_model.__cpu_features[0] = Features[0]; 1179 __cpu_features2[0] = Features[1]; 1180 __cpu_features2[1] = Features[2]; 1181 __cpu_features2[2] = Features[3]; 1182 1183 if (Vendor == SIG_INTEL) { 1184 // Get CPU type. 1185 getIntelProcessorTypeAndSubtype(Family, Model, &Features[0], 1186 &(__cpu_model.__cpu_type), 1187 &(__cpu_model.__cpu_subtype)); 1188 __cpu_model.__cpu_vendor = VENDOR_INTEL; 1189 } else if (Vendor == SIG_AMD) { 1190 // Get CPU type. 1191 getAMDProcessorTypeAndSubtype(Family, Model, &Features[0], 1192 &(__cpu_model.__cpu_type), 1193 &(__cpu_model.__cpu_subtype)); 1194 __cpu_model.__cpu_vendor = VENDOR_AMD; 1195 } else 1196 __cpu_model.__cpu_vendor = VENDOR_OTHER; 1197 1198 assert(__cpu_model.__cpu_vendor < VENDOR_MAX); 1199 assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); 1200 assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); 1201 1202 return 0; 1203 } 1204 #endif // defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) 1205