Skip to content

Commit 2039e13

Browse files
Revert "[compiler-rt][X86] Use functions in cpuid.h instead of inline assembly (llvm#97877)"
This reverts commit 19cf8de. This was causing quite a few buildbot failures (see the PR description). Reverting for now while I have time to sort it out. Seems like it should just be conditional preprocessor macros for X86 however.
1 parent 19cf8de commit 2039e13

File tree

2 files changed

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

2 files changed

+150
-28
lines changed

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

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

2424
#include <assert.h>
2525

26-
#if defined(__GNUC__) || defined(__clang__)
27-
#include <cpuid.h>
28-
#endif
29-
3026
#ifdef _MSC_VER
3127
#include <intrin.h>
3228
#endif
@@ -228,6 +224,38 @@ enum ProcessorFeatures {
228224
CPU_FEATURE_MAX
229225
};
230226

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+
231259
// This code is copied from lib/Support/Host.cpp.
232260
// Changes to either file should be mirrored in the other.
233261

@@ -236,7 +264,25 @@ enum ProcessorFeatures {
236264
static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
237265
unsigned *rECX, unsigned *rEDX) {
238266
#if defined(__GNUC__) || defined(__clang__)
239-
return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX);
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
240286
#elif defined(_MSC_VER)
241287
// The MSVC intrinsic is portable across x86 and x64.
242288
int registers[4];
@@ -257,12 +303,26 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
257303
static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
258304
unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
259305
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.
264306
#if defined(__GNUC__) || defined(__clang__)
265-
return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX);
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
266326
#elif defined(_MSC_VER)
267327
int registers[4];
268328
__cpuidex(registers, value, subleaf);
@@ -278,9 +338,6 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
278338

279339
// Read control register 0 (XCR0). Used to detect features such as AVX.
280340
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.
284341
#if defined(__GNUC__) || defined(__clang__)
285342
// Check xgetbv; this uses a .byte sequence instead of the instruction
286343
// directly because older assemblers do not include support for xgetbv and
@@ -1051,7 +1108,8 @@ int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {
10511108
if (__cpu_model.__cpu_vendor)
10521109
return 0;
10531110

1054-
if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
1111+
if (!isCpuIdSupported() ||
1112+
getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
10551113
__cpu_model.__cpu_vendor = VENDOR_OTHER;
10561114
return -1;
10571115
}

llvm/lib/TargetParser/Host.cpp

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@
5050
#if defined(__sun__) && defined(__svr4__)
5151
#include <kstat.h>
5252
#endif
53-
#if defined(__GNUC__) || defined(__clang__)
54-
#include <cpuid.h>
55-
#endif
5653

5754
#define DEBUG_TYPE "host-detection"
5855

@@ -524,15 +521,68 @@ StringRef sys::detail::getHostCPUNameForBPF() {
524521
#endif
525522
}
526523

527-
#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \
528-
defined(_M_X64)
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+
}
529561

530562
/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
531563
/// the specified arguments. If we can't run cpuid on the host, return true.
532564
static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
533565
unsigned *rECX, unsigned *rEDX) {
534566
#if defined(__GNUC__) || defined(__clang__)
535-
return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX);
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
536586
#elif defined(_MSC_VER)
537587
// The MSVC intrinsic is portable across x86 and x64.
538588
int registers[4];
@@ -559,6 +609,9 @@ VendorSignatures getVendorSignature(unsigned *MaxLeaf) {
559609
else
560610
*MaxLeaf = 0;
561611

612+
if (!isCpuIdSupported())
613+
return VendorSignatures::UNKNOWN;
614+
562615
if (getX86CpuIDAndInfo(0, MaxLeaf, &EBX, &ECX, &EDX) || *MaxLeaf < 1)
563616
return VendorSignatures::UNKNOWN;
564617

@@ -586,12 +639,26 @@ using namespace llvm::sys::detail::x86;
586639
static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
587640
unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
588641
unsigned *rEDX) {
589-
// TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
590-
// are such that __cpuidex is defined within cpuid.h for both, we can remove
591-
// the __get_cpuid_count function and share the MSVC implementation between
592-
// all three.
593642
#if defined(__GNUC__) || defined(__clang__)
594-
return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX);
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
595662
#elif defined(_MSC_VER)
596663
int registers[4];
597664
__cpuidex(registers, value, subleaf);
@@ -607,9 +674,6 @@ static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
607674

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

0 commit comments

Comments
 (0)