[Pixman] [PATCH 08/10] Cleanups and simplifications in x86 CPU feature detection

2012-06-29 Thread Søren Sandmann Pedersen
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 

Re: [Pixman] [PATCH 08/10] Cleanups and simplifications in x86 CPU feature detection

2012-06-29 Thread Søren Sandmann
Alan Coopersmith alan.coopersm...@oracle.com writes:

 Don't you need to update the feature flags set in the getisax code to match
 the renaming you did to cpu_features_t ?

Yes, I do, and I also need to initialize features to 0 and reinstate the
results variable.


Thanks,
Soren
___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman


Re: [Pixman] [PATCH 08/10] Cleanups and simplifications in x86 CPU feature detection

2012-06-29 Thread Alan Coopersmith
On 06/29/12 01:44 PM, Søren Sandmann Pedersen wrote:
  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;
  }
 +

Don't you need to update the feature flags set in the getisax code to match
the renaming you did to cpu_features_t ?

-- 
-Alan Coopersmith-  alan.coopersm...@oracle.com
 Oracle Solaris Engineering - http://blogs.oracle.com/alanc
___
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman