merge with master.
[ardour.git] / libs / pbd / msvc / fpu.cc
1 #ifdef COMPILER_MSVC  // Added by JE - 05-12-2009. Inline assembler instructions
2                       // have been changed to Intel format and (in the case of
3                       // cpuid) was replaced by the equivalent VC++ system call).
4 #define _XOPEN_SOURCE 600
5 #include <cstdlib>
6 #include <stdint.h>
7 #include <intrin.h>  // Added by JE - 05-12-2009
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 #ifndef ARCH_X86
24         return;
25
26 #else
27
28 #ifndef USE_X86_64_ASM
29 int cpuInfo[4];
30
31         __cpuid (cpuInfo, 1);
32         cpuflags = cpuInfo[3];
33 /*
34         __asm {  // This is how the original section would look if converted to Intel syntax.
35              // However, I have grave doubts about whether it's doing the right thing.
36              // It seems as if the intention was to retrieve feature information from
37              // the processor. However, feature information is returned in the ebx register
38              // (if you believe Wikipedia) or in edx (if you believe Microsoft). Unfortunately,
39              // both registers get ignored in the original code!! Confused?? Join the club!!
40                 mov   eax, 1
41                 push  ebx
42                 cpuid
43                 mov   edx, 0
44                 pop   ebx
45                 mov   cpuflags, ecx // This can't be right, surely???
46         }; */
47 #else
48 // Note that this syntax is currently still in AT&T format !
49         asm volatile (
50                 "pushq %%rbx\n"
51                 "movq $1, %%rax\n"
52                 "cpuid\n"
53                 "movq %%rdx, %0\n"
54                 "popq %%rbx\n"
55                 : "=r" (cpuflags)
56                 :
57                 : "%rax", "%rcx", "%rdx", "memory"
58                 );
59
60 #endif /* USE_X86_64_ASM */
61
62         if (cpuflags & (1<<25)) {
63                 _flags = Flags (_flags | (HasSSE|HasFlushToZero));
64         }
65
66         if (cpuflags & (1<<26)) {
67                 _flags = Flags (_flags | HasSSE2);
68         }
69
70         if (cpuflags & (1 << 24)) {
71                 bool  aligned_malloc = false; // Added by JE - 05-12-2009
72                 char* fxbuf = 0;
73 // This section changed by JE - 05-12-2009
74 #ifdef NO_POSIX_MEMALIGN
75 #if defined(COMPILER_MSVC) || defined(COMPILER_MINGW)       // All of these support '_aligned_malloc()'
76                 fxbuf = (char *) _aligned_malloc(512, 16);  // (note that they all need at least MSVC runtime 7.0)
77                 aligned_malloc = true;
78 #else
79                 fxbuf = (char *) malloc(512);
80 #endif
81 #else
82                 fxbuf = posix_memalign ((void**)&fxbuf, 16, 512);
83 #endif
84                 // Verify that fxbuf is correctly aligned
85                 unsigned long buf_addr = (unsigned long)(void*)fxbuf;
86                 if ((0 == buf_addr) || (buf_addr % 16))
87                         error << _("cannot allocate 16 byte aligned buffer for h/w feature detection") << endmsg;
88                 else
89                 {
90                         memset(fxbuf, 0, 512); // Initialize the buffer !!! Added by JE - 12-12-2009
91
92                         __asm {
93                                 mov eax, fxbuf
94                                 fxsave   [eax]
95                         };
96
97                         uint32_t mxcsr_mask = *((uint32_t*) &fxbuf[28]);
98
99                         /* if the mask is zero, set its default value (from intel specs) */
100
101                         if (mxcsr_mask == 0) {
102                                 mxcsr_mask = 0xffbf;
103                         }
104
105                         if (mxcsr_mask & (1<<6)) {
106                                 _flags = Flags (_flags | HasDenormalsAreZero);
107                         }
108
109                         if (aligned_malloc)
110                                 _aligned_free (fxbuf);
111                         else
112                                 free (fxbuf);
113                 }
114         }
115 #endif  // ARCH_X86
116 }
117
118 FPU::~FPU ()
119 {
120 }
121
122 #else  // !COMPILER_MSVC
123         const char* pbd_fpu = "original pbd/fpu.cc takes precedence over this file";
124 #endif // COMPILER_MSVC