]> granicus.if.org Git - clang/commitdiff
Fix bugs in cpuid.h.
authorAkira Hatanaka <ahatanaka@apple.com>
Sat, 20 Sep 2014 01:31:09 +0000 (01:31 +0000)
committerAkira Hatanaka <ahatanaka@apple.com>
Sat, 20 Sep 2014 01:31:09 +0000 (01:31 +0000)
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

lib/Headers/cpuid.h
test/Headers/cpuid.c [new file with mode: 0644]

index f9254e9738e7487189ab0b47bc1df3602b5dbeef..5f3b01a9e5a636f9f76c5e54f50f153e3a4c4033 100644 (file)
 #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 (file)
index 0000000..b0ba07a
--- /dev/null
@@ -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 <cpuid.h>
+
+// 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);
+}