gfx/cairo/libpixman/src/pixman-x86.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*
     2  * Copyright © 2000 SuSE, Inc.
     3  * Copyright © 2007 Red Hat, Inc.
     4  *
     5  * Permission to use, copy, modify, distribute, and sell this software and its
     6  * documentation for any purpose is hereby granted without fee, provided that
     7  * the above copyright notice appear in all copies and that both that
     8  * copyright notice and this permission notice appear in supporting
     9  * documentation, and that the name of SuSE not be used in advertising or
    10  * publicity pertaining to distribution of the software without specific,
    11  * written prior permission.  SuSE makes no representations about the
    12  * suitability of this software for any purpose.  It is provided "as is"
    13  * without express or implied warranty.
    14  *
    15  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
    16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
    17  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
    19  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
    20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    21  */
    22 #ifdef HAVE_CONFIG_H
    23 #include <config.h>
    24 #endif
    26 #include "pixman-private.h"
    28 #if defined(USE_X86_MMX) || defined (USE_SSE2)
    30 /* The CPU detection code needs to be in a file not compiled with
    31  * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
    32  * that would lead to SIGILL instructions on old CPUs that don't have
    33  * it.
    34  */
    36 typedef enum
    37 {
    38     X86_MMX			= (1 << 0),
    39     X86_MMX_EXTENSIONS		= (1 << 1),
    40     X86_SSE			= (1 << 2) | X86_MMX_EXTENSIONS,
    41     X86_SSE2			= (1 << 3),
    42     X86_CMOV			= (1 << 4)
    43 } cpu_features_t;
    45 #ifdef HAVE_GETISAX
    47 #include <sys/auxv.h>
    49 static cpu_features_t
    50 detect_cpu_features (void)
    51 {
    52     cpu_features_t features = 0;
    53     unsigned int result = 0;
    55     if (getisax (&result, 1))
    56     {
    57 	if (result & AV_386_CMOV)
    58 	    features |= X86_CMOV;
    59 	if (result & AV_386_MMX)
    60 	    features |= X86_MMX;
    61 	if (result & AV_386_AMD_MMX)
    62 	    features |= X86_MMX_EXTENSIONS;
    63 	if (result & AV_386_SSE)
    64 	    features |= X86_SSE;
    65 	if (result & AV_386_SSE2)
    66 	    features |= X86_SSE2;
    67     }
    69     return features;
    70 }
    72 #else
    74 #define _PIXMAN_X86_64							\
    75     (defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
    77 static pixman_bool_t
    78 have_cpuid (void)
    79 {
    80 #if _PIXMAN_X86_64 || defined (_MSC_VER)
    82     return TRUE;
    84 #elif defined (__GNUC__)
    85     uint32_t result;
    87     __asm__ volatile (
    88         "pushf"				"\n\t"
    89         "pop %%eax"			"\n\t"
    90         "mov %%eax, %%ecx"		"\n\t"
    91         "xor $0x00200000, %%eax"	"\n\t"
    92         "push %%eax"			"\n\t"
    93         "popf"				"\n\t"
    94         "pushf"				"\n\t"
    95         "pop %%eax"			"\n\t"
    96         "xor %%ecx, %%eax"		"\n\t"
    97 	"mov %%eax, %0"			"\n\t"
    98 	: "=r" (result)
    99 	:
   100 	: "%eax", "%ecx");
   102     return !!result;
   104 #else
   105 #error "Unknown compiler"
   106 #endif
   107 }
   109 static void
   110 pixman_cpuid (uint32_t feature,
   111 	      uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
   112 {
   113 #if defined (__GNUC__)
   115 #if _PIXMAN_X86_64
   116     __asm__ volatile (
   117         "cpuid"				"\n\t"
   118 	: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
   119 	: "a" (feature));
   120 #else
   121     /* On x86-32 we need to be careful about the handling of %ebx
   122      * and %esp. We can't declare either one as clobbered
   123      * since they are special registers (%ebx is the "PIC
   124      * register" holding an offset to global data, %esp the
   125      * stack pointer), so we need to make sure that %ebx is
   126      * preserved, and that %esp has its original value when
   127      * accessing the output operands.
   128      */
   129     __asm__ volatile (
   130 	"xchg %%ebx, %1"		"\n\t"
   131 	"cpuid"				"\n\t"
   132 	"xchg %%ebx, %1"		"\n\t"
   133 	: "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
   134 	: "a" (feature));
   135 #endif
   137 #elif defined (_MSC_VER)
   138     int info[4];
   140     __cpuid (info, feature);
   142     *a = info[0];
   143     *b = info[1];
   144     *c = info[2];
   145     *d = info[3];
   146 #else
   147 #error Unknown compiler
   148 #endif
   149 }
   151 static cpu_features_t
   152 detect_cpu_features (void)
   153 {
   154     uint32_t a, b, c, d;
   155     cpu_features_t features = 0;
   157     if (!have_cpuid())
   158 	return features;
   160     /* Get feature bits */
   161     pixman_cpuid (0x01, &a, &b, &c, &d);
   162     if (d & (1 << 15))
   163 	features |= X86_CMOV;
   164     if (d & (1 << 23))
   165 	features |= X86_MMX;
   166     if (d & (1 << 25))
   167 	features |= X86_SSE;
   168     if (d & (1 << 26))
   169 	features |= X86_SSE2;
   171     /* Check for AMD specific features */
   172     if ((features & X86_MMX) && !(features & X86_SSE))
   173     {
   174 	char vendor[13];
   176 	/* Get vendor string */
   177 	memset (vendor, 0, sizeof vendor);
   179 	pixman_cpuid (0x00, &a, &b, &c, &d);
   180 	memcpy (vendor + 0, &b, 4);
   181 	memcpy (vendor + 4, &d, 4);
   182 	memcpy (vendor + 8, &c, 4);
   184 	if (strcmp (vendor, "AuthenticAMD") == 0 ||
   185 	    strcmp (vendor, "Geode by NSC") == 0)
   186 	{
   187 	    pixman_cpuid (0x80000000, &a, &b, &c, &d);
   188 	    if (a >= 0x80000001)
   189 	    {
   190 		pixman_cpuid (0x80000001, &a, &b, &c, &d);
   192 		if (d & (1 << 22))
   193 		    features |= X86_MMX_EXTENSIONS;
   194 	    }
   195 	}
   196     }
   198     return features;
   199 }
   201 #endif
   203 static pixman_bool_t
   204 have_feature (cpu_features_t feature)
   205 {
   206     static pixman_bool_t initialized;
   207     static cpu_features_t features;
   209     if (!initialized)
   210     {
   211 	features = detect_cpu_features();
   212 	initialized = TRUE;
   213     }
   215     return (features & feature) == feature;
   216 }
   218 #endif
   220 pixman_implementation_t *
   221 _pixman_x86_get_implementations (pixman_implementation_t *imp)
   222 {
   223 #define MMX_BITS  (X86_MMX | X86_MMX_EXTENSIONS)
   224 #define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
   226 #ifdef USE_X86_MMX
   227     if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
   228 	imp = _pixman_implementation_create_mmx (imp);
   229 #endif
   231 #ifdef USE_SSE2
   232     if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
   233 	imp = _pixman_implementation_create_sse2 (imp);
   234 #endif
   236     return imp;
   237 }

mercurial