From: Akira Hatanaka Date: Sat, 20 Sep 2014 01:31:09 +0000 (+0000) Subject: Fix bugs in cpuid.h. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4d43b42fa583e993d0445fb9a35f4bdfe62ffc01;p=clang Fix bugs in cpuid.h. This commit makes two changes: - Remove the push and pop instructions that were saving and restoring %ebx before and after cpuid in 32-bit pic mode. We were doing this to ensure we don't lose the GOT address in pic register %ebx, but this isn't necessary because the GOT address is kept in a virtual register. - In 64-bit mode, preserve base register %rbx around cpuid. This fixes PR20311 and rdar://problem/17686779. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218173 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h index f9254e9738..5f3b01a9e5 100644 --- a/lib/Headers/cpuid.h +++ b/lib/Headers/cpuid.h @@ -92,31 +92,29 @@ #define bit_SMEP 0x00000080 #define bit_ENH_MOVSB 0x00000200 -/* PIC on i386 uses %ebx, so preserve it. */ #if __i386__ #define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ - __asm(" pushl %%ebx\n" \ + __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ + : "0"(__level)) + +#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ + __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ + : "0"(__level), "2"(__count)) +#else +/* x86-64 uses %rbx as the base register, so preserve it. */ +#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ + __asm(" xchgq %%rbx,%q1\n" \ " cpuid\n" \ - " mov %%ebx,%1\n" \ - " popl %%ebx" \ + " xchgq %%rbx,%q1" \ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \ : "0"(__level)) #define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ - __asm(" pushl %%ebx\n" \ + __asm(" xchgq %%rbx,%q1\n" \ " cpuid\n" \ - " mov %%ebx,%1\n" \ - " popl %%ebx" \ + " xchgq %%rbx,%q1" \ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \ : "0"(__level), "2"(__count)) -#else -#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ - __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level)) - -#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ - __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level), "2"(__count)) #endif static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax, diff --git a/test/Headers/cpuid.c b/test/Headers/cpuid.c new file mode 100644 index 0000000000..b0ba07af2f --- /dev/null +++ b/test/Headers/cpuid.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -ffreestanding -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-64 +// RUN: %clang_cc1 %s -ffreestanding -triple i386 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-32 + +#include + +// CHECK-64: {{.*}} call { i32, i32, i32, i32 } asm " xchgq %rbx,${1:q}\0A cpuid\0A xchgq %rbx,${1:q}", "={ax},=r,={cx},={dx},0,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}}) +// CHECK-64: {{.*}} call { i32, i32, i32, i32 } asm " xchgq %rbx,${1:q}\0A cpuid\0A xchgq %rbx,${1:q}", "={ax},=r,={cx},={dx},0,2,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}}, i32 %{{[a-z0-9]+}}) + +// CHECK-32: {{.*}} call { i32, i32, i32, i32 } asm "cpuid", "={ax},={bx},={cx},={dx},0,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}}) +// CHECK-32: {{.*}} call { i32, i32, i32, i32 } asm "cpuid", "={ax},={bx},={cx},={dx},0,2,~{dirflag},~{fpsr},~{flags}"(i32 %{{[a-z0-9]+}}, i32 %{{[a-z0-9]+}}) + +unsigned eax0, ebx0, ecx0, edx0; +unsigned eax1, ebx1, ecx1, edx1; + +void test_cpuid(unsigned level, unsigned count) { + __cpuid(level, eax1, ebx1, ecx1, edx1); + __cpuid_count(level, count, eax0, ebx0, ecx0, edx0); +}