Merge windows+cc branch into cairocanvas branch. Not finished, need to now merge...
[ardour.git] / libs / pbd / fpu.cc
index 9ca59072214c6d4c74a63fdb21ebae30b757a063..73bc7e599d3313cdb215ad40824823c65deaf6b3 100644 (file)
@@ -1,7 +1,29 @@
+/*
+    Copyright (C) 2012 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef  COMPILER_MSVC
+#include "libpbd-config.h"
+
 #define _XOPEN_SOURCE 600
 #include <cstring> // for memset
 #include <cstdlib>
 #include <stdint.h>
+#include <assert.h>
 
 #include "pbd/fpu.h"
 #include "pbd/error.h"
@@ -17,17 +39,12 @@ FPU::FPU ()
 
        _flags = Flags (0);
 
-#ifndef ARCH_X86
+#if !( (defined __x86_64__) || (defined __i386__) ) // !ARCH_X86
        return;
-#endif
+#else
 
-       /* asm notes: although we explicitly save&restore ebx/rbx (stack pointer), we must tell
-          gcc that ebx,rbx is clobbered so that it doesn't try to use it as an intermediate
-          register when storing edx/rdx. gcc 4.3 didn't make this "mistake", but gcc 4.4
-          does, at least on x86_64.
-       */
        
-#ifndef USE_X86_64_ASM
+#ifndef _LP64 //USE_X86_64_ASM
        asm volatile (
                "mov $1, %%eax\n"
                "pushl %%ebx\n"
@@ -41,6 +58,12 @@ FPU::FPU ()
        
 #else
        
+       /* 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.
+       */
+
        asm volatile (
                "pushq %%rbx\n"
                "movq $1, %%rax\n"
@@ -64,43 +87,61 @@ FPU::FPU ()
 
        if (cpuflags & (1 << 24)) {
                
-               char* fxbuf = 0;
+               char** fxbuf = 0;
+               
+               /* DAZ wasn't available in the first version of SSE. Since
+                  setting a reserved bit in MXCSR causes a general protection
+                  fault, we need to be able to check the availability of this
+                  feature without causing problems. To do this, one needs to
+                  set up a 512-byte area of memory to save the SSE state to,
+                  using fxsave, and then one needs to inspect bytes 28 through
+                  31 for the MXCSR_MASK value. If bit 6 is set, DAZ is
+                  supported, otherwise, it isn't.
+               */
                
-#ifdef NO_POSIX_MEMALIGN
-               if ((fxbuf = (char *) malloc(512)) == 0)
+#ifndef HAVE_POSIX_MEMALIGN
+               fxbuf = (char **) malloc (sizeof (char *));
+               assert (fxbuf);
+               *fxbuf = (char *) malloc (512);
+               assert (*fxbuf);
 #else
-               if (posix_memalign ((void**)&fxbuf, 16, 512)) 
+               (void) posix_memalign ((void **) &fxbuf, 16, sizeof (char *));
+               assert (fxbuf);
+               (void) posix_memalign ((void **) fxbuf, 16, 512);
+               assert (*fxbuf);
 #endif                 
-               {
-                       error << _("cannot allocate 16 byte aligned buffer for h/w feature detection") << endmsg;
-               } else {
-                       
-                       memset (fxbuf, 0, 512);
-
-                       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);
+               
+               memset (*fxbuf, 0, 512);
+               
+               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);
+               free (fxbuf);
        }
+#endif
 }                      
 
 FPU::~FPU ()
 {
 }
+
+#else  // COMPILER_MSVC
+       const char* pbd_fpu = "pbd/msvc/fpu.cc takes precedence over this file";
+#endif // COMPILER_MSVC