Skip to content

Commit f6616e9

Browse files
Reland "Revert "[compiler-rt][X86] Use functions in cpuid.h instead of inline assembly (llvm#97877)""
This reverts commit 2039e13. This relands commit 19cf8de. Added some additional preprocessor directives to ensure that Host.cpp only includes cpuid.h when being built on x86.
1 parent 07bb044 commit f6616e9

File tree

2 files changed

+30
-150
lines changed
  • compiler-rt/lib/builtins/cpu_model
  • llvm/lib/TargetParser

2 files changed

+30
-150
lines changed

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

Lines changed: 14 additions & 72 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__)
27+
#include <cpuid.h>
28+
#endif
29+
2630
#ifdef _MSC_VER
2731
#include <intrin.h>
2832
#endif
@@ -224,38 +228,6 @@ 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

@@ -264,25 +236,7 @@ static bool isCpuIdSupported(void) {
264236
static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
265237
unsigned *rECX, unsigned *rEDX) {
266238
#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
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) {
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.
306264
#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
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: 16 additions & 78 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__)
55+
#include <cpuid.h>
56+
#endif
57+
#endif
5358

5459
#define DEBUG_TYPE "host-detection"
5560

@@ -521,68 +526,15 @@ StringRef sys::detail::getHostCPUNameForBPF() {
521526
#endif
522527
}
523528

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

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

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

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

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

0 commit comments

Comments
 (0)