Skip to content

Commit 599f8e1

Browse files
Reland "[compiler-rt][X86] Use functions in cpuid.h instead of inline assembly (#97877)"
This reverts commit f1905f0. This relands commit 19cf8de. 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.
1 parent b91c75f commit 599f8e1

File tree

2 files changed

+34
-154
lines changed
  • compiler-rt/lib/builtins/cpu_model
  • llvm/lib/TargetParser

2 files changed

+34
-154
lines changed

compiler-rt/lib/builtins/cpu_model/x86.c

Lines changed: 16 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
#include <assert.h>
2525

26+
#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
27+
#include <cpuid.h>
28+
#endif
29+
2630
#ifdef _MSC_VER
2731
#include <intrin.h>
2832
#endif
@@ -224,65 +228,15 @@ enum ProcessorFeatures {
224228
CPU_FEATURE_MAX
225229
};
226230

227-
// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
228-
// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID
229-
// support. Consequently, for i386, the presence of CPUID is checked first
230-
// via the corresponding eflags bit.
231-
static bool isCpuIdSupported(void) {
232-
#if defined(__GNUC__) || defined(__clang__)
233-
#if defined(__i386__)
234-
int __cpuid_supported;
235-
__asm__(" pushfl\n"
236-
" popl %%eax\n"
237-
" movl %%eax,%%ecx\n"
238-
" xorl $0x00200000,%%eax\n"
239-
" pushl %%eax\n"
240-
" popfl\n"
241-
" pushfl\n"
242-
" popl %%eax\n"
243-
" movl $0,%0\n"
244-
" cmpl %%eax,%%ecx\n"
245-
" je 1f\n"
246-
" movl $1,%0\n"
247-
"1:"
248-
: "=r"(__cpuid_supported)
249-
:
250-
: "eax", "ecx");
251-
if (!__cpuid_supported)
252-
return false;
253-
#endif
254-
return true;
255-
#endif
256-
return true;
257-
}
258-
259231
// This code is copied from lib/Support/Host.cpp.
260232
// Changes to either file should be mirrored in the other.
261233

262234
/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
263235
/// the specified arguments. If we can't run cpuid on the host, return true.
264236
static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
265237
unsigned *rECX, unsigned *rEDX) {
266-
#if defined(__GNUC__) || defined(__clang__)
267-
#if defined(__x86_64__)
268-
// gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
269-
// FIXME: should we save this for Clang?
270-
__asm__("movq\t%%rbx, %%rsi\n\t"
271-
"cpuid\n\t"
272-
"xchgq\t%%rbx, %%rsi\n\t"
273-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
274-
: "a"(value));
275-
return false;
276-
#elif defined(__i386__)
277-
__asm__("movl\t%%ebx, %%esi\n\t"
278-
"cpuid\n\t"
279-
"xchgl\t%%ebx, %%esi\n\t"
280-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
281-
: "a"(value));
282-
return false;
283-
#else
284-
return true;
285-
#endif
238+
#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
239+
return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX);
286240
#elif defined(_MSC_VER)
287241
// The MSVC intrinsic is portable across x86 and x64.
288242
int registers[4];
@@ -303,26 +257,12 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
303257
static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
304258
unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
305259
unsigned *rEDX) {
306-
#if defined(__GNUC__) || defined(__clang__)
307-
#if defined(__x86_64__)
308-
// gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
309-
// FIXME: should we save this for Clang?
310-
__asm__("movq\t%%rbx, %%rsi\n\t"
311-
"cpuid\n\t"
312-
"xchgq\t%%rbx, %%rsi\n\t"
313-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
314-
: "a"(value), "c"(subleaf));
315-
return false;
316-
#elif defined(__i386__)
317-
__asm__("movl\t%%ebx, %%esi\n\t"
318-
"cpuid\n\t"
319-
"xchgl\t%%ebx, %%esi\n\t"
320-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
321-
: "a"(value), "c"(subleaf));
322-
return false;
323-
#else
324-
return true;
325-
#endif
260+
// TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
261+
// are such that __cpuidex is defined within cpuid.h for both, we can remove
262+
// the __get_cpuid_count function and share the MSVC implementation between
263+
// all three.
264+
#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
265+
return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX);
326266
#elif defined(_MSC_VER)
327267
int registers[4];
328268
__cpuidex(registers, value, subleaf);
@@ -338,6 +278,9 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
338278

339279
// Read control register 0 (XCR0). Used to detect features such as AVX.
340280
static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
281+
// TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
282+
// are such that _xgetbv is supported by both, we can unify the implementation
283+
// with MSVC and remove all inline assembly.
341284
#if defined(__GNUC__) || defined(__clang__)
342285
// Check xgetbv; this uses a .byte sequence instead of the instruction
343286
// directly because older assemblers do not include support for xgetbv and
@@ -1144,8 +1087,7 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {
11441087
if (__cpu_model.__cpu_vendor)
11451088
return 0;
11461089

1147-
if (!isCpuIdSupported() ||
1148-
getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
1090+
if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
11491091
__cpu_model.__cpu_vendor = VENDOR_OTHER;
11501092
return -1;
11511093
}

llvm/lib/TargetParser/Host.cpp

Lines changed: 18 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
#if defined(__sun__) && defined(__svr4__)
5151
#include <kstat.h>
5252
#endif
53+
#if defined(__GNUC__) || defined(__clang__)
54+
#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)
55+
#include <cpuid.h>
56+
#endif
57+
#endif
5358

5459
#define DEBUG_TYPE "host-detection"
5560

@@ -522,68 +527,15 @@ StringRef sys::detail::getHostCPUNameForBPF() {
522527
#endif
523528
}
524529

525-
#if defined(__i386__) || defined(_M_IX86) || \
526-
defined(__x86_64__) || defined(_M_X64)
527-
528-
// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
529-
// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID
530-
// support. Consequently, for i386, the presence of CPUID is checked first
531-
// via the corresponding eflags bit.
532-
// Removal of cpuid.h header motivated by PR30384
533-
// Header cpuid.h and method __get_cpuid_max are not used in llvm, clang, openmp
534-
// or test-suite, but are used in external projects e.g. libstdcxx
535-
static bool isCpuIdSupported() {
536-
#if defined(__GNUC__) || defined(__clang__)
537-
#if defined(__i386__)
538-
int __cpuid_supported;
539-
__asm__(" pushfl\n"
540-
" popl %%eax\n"
541-
" movl %%eax,%%ecx\n"
542-
" xorl $0x00200000,%%eax\n"
543-
" pushl %%eax\n"
544-
" popfl\n"
545-
" pushfl\n"
546-
" popl %%eax\n"
547-
" movl $0,%0\n"
548-
" cmpl %%eax,%%ecx\n"
549-
" je 1f\n"
550-
" movl $1,%0\n"
551-
"1:"
552-
: "=r"(__cpuid_supported)
553-
:
554-
: "eax", "ecx");
555-
if (!__cpuid_supported)
556-
return false;
557-
#endif
558-
return true;
559-
#endif
560-
return true;
561-
}
530+
#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \
531+
defined(_M_X64)
562532

563533
/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
564534
/// the specified arguments. If we can't run cpuid on the host, return true.
565535
static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
566536
unsigned *rECX, unsigned *rEDX) {
567-
#if defined(__GNUC__) || defined(__clang__)
568-
#if defined(__x86_64__)
569-
// gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
570-
// FIXME: should we save this for Clang?
571-
__asm__("movq\t%%rbx, %%rsi\n\t"
572-
"cpuid\n\t"
573-
"xchgq\t%%rbx, %%rsi\n\t"
574-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
575-
: "a"(value));
576-
return false;
577-
#elif defined(__i386__)
578-
__asm__("movl\t%%ebx, %%esi\n\t"
579-
"cpuid\n\t"
580-
"xchgl\t%%ebx, %%esi\n\t"
581-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
582-
: "a"(value));
583-
return false;
584-
#else
585-
return true;
586-
#endif
537+
#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)
538+
return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX);
587539
#elif defined(_MSC_VER)
588540
// The MSVC intrinsic is portable across x86 and x64.
589541
int registers[4];
@@ -610,9 +562,6 @@ VendorSignatures getVendorSignature(unsigned *MaxLeaf) {
610562
else
611563
*MaxLeaf = 0;
612564

613-
if (!isCpuIdSupported())
614-
return VendorSignatures::UNKNOWN;
615-
616565
if (getX86CpuIDAndInfo(0, MaxLeaf, &EBX, &ECX, &EDX) || *MaxLeaf < 1)
617566
return VendorSignatures::UNKNOWN;
618567

@@ -640,26 +589,12 @@ using namespace llvm::sys::detail::x86;
640589
static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
641590
unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
642591
unsigned *rEDX) {
643-
#if defined(__GNUC__) || defined(__clang__)
644-
#if defined(__x86_64__)
645-
// gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
646-
// FIXME: should we save this for Clang?
647-
__asm__("movq\t%%rbx, %%rsi\n\t"
648-
"cpuid\n\t"
649-
"xchgq\t%%rbx, %%rsi\n\t"
650-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
651-
: "a"(value), "c"(subleaf));
652-
return false;
653-
#elif defined(__i386__)
654-
__asm__("movl\t%%ebx, %%esi\n\t"
655-
"cpuid\n\t"
656-
"xchgl\t%%ebx, %%esi\n\t"
657-
: "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
658-
: "a"(value), "c"(subleaf));
659-
return false;
660-
#else
661-
return true;
662-
#endif
592+
// TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
593+
// are such that __cpuidex is defined within cpuid.h for both, we can remove
594+
// the __get_cpuid_count function and share the MSVC implementation between
595+
// all three.
596+
#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER)
597+
return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX);
663598
#elif defined(_MSC_VER)
664599
int registers[4];
665600
__cpuidex(registers, value, subleaf);
@@ -675,6 +610,9 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
675610

676611
// Read control register 0 (XCR0). Used to detect features such as AVX.
677612
static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
613+
// TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
614+
// are such that _xgetbv is supported by both, we can unify the implementation
615+
// with MSVC and remove all inline assembly.
678616
#if defined(__GNUC__) || defined(__clang__)
679617
// Check xgetbv; this uses a .byte sequence instead of the instruction
680618
// directly because older assemblers do not include support for xgetbv and

0 commit comments

Comments
 (0)