|
Packit |
030a23 |
/*
|
|
Packit |
030a23 |
* Copyright © 2000 SuSE, Inc.
|
|
Packit |
030a23 |
* Copyright © 2007 Red Hat, Inc.
|
|
Packit |
030a23 |
*
|
|
Packit |
030a23 |
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
Packit |
030a23 |
* documentation for any purpose is hereby granted without fee, provided that
|
|
Packit |
030a23 |
* the above copyright notice appear in all copies and that both that
|
|
Packit |
030a23 |
* copyright notice and this permission notice appear in supporting
|
|
Packit |
030a23 |
* documentation, and that the name of SuSE not be used in advertising or
|
|
Packit |
030a23 |
* publicity pertaining to distribution of the software without specific,
|
|
Packit |
030a23 |
* written prior permission. SuSE makes no representations about the
|
|
Packit |
030a23 |
* suitability of this software for any purpose. It is provided "as is"
|
|
Packit |
030a23 |
* without express or implied warranty.
|
|
Packit |
030a23 |
*
|
|
Packit |
030a23 |
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
|
Packit |
030a23 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
|
|
Packit |
030a23 |
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
Packit |
030a23 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
Packit |
030a23 |
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
Packit |
030a23 |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
030a23 |
*/
|
|
Packit |
030a23 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
030a23 |
#include <config.h>
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#include "pixman-private.h"
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#if defined(USE_X86_MMX) || defined (USE_SSE2) || defined (USE_SSSE3)
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
/* The CPU detection code needs to be in a file not compiled with
|
|
Packit |
030a23 |
* "-mmmx -msse", as gcc would generate CMOV instructions otherwise
|
|
Packit |
030a23 |
* that would lead to SIGILL instructions on old CPUs that don't have
|
|
Packit |
030a23 |
* it.
|
|
Packit |
030a23 |
*/
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
typedef enum
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
X86_MMX = (1 << 0),
|
|
Packit |
030a23 |
X86_MMX_EXTENSIONS = (1 << 1),
|
|
Packit |
030a23 |
X86_SSE = (1 << 2) | X86_MMX_EXTENSIONS,
|
|
Packit |
030a23 |
X86_SSE2 = (1 << 3),
|
|
Packit |
030a23 |
X86_CMOV = (1 << 4),
|
|
Packit |
030a23 |
X86_SSSE3 = (1 << 5)
|
|
Packit |
030a23 |
} cpu_features_t;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#ifdef HAVE_GETISAX
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#include <sys/auxv.h>
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
static cpu_features_t
|
|
Packit |
030a23 |
detect_cpu_features (void)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
cpu_features_t features = 0;
|
|
Packit |
030a23 |
unsigned int result = 0;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
if (getisax (&result, 1))
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
if (result & AV_386_CMOV)
|
|
Packit |
030a23 |
features |= X86_CMOV;
|
|
Packit |
030a23 |
if (result & AV_386_MMX)
|
|
Packit |
030a23 |
features |= X86_MMX;
|
|
Packit |
030a23 |
if (result & AV_386_AMD_MMX)
|
|
Packit |
030a23 |
features |= X86_MMX_EXTENSIONS;
|
|
Packit |
030a23 |
if (result & AV_386_SSE)
|
|
Packit |
030a23 |
features |= X86_SSE;
|
|
Packit |
030a23 |
if (result & AV_386_SSE2)
|
|
Packit |
030a23 |
features |= X86_SSE2;
|
|
Packit |
030a23 |
if (result & AV_386_SSSE3)
|
|
Packit |
030a23 |
features |= X86_SSSE3;
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
return features;
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#else
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#define _PIXMAN_X86_64 \
|
|
Packit |
030a23 |
(defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
static pixman_bool_t
|
|
Packit |
030a23 |
have_cpuid (void)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
#if _PIXMAN_X86_64 || defined (_MSC_VER)
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
return TRUE;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#elif defined (__GNUC__)
|
|
Packit |
030a23 |
uint32_t result;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
__asm__ volatile (
|
|
Packit |
030a23 |
"pushf" "\n\t"
|
|
Packit |
030a23 |
"pop %%eax" "\n\t"
|
|
Packit |
030a23 |
"mov %%eax, %%ecx" "\n\t"
|
|
Packit |
030a23 |
"xor $0x00200000, %%eax" "\n\t"
|
|
Packit |
030a23 |
"push %%eax" "\n\t"
|
|
Packit |
030a23 |
"popf" "\n\t"
|
|
Packit |
030a23 |
"pushf" "\n\t"
|
|
Packit |
030a23 |
"pop %%eax" "\n\t"
|
|
Packit |
030a23 |
"xor %%ecx, %%eax" "\n\t"
|
|
Packit |
030a23 |
"mov %%eax, %0" "\n\t"
|
|
Packit |
030a23 |
: "=r" (result)
|
|
Packit |
030a23 |
:
|
|
Packit |
030a23 |
: "%eax", "%ecx");
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
return !!result;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#else
|
|
Packit |
030a23 |
#error "Unknown compiler"
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
static void
|
|
Packit |
030a23 |
pixman_cpuid (uint32_t feature,
|
|
Packit |
030a23 |
uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
#if defined (__GNUC__)
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#if _PIXMAN_X86_64
|
|
Packit |
030a23 |
__asm__ volatile (
|
|
Packit |
030a23 |
"cpuid" "\n\t"
|
|
Packit |
030a23 |
: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
|
|
Packit |
030a23 |
: "a" (feature));
|
|
Packit |
030a23 |
#else
|
|
Packit |
030a23 |
/* On x86-32 we need to be careful about the handling of %ebx
|
|
Packit |
030a23 |
* and %esp. We can't declare either one as clobbered
|
|
Packit |
030a23 |
* since they are special registers (%ebx is the "PIC
|
|
Packit |
030a23 |
* register" holding an offset to global data, %esp the
|
|
Packit |
030a23 |
* stack pointer), so we need to make sure that %ebx is
|
|
Packit |
030a23 |
* preserved, and that %esp has its original value when
|
|
Packit |
030a23 |
* accessing the output operands.
|
|
Packit |
030a23 |
*/
|
|
Packit |
030a23 |
__asm__ volatile (
|
|
Packit |
030a23 |
"xchg %%ebx, %1" "\n\t"
|
|
Packit |
030a23 |
"cpuid" "\n\t"
|
|
Packit |
030a23 |
"xchg %%ebx, %1" "\n\t"
|
|
Packit |
030a23 |
: "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
|
|
Packit |
030a23 |
: "a" (feature));
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#elif defined (_MSC_VER)
|
|
Packit |
030a23 |
int info[4];
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
__cpuid (info, feature);
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
*a = info[0];
|
|
Packit |
030a23 |
*b = info[1];
|
|
Packit |
030a23 |
*c = info[2];
|
|
Packit |
030a23 |
*d = info[3];
|
|
Packit |
030a23 |
#else
|
|
Packit |
030a23 |
#error Unknown compiler
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
static cpu_features_t
|
|
Packit |
030a23 |
detect_cpu_features (void)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
uint32_t a, b, c, d;
|
|
Packit |
030a23 |
cpu_features_t features = 0;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
if (!have_cpuid())
|
|
Packit |
030a23 |
return features;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
/* Get feature bits */
|
|
Packit |
030a23 |
pixman_cpuid (0x01, &a, &b, &c, &d);
|
|
Packit |
030a23 |
if (d & (1 << 15))
|
|
Packit |
030a23 |
features |= X86_CMOV;
|
|
Packit |
030a23 |
if (d & (1 << 23))
|
|
Packit |
030a23 |
features |= X86_MMX;
|
|
Packit |
030a23 |
if (d & (1 << 25))
|
|
Packit |
030a23 |
features |= X86_SSE;
|
|
Packit |
030a23 |
if (d & (1 << 26))
|
|
Packit |
030a23 |
features |= X86_SSE2;
|
|
Packit |
030a23 |
if (c & (1 << 9))
|
|
Packit |
030a23 |
features |= X86_SSSE3;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
/* Check for AMD specific features */
|
|
Packit |
030a23 |
if ((features & X86_MMX) && !(features & X86_SSE))
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
char vendor[13];
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
/* Get vendor string */
|
|
Packit |
030a23 |
memset (vendor, 0, sizeof vendor);
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
pixman_cpuid (0x00, &a, &b, &c, &d);
|
|
Packit |
030a23 |
memcpy (vendor + 0, &b, 4);
|
|
Packit |
030a23 |
memcpy (vendor + 4, &d, 4);
|
|
Packit |
030a23 |
memcpy (vendor + 8, &c, 4);
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
if (strcmp (vendor, "AuthenticAMD") == 0 ||
|
|
Packit |
030a23 |
strcmp (vendor, "Geode by NSC") == 0)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
pixman_cpuid (0x80000000, &a, &b, &c, &d);
|
|
Packit |
030a23 |
if (a >= 0x80000001)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
pixman_cpuid (0x80000001, &a, &b, &c, &d);
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
if (d & (1 << 22))
|
|
Packit |
030a23 |
features |= X86_MMX_EXTENSIONS;
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
return features;
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
static pixman_bool_t
|
|
Packit |
030a23 |
have_feature (cpu_features_t feature)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
static pixman_bool_t initialized;
|
|
Packit |
030a23 |
static cpu_features_t features;
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
if (!initialized)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
features = detect_cpu_features();
|
|
Packit |
030a23 |
initialized = TRUE;
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
return (features & feature) == feature;
|
|
Packit |
030a23 |
}
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
pixman_implementation_t *
|
|
Packit |
030a23 |
_pixman_x86_get_implementations (pixman_implementation_t *imp)
|
|
Packit |
030a23 |
{
|
|
Packit |
030a23 |
#define MMX_BITS (X86_MMX | X86_MMX_EXTENSIONS)
|
|
Packit |
030a23 |
#define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
|
|
Packit |
030a23 |
#define SSSE3_BITS (X86_SSE | X86_SSE2 | X86_SSSE3)
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#ifdef USE_X86_MMX
|
|
Packit |
030a23 |
if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
|
|
Packit |
030a23 |
imp = _pixman_implementation_create_mmx (imp);
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#ifdef USE_SSE2
|
|
Packit |
030a23 |
if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
|
|
Packit |
030a23 |
imp = _pixman_implementation_create_sse2 (imp);
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
#ifdef USE_SSSE3
|
|
Packit |
030a23 |
if (!_pixman_disabled ("ssse3") && have_feature (SSSE3_BITS))
|
|
Packit |
030a23 |
imp = _pixman_implementation_create_ssse3 (imp);
|
|
Packit |
030a23 |
#endif
|
|
Packit |
030a23 |
|
|
Packit |
030a23 |
return imp;
|
|
Packit |
030a23 |
}
|