/*
CPU features detection
Copyright (C) 2010 by Andrew Zabolotny
*/
#include "config.h"
#include "lensfun.h"
#include "lensfunprv.h"
#if defined (_MSC_VER)
#include <intrin.h>
guint _lf_detect_cpu_features ()
{
static guint cpuflags = -1;
#if defined(GLIB_CHECK_VERSION) && GLIB_CHECK_VERSION(2,32,0)
static GMutex lock;
g_mutex_lock (&lock);
#else
static GStaticMutex lock = G_STATIC_MUTEX_INIT;
g_static_mutex_lock (&lock);
#endif
if (cpuflags == (guint)-1)
{
cpuflags = 0;
int CPUInfo [4] = {-1};
__cpuid (CPUInfo, 0);
/* Are there are standard features? */
if (CPUInfo [0] >= 1)
{
/* Get the standard level */
__cpuid (CPUInfo, 1);
if (CPUInfo [3] & 0x800000)
cpuflags |= LF_CPU_FLAG_MMX;
if (CPUInfo [3] & 0x2000000)
cpuflags |= LF_CPU_FLAG_SSE;
if (CPUInfo [3] & 0x4000000)
cpuflags |= LF_CPU_FLAG_SSE2;
if (CPUInfo [3] & 0x8000)
cpuflags |= LF_CPU_FLAG_CMOV;
if (CPUInfo [2] & 0x1)
cpuflags |= LF_CPU_FLAG_SSE3;
if (CPUInfo [2] & 0x200)
cpuflags |= LF_CPU_FLAG_SSSE3;
if (CPUInfo [2] & 0x80000)
cpuflags |= LF_CPU_FLAG_SSE4_1;
if (CPUInfo [2] & 0x100000)
cpuflags |= LF_CPU_FLAG_SSE4_2;
/* Are there extensions? */
__cpuid (CPUInfo, 0x80000000);
if (CPUInfo [0] >= 1)
{
/* ask extensions */
__cpuid (CPUInfo, 0x80000001);
if (CPUInfo [3] & 0x80000000)
cpuflags |= LF_CPU_FLAG_3DNOW;
if (CPUInfo [3] & 0x40000000)
cpuflags |= LF_CPU_FLAG_3DNOW_EXT;
if (CPUInfo [3] & 0x00400000)
cpuflags |= LF_CPU_FLAG_AMD_ISSE;
};
};
};
#if defined(GLIB_CHECK_VERSION) && GLIB_CHECK_VERSION(2,32,0)
g_mutex_unlock (&lock);
#else
g_static_mutex_unlock (&lock);
#endif
return cpuflags;
};
#else
#if defined (__i386__) || defined (__x86_64__)
#ifdef __x86_64__
# define R_AX "rax"
# define R_BX "rbx"
# define R_CX "rcx"
# define R_DX "rdx"
#else
# define R_AX "eax"
# define R_BX "ebx"
# define R_CX "ecx"
# define R_DX "edx"
#endif
// Borrowed from RawStudio
guint _lf_detect_cpu_features ()
{
#define cpuid(cmd) \
__asm volatile ( \
"push %%"R_BX"\n" \
"cpuid\n" \
"pop %%"R_BX"\n" \
: "=a" (ax), "=c" (cx), "=d" (dx) \
: "0" (cmd))
#ifdef __x86_64__
guint64 ax, cx, dx, tmp;
#else
guint32 ax, cx, dx, tmp;
#endif
static guint cpuflags = -1;
#if defined(GLIB_CHECK_VERSION) && GLIB_CHECK_VERSION(2,32,0)
static GMutex lock;
g_mutex_lock (&lock);
#else
static GStaticMutex lock = G_STATIC_MUTEX_INIT;
g_static_mutex_lock (&lock);
#endif
if (cpuflags == (guint)-1)
{
cpuflags = 0;
/* Test cpuid presence by checking bit 21 of eflags */
__asm volatile (
"pushf\n"
"pop %0\n"
"mov %0, %1\n"
"xor $0x00200000, %0\n"
"push %0\n"
"popf\n"
"pushf\n"
"pop %0\n"
"cmp %0, %1\n"
"setne %%al\n"
"movzb %%al, %0\n"
: "=r" (ax), "=r" (tmp));
if (ax)
{
/* Get the standard level */
cpuid (0x00000000);
if (ax)
{
/* Request for standard features */
cpuid (0x00000001);
if (dx & 0x00800000)
cpuflags |= LF_CPU_FLAG_MMX;
if (dx & 0x02000000)
cpuflags |= LF_CPU_FLAG_SSE;
if (dx & 0x04000000)
cpuflags |= LF_CPU_FLAG_SSE2;
if (dx & 0x00008000)
cpuflags |= LF_CPU_FLAG_CMOV;
if (cx & 0x00000001)
cpuflags |= LF_CPU_FLAG_SSE3;
if (cx & 0x00000200)
cpuflags |= LF_CPU_FLAG_SSSE3;
if (cx & 0x00040000)
cpuflags |= LF_CPU_FLAG_SSE4_1;
if (cx & 0x00080000)
cpuflags |= LF_CPU_FLAG_SSE4_2;
}
/* Are there extensions? */
cpuid (0x80000000);
if (ax)
{
/* Ask extensions */
cpuid (0x80000001);
if (dx & 0x80000000)
cpuflags |= LF_CPU_FLAG_3DNOW;
if (dx & 0x40000000)
cpuflags |= LF_CPU_FLAG_3DNOW_EXT;
if (dx & 0x00400000)
cpuflags |= LF_CPU_FLAG_AMD_ISSE;
}
}
}
#if defined(GLIB_CHECK_VERSION) && GLIB_CHECK_VERSION(2,32,0)
g_mutex_unlock (&lock);
#else
g_static_mutex_unlock (&lock);
#endif
return cpuflags;
#undef cpuid
}
#endif /* __i386__ || __x86_64__ */
#endif