2010-11-10 18:13:29 -05:00
|
|
|
#include "libpbd-config.h"
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
#define _XOPEN_SOURCE 600
|
2009-12-31 12:51:27 -05:00
|
|
|
#include <cstring> // for memset
|
2008-09-10 11:03:30 -04:00
|
|
|
#include <cstdlib>
|
2008-06-02 17:41:35 -04:00
|
|
|
#include <stdint.h>
|
|
|
|
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "pbd/fpu.h"
|
|
|
|
#include "pbd/error.h"
|
2008-06-02 17:41:35 -04:00
|
|
|
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
|
|
using namespace PBD;
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
FPU::FPU ()
|
|
|
|
{
|
|
|
|
unsigned long cpuflags = 0;
|
|
|
|
|
|
|
|
_flags = Flags (0);
|
|
|
|
|
2011-12-02 15:38:31 -05:00
|
|
|
#if !( (defined __x86_64__) || (defined __i386__) ) // !ARCH_X86
|
2008-06-02 17:41:35 -04:00
|
|
|
return;
|
2011-12-02 15:38:31 -05:00
|
|
|
#else
|
2009-12-31 12:51:27 -05:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
|
2011-12-02 15:38:31 -05:00
|
|
|
#ifndef _LP64 //USE_X86_64_ASM
|
2008-06-02 17:41:35 -04:00
|
|
|
asm volatile (
|
|
|
|
"mov $1, %%eax\n"
|
|
|
|
"pushl %%ebx\n"
|
|
|
|
"cpuid\n"
|
|
|
|
"movl %%edx, %0\n"
|
|
|
|
"popl %%ebx\n"
|
|
|
|
: "=r" (cpuflags)
|
|
|
|
:
|
2009-12-31 13:16:03 -05:00
|
|
|
: "%eax", "%ecx", "%edx"
|
2008-06-02 17:41:35 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2009-12-31 13:19:46 -05:00
|
|
|
/* asm notes: although we explicitly save&restore rbx, we must tell
|
|
|
|
gcc that ebx,rbx is clobbered so that it doesn't try to use it as an intermediate
|
|
|
|
register when storing rbx. gcc 4.3 didn't make this "mistake", but gcc 4.4
|
|
|
|
does, at least on x86_64.
|
|
|
|
*/
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
asm volatile (
|
|
|
|
"pushq %%rbx\n"
|
|
|
|
"movq $1, %%rax\n"
|
|
|
|
"cpuid\n"
|
|
|
|
"movq %%rdx, %0\n"
|
|
|
|
"popq %%rbx\n"
|
|
|
|
: "=r" (cpuflags)
|
|
|
|
:
|
2009-12-31 12:51:27 -05:00
|
|
|
: "%rax", "%rbx", "%rcx", "%rdx"
|
2008-06-02 17:41:35 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
#endif /* USE_X86_64_ASM */
|
2009-12-31 12:51:27 -05:00
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
if (cpuflags & (1<<25)) {
|
|
|
|
_flags = Flags (_flags | (HasSSE|HasFlushToZero));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cpuflags & (1<<26)) {
|
|
|
|
_flags = Flags (_flags | HasSSE2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cpuflags & (1 << 24)) {
|
|
|
|
|
|
|
|
char* fxbuf = 0;
|
|
|
|
|
|
|
|
#ifdef NO_POSIX_MEMALIGN
|
|
|
|
if ((fxbuf = (char *) malloc(512)) == 0)
|
|
|
|
#else
|
|
|
|
if (posix_memalign ((void**)&fxbuf, 16, 512))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
error << _("cannot allocate 16 byte aligned buffer for h/w feature detection") << endmsg;
|
|
|
|
} else {
|
|
|
|
|
2009-12-31 12:51:27 -05:00
|
|
|
memset (fxbuf, 0, 512);
|
|
|
|
|
2008-06-02 17:41:35 -04:00
|
|
|
asm volatile (
|
|
|
|
"fxsave (%0)"
|
|
|
|
:
|
|
|
|
: "r" (fxbuf)
|
|
|
|
: "memory"
|
|
|
|
);
|
|
|
|
|
|
|
|
uint32_t mxcsr_mask = *((uint32_t*) &fxbuf[28]);
|
|
|
|
|
|
|
|
/* if the mask is zero, set its default value (from intel specs) */
|
|
|
|
|
|
|
|
if (mxcsr_mask == 0) {
|
|
|
|
mxcsr_mask = 0xffbf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mxcsr_mask & (1<<6)) {
|
|
|
|
_flags = Flags (_flags | HasDenormalsAreZero);
|
|
|
|
}
|
|
|
|
|
|
|
|
free (fxbuf);
|
|
|
|
}
|
|
|
|
}
|
2011-12-02 15:38:31 -05:00
|
|
|
#endif
|
2008-06-02 17:41:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
FPU::~FPU ()
|
|
|
|
{
|
|
|
|
}
|