base/dispatch.c: Check operating system support for XMM registers.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 30 May 2015 19:26:39 +0000 (20:26 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 20 Jul 2015 12:54:22 +0000 (13:54 +0100)
I found a technique for doing this described by Agner Fog: see

http://www.agner.org/optimize/#manual_asm

which is conveniently independent of any particular system.  Quite why
Intel don't document this clearly is something of a mystery to me.

base/dispatch.c

index 08c189c..87d41b3 100644 (file)
@@ -43,6 +43,7 @@
 
 #define EFLAGS_ID (1u << 21)
 #define CPUID1D_SSE2 (1u << 26)
+#define CPUID1D_FXSR (1u << 24)
 
 struct cpuid { unsigned a, b, c, d; };
 
@@ -107,6 +108,30 @@ static int cpuid_features_p(unsigned dbits, unsigned cbits)
   return ((c.d & dbits) == dbits && (c.c & cbits) == cbits);
 }
 
+static int xmm_registers_available_p(void)
+{
+#ifdef __GNUC__
+  unsigned f;
+  /* This hack is by Agner Fog.  Use FXSAVE/FXRSTOR to figure out whether the
+   * XMM registers are actually alive.
+   */
+  if (!cpuid_features_p(CPUID1D_FXSR, 0)) return (0);
+  __asm__ ("movl %%esp, %%edx; subl $512, %%esp; andl $~15, %%esp\n"
+          "fxsave (%%esp)\n"
+          "movl 160(%%esp), %%eax; xorl $0xaaaa5555, 160(%%esp)\n"
+          "fxrstor (%%esp); fxsave (%%esp)\n"
+          "movl 160(%%esp), %%ecx; movl %%eax, 160(%%esp)\n"
+          "fxrstor (%%esp); movl %%edx, %%esp\n"
+          "xorl %%ecx, %%eax"
+          : "=a" (f)
+          : /* no inputs */
+          : "%ecx", "%edx");
+  return (f);
+#else
+  return (0);
+#endif
+}
+
 #endif
 
 /* --- @check_env@ --- *
@@ -168,7 +193,8 @@ int cpu_feature_p(int feat)
 #ifdef CPUFAM_X86
     case CPUFEAT_X86_SSE2: {
       CHECK_ENV("x86:sse2");
-      return (cpuid_features_p(CPUID1D_SSE2, 0));
+      return (xmm_registers_available_p() &&
+             cpuid_features_p(CPUID1D_SSE2, 0));
     }
 #endif
     default: