diff options
Diffstat (limited to 'libs/pbd/fpu.cc')
-rw-r--r-- | libs/pbd/fpu.cc | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/libs/pbd/fpu.cc b/libs/pbd/fpu.cc new file mode 100644 index 0000000000..ae69b62e8d --- /dev/null +++ b/libs/pbd/fpu.cc @@ -0,0 +1,92 @@ +#define _XOPEN_SOURCE 600 +#include <stdlib.h> +#include <stdint.h> + +#include <pbd/fpu.h> +#include <pbd/error.h> + +#include "i18n.h" + +using namespace PBD; +using namespace std; + +FPU::FPU () +{ + unsigned long cpuflags = 0; + + _flags = Flags (0); + +#ifndef ARCH_X86 + return; +#endif + +#ifndef USE_X86_64_ASM + asm volatile ( + "mov $1, %%eax\n" + "pushl %%ebx\n" + "cpuid\n" + "movl %%edx, %0\n" + "popl %%ebx\n" + : "=r" (cpuflags) + : + : "%eax", "%ecx", "%edx", "memory" + ); + +#else + + asm volatile ( + "pushq %%rbx\n" + "movq $1, %%rax\n" + "cpuid\n" + "movq %%rdx, %0\n" + "popq %%rbx\n" + : "=r" (cpuflags) + : + : "%rax", "%rcx", "%rdx", "memory" + ); + +#endif /* USE_X86_64_ASM */ + + if (cpuflags & (1<<25)) { + _flags = Flags (_flags | (HasSSE|HasFlushToZero)); + } + + if (cpuflags & (1<<26)) { + _flags = Flags (_flags | HasSSE2); + } + + if (cpuflags & (1 << 24)) { + + char* fxbuf = 0; + + if (posix_memalign ((void**)&fxbuf, 16, 512)) { + error << _("cannot allocate 16 byte aligned buffer for h/w feature detection") << endmsg; + } else { + + 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); + } + } +} + +FPU::~FPU () +{ +} |