base/dispatch.c: Make `cpuid_feature_p' more easily extensible.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 5 Apr 2020 23:52:56 +0000 (23:52 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 9 May 2020 19:57:33 +0000 (20:57 +0100)
It turns out that Intel scatter feature flags throughout the various
CPUID leaves.  Change the interface for checking these flags so that we
can cover more ground without too much extra work.

  * Firstly, rename the function to `cpuid_feature_p' because it's only
    really useful for checking one feature at a time.

  * Secondly, make the first argument be a code indicating which
    particular `cpuid' output we're interested in; the second is still a
    mask used to check for the bit we're interested in.

Obviously this involves changing all of the callers too.

base/dispatch.c

index 71a9da9..7652f32 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "config.h"
 
+#include <assert.h>
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 
+enum {
+  CPUID_1_D,                           /* eax = 1 => edx&?? */
 #  define CPUID1D_SSE2 (1u << 26)
 #  define CPUID1D_FXSR (1u << 24)
+
+  CPUID_1_C,                           /* eax = 1 => ecx&?? */
 #  define CPUID1C_PCLMUL (1u << 1)
 #  define CPUID1C_SSSE3 (1u << 9)
 #  define CPUID1C_AESNI (1u << 25)
 #  define CPUID1C_AVX (1u << 28)
 #  define CPUID1C_RDRAND (1u << 30)
 
+};
+
 struct cpuid { unsigned a, b, c, d; };
 extern int dispatch_x86ish_cpuid(struct cpuid *, unsigned a, unsigned c);
 extern int dispatch_x86ish_xmmregisters_p(void);
@@ -69,21 +76,33 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
 static unsigned cpuid_maxleaf(void)
   { struct cpuid c; cpuid(&c, 0, 0); return (c.a); }
 
-/* --- @cpuid_features_p@ --- *
+/* --- @cpuid_feature_p@ --- *
  *
- * Arguments:  @unsigned dbits@ = bits to check in EDX
- *             @unsigned cbits@ = bits to check in ECX
+ * Arguments:  @unsigned leaf@ = leaf to look up
+ *             @unsigned bits@ = bits to check
  *
- * Returns:    Nonzero if all the requested bits are set in the CPUID result
- *             on leaf 1.
+ * Returns:    Nonzero if all the requested bits are set in the requested
+ *             CPUID result.
  */
 
-static int cpuid_features_p(unsigned dbits, unsigned cbits)
+static int cpuid_feature_p(unsigned leaf, unsigned bits)
 {
   struct cpuid c;
-  if (cpuid_maxleaf() < 1) return (0);
-  cpuid(&c, 1, 0);
-  return ((c.d & dbits) == dbits && (c.c & cbits) == cbits);
+  unsigned r;
+
+  switch (leaf) {
+    case CPUID_1_D:
+      if (cpuid_maxleaf() < 1) return (0);
+      cpuid(&c, 1, 0); r = c.d;
+      break;
+    case CPUID_1_C:
+      if (cpuid_maxleaf() < 1) return (0);
+      cpuid(&c, 1, 0); r = c.c;
+      break;
+    default:
+      assert(!"unknown cpuid leaf");
+  }
+  return ((r&bits) == bits);
 }
 
 /* --- @xmm_registers_available_p@ --- *
@@ -483,21 +502,22 @@ int cpu_feature_p(int feat)
   switch (feat) {
 #if CPUFAM_X86 || CPUFAM_AMD64
     CASE_CPUFEAT(X86_SSE2, "x86:sse2",
-                cpuid_features_p(CPUID1D_SSE2, 0) &&
+                cpuid_feature_p(CPUID_1_D, CPUID1D_SSE2) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_AESNI, "x86:aesni",
-                cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI) &&
+                cpuid_feature_p(CPUID_1_D, CPUID1C_AESNI) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_RDRAND, "x86:rdrand",
-                cpuid_features_p(0, CPUID1C_RDRAND) && rdrand_works_p());
+                cpuid_feature_p(CPUID_1_C, CPUID1C_RDRAND) &&
+                rdrand_works_p());
     CASE_CPUFEAT(X86_AVX, "x86:avx",
-                cpuid_features_p(0, CPUID1C_AVX) &&
+                cpuid_feature_p(CPUID_1_C, CPUID1C_AVX) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_SSSE3, "x86:ssse3",
-                cpuid_features_p(0, CPUID1C_SSSE3) &&
+                cpuid_feature_p(CPUID_1_C, CPUID1C_SSSE3) &&
                 xmm_registers_available_p());
     CASE_CPUFEAT(X86_PCLMUL, "x86:pclmul",
-                cpuid_features_p(0, CPUID1C_PCLMUL) &&
+                cpuid_feature_p(CPUID_1_C, CPUID1C_PCLMUL) &&
                 xmm_registers_available_p());
 #endif
 #ifdef CAPMAP