X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FSupport%2FHost.cpp;h=e2dd6d522bb7f19863125128cf9d9b5f3259ee42;hb=be63d589633bbfa068b923c60eaaeee1b27647c5;hp=372b7fcc6c41c237edf1d55a7000760c4320a7fe;hpb=3b148e5be8ac0683e53793cfa3761b4d84e3eda2;p=oota-llvm.git diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index 372b7fcc6c4..e2dd6d522bb 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This header file implements the operating system Host concept. +// This file implements the operating system Host concept. // //===----------------------------------------------------------------------===// @@ -39,6 +39,8 @@ #include #endif +#define DEBUG_TYPE "host-detection" + //===----------------------------------------------------------------------===// // // Implementations of the CPU detection routines @@ -52,8 +54,55 @@ using namespace llvm; /// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the /// specified arguments. If we can't run cpuid on the host, return true. -static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, - unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, + unsigned *rECX, unsigned *rEDX) { +#if defined(__GNUC__) || defined(__clang__) + #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm ("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) + asm ("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; +// pedantic #else returns to appease -Wunreachable-code (so we don't generate +// postprocessed code that looks like "return true; return false;") + #else + return true; + #endif +#elif defined(_MSC_VER) + // The MSVC intrinsic is portable across x86 and x64. + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; +#else + return true; +#endif +} + +/// GetX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return the +/// 4 values in the specified arguments. If we can't run cpuid on the host, +/// return true. +static bool GetX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, + unsigned *rEAX, unsigned *rEBX, unsigned *rECX, + unsigned *rEDX) { #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) #if defined(__GNUC__) // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. @@ -64,16 +113,22 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, "=S" (*rEBX), "=c" (*rECX), "=d" (*rEDX) - : "a" (value)); + : "a" (value), + "c" (subleaf)); return false; #elif defined(_MSC_VER) - int registers[4]; - __cpuid(registers, value); - *rEAX = registers[0]; - *rEBX = registers[1]; - *rECX = registers[2]; - *rEDX = registers[3]; - return false; + // __cpuidex was added in MSVC++ 9.0 SP1 + #if (_MSC_VER > 1500) || (_MSC_VER == 1500 && _MSC_FULL_VER >= 150030729) + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; + #else + return true; + #endif #else return true; #endif @@ -86,11 +141,13 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, "=S" (*rEBX), "=c" (*rECX), "=d" (*rEDX) - : "a" (value)); + : "a" (value), + "c" (subleaf)); return false; #elif defined(_MSC_VER) __asm { mov eax,value + mov ecx,subleaf cpuid mov esi,rEAX mov dword ptr [esi],eax @@ -102,8 +159,6 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, mov dword ptr [esi],edx } return false; -// pedantic #else returns to appease -Wunreachable-code (so we don't generate -// postprocessed code that looks like "return true; return false;") #else return true; #endif @@ -112,16 +167,19 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, #endif } -static bool OSHasAVXSupport() { -#if defined(__GNUC__) - int rEAX, rEDX; - __asm__ ("xgetbv" : "=a" (rEAX), "=d" (rEDX) : "c" (0)); -#elif defined(_MSC_VER) - unsigned long long rEAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); -#else - int rEAX = 0; // Ensures we return false -#endif - return (rEAX & 6) == 6; +static bool OSHasAVXSupport() { +#if defined(__GNUC__) + // Check xgetbv; this uses a .byte sequence instead of the instruction + // directly because older assemblers do not include support for xgetbv and + // there is no easy way to conditionally compile based on the assembler used. + int rEAX, rEDX; + __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a" (rEAX), "=d" (rEDX) : "c" (0)); +#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) + unsigned long long rEAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); +#else + int rEAX = 0; // Ensures we return false +#endif + return (rEAX & 6) == 6; } static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, @@ -137,7 +195,7 @@ static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, } } -std::string sys::getHostCPUName() { +StringRef sys::getHostCPUName() { unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; if (GetX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) return "generic"; @@ -145,20 +203,28 @@ std::string sys::getHostCPUName() { unsigned Model = 0; DetectX86FamilyModel(EAX, Family, Model); - bool HasSSE3 = (ECX & 0x1); - // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV - // indicates that the AVX registers will be saved and restored on context - // switch, when we have full AVX support. - bool HasAVX = (ECX & ((1 << 28) | (1 << 27))) != 0 && OSHasAVXSupport(); - GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); - bool Em64T = (EDX >> 29) & 0x1; - union { unsigned u[3]; char c[12]; } text; GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); + + unsigned MaxLeaf = EAX; + bool HasSSE3 = (ECX & 0x1); + bool HasSSE41 = (ECX & 0x80000); + // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV + // indicates that the AVX registers will be saved and restored on context + // switch, then we have full AVX support. + const unsigned AVXBits = (1 << 27) | (1 << 28); + bool HasAVX = ((ECX & AVXBits) == AVXBits) && OSHasAVXSupport(); + bool HasAVX2 = HasAVX && MaxLeaf >= 0x7 && + !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX) && + (EBX & 0x20); + GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + bool Em64T = (EDX >> 29) & 0x1; + bool HasTBM = (ECX >> 21) & 0x1; + if (memcmp(text.c, "GenuineIntel", 12) == 0) { switch (Family) { case 3: @@ -240,7 +306,8 @@ std::string sys::getHostCPUName() { // 17h. All processors are manufactured using the 45 nm process. // // 45nm: Penryn , Wolfdale, Yorkfield (XE) - return "penryn"; + // Not all Penryn processors support SSE 4.1 (such as the Pentium brand) + return HasSSE41 ? "penryn" : "core2"; case 26: // Intel Core i7 processor and Intel Xeon processor. All // processors are manufactured using the 45 nm process. @@ -265,10 +332,20 @@ std::string sys::getHostCPUName() { // Ivy Bridge: case 58: + case 62: // Ivy Bridge EP // Not all Ivy Bridge processors support AVX (such as the Pentium // versions instead of the i7 versions). return HasAVX ? "core-avx-i" : "corei7"; + // Haswell: + case 60: + case 63: + case 69: + case 70: + // Not all Haswell processors support AVX too (such as the Pentium + // versions instead of the i7 versions). + return HasAVX2 ? "core-avx2" : "corei7"; + case 28: // Most 45 nm Intel Atom processors case 38: // 45 nm Atom Lincroft case 39: // 32 nm Atom Medfield @@ -276,6 +353,12 @@ std::string sys::getHostCPUName() { case 54: // 32 nm Atom Midview return "atom"; + // Atom Silvermont codes from the Intel software optimization guide. + case 55: + case 74: + case 77: + return "slm"; + default: return (Em64T) ? "x86-64" : "i686"; } case 15: { @@ -351,10 +434,19 @@ std::string sys::getHostCPUName() { case 20: return "btver1"; case 21: - if (Model <= 15) - return "bdver1"; - else if (Model <= 31) - return "bdver2"; + if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. + return "btver1"; + if (Model >= 0x50) + return "bdver4"; // 50h-6Fh: Excavator + if (Model >= 0x30) + return "bdver3"; // 30h-3Fh: Steamroller + if (Model >= 0x10 || HasTBM) + return "bdver2"; // 10h-1Fh: Piledriver + return "bdver1"; // 00h-0Fh: Bulldozer + case 22: + if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback. + return "btver1"; + return "btver2"; default: return "generic"; } @@ -362,7 +454,7 @@ std::string sys::getHostCPUName() { return "generic"; } #elif defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__)) -std::string sys::getHostCPUName() { +StringRef sys::getHostCPUName() { host_basic_info_data_t hostInfo; mach_msg_type_number_t infoCount; @@ -391,7 +483,7 @@ std::string sys::getHostCPUName() { return "generic"; } #elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__)) -std::string sys::getHostCPUName() { +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. @@ -478,10 +570,12 @@ std::string sys::getHostCPUName() { .Case("A2", "a2") .Case("POWER6", "pwr6") .Case("POWER7", "pwr7") + .Case("POWER8", "pwr8") + .Case("POWER8E", "pwr8") .Default(generic); } #elif defined(__linux__) && defined(__arm__) -std::string sys::getHostCPUName() { +StringRef sys::getHostCPUName() { // The cpuid register on arm is not accessible from user space. On Linux, // it is exposed through the /proc/cpuinfo file. // Note: We cannot mmap /proc/cpuinfo here and then process the resulting @@ -533,15 +627,68 @@ std::string sys::getHostCPUName() { .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(Lines[I].substr(8).ltrim("\t :")) + .Case("0x06f", "krait") // APQ8064 + .Default("generic"); + + return "generic"; +} +#elif defined(__linux__) && defined(__s390x__) +StringRef sys::getHostCPUName() { + // STIDP is a privileged operation, so use /proc/cpuinfo instead. + // 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). + + std::string Err; + DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err); + if (!DS) { + DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n"); + return "generic"; + } + + // The "processor 0:" line comes after a fair amount of other information, + // including a cache breakdown, but this should be plenty. + char buffer[2048]; + size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer)); + delete DS; + + StringRef Str(buffer, CPUInfoSize); + SmallVector Lines; + Str.split(Lines, "\n"); + 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 >= 2827) + return "zEC12"; + if (Id >= 2817) + return "z196"; + } + } + break; + } + } + return "generic"; } #else -std::string sys::getHostCPUName() { +StringRef sys::getHostCPUName() { return "generic"; } #endif -#if defined(__linux__) && defined(__arm__) +#if defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) bool sys::getHostCPUFeatures(StringMap &Features) { std::string Err; DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err); @@ -561,41 +708,67 @@ bool sys::getHostCPUFeatures(StringMap &Features) { SmallVector 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 :"); + SmallVector CPUFeatures; - if (Implementer == "0x41") { // ARM Ltd. - SmallVector CPUFeatures; + // Look for the CPU features. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("Features")) { + Lines[I].split(CPUFeatures, " "); + break; + } - // Look for the CPU features. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("Features")) { - Lines[I].split(CPUFeatures, " "); - break; - } +#if defined(__aarch64__) + // Keep track of which crypto features we have seen + enum { + CAP_AES = 0x1, + CAP_PMULL = 0x2, + CAP_SHA1 = 0x4, + CAP_SHA2 = 0x8 + }; + uint32_t crypto = 0; +#endif - for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { - StringRef LLVMFeatureStr = StringSwitch(CPUFeatures[I]) - .Case("half", "fp16") - .Case("neon", "neon") - .Case("vfpv3", "vfp3") - .Case("vfpv3d16", "d16") - .Case("vfpv4", "vfp4") - .Case("idiva", "hwdiv-arm") - .Case("idivt", "hwdiv") - .Default(""); - - if (LLVMFeatureStr != "") - Features.GetOrCreateValue(LLVMFeatureStr).setValue(true); - } + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + StringRef LLVMFeatureStr = StringSwitch(CPUFeatures[I]) +#if defined(__aarch64__) + .Case("asimd", "neon") + .Case("fp", "fp-armv8") + .Case("crc32", "crc") +#else + .Case("half", "fp16") + .Case("neon", "neon") + .Case("vfpv3", "vfp3") + .Case("vfpv3d16", "d16") + .Case("vfpv4", "vfp4") + .Case("idiva", "hwdiv-arm") + .Case("idivt", "hwdiv") +#endif + .Default(""); + +#if defined(__aarch64__) + // We need to check crypto separately since we need all of the crypto + // extensions to enable the subtarget feature + if (CPUFeatures[I] == "aes") + crypto |= CAP_AES; + else if (CPUFeatures[I] == "pmull") + crypto |= CAP_PMULL; + else if (CPUFeatures[I] == "sha1") + crypto |= CAP_SHA1; + else if (CPUFeatures[I] == "sha2") + crypto |= CAP_SHA2; +#endif - return true; + if (LLVMFeatureStr != "") + Features.GetOrCreateValue(LLVMFeatureStr).setValue(true); } - return false; +#if defined(__aarch64__) + // If we have all crypto bits we can add the feature + if (crypto == (CAP_AES | CAP_PMULL | CAP_SHA1 | CAP_SHA2)) + Features.GetOrCreateValue("crypto").setValue(true); +#endif + + return true; } #else bool sys::getHostCPUFeatures(StringMap &Features){ @@ -604,7 +777,7 @@ bool sys::getHostCPUFeatures(StringMap &Features){ #endif std::string sys::getProcessTriple() { - Triple PT(LLVM_HOSTTRIPLE); + Triple PT(Triple::normalize(LLVM_HOST_TRIPLE)); if (sizeof(void *) == 8 && PT.isArch32Bit()) PT = PT.get64BitArchVariant();