aboutsummaryrefslogtreecommitdiff
path: root/lib/Support/Host.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Support/Host.cpp')
-rw-r--r--lib/Support/Host.cpp447
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;