1//===-- cpu_model.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 only. 12// 13//===----------------------------------------------------------------------===// 14 15#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \ 16 defined(_M_X64)) && \ 17 (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)) 18 19#include <assert.h> 20 21#define bool int 22#define true 1 23#define false 0 24 25#ifdef _MSC_VER 26#include <intrin.h> 27#endif 28 29#ifndef __has_attribute 30#define __has_attribute(attr) 0 31#endif 32 33enum VendorSignatures { 34 SIG_INTEL = 0x756e6547, // Genu 35 SIG_AMD = 0x68747541, // Auth 36}; 37 38enum ProcessorVendors { 39 VENDOR_INTEL = 1, 40 VENDOR_AMD, 41 VENDOR_OTHER, 42 VENDOR_MAX 43}; 44 45enum ProcessorTypes { 46 INTEL_BONNELL = 1, 47 INTEL_CORE2, 48 INTEL_COREI7, 49 AMDFAM10H, 50 AMDFAM15H, 51 INTEL_SILVERMONT, 52 INTEL_KNL, 53 AMD_BTVER1, 54 AMD_BTVER2, 55 AMDFAM17H, 56 INTEL_KNM, 57 INTEL_GOLDMONT, 58 INTEL_GOLDMONT_PLUS, 59 INTEL_TREMONT, 60 CPU_TYPE_MAX 61}; 62 63enum ProcessorSubtypes { 64 INTEL_COREI7_NEHALEM = 1, 65 INTEL_COREI7_WESTMERE, 66 INTEL_COREI7_SANDYBRIDGE, 67 AMDFAM10H_BARCELONA, 68 AMDFAM10H_SHANGHAI, 69 AMDFAM10H_ISTANBUL, 70 AMDFAM15H_BDVER1, 71 AMDFAM15H_BDVER2, 72 AMDFAM15H_BDVER3, 73 AMDFAM15H_BDVER4, 74 AMDFAM17H_ZNVER1, 75 INTEL_COREI7_IVYBRIDGE, 76 INTEL_COREI7_HASWELL, 77 INTEL_COREI7_BROADWELL, 78 INTEL_COREI7_SKYLAKE, 79 INTEL_COREI7_SKYLAKE_AVX512, 80 INTEL_COREI7_CANNONLAKE, 81 INTEL_COREI7_ICELAKE_CLIENT, 82 INTEL_COREI7_ICELAKE_SERVER, 83 AMDFAM17H_ZNVER2, 84 INTEL_COREI7_CASCADELAKE, 85 CPU_SUBTYPE_MAX 86}; 87 88enum ProcessorFeatures { 89 FEATURE_CMOV = 0, 90 FEATURE_MMX, 91 FEATURE_POPCNT, 92 FEATURE_SSE, 93 FEATURE_SSE2, 94 FEATURE_SSE3, 95 FEATURE_SSSE3, 96 FEATURE_SSE4_1, 97 FEATURE_SSE4_2, 98 FEATURE_AVX, 99 FEATURE_AVX2, 100 FEATURE_SSE4_A, 101 FEATURE_FMA4, 102 FEATURE_XOP, 103 FEATURE_FMA, 104 FEATURE_AVX512F, 105 FEATURE_BMI, 106 FEATURE_BMI2, 107 FEATURE_AES, 108 FEATURE_PCLMUL, 109 FEATURE_AVX512VL, 110 FEATURE_AVX512BW, 111 FEATURE_AVX512DQ, 112 FEATURE_AVX512CD, 113 FEATURE_AVX512ER, 114 FEATURE_AVX512PF, 115 FEATURE_AVX512VBMI, 116 FEATURE_AVX512IFMA, 117 FEATURE_AVX5124VNNIW, 118 FEATURE_AVX5124FMAPS, 119 FEATURE_AVX512VPOPCNTDQ, 120 FEATURE_AVX512VBMI2, 121 FEATURE_GFNI, 122 FEATURE_VPCLMULQDQ, 123 FEATURE_AVX512VNNI, 124 FEATURE_AVX512BITALG 125}; 126 127// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max). 128// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID 129// support. Consequently, for i386, the presence of CPUID is checked first 130// via the corresponding eflags bit. 131static bool isCpuIdSupported() { 132#if defined(__GNUC__) || defined(__clang__) 133#if defined(__i386__) 134 int __cpuid_supported; 135 __asm__(" pushfl\n" 136 " popl %%eax\n" 137 " movl %%eax,%%ecx\n" 138 " xorl $0x00200000,%%eax\n" 139 " pushl %%eax\n" 140 " popfl\n" 141 " pushfl\n" 142 " popl %%eax\n" 143 " movl $0,%0\n" 144 " cmpl %%eax,%%ecx\n" 145 " je 1f\n" 146 " movl $1,%0\n" 147 "1:" 148 : "=r"(__cpuid_supported) 149 : 150 : "eax", "ecx"); 151 if (!__cpuid_supported) 152 return false; 153#endif 154 return true; 155#endif 156 return true; 157} 158 159// This code is copied from lib/Support/Host.cpp. 160// Changes to either file should be mirrored in the other. 161 162/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in 163/// the specified arguments. If we can't run cpuid on the host, return true. 164static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, 165 unsigned *rECX, unsigned *rEDX) { 166#if defined(__GNUC__) || defined(__clang__) 167#if defined(__x86_64__) 168 // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 169 // FIXME: should we save this for Clang? 170 __asm__("movq\t%%rbx, %%rsi\n\t" 171 "cpuid\n\t" 172 "xchgq\t%%rbx, %%rsi\n\t" 173 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 174 : "a"(value)); 175 return false; 176#elif defined(__i386__) 177 __asm__("movl\t%%ebx, %%esi\n\t" 178 "cpuid\n\t" 179 "xchgl\t%%ebx, %%esi\n\t" 180 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 181 : "a"(value)); 182 return false; 183#else 184 return true; 185#endif 186#elif defined(_MSC_VER) 187 // The MSVC intrinsic is portable across x86 and x64. 188 int registers[4]; 189 __cpuid(registers, value); 190 *rEAX = registers[0]; 191 *rEBX = registers[1]; 192 *rECX = registers[2]; 193 *rEDX = registers[3]; 194 return false; 195#else 196 return true; 197#endif 198} 199 200/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return 201/// the 4 values in the specified arguments. If we can't run cpuid on the host, 202/// return true. 203static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, 204 unsigned *rEAX, unsigned *rEBX, unsigned *rECX, 205 unsigned *rEDX) { 206#if defined(__GNUC__) || defined(__clang__) 207#if defined(__x86_64__) 208 // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. 209 // FIXME: should we save this for Clang? 210 __asm__("movq\t%%rbx, %%rsi\n\t" 211 "cpuid\n\t" 212 "xchgq\t%%rbx, %%rsi\n\t" 213 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 214 : "a"(value), "c"(subleaf)); 215 return false; 216#elif defined(__i386__) 217 __asm__("movl\t%%ebx, %%esi\n\t" 218 "cpuid\n\t" 219 "xchgl\t%%ebx, %%esi\n\t" 220 : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) 221 : "a"(value), "c"(subleaf)); 222 return false; 223#else 224 return true; 225#endif 226#elif defined(_MSC_VER) 227 int registers[4]; 228 __cpuidex(registers, value, subleaf); 229 *rEAX = registers[0]; 230 *rEBX = registers[1]; 231 *rECX = registers[2]; 232 *rEDX = registers[3]; 233 return false; 234#else 235 return true; 236#endif 237} 238 239// Read control register 0 (XCR0). Used to detect features such as AVX. 240static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { 241#if defined(__GNUC__) || defined(__clang__) 242 // Check xgetbv; this uses a .byte sequence instead of the instruction 243 // directly because older assemblers do not include support for xgetbv and 244 // there is no easy way to conditionally compile based on the assembler used. 245 __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0)); 246 return false; 247#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) 248 unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); 249 *rEAX = Result; 250 *rEDX = Result >> 32; 251 return false; 252#else 253 return true; 254#endif 255} 256 257static void detectX86FamilyModel(unsigned EAX, unsigned *Family, 258 unsigned *Model) { 259 *Family = (EAX >> 8) & 0xf; // Bits 8 - 11 260 *Model = (EAX >> 4) & 0xf; // Bits 4 - 7 261 if (*Family == 6 || *Family == 0xf) { 262 if (*Family == 0xf) 263 // Examine extended family ID if family ID is F. 264 *Family += (EAX >> 20) & 0xff; // Bits 20 - 27 265 // Examine extended model ID if family ID is 6 or F. 266 *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 267 } 268} 269 270static void getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, 271 unsigned Brand_id, 272 unsigned Features, 273 unsigned Features2, unsigned *Type, 274 unsigned *Subtype) { 275 if (Brand_id != 0) 276 return; 277 switch (Family) { 278 case 6: 279 switch (Model) { 280 case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile 281 // processor, Intel Core 2 Quad processor, Intel Core 2 Quad 282 // mobile processor, Intel Core 2 Extreme processor, Intel 283 // Pentium Dual-Core processor, Intel Xeon processor, model 284 // 0Fh. All processors are manufactured using the 65 nm process. 285 case 0x16: // Intel Celeron processor model 16h. All processors are 286 // manufactured using the 65 nm process 287 case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model 288 // 17h. All processors are manufactured using the 45 nm process. 289 // 290 // 45nm: Penryn , Wolfdale, Yorkfield (XE) 291 case 0x1d: // Intel Xeon processor MP. All processors are manufactured using 292 // the 45 nm process. 293 *Type = INTEL_CORE2; // "penryn" 294 break; 295 case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All 296 // processors are manufactured using the 45 nm process. 297 case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. 298 // As found in a Summer 2010 model iMac. 299 case 0x1f: 300 case 0x2e: // Nehalem EX 301 *Type = INTEL_COREI7; // "nehalem" 302 *Subtype = INTEL_COREI7_NEHALEM; 303 break; 304 case 0x25: // Intel Core i7, laptop version. 305 case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All 306 // processors are manufactured using the 32 nm process. 307 case 0x2f: // Westmere EX 308 *Type = INTEL_COREI7; // "westmere" 309 *Subtype = INTEL_COREI7_WESTMERE; 310 break; 311 case 0x2a: // Intel Core i7 processor. All processors are manufactured 312 // using the 32 nm process. 313 case 0x2d: 314 *Type = INTEL_COREI7; //"sandybridge" 315 *Subtype = INTEL_COREI7_SANDYBRIDGE; 316 break; 317 case 0x3a: 318 case 0x3e: // Ivy Bridge EP 319 *Type = INTEL_COREI7; // "ivybridge" 320 *Subtype = INTEL_COREI7_IVYBRIDGE; 321 break; 322 323 // Haswell: 324 case 0x3c: 325 case 0x3f: 326 case 0x45: 327 case 0x46: 328 *Type = INTEL_COREI7; // "haswell" 329 *Subtype = INTEL_COREI7_HASWELL; 330 break; 331 332 // Broadwell: 333 case 0x3d: 334 case 0x47: 335 case 0x4f: 336 case 0x56: 337 *Type = INTEL_COREI7; // "broadwell" 338 *Subtype = INTEL_COREI7_BROADWELL; 339 break; 340 341 // Skylake: 342 case 0x4e: // Skylake mobile 343 case 0x5e: // Skylake desktop 344 case 0x8e: // Kaby Lake mobile 345 case 0x9e: // Kaby Lake desktop 346 *Type = INTEL_COREI7; // "skylake" 347 *Subtype = INTEL_COREI7_SKYLAKE; 348 break; 349 350 // Skylake Xeon: 351 case 0x55: 352 *Type = INTEL_COREI7; 353 if (Features2 & (1 << (FEATURE_AVX512VNNI - 32))) 354 *Subtype = INTEL_COREI7_CASCADELAKE; // "cascadelake" 355 else 356 *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" 357 break; 358 359 // Cannonlake: 360 case 0x66: 361 *Type = INTEL_COREI7; 362 *Subtype = INTEL_COREI7_CANNONLAKE; // "cannonlake" 363 break; 364 365 // Icelake: 366 case 0x7d: 367 case 0x7e: 368 *Type = INTEL_COREI7; 369 *Subtype = INTEL_COREI7_ICELAKE_CLIENT; // "icelake-client" 370 break; 371 372 // Icelake Xeon: 373 case 0x6a: 374 case 0x6c: 375 *Type = INTEL_COREI7; 376 *Subtype = INTEL_COREI7_ICELAKE_SERVER; // "icelake-server" 377 break; 378 379 case 0x1c: // Most 45 nm Intel Atom processors 380 case 0x26: // 45 nm Atom Lincroft 381 case 0x27: // 32 nm Atom Medfield 382 case 0x35: // 32 nm Atom Midview 383 case 0x36: // 32 nm Atom Midview 384 *Type = INTEL_BONNELL; 385 break; // "bonnell" 386 387 // Atom Silvermont codes from the Intel software optimization guide. 388 case 0x37: 389 case 0x4a: 390 case 0x4d: 391 case 0x5a: 392 case 0x5d: 393 case 0x4c: // really airmont 394 *Type = INTEL_SILVERMONT; 395 break; // "silvermont" 396 // Goldmont: 397 case 0x5c: // Apollo Lake 398 case 0x5f: // Denverton 399 *Type = INTEL_GOLDMONT; 400 break; // "goldmont" 401 case 0x7a: 402 *Type = INTEL_GOLDMONT_PLUS; 403 break; 404 case 0x86: 405 *Type = INTEL_TREMONT; 406 break; 407 408 case 0x57: 409 *Type = INTEL_KNL; // knl 410 break; 411 412 case 0x85: 413 *Type = INTEL_KNM; // knm 414 break; 415 416 default: // Unknown family 6 CPU. 417 break; 418 break; 419 } 420 default: 421 break; // Unknown. 422 } 423} 424 425static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, 426 unsigned Features, unsigned Features2, 427 unsigned *Type, unsigned *Subtype) { 428 // FIXME: this poorly matches the generated SubtargetFeatureKV table. There 429 // appears to be no way to generate the wide variety of AMD-specific targets 430 // from the information returned from CPUID. 431 switch (Family) { 432 case 16: 433 *Type = AMDFAM10H; // "amdfam10" 434 switch (Model) { 435 case 2: 436 *Subtype = AMDFAM10H_BARCELONA; 437 break; 438 case 4: 439 *Subtype = AMDFAM10H_SHANGHAI; 440 break; 441 case 8: 442 *Subtype = AMDFAM10H_ISTANBUL; 443 break; 444 } 445 break; 446 case 20: 447 *Type = AMD_BTVER1; 448 break; // "btver1"; 449 case 21: 450 *Type = AMDFAM15H; 451 if (Model >= 0x60 && Model <= 0x7f) { 452 *Subtype = AMDFAM15H_BDVER4; 453 break; // "bdver4"; 60h-7Fh: Excavator 454 } 455 if (Model >= 0x30 && Model <= 0x3f) { 456 *Subtype = AMDFAM15H_BDVER3; 457 break; // "bdver3"; 30h-3Fh: Steamroller 458 } 459 if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) { 460 *Subtype = AMDFAM15H_BDVER2; 461 break; // "bdver2"; 02h, 10h-1Fh: Piledriver 462 } 463 if (Model <= 0x0f) { 464 *Subtype = AMDFAM15H_BDVER1; 465 break; // "bdver1"; 00h-0Fh: Bulldozer 466 } 467 break; 468 case 22: 469 *Type = AMD_BTVER2; 470 break; // "btver2" 471 case 23: 472 *Type = AMDFAM17H; 473 if (Model >= 0x30 && Model <= 0x3f) { 474 *Subtype = AMDFAM17H_ZNVER2; 475 break; // "znver2"; 30h-3fh: Zen2 476 } 477 if (Model <= 0x0f) { 478 *Subtype = AMDFAM17H_ZNVER1; 479 break; // "znver1"; 00h-0Fh: Zen1 480 } 481 break; 482 default: 483 break; // "generic" 484 } 485} 486 487static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, 488 unsigned *FeaturesOut, 489 unsigned *Features2Out) { 490 unsigned Features = 0; 491 unsigned Features2 = 0; 492 unsigned EAX, EBX; 493 494#define setFeature(F) \ 495 do { \ 496 if (F < 32) \ 497 Features |= 1U << (F & 0x1f); \ 498 else if (F < 64) \ 499 Features2 |= 1U << ((F - 32) & 0x1f); \ 500 } while (0) 501 502 if ((EDX >> 15) & 1) 503 setFeature(FEATURE_CMOV); 504 if ((EDX >> 23) & 1) 505 setFeature(FEATURE_MMX); 506 if ((EDX >> 25) & 1) 507 setFeature(FEATURE_SSE); 508 if ((EDX >> 26) & 1) 509 setFeature(FEATURE_SSE2); 510 511 if ((ECX >> 0) & 1) 512 setFeature(FEATURE_SSE3); 513 if ((ECX >> 1) & 1) 514 setFeature(FEATURE_PCLMUL); 515 if ((ECX >> 9) & 1) 516 setFeature(FEATURE_SSSE3); 517 if ((ECX >> 12) & 1) 518 setFeature(FEATURE_FMA); 519 if ((ECX >> 19) & 1) 520 setFeature(FEATURE_SSE4_1); 521 if ((ECX >> 20) & 1) 522 setFeature(FEATURE_SSE4_2); 523 if ((ECX >> 23) & 1) 524 setFeature(FEATURE_POPCNT); 525 if ((ECX >> 25) & 1) 526 setFeature(FEATURE_AES); 527 528 // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV 529 // indicates that the AVX registers will be saved and restored on context 530 // switch, then we have full AVX support. 531 const unsigned AVXBits = (1 << 27) | (1 << 28); 532 bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && 533 ((EAX & 0x6) == 0x6); 534 bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); 535 536 if (HasAVX) 537 setFeature(FEATURE_AVX); 538 539 bool HasLeaf7 = 540 MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); 541 542 if (HasLeaf7 && ((EBX >> 3) & 1)) 543 setFeature(FEATURE_BMI); 544 if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) 545 setFeature(FEATURE_AVX2); 546 if (HasLeaf7 && ((EBX >> 8) & 1)) 547 setFeature(FEATURE_BMI2); 548 if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) 549 setFeature(FEATURE_AVX512F); 550 if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) 551 setFeature(FEATURE_AVX512DQ); 552 if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) 553 setFeature(FEATURE_AVX512IFMA); 554 if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) 555 setFeature(FEATURE_AVX512PF); 556 if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) 557 setFeature(FEATURE_AVX512ER); 558 if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) 559 setFeature(FEATURE_AVX512CD); 560 if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) 561 setFeature(FEATURE_AVX512BW); 562 if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) 563 setFeature(FEATURE_AVX512VL); 564 565 if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) 566 setFeature(FEATURE_AVX512VBMI); 567 if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save) 568 setFeature(FEATURE_AVX512VBMI2); 569 if (HasLeaf7 && ((ECX >> 8) & 1)) 570 setFeature(FEATURE_GFNI); 571 if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX) 572 setFeature(FEATURE_VPCLMULQDQ); 573 if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save) 574 setFeature(FEATURE_AVX512VNNI); 575 if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save) 576 setFeature(FEATURE_AVX512BITALG); 577 if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) 578 setFeature(FEATURE_AVX512VPOPCNTDQ); 579 580 if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) 581 setFeature(FEATURE_AVX5124VNNIW); 582 if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) 583 setFeature(FEATURE_AVX5124FMAPS); 584 585 unsigned MaxExtLevel; 586 getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); 587 588 bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && 589 !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); 590 if (HasExtLeaf1 && ((ECX >> 6) & 1)) 591 setFeature(FEATURE_SSE4_A); 592 if (HasExtLeaf1 && ((ECX >> 11) & 1)) 593 setFeature(FEATURE_XOP); 594 if (HasExtLeaf1 && ((ECX >> 16) & 1)) 595 setFeature(FEATURE_FMA4); 596 597 *FeaturesOut = Features; 598 *Features2Out = Features2; 599#undef setFeature 600} 601 602#if defined(HAVE_INIT_PRIORITY) 603#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__ 101)) 604#elif __has_attribute(__constructor__) 605#define CONSTRUCTOR_ATTRIBUTE __attribute__((__constructor__)) 606#else 607// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that 608// this runs during initialization. 609#define CONSTRUCTOR_ATTRIBUTE 610#endif 611 612#ifndef _WIN32 613__attribute__((visibility("hidden"))) 614#endif 615int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE; 616 617#ifndef _WIN32 618__attribute__((visibility("hidden"))) 619#endif 620struct __processor_model { 621 unsigned int __cpu_vendor; 622 unsigned int __cpu_type; 623 unsigned int __cpu_subtype; 624 unsigned int __cpu_features[1]; 625} __cpu_model = {0, 0, 0, {0}}; 626 627#ifndef _WIN32 628__attribute__((visibility("hidden"))) 629#endif 630unsigned int __cpu_features2; 631 632// A constructor function that is sets __cpu_model and __cpu_features2 with 633// the right values. This needs to run only once. This constructor is 634// given the highest priority and it should run before constructors without 635// the priority set. However, it still runs after ifunc initializers and 636// needs to be called explicitly there. 637 638int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) { 639 unsigned EAX, EBX, ECX, EDX; 640 unsigned MaxLeaf = 5; 641 unsigned Vendor; 642 unsigned Model, Family, Brand_id; 643 unsigned Features = 0; 644 unsigned Features2 = 0; 645 646 // This function needs to run just once. 647 if (__cpu_model.__cpu_vendor) 648 return 0; 649 650 if (!isCpuIdSupported()) 651 return -1; 652 653 // Assume cpuid insn present. Run in level 0 to get vendor id. 654 if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) { 655 __cpu_model.__cpu_vendor = VENDOR_OTHER; 656 return -1; 657 } 658 getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); 659 detectX86FamilyModel(EAX, &Family, &Model); 660 Brand_id = EBX & 0xff; 661 662 // Find available features. 663 getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2); 664 __cpu_model.__cpu_features[0] = Features; 665 __cpu_features2 = Features2; 666 667 if (Vendor == SIG_INTEL) { 668 // Get CPU type. 669 getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, 670 Features2, &(__cpu_model.__cpu_type), 671 &(__cpu_model.__cpu_subtype)); 672 __cpu_model.__cpu_vendor = VENDOR_INTEL; 673 } else if (Vendor == SIG_AMD) { 674 // Get CPU type. 675 getAMDProcessorTypeAndSubtype(Family, Model, Features, Features2, 676 &(__cpu_model.__cpu_type), 677 &(__cpu_model.__cpu_subtype)); 678 __cpu_model.__cpu_vendor = VENDOR_AMD; 679 } else 680 __cpu_model.__cpu_vendor = VENDOR_OTHER; 681 682 assert(__cpu_model.__cpu_vendor < VENDOR_MAX); 683 assert(__cpu_model.__cpu_type < CPU_TYPE_MAX); 684 assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); 685 686 return 0; 687} 688 689#endif 690