| 
11 | 11 | //===----------------------------------------------------------------------===//  | 
12 | 12 | 
 
  | 
13 | 13 | #include "llvm/TargetParser/Host.h"  | 
 | 14 | +#include "llvm/ADT/STLFunctionalExtras.h"  | 
14 | 15 | #include "llvm/ADT/SmallVector.h"  | 
 | 16 | +#include "llvm/ADT/StringExtras.h"  | 
15 | 17 | #include "llvm/ADT/StringMap.h"  | 
16 | 18 | #include "llvm/ADT/StringRef.h"  | 
17 | 19 | #include "llvm/ADT/StringSwitch.h"  | 
@@ -167,35 +169,10 @@ StringRef sys::detail::getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent) {  | 
167 | 169 |       .Default(generic);  | 
168 | 170 | }  | 
169 | 171 | 
 
  | 
170 |  | -StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {  | 
171 |  | -  // The cpuid register on arm is not accessible from user space. On Linux,  | 
172 |  | -  // it is exposed through the /proc/cpuinfo file.  | 
173 |  | - | 
174 |  | -  // Read 32 lines from /proc/cpuinfo, which should contain the CPU part line  | 
175 |  | -  // in all cases.  | 
176 |  | -  SmallVector<StringRef, 32> Lines;  | 
177 |  | -  ProcCpuinfoContent.split(Lines, '\n');  | 
178 |  | - | 
179 |  | -  // Look for the CPU implementer and hardware lines, and store the CPU part  | 
180 |  | -  // numbers found.  | 
181 |  | -  StringRef Implementer;  | 
182 |  | -  StringRef Hardware;  | 
183 |  | -  SmallVector<StringRef, 32> Parts;  | 
184 |  | -  for (StringRef Line : Lines) {  | 
185 |  | -    if (Line.consume_front("CPU implementer"))  | 
186 |  | -      Implementer = Line.ltrim("\t :");  | 
187 |  | -    else if (Line.consume_front("Hardware"))  | 
188 |  | -      Hardware = Line.ltrim("\t :");  | 
189 |  | -    else if (Line.consume_front("CPU part"))  | 
190 |  | -      Parts.emplace_back(Line.ltrim("\t :"));  | 
191 |  | -  }  | 
192 |  | - | 
193 |  | -  // Last `Part' seen, in case we don't analyse all `Parts' parsed.  | 
194 |  | -  StringRef Part = Parts.empty() ? StringRef() : Parts.back();  | 
195 |  | - | 
196 |  | -  // Remove duplicate `Parts'.  | 
197 |  | -  llvm::sort(Parts);  | 
198 |  | -  Parts.erase(llvm::unique(Parts), Parts.end());  | 
 | 172 | +StringRef  | 
 | 173 | +getHostCPUNameForARMFromComponents(StringRef Implementer, StringRef Hardware,  | 
 | 174 | +                                   StringRef Part, ArrayRef<StringRef> Parts,  | 
 | 175 | +                                   function_ref<unsigned()> GetVariant) {  | 
199 | 176 | 
 
  | 
200 | 177 |   auto MatchBigLittle = [](auto const &Parts, StringRef Big, StringRef Little) {  | 
201 | 178 |     if (Parts.size() == 2)  | 
@@ -343,21 +320,17 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {  | 
343 | 320 |   if (Implementer == "0x53") { // Samsung Electronics Co., Ltd.  | 
344 | 321 |     // The Exynos chips have a convoluted ID scheme that doesn't seem to follow  | 
345 | 322 |     // any predictive pattern across variants and parts.  | 
346 |  | -    unsigned Variant = 0, Part = 0;  | 
347 | 323 | 
 
  | 
348 | 324 |     // Look for the CPU variant line, whose value is a 1 digit hexadecimal  | 
349 | 325 |     // number, corresponding to the Variant bits in the CP15/C0 register.  | 
350 |  | -    for (auto I : Lines)  | 
351 |  | -      if (I.consume_front("CPU variant"))  | 
352 |  | -        I.ltrim("\t :").getAsInteger(0, Variant);  | 
 | 326 | +    unsigned Variant = GetVariant();  | 
353 | 327 | 
 
  | 
354 |  | -    // Look for the CPU part line, whose value is a 3 digit hexadecimal  | 
355 |  | -    // number, corresponding to the PartNum bits in the CP15/C0 register.  | 
356 |  | -    for (auto I : Lines)  | 
357 |  | -      if (I.consume_front("CPU part"))  | 
358 |  | -        I.ltrim("\t :").getAsInteger(0, Part);  | 
 | 328 | +    // Convert the CPU part line, whose value is a 3 digit hexadecimal number,  | 
 | 329 | +    // corresponding to the PartNum bits in the CP15/C0 register.  | 
 | 330 | +    unsigned PartAsInt;  | 
 | 331 | +    Part.getAsInteger(0, PartAsInt);  | 
359 | 332 | 
 
  | 
360 |  | -    unsigned Exynos = (Variant << 12) | Part;  | 
 | 333 | +    unsigned Exynos = (Variant << 12) | PartAsInt;  | 
361 | 334 |     switch (Exynos) {  | 
362 | 335 |     default:  | 
363 | 336 |       // Default by falling through to Exynos M3.  | 
@@ -416,6 +389,86 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {  | 
416 | 389 |   return "generic";  | 
417 | 390 | }  | 
418 | 391 | 
 
  | 
 | 392 | +StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {  | 
 | 393 | +  // The cpuid register on arm is not accessible from user space. On Linux,  | 
 | 394 | +  // it is exposed through the /proc/cpuinfo file.  | 
 | 395 | + | 
 | 396 | +  // Read 32 lines from /proc/cpuinfo, which should contain the CPU part line  | 
 | 397 | +  // in all cases.  | 
 | 398 | +  SmallVector<StringRef, 32> Lines;  | 
 | 399 | +  ProcCpuinfoContent.split(Lines, '\n');  | 
 | 400 | + | 
 | 401 | +  // Look for the CPU implementer and hardware lines, and store the CPU part  | 
 | 402 | +  // numbers found.  | 
 | 403 | +  StringRef Implementer;  | 
 | 404 | +  StringRef Hardware;  | 
 | 405 | +  SmallVector<StringRef, 32> Parts;  | 
 | 406 | +  for (StringRef Line : Lines) {  | 
 | 407 | +    if (Line.consume_front("CPU implementer"))  | 
 | 408 | +      Implementer = Line.ltrim("\t :");  | 
 | 409 | +    else if (Line.consume_front("Hardware"))  | 
 | 410 | +      Hardware = Line.ltrim("\t :");  | 
 | 411 | +    else if (Line.consume_front("CPU part"))  | 
 | 412 | +      Parts.emplace_back(Line.ltrim("\t :"));  | 
 | 413 | +  }  | 
 | 414 | + | 
 | 415 | +  // Last `Part' seen, in case we don't analyse all `Parts' parsed.  | 
 | 416 | +  StringRef Part = Parts.empty() ? StringRef() : Parts.back();  | 
 | 417 | + | 
 | 418 | +  // Remove duplicate `Parts'.  | 
 | 419 | +  llvm::sort(Parts);  | 
 | 420 | +  Parts.erase(llvm::unique(Parts), Parts.end());  | 
 | 421 | + | 
 | 422 | +  auto GetVariant = [&]() {  | 
 | 423 | +    unsigned Variant = 0;  | 
 | 424 | +    for (auto I : Lines)  | 
 | 425 | +      if (I.consume_front("CPU variant"))  | 
 | 426 | +        I.ltrim("\t :").getAsInteger(0, Variant);  | 
 | 427 | +    return Variant;  | 
 | 428 | +  };  | 
 | 429 | + | 
 | 430 | +  return getHostCPUNameForARMFromComponents(Implementer, Hardware, Part, Parts,  | 
 | 431 | +                                            GetVariant);  | 
 | 432 | +}  | 
 | 433 | + | 
 | 434 | +StringRef sys::detail::getHostCPUNameForARM(uint64_t PrimaryCpuInfo,  | 
 | 435 | +                                            ArrayRef<uint64_t> UniqueCpuInfos) {  | 
 | 436 | +  // On Windows, the registry provides cached copied of the MIDR_EL1 register.  | 
 | 437 | +  union MIDR_EL1 {  | 
 | 438 | +    uint64_t Raw;  | 
 | 439 | +    struct _Components {  | 
 | 440 | +      uint64_t Revision : 4;  | 
 | 441 | +      uint64_t Partnum : 12;  | 
 | 442 | +      uint64_t Architecture : 4;  | 
 | 443 | +      uint64_t Variant : 4;  | 
 | 444 | +      uint64_t Implementer : 8;  | 
 | 445 | +      uint64_t Reserved : 32;  | 
 | 446 | +    } Components;  | 
 | 447 | +  };  | 
 | 448 | + | 
 | 449 | +  SmallVector<std::string> PartsHolder;  | 
 | 450 | +  PartsHolder.reserve(UniqueCpuInfos.size());  | 
 | 451 | +  for (auto Info : UniqueCpuInfos)  | 
 | 452 | +    PartsHolder.push_back("0x" + utohexstr(MIDR_EL1{Info}.Components.Partnum,  | 
 | 453 | +                                           /*LowerCase*/ true,  | 
 | 454 | +                                           /*Width*/ 3));  | 
 | 455 | + | 
 | 456 | +  SmallVector<StringRef> Parts;  | 
 | 457 | +  Parts.reserve(PartsHolder.size());  | 
 | 458 | +  for (const auto &Part : PartsHolder)  | 
 | 459 | +    Parts.push_back(Part);  | 
 | 460 | + | 
 | 461 | +  return getHostCPUNameForARMFromComponents(  | 
 | 462 | +      "0x" + utohexstr(MIDR_EL1{PrimaryCpuInfo}.Components.Implementer,  | 
 | 463 | +                       /*LowerCase*/ true,  | 
 | 464 | +                       /*Width*/ 2),  | 
 | 465 | +      /*Hardware*/ "",  | 
 | 466 | +      "0x" + utohexstr(MIDR_EL1{PrimaryCpuInfo}.Components.Partnum,  | 
 | 467 | +                       /*LowerCase*/ true,  | 
 | 468 | +                       /*Width*/ 3),  | 
 | 469 | +      Parts, [=]() { return MIDR_EL1{PrimaryCpuInfo}.Components.Variant; });  | 
 | 470 | +}  | 
 | 471 | + | 
419 | 472 | namespace {  | 
420 | 473 | StringRef getCPUNameFromS390Model(unsigned int Id, bool HaveVectorSupport) {  | 
421 | 474 |   switch (Id) {  | 
@@ -1450,6 +1503,75 @@ StringRef sys::getHostCPUName() {  | 
1450 | 1503 |   return "generic";  | 
1451 | 1504 | }  | 
1452 | 1505 | 
 
  | 
 | 1506 | +#elif defined(_M_ARM64) || defined(_M_ARM64EC)  | 
 | 1507 | + | 
 | 1508 | +StringRef sys::getHostCPUName() {  | 
 | 1509 | +  constexpr char CentralProcessorKeyName[] =  | 
 | 1510 | +      "HARDWARE\\DESCRIPTION\\System\\CentralProcessor";  | 
 | 1511 | +  // Sub keys names are simple numbers ("0", "1", etc.) so 10 chars should be  | 
 | 1512 | +  // enough for the slash and name.  | 
 | 1513 | +  constexpr size_t SubKeyNameMaxSize = ARRAYSIZE(CentralProcessorKeyName) + 10;  | 
 | 1514 | + | 
 | 1515 | +  SmallVector<uint64_t> Values;  | 
 | 1516 | +  uint64_t PrimaryCpuInfo;  | 
 | 1517 | +  char PrimaryPartKeyName[SubKeyNameMaxSize];  | 
 | 1518 | +  DWORD PrimaryPartKeyNameSize = 0;  | 
 | 1519 | +  HKEY CentralProcessorKey;  | 
 | 1520 | +  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, CentralProcessorKeyName, 0, KEY_READ,  | 
 | 1521 | +                    &CentralProcessorKey) == ERROR_SUCCESS) {  | 
 | 1522 | +    for (unsigned Index = 0; Index < UINT32_MAX; ++Index) {  | 
 | 1523 | +      char SubKeyName[SubKeyNameMaxSize];  | 
 | 1524 | +      DWORD SubKeySize = SubKeyNameMaxSize;  | 
 | 1525 | +      HKEY SubKey;  | 
 | 1526 | +      if ((RegEnumKeyExA(CentralProcessorKey, Index, SubKeyName, &SubKeySize,  | 
 | 1527 | +                         nullptr, nullptr, nullptr,  | 
 | 1528 | +                         nullptr) == ERROR_SUCCESS) &&  | 
 | 1529 | +          (RegOpenKeyExA(CentralProcessorKey, SubKeyName, 0, KEY_READ,  | 
 | 1530 | +                         &SubKey) == ERROR_SUCCESS)) {  | 
 | 1531 | +        // The "CP 4000" registry key contains a cached copy of the MIDR_EL1  | 
 | 1532 | +        // register.  | 
 | 1533 | +        uint64_t RegValue;  | 
 | 1534 | +        DWORD ActualType;  | 
 | 1535 | +        DWORD RegValueSize = sizeof(RegValue);  | 
 | 1536 | +        if ((RegQueryValueExA(SubKey, "CP 4000", nullptr, &ActualType,  | 
 | 1537 | +                              (PBYTE)&RegValue,  | 
 | 1538 | +                              &RegValueSize) == ERROR_SUCCESS) &&  | 
 | 1539 | +            (ActualType == REG_QWORD) && RegValueSize == sizeof(RegValue)) {  | 
 | 1540 | +          // Assume that the part with the "highest" reg key name is the primary  | 
 | 1541 | +          // part (to match the way that Linux's cpuinfo is written). Win32  | 
 | 1542 | +          // makes no guarantees about the order of sub keys, so we have to  | 
 | 1543 | +          // compare the names.  | 
 | 1544 | +          if (PrimaryPartKeyNameSize < SubKeySize ||  | 
 | 1545 | +              (PrimaryPartKeyNameSize == SubKeySize &&  | 
 | 1546 | +               ::memcmp(SubKeyName, PrimaryPartKeyName, SubKeySize) > 0)) {  | 
 | 1547 | +            PrimaryCpuInfo = RegValue;  | 
 | 1548 | +            ::memcpy(PrimaryPartKeyName, SubKeyName, SubKeySize + 1);  | 
 | 1549 | +            PrimaryPartKeyNameSize = SubKeySize;  | 
 | 1550 | +          }  | 
 | 1551 | +          if (!llvm::is_contained(Values, RegValue)) {  | 
 | 1552 | +            Values.push_back(RegValue);  | 
 | 1553 | +          }  | 
 | 1554 | +        }  | 
 | 1555 | +        RegCloseKey(SubKey);  | 
 | 1556 | +      } else {  | 
 | 1557 | +        // No more sub keys.  | 
 | 1558 | +        break;  | 
 | 1559 | +      }  | 
 | 1560 | +    }  | 
 | 1561 | +    RegCloseKey(CentralProcessorKey);  | 
 | 1562 | +  }  | 
 | 1563 | + | 
 | 1564 | +  if (Values.empty()) {  | 
 | 1565 | +    return "generic";  | 
 | 1566 | +  }  | 
 | 1567 | + | 
 | 1568 | +  // Win32 makes no guarantees about the order of sub keys, so sort to ensure  | 
 | 1569 | +  // reproducibility.  | 
 | 1570 | +  llvm::sort(Values);  | 
 | 1571 | + | 
 | 1572 | +  return detail::getHostCPUNameForARM(PrimaryCpuInfo, Values);  | 
 | 1573 | +}  | 
 | 1574 | + | 
1453 | 1575 | #elif defined(__APPLE__) && defined(__powerpc__)  | 
1454 | 1576 | StringRef sys::getHostCPUName() {  | 
1455 | 1577 |   host_basic_info_data_t hostInfo;  | 
 | 
0 commit comments