From: Søren Sandmann Pedersen s...@redhat.com
A new function pixman_cpuid() is added that runs the cpuid instruction
and returns the results.
On GCC this function uses inline assembly that is written such that it
will work on both 32 and 64 bit. Compared to the old code, the only
difference is %ebx is saved in %esi instead of on the stack. Saving 32
bit registers on a 64 bit stack is difficult or impossible because in
64 bit mode, the push and pop instructions work on 64 bit registers.
On MSVC, the function calls the __cpuid intrinsic.
There is also a new function called have_cpuid() which detects whether
cpuid is available. On x86-64 and MSVC, it simply returns TRUE; on
x86-32 bit, it checks whether the 22nd bit of eflags can be
modified. On MSVC this does have the consequence that pixman will no
longer work CPUS without cpuid (ie., older than 486 and some 486
models).
These two functions together makes it possible to write a generic
detect_cpu_features() in plain C. This function is then used in a new
have_feature() function that checks whether a specific set of feature
bits is available.
Aside from the cleanups and simplifications, the main benefit from
this patch is that pixman now can do feature detection on x86-64, so
that newer instruction sets such as SSSE3 and SSE4.1 can be used. (And
apparently the assumption that x86-64 CPUs always have MMX and SSE2 is
no longer correct: Knight's Corner is x86-64, but doesn't have them).
---
pixman/pixman-x86.c | 311 +--
1 file changed, 129 insertions(+), 182 deletions(-)
diff --git a/pixman/pixman-x86.c b/pixman/pixman-x86.c
index 52ad3df..84590d2 100644
--- a/pixman/pixman-x86.c
+++ b/pixman/pixman-x86.c
@@ -32,30 +32,25 @@
* that would lead to SIGILL instructions on old CPUs that don't have
* it.
*/
-#if !defined(__amd64__) !defined(__x86_64__) !defined(_M_AMD64)
-
-#ifdef HAVE_GETISAX
-#include sys/auxv.h
-#endif
typedef enum
{
-NO_FEATURES = 0,
-MMX = 0x1,
-MMX_EXTENSIONS = 0x2,
-SSE = 0x6,
-SSE2 = 0x8,
-CMOV = 0x10
+X86_MMX= (1 0),
+X86_MMX_EXTENSIONS = (1 1),
+X86_SSE= (1 2) | X86_MMX_EXTENSIONS,
+X86_SSE2 = (1 3),
+X86_CMOV = (1 4)
} cpu_features_t;
+#ifdef HAVE_GETISAX
-static unsigned int
+#include sys/auxv.h
+
+static cpu_features_t
detect_cpu_features (void)
{
-unsigned int features = 0;
-unsigned int result = 0;
-
-#ifdef HAVE_GETISAX
+cpu_features_t features;
+
if (getisax (result, 1))
{
if (result AV_386_CMOV)
@@ -69,15 +64,47 @@ detect_cpu_features (void)
if (result AV_386_SSE2)
features |= SSE2;
}
+
+return features;
+}
+
+#else
+
+static pixman_bool_t
+have_cpuid (void)
+{
+#if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) || defined
(_MSC_VER)
+
+return TRUE;
+
+#elif defined (__GNUC__)
+uint32_t result;
+
+__asm__ volatile (
+pushf\n\t
+pop %%eax\n\t
+mov %%eax, %%ecx \n\t
+xor $0x0020, %%eax \n\t
+push %%eax \n\t
+popf \n\t
+pushf\n\t
+pop %%eax\n\t
+xor %%ecx, %%eax \n\t
+ mov %%eax, %0 \n\t
+ : =r (result)
+ :
+ : %eax, %ecx);
+
+return !!result;
+
#else
-char vendor[13];
-#ifdef _MSC_VER
-int vendor0 = 0, vendor1, vendor2;
+#error Unknown compiler
#endif
-vendor[0] = 0;
-vendor[12] = 0;
-
-#ifdef __GNUC__
+}
+
+static void
+pixman_cpuid (uint32_t feature, uint32_t *a, uint32_t *b, uint32_t *c,
uint32_t *d)
+{
/* see p. 118 of amd64 instruction set manual Vol3 */
/* We need to be careful about the handling of %ebx and
* %esp here. We can't declare either one as clobbered
@@ -86,195 +113,115 @@ detect_cpu_features (void)
* stack pointer), so we need to make sure they have their
* original values when we access the output operands.
*/
-__asm__ (
-pushf\n
-pop %%eax\n
-mov %%eax, %%ecx\n
-xor $0x0020, %%eax\n
-push %%eax\n
-popf\n
-pushf\n
-pop %%eax\n
-mov $0x0, %%edx\n
-xor %%ecx, %%eax\n
-jz 1f\n
-
-mov $0x, %%eax\n
-push %%ebx\n
-cpuid\n
-mov %%ebx, %%eax\n
-pop %%ebx\n
-mov %%eax, %1\n
-mov %%edx, %2\n
-mov %%ecx, %3\n
-mov $0x0001, %%eax\n
-push %%ebx\n
-cpuid\n
-pop %%ebx\n
-1:\n
-mov %%edx, %0\n
- : =r (result),
- =m (vendor[0]),
- =m (vendor[4]),
- =m (vendor[8])
- :
- : %eax, %ecx, %edx
-);
-
+#if defined