12400221ccbfb8b3afbcab1e0f425adcb34f9d8b
[ardour.git] / libs / pbd / fpu.cc
1 #define _XOPEN_SOURCE 600
2 #include <cstring> // for memset
3 #include <cstdlib>
4 #include <stdint.h>
5
6 #include "pbd/fpu.h"
7 #include "pbd/error.h"
8
9 #include "i18n.h"
10
11 using namespace PBD;
12 using namespace std;
13
14 FPU::FPU ()
15 {
16         unsigned long cpuflags = 0;
17
18         _flags = Flags (0);
19
20 #ifndef ARCH_X86
21         return;
22 #endif
23
24         /* asm notes: although we explicitly save&restore ebx/rbx (stack pointer), we must tell
25            gcc that ebx,rbx is clobbered so that it doesn't try to use it as an intermediate
26            register when storing edx/rdx. gcc 4.3 didn't make this "mistake", but gcc 4.4
27            does, at least on x86_64.
28         */
29         
30 #ifndef USE_X86_64_ASM
31         asm volatile (
32                 "mov $1, %%eax\n"
33                 "pushl %%ebx\n"
34                 "cpuid\n"
35                 "movl %%edx, %0\n"
36                 "popl %%ebx\n"
37                 : "=r" (cpuflags)
38                 : 
39                 : "%eax", "%ebx", "%ecx", "%edx"
40                 );
41         
42 #else
43         
44         asm volatile (
45                 "pushq %%rbx\n"
46                 "movq $1, %%rax\n"
47                 "cpuid\n"
48                 "movq %%rdx, %0\n"
49                 "popq %%rbx\n"
50                 : "=r" (cpuflags)
51                 : 
52                 : "%rax", "%rbx", "%rcx", "%rdx"
53                 );
54
55 #endif /* USE_X86_64_ASM */
56
57         if (cpuflags & (1<<25)) {
58                 _flags = Flags (_flags | (HasSSE|HasFlushToZero));
59         }
60
61         if (cpuflags & (1<<26)) {
62                 _flags = Flags (_flags | HasSSE2);
63         }
64
65         if (cpuflags & (1 << 24)) {
66                 
67                 char* fxbuf = 0;
68                 
69 #ifdef NO_POSIX_MEMALIGN
70                 if ((fxbuf = (char *) malloc(512)) == 0)
71 #else
72                 if (posix_memalign ((void**)&fxbuf, 16, 512)) 
73 #endif                  
74                 {
75                         error << _("cannot allocate 16 byte aligned buffer for h/w feature detection") << endmsg;
76                 } else {
77                         
78                         memset (fxbuf, 0, 512);
79
80                         asm volatile (
81                                 "fxsave (%0)"
82                                 :
83                                 : "r" (fxbuf)
84                                 : "memory"
85                                 );
86                         
87                         uint32_t mxcsr_mask = *((uint32_t*) &fxbuf[28]);
88                         
89                         /* if the mask is zero, set its default value (from intel specs) */
90                         
91                         if (mxcsr_mask == 0) {
92                                 mxcsr_mask = 0xffbf;
93                         }
94                         
95                         if (mxcsr_mask & (1<<6)) {
96                                 _flags = Flags (_flags | HasDenormalsAreZero);
97                         } 
98
99                         free (fxbuf);
100                 }
101         }
102 }                       
103
104 FPU::~FPU ()
105 {
106 }