diff options
Diffstat (limited to 'lib/Support/Host.cpp')
-rw-r--r-- | lib/Support/Host.cpp | 447 |
1 files changed, 228 insertions, 219 deletions
diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index d1b40412a6fc..970ecfd7df90 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -52,25 +52,218 @@ using namespace llvm; -#if defined(__linux__) -static ssize_t LLVM_ATTRIBUTE_UNUSED readCpuInfo(void *Buf, size_t Size) { - // Note: We cannot mmap /proc/cpuinfo here and then process the resulting - // memory buffer because the 'file' has 0 size (it can be read from only - // as a stream). - - int FD; - std::error_code EC = sys::fs::openFileForRead("/proc/cpuinfo", FD); - if (EC) { - DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << EC.message() << "\n"); - return -1; +static std::unique_ptr<llvm::MemoryBuffer> + LLVM_ATTRIBUTE_UNUSED getProcCpuinfoContent() { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = + llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo"); + if (std::error_code EC = Text.getError()) { + llvm::errs() << "Can't read " + << "/proc/cpuinfo: " << EC.message() << "\n"; + return nullptr; } - int Ret = read(FD, Buf, Size); - int CloseStatus = close(FD); - if (CloseStatus) - return -1; - return Ret; + return std::move(*Text); +} + +StringRef sys::detail::getHostCPUNameForPowerPC( + const StringRef &ProcCpuinfoContent) { + // Access to the Processor Version Register (PVR) on PowerPC is privileged, + // and so we must use an operating-system interface to determine the current + // processor type. On Linux, this is exposed through the /proc/cpuinfo file. + const char *generic = "generic"; + + // The cpu line is second (after the 'processor: 0' line), so if this + // buffer is too small then something has changed (or is wrong). + StringRef::const_iterator CPUInfoStart = ProcCpuinfoContent.begin(); + StringRef::const_iterator CPUInfoEnd = ProcCpuinfoContent.end(); + + StringRef::const_iterator CIP = CPUInfoStart; + + StringRef::const_iterator CPUStart = 0; + size_t CPULen = 0; + + // We need to find the first line which starts with cpu, spaces, and a colon. + // After the colon, there may be some additional spaces and then the cpu type. + while (CIP < CPUInfoEnd && CPUStart == 0) { + if (CIP < CPUInfoEnd && *CIP == '\n') + ++CIP; + + if (CIP < CPUInfoEnd && *CIP == 'c') { + ++CIP; + if (CIP < CPUInfoEnd && *CIP == 'p') { + ++CIP; + if (CIP < CPUInfoEnd && *CIP == 'u') { + ++CIP; + while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) + ++CIP; + + if (CIP < CPUInfoEnd && *CIP == ':') { + ++CIP; + while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) + ++CIP; + + if (CIP < CPUInfoEnd) { + CPUStart = CIP; + while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' && + *CIP != ',' && *CIP != '\n')) + ++CIP; + CPULen = CIP - CPUStart; + } + } + } + } + } + + if (CPUStart == 0) + while (CIP < CPUInfoEnd && *CIP != '\n') + ++CIP; + } + + if (CPUStart == 0) + return generic; + + return StringSwitch<const char *>(StringRef(CPUStart, CPULen)) + .Case("604e", "604e") + .Case("604", "604") + .Case("7400", "7400") + .Case("7410", "7400") + .Case("7447", "7400") + .Case("7455", "7450") + .Case("G4", "g4") + .Case("POWER4", "970") + .Case("PPC970FX", "970") + .Case("PPC970MP", "970") + .Case("G5", "g5") + .Case("POWER5", "g5") + .Case("A2", "a2") + .Case("POWER6", "pwr6") + .Case("POWER7", "pwr7") + .Case("POWER8", "pwr8") + .Case("POWER8E", "pwr8") + .Case("POWER8NVL", "pwr8") + .Case("POWER9", "pwr9") + .Default(generic); +} + +StringRef sys::detail::getHostCPUNameForARM( + const StringRef &ProcCpuinfoContent) { + // The cpuid register on arm is not accessible from user space. On Linux, + // it is exposed through the /proc/cpuinfo file. + + // Read 32 lines from /proc/cpuinfo, which should contain the CPU part line + // in all cases. + SmallVector<StringRef, 32> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for the CPU implementer line. + StringRef Implementer; + StringRef Hardware; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("CPU implementer")) + Implementer = Lines[I].substr(15).ltrim("\t :"); + if (Lines[I].startswith("Hardware")) + Hardware = Lines[I].substr(8).ltrim("\t :"); + } + + if (Implementer == "0x41") { // ARM Ltd. + // MSM8992/8994 may give cpu part for the core that the kernel is running on, + // which is undeterministic and wrong. Always return cortex-a53 for these SoC. + if (Hardware.endswith("MSM8994") || Hardware.endswith("MSM8996")) + return "cortex-a53"; + + + // Look for the CPU part line. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("CPU part")) + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) + .Case("0x926", "arm926ej-s") + .Case("0xb02", "mpcore") + .Case("0xb36", "arm1136j-s") + .Case("0xb56", "arm1156t2-s") + .Case("0xb76", "arm1176jz-s") + .Case("0xc08", "cortex-a8") + .Case("0xc09", "cortex-a9") + .Case("0xc0f", "cortex-a15") + .Case("0xc20", "cortex-m0") + .Case("0xc23", "cortex-m3") + .Case("0xc24", "cortex-m4") + .Case("0xd04", "cortex-a35") + .Case("0xd03", "cortex-a53") + .Case("0xd07", "cortex-a57") + .Case("0xd08", "cortex-a72") + .Case("0xd09", "cortex-a73") + .Default("generic"); + } + + if (Implementer == "0x51") // Qualcomm Technologies, Inc. + // Look for the CPU part line. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("CPU part")) + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) + .Case("0x06f", "krait") // APQ8064 + .Case("0x201", "kryo") + .Case("0x205", "kryo") + .Default("generic"); + + return "generic"; +} + +StringRef sys::detail::getHostCPUNameForS390x( + const StringRef &ProcCpuinfoContent) { + // STIDP is a privileged operation, so use /proc/cpuinfo instead. + + // The "processor 0:" line comes after a fair amount of other information, + // including a cache breakdown, but this should be plenty. + SmallVector<StringRef, 32> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for the CPU features. + SmallVector<StringRef, 32> CPUFeatures; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("features")) { + size_t Pos = Lines[I].find(":"); + if (Pos != StringRef::npos) { + Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' '); + break; + } + } + + // We need to check for the presence of vector support independently of + // the machine type, since we may only use the vector register set when + // supported by the kernel (and hypervisor). + bool HaveVectorSupport = false; + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + if (CPUFeatures[I] == "vx") + HaveVectorSupport = true; + } + + // Now check the processor machine type. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("processor ")) { + size_t Pos = Lines[I].find("machine = "); + if (Pos != StringRef::npos) { + Pos += sizeof("machine = ") - 1; + unsigned int Id; + if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { + if (Id >= 2964 && HaveVectorSupport) + return "z13"; + if (Id >= 2827) + return "zEC12"; + if (Id >= 2817) + return "z196"; + } + } + break; + } + } + + return "generic"; } -#endif #if defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64__) || defined(_M_X64) @@ -1020,201 +1213,21 @@ StringRef sys::getHostCPUName() { } #elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__)) StringRef sys::getHostCPUName() { - // Access to the Processor Version Register (PVR) on PowerPC is privileged, - // and so we must use an operating-system interface to determine the current - // processor type. On Linux, this is exposed through the /proc/cpuinfo file. - const char *generic = "generic"; - - // The cpu line is second (after the 'processor: 0' line), so if this - // buffer is too small then something has changed (or is wrong). - char buffer[1024]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) - return generic; - - const char *CPUInfoStart = buffer; - const char *CPUInfoEnd = buffer + CPUInfoSize; - - const char *CIP = CPUInfoStart; - - const char *CPUStart = 0; - size_t CPULen = 0; - - // We need to find the first line which starts with cpu, spaces, and a colon. - // After the colon, there may be some additional spaces and then the cpu type. - while (CIP < CPUInfoEnd && CPUStart == 0) { - if (CIP < CPUInfoEnd && *CIP == '\n') - ++CIP; - - if (CIP < CPUInfoEnd && *CIP == 'c') { - ++CIP; - if (CIP < CPUInfoEnd && *CIP == 'p') { - ++CIP; - if (CIP < CPUInfoEnd && *CIP == 'u') { - ++CIP; - while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) - ++CIP; - - if (CIP < CPUInfoEnd && *CIP == ':') { - ++CIP; - while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) - ++CIP; - - if (CIP < CPUInfoEnd) { - CPUStart = CIP; - while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' && - *CIP != ',' && *CIP != '\n')) - ++CIP; - CPULen = CIP - CPUStart; - } - } - } - } - } - - if (CPUStart == 0) - while (CIP < CPUInfoEnd && *CIP != '\n') - ++CIP; - } - - if (CPUStart == 0) - return generic; - - return StringSwitch<const char *>(StringRef(CPUStart, CPULen)) - .Case("604e", "604e") - .Case("604", "604") - .Case("7400", "7400") - .Case("7410", "7400") - .Case("7447", "7400") - .Case("7455", "7450") - .Case("G4", "g4") - .Case("POWER4", "970") - .Case("PPC970FX", "970") - .Case("PPC970MP", "970") - .Case("G5", "g5") - .Case("POWER5", "g5") - .Case("A2", "a2") - .Case("POWER6", "pwr6") - .Case("POWER7", "pwr7") - .Case("POWER8", "pwr8") - .Case("POWER8E", "pwr8") - .Case("POWER8NVL", "pwr8") - .Case("POWER9", "pwr9") - .Default(generic); + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + const StringRef& Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForPowerPC(Content); } -#elif defined(__linux__) && defined(__arm__) +#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) StringRef sys::getHostCPUName() { - // The cpuid register on arm is not accessible from user space. On Linux, - // it is exposed through the /proc/cpuinfo file. - - // Read 1024 bytes from /proc/cpuinfo, which should contain the CPU part line - // in all cases. - char buffer[1024]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) - return "generic"; - - StringRef Str(buffer, CPUInfoSize); - - SmallVector<StringRef, 32> Lines; - Str.split(Lines, "\n"); - - // Look for the CPU implementer line. - StringRef Implementer; - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU implementer")) - Implementer = Lines[I].substr(15).ltrim("\t :"); - - if (Implementer == "0x41") // ARM Ltd. - // Look for the CPU part line. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU part")) - // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The - // values correspond to the "Part number" in the CP15/c0 register. The - // contents are specified in the various processor manuals. - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x926", "arm926ej-s") - .Case("0xb02", "mpcore") - .Case("0xb36", "arm1136j-s") - .Case("0xb56", "arm1156t2-s") - .Case("0xb76", "arm1176jz-s") - .Case("0xc08", "cortex-a8") - .Case("0xc09", "cortex-a9") - .Case("0xc0f", "cortex-a15") - .Case("0xc20", "cortex-m0") - .Case("0xc23", "cortex-m3") - .Case("0xc24", "cortex-m4") - .Default("generic"); - - if (Implementer == "0x51") // Qualcomm Technologies, Inc. - // Look for the CPU part line. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU part")) - // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The - // values correspond to the "Part number" in the CP15/c0 register. The - // contents are specified in the various processor manuals. - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x06f", "krait") // APQ8064 - .Default("generic"); - - return "generic"; + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + const StringRef& Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForARM(Content); } #elif defined(__linux__) && defined(__s390x__) StringRef sys::getHostCPUName() { - // STIDP is a privileged operation, so use /proc/cpuinfo instead. - - // The "processor 0:" line comes after a fair amount of other information, - // including a cache breakdown, but this should be plenty. - char buffer[2048]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) - return "generic"; - - StringRef Str(buffer, CPUInfoSize); - SmallVector<StringRef, 32> Lines; - Str.split(Lines, "\n"); - - // Look for the CPU features. - SmallVector<StringRef, 32> CPUFeatures; - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("features")) { - size_t Pos = Lines[I].find(":"); - if (Pos != StringRef::npos) { - Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' '); - break; - } - } - - // We need to check for the presence of vector support independently of - // the machine type, since we may only use the vector register set when - // supported by the kernel (and hypervisor). - bool HaveVectorSupport = false; - for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { - if (CPUFeatures[I] == "vx") - HaveVectorSupport = true; - } - - // Now check the processor machine type. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) { - if (Lines[I].startswith("processor ")) { - size_t Pos = Lines[I].find("machine = "); - if (Pos != StringRef::npos) { - Pos += sizeof("machine = ") - 1; - unsigned int Id; - if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { - if (Id >= 2964 && HaveVectorSupport) - return "z13"; - if (Id >= 2827) - return "zEC12"; - if (Id >= 2817) - return "z196"; - } - } - break; - } - } - - return "generic"; + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + const StringRef& Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForS390x(Content); } #else StringRef sys::getHostCPUName() { return "generic"; } @@ -1232,6 +1245,7 @@ static int computeHostNumPhysicalCores() { if (std::error_code EC = Text.getError()) { llvm::errs() << "Can't read " << "/proc/cpuinfo: " << EC.message() << "\n"; + return -1; } SmallVector<StringRef, 8> strs; (*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, @@ -1353,6 +1367,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1); + bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && + !getX86CpuIDAndInfoEx(0x80000008,0x0, &EAX, &EBX, &ECX, &EDX); + Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1); + bool HasLeaf7 = MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); @@ -1362,14 +1380,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); Features["sgx"] = HasLeaf7 && ((EBX >> 2) & 1); Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1); - Features["hle"] = HasLeaf7 && ((EBX >> 4) & 1); Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); - Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1); Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1); Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1); - Features["smap"] = HasLeaf7 && ((EBX >> 20) & 1); - Features["pcommit"] = HasLeaf7 && ((EBX >> 22) & 1); Features["clflushopt"] = HasLeaf7 && ((EBX >> 23) & 1); Features["clwb"] = HasLeaf7 && ((EBX >> 24) & 1); Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); @@ -1401,17 +1415,12 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { } #elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) bool sys::getHostCPUFeatures(StringMap<bool> &Features) { - // Read 1024 bytes from /proc/cpuinfo, which should contain the Features line - // in all cases. - char buffer[1024]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + if (!P) return false; - StringRef Str(buffer, CPUInfoSize); - SmallVector<StringRef, 32> Lines; - Str.split(Lines, "\n"); + P->getBuffer().split(Lines, "\n"); SmallVector<StringRef, 32> CPUFeatures; |