|
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