Fix posix_memalign checks.
[ardour.git] / libs / pbd / fpu.cc
1 #include "libpbd-config.h"
2
3 #define _XOPEN_SOURCE 600
4 #include <cstring> // for memset
5 #include <cstdlib>
6 #include <stdint.h>
7 #include <assert.h>
8
9 #include "pbd/fpu.h"
10 #include "pbd/error.h"
11
12 #include "i18n.h"
13
14 using namespace PBD;
15 using namespace std;
16
17 FPU::FPU ()
18 {
19         unsigned long cpuflags = 0;
20
21         _flags = Flags (0);
22
23 #if !( (defined __x86_64__) || (defined __i386__) ) // !ARCH_X86
24         return;
25 #else
26
27         
28 #ifndef _LP64 //USE_X86_64_ASM
29         asm volatile (
30                 "mov $1, %%eax\n"
31                 "pushl %%ebx\n"
32                 "cpuid\n"
33                 "movl %%edx, %0\n"
34                 "popl %%ebx\n"
35                 : "=r" (cpuflags)
36                 : 
37                 : "%eax", "%ecx", "%edx"
38                 );
39         
40 #else
41         
42         /* asm notes: although we explicitly save&restore rbx, we must tell
43            gcc that ebx,rbx is clobbered so that it doesn't try to use it as an intermediate
44            register when storing rbx. gcc 4.3 didn't make this "mistake", but gcc 4.4
45            does, at least on x86_64.
46         */
47
48         asm volatile (
49                 "pushq %%rbx\n"
50                 "movq $1, %%rax\n"
51                 "cpuid\n"
52                 "movq %%rdx, %0\n"
53                 "popq %%rbx\n"
54                 : "=r" (cpuflags)
55                 : 
56                 : "%rax", "%rbx", "%rcx", "%rdx"
57                 );
58
59 #endif /* USE_X86_64_ASM */
60
61         if (cpuflags & (1<<25)) {
62                 _flags = Flags (_flags | (HasSSE|HasFlushToZero));
63         }
64
65         if (cpuflags & (1<<26)) {
66                 _flags = Flags (_flags | HasSSE2);
67         }
68
69         if (cpuflags & (1 << 24)) {
70                 
71                 char** fxbuf = 0;
72                 
73                 /* DAZ wasn't available in the first version of SSE. Since
74                    setting a reserved bit in MXCSR causes a general protection
75                    fault, we need to be able to check the availability of this
76                    feature without causing problems. To do this, one needs to
77                    set up a 512-byte area of memory to save the SSE state to,
78                    using fxsave, and then one needs to inspect bytes 28 through
79                    31 for the MXCSR_MASK value. If bit 6 is set, DAZ is
80                    supported, otherwise, it isn't.
81                 */
82                 
83 #ifndef HAVE_POSIX_MEMALIGN
84                 fxbuf = (char **) malloc (sizeof (char *));
85                 assert (fxbuf);
86                 *fxbuf = (char *) malloc (512);
87                 assert (*fxbuf);
88 #else
89                 posix_memalign ((void **) &fxbuf, 16, sizeof (char *));
90                 assert (fxbuf);
91                 posix_memalign ((void **) fxbuf, 16, 512);
92                 assert (*fxbuf);
93 #endif                  
94                 
95                 memset (*fxbuf, 0, 512);
96                 
97                 asm volatile (
98                         "fxsave (%0)"
99                         :
100                         : "r" (*fxbuf)
101                         : "memory"
102                         );
103                 
104                 uint32_t mxcsr_mask = *((uint32_t*) &((*fxbuf)[28]));
105                 
106                 /* if the mask is zero, set its default value (from intel specs) */
107                 
108                 if (mxcsr_mask == 0) {
109                         mxcsr_mask = 0xffbf;
110                 }
111                 
112                 if (mxcsr_mask & (1<<6)) {
113                         _flags = Flags (_flags | HasDenormalsAreZero);
114                 } 
115                 
116                 free (*fxbuf);
117                 free (fxbuf);
118         }
119 #endif
120 }                       
121
122 FPU::~FPU ()
123 {
124 }