[compiler-rt] 599f8e1 - Reland "[compiler-rt][X86] Use functions in cpuid.h instead of inline assembly (#97877)"
Aiden Grossman via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 23 20:58:32 PDT 2024
Author: Aiden Grossman
Date: 2024-07-24T03:58:23Z
New Revision: 599f8e1120db8c8c7a5e42134ea52650e8fb0f1c
URL: https://github.com/llvm/llvm-project/commit/599f8e1120db8c8c7a5e42134ea52650e8fb0f1c
DIFF: https://github.com/llvm/llvm-project/commit/599f8e1120db8c8c7a5e42134ea52650e8fb0f1c.diff
LOG: Reland "[compiler-rt][X86] Use functions in cpuid.h instead of inline assembly (#97877)"
This reverts commit f1905f064451bf688577976a13000c9c47e58452.
This relands commit 19cf8deabe1124831164987f1b9bf2f806c0a875.
There were issues with the preprocessor includes that should have
excluded MSVC still including clang functions building on windows and
using intrin.h. This relanding fixes this behavior by additionally
wrapping the uses of __get_cpuid and __get_cpuid_count in _MSC_VER so
that clang in MSVC mode, which includes intrin.h, does not have any
conflicts.
Added:
Modified:
compiler-rt/lib/builtins/cpu_model/x86.c
llvm/lib/TargetParser/Host.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/builtins/cpu_model/x86.c b/compiler-rt/lib/builtins/cpu_model/x86.c
index 867ed97e57bf2..47be7febdc2dd 100644
--- a/compiler-rt/lib/builtins/cpu_model/x86.c
+++ b/compiler-rt/lib/builtins/cpu_model/x86.c
@@ -23,6 +23,10 @@
#include <assert.h>
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
+#include <cpuid.h>
+#endif
+
#ifdef _MSC_VER
#include <intrin.h>
#endif
@@ -224,38 +228,6 @@ enum ProcessorFeatures {
CPU_FEATURE_MAX
};
-// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
-// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID
-// support. Consequently, for i386, the presence of CPUID is checked first
-// via the corresponding eflags bit.
-static bool isCpuIdSupported(void) {
-#if defined(__GNUC__) || defined(__clang__)
-#if defined(__i386__)
- int __cpuid_supported;
- __asm__(" pushfl\n"
- " popl %%eax\n"
- " movl %%eax,%%ecx\n"
- " xorl $0x00200000,%%eax\n"
- " pushl %%eax\n"
- " popfl\n"
- " pushfl\n"
- " popl %%eax\n"
- " movl $0,%0\n"
- " cmpl %%eax,%%ecx\n"
- " je 1f\n"
- " movl $1,%0\n"
- "1:"
- : "=r"(__cpuid_supported)
- :
- : "eax", "ecx");
- if (!__cpuid_supported)
- return false;
-#endif
- return true;
-#endif
- return true;
-}
-
// This code is copied from lib/Support/Host.cpp.
// Changes to either file should be mirrored in the other.
@@ -263,26 +235,8 @@ static bool isCpuIdSupported(void) {
/// 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) {
-#if defined(__GNUC__) || defined(__clang__)
-#if defined(__x86_64__)
- // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
- // FIXME: should we save this for Clang?
- __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__)
- __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;
-#else
- return true;
-#endif
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
+ return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX);
#elif defined(_MSC_VER)
// The MSVC intrinsic is portable across x86 and x64.
int registers[4];
@@ -303,26 +257,12 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
unsigned *rEDX) {
-#if defined(__GNUC__) || defined(__clang__)
-#if defined(__x86_64__)
- // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
- // FIXME: should we save this for Clang?
- __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), "c"(subleaf));
- return false;
-#elif defined(__i386__)
- __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), "c"(subleaf));
- return false;
-#else
- return true;
-#endif
+ // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
+ // are such that __cpuidex is defined within cpuid.h for both, we can remove
+ // the __get_cpuid_count function and share the MSVC implementation between
+ // all three.
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
+ return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX);
#elif defined(_MSC_VER)
int registers[4];
__cpuidex(registers, value, subleaf);
@@ -338,6 +278,9 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
// Read control register 0 (XCR0). Used to detect features such as AVX.
static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
+ // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
+ // are such that _xgetbv is supported by both, we can unify the implementation
+ // with MSVC and remove all inline assembly.
#if defined(__GNUC__) || defined(__clang__)
// Check xgetbv; this uses a .byte sequence instead of the instruction
// directly because older assemblers do not include support for xgetbv and
@@ -1144,8 +1087,7 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {
if (__cpu_model.__cpu_vendor)
return 0;
- if (!isCpuIdSupported() ||
- getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
+ if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
__cpu_model.__cpu_vendor = VENDOR_OTHER;
return -1;
}
diff --git a/llvm/lib/TargetParser/Host.cpp b/llvm/lib/TargetParser/Host.cpp
index 7e637cba4cfbc..0803521f31b91 100644
--- a/llvm/lib/TargetParser/Host.cpp
+++ b/llvm/lib/TargetParser/Host.cpp
@@ -50,6 +50,11 @@
#if defined(__sun__) && defined(__svr4__)
#include <kstat.h>
#endif
+#if defined(__GNUC__) || defined(__clang__)
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)
+#include <cpuid.h>
+#endif
+#endif
#define DEBUG_TYPE "host-detection"
@@ -522,68 +527,15 @@ StringRef sys::detail::getHostCPUNameForBPF() {
#endif
}
-#if defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64__) || defined(_M_X64)
-
-// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
-// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID
-// support. Consequently, for i386, the presence of CPUID is checked first
-// via the corresponding eflags bit.
-// Removal of cpuid.h header motivated by PR30384
-// Header cpuid.h and method __get_cpuid_max are not used in llvm, clang, openmp
-// or test-suite, but are used in external projects e.g. libstdcxx
-static bool isCpuIdSupported() {
-#if defined(__GNUC__) || defined(__clang__)
-#if defined(__i386__)
- int __cpuid_supported;
- __asm__(" pushfl\n"
- " popl %%eax\n"
- " movl %%eax,%%ecx\n"
- " xorl $0x00200000,%%eax\n"
- " pushl %%eax\n"
- " popfl\n"
- " pushfl\n"
- " popl %%eax\n"
- " movl $0,%0\n"
- " cmpl %%eax,%%ecx\n"
- " je 1f\n"
- " movl $1,%0\n"
- "1:"
- : "=r"(__cpuid_supported)
- :
- : "eax", "ecx");
- if (!__cpuid_supported)
- return false;
-#endif
- return true;
-#endif
- return true;
-}
+#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \
+ defined(_M_X64)
/// 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) {
-#if defined(__GNUC__) || defined(__clang__)
-#if defined(__x86_64__)
- // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
- // FIXME: should we save this for Clang?
- __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__)
- __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;
-#else
- return true;
-#endif
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)
+ return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX);
#elif defined(_MSC_VER)
// The MSVC intrinsic is portable across x86 and x64.
int registers[4];
@@ -610,9 +562,6 @@ VendorSignatures getVendorSignature(unsigned *MaxLeaf) {
else
*MaxLeaf = 0;
- if (!isCpuIdSupported())
- return VendorSignatures::UNKNOWN;
-
if (getX86CpuIDAndInfo(0, MaxLeaf, &EBX, &ECX, &EDX) || *MaxLeaf < 1)
return VendorSignatures::UNKNOWN;
@@ -640,26 +589,12 @@ using namespace llvm::sys::detail::x86;
static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
unsigned *rEDX) {
-#if defined(__GNUC__) || defined(__clang__)
-#if defined(__x86_64__)
- // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
- // FIXME: should we save this for Clang?
- __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), "c"(subleaf));
- return false;
-#elif defined(__i386__)
- __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), "c"(subleaf));
- return false;
-#else
- return true;
-#endif
+ // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
+ // are such that __cpuidex is defined within cpuid.h for both, we can remove
+ // the __get_cpuid_count function and share the MSVC implementation between
+ // all three.
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)
+ return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX);
#elif defined(_MSC_VER)
int registers[4];
__cpuidex(registers, value, subleaf);
@@ -675,6 +610,9 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
// Read control register 0 (XCR0). Used to detect features such as AVX.
static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
+ // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
+ // are such that _xgetbv is supported by both, we can unify the implementation
+ // with MSVC and remove all inline assembly.
#if defined(__GNUC__) || defined(__clang__)
// Check xgetbv; this uses a .byte sequence instead of the instruction
// directly because older assemblers do not include support for xgetbv and
More information about the llvm-commits
mailing list