11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/*
21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2000 SuSE, Inc.
31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright © 2007 Red Hat, Inc.
41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission to use, copy, modify, distribute, and sell this software and its
61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation for any purpose is hereby granted without fee, provided that
71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the above copyright notice appear in all copies and that both that
81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copyright notice and this permission notice appear in supporting
91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * documentation, and that the name of SuSE not be used in advertising or
101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * publicity pertaining to distribution of the software without specific,
111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * written prior permission.  SuSE makes no representations about the
121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * suitability of this software for any purpose.  It is provided "as is"
131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * without express or implied warranty.
141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *
151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_CONFIG_H
231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <config.h>
241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "pixman-private.h"
271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#if defined(USE_X86_MMX) || defined (USE_SSE2)
291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* The CPU detection code needs to be in a file not compiled with
311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * that would lead to SIGILL instructions on old CPUs that don't have
331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * it.
341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */
351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
361176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef enum
371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    X86_MMX			= (1 << 0),
391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    X86_MMX_EXTENSIONS		= (1 << 1),
401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    X86_SSE			= (1 << 2) | X86_MMX_EXTENSIONS,
411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    X86_SSE2			= (1 << 3),
421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    X86_CMOV			= (1 << 4)
431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} cpu_features_t;
441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_GETISAX
461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <sys/auxv.h>
481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
491176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic cpu_features_t
501176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdetect_cpu_features (void)
511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cpu_features_t features = 0;
531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    unsigned int result = 0;
541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (getisax (&result, 1))
561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (result & AV_386_CMOV)
581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    features |= X86_CMOV;
591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (result & AV_386_MMX)
601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    features |= X86_MMX;
611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (result & AV_386_AMD_MMX)
621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    features |= X86_MMX_EXTENSIONS;
631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (result & AV_386_SSE)
641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    features |= X86_SSE;
651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (result & AV_386_SSE2)
661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    features |= X86_SSE2;
671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return features;
701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#else
731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define _PIXMAN_X86_64							\
751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    (defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
771176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic pixman_bool_t
781176bdada62cabc6ec4b0308a930e83b679d5d36John Reckhave_cpuid (void)
791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#if _PIXMAN_X86_64 || defined (_MSC_VER)
811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return TRUE;
831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#elif defined (__GNUC__)
851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t result;
861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    __asm__ volatile (
881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "pushf"				"\n\t"
891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "pop %%eax"			"\n\t"
901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "mov %%eax, %%ecx"		"\n\t"
911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "xor $0x00200000, %%eax"	"\n\t"
921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "push %%eax"			"\n\t"
931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "popf"				"\n\t"
941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "pushf"				"\n\t"
951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "pop %%eax"			"\n\t"
961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "xor %%ecx, %%eax"		"\n\t"
971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	"mov %%eax, %0"			"\n\t"
981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	: "=r" (result)
991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	:
1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	: "%eax", "%ecx");
1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return !!result;
1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#else
1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#error "Unknown compiler"
1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void
1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_cpuid (uint32_t feature,
1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	      uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#if defined (__GNUC__)
1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#if _PIXMAN_X86_64
1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    __asm__ volatile (
1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck        "cpuid"				"\n\t"
1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	: "a" (feature));
1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#else
1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* On x86-32 we need to be careful about the handling of %ebx
1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * and %esp. We can't declare either one as clobbered
1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * since they are special registers (%ebx is the "PIC
1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * register" holding an offset to global data, %esp the
1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * stack pointer), so we need to make sure that %ebx is
1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * preserved, and that %esp has its original value when
1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     * accessing the output operands.
1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck     */
1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    __asm__ volatile (
1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	"xchg %%ebx, %1"		"\n\t"
1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	"cpuid"				"\n\t"
1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	"xchg %%ebx, %1"		"\n\t"
1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	: "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	: "a" (feature));
1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#elif defined (_MSC_VER)
1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    int info[4];
1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    __cpuid (info, feature);
1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    *a = info[0];
1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    *b = info[1];
1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    *c = info[2];
1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    *d = info[3];
1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#else
1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#error Unknown compiler
1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic cpu_features_t
1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reckdetect_cpu_features (void)
1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    uint32_t a, b, c, d;
1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    cpu_features_t features = 0;
1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!have_cpuid())
1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	return features;
1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* Get feature bits */
1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    pixman_cpuid (0x01, &a, &b, &c, &d);
1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (d & (1 << 15))
1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	features |= X86_CMOV;
1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (d & (1 << 23))
1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	features |= X86_MMX;
1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (d & (1 << 25))
1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	features |= X86_SSE;
1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (d & (1 << 26))
1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	features |= X86_SSE2;
1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    /* Check for AMD specific features */
1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if ((features & X86_MMX) && !(features & X86_SSE))
1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	char vendor[13];
1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	/* Get vendor string */
1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	memset (vendor, 0, sizeof vendor);
1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	pixman_cpuid (0x00, &a, &b, &c, &d);
1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	memcpy (vendor + 0, &b, 4);
1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	memcpy (vendor + 4, &d, 4);
1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	memcpy (vendor + 8, &c, 4);
1831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	if (strcmp (vendor, "AuthenticAMD") == 0 ||
1851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    strcmp (vendor, "Geode by NSC") == 0)
1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	{
1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    pixman_cpuid (0x80000000, &a, &b, &c, &d);
1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    if (a >= 0x80000001)
1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    {
1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		pixman_cpuid (0x80000001, &a, &b, &c, &d);
1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		if (d & (1 << 22))
1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck		    features |= X86_MMX_EXTENSIONS;
1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	    }
1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	}
1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return features;
1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2031176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic pixman_bool_t
2041176bdada62cabc6ec4b0308a930e83b679d5d36John Reckhave_feature (cpu_features_t feature)
2051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
2061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    static pixman_bool_t initialized;
2071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    static cpu_features_t features;
2081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!initialized)
2101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    {
2111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	features = detect_cpu_features();
2121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	initialized = TRUE;
2131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    }
2141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return (features & feature) == feature;
2161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
2171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
2191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2201176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_implementation_t *
2211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck_pixman_x86_get_implementations (pixman_implementation_t *imp)
2221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{
2231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define MMX_BITS  (X86_MMX | X86_MMX_EXTENSIONS)
2241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
2251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef USE_X86_MMX
2271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
2281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	imp = _pixman_implementation_create_mmx (imp);
2291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
2301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef USE_SSE2
2321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
2331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck	imp = _pixman_implementation_create_sse2 (imp);
2341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif
2351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck
2361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck    return imp;
2371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}
238