Blame pixman/pixman-x86.c

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
}