#include "config.h"
#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __GNUC__
/* Stupid dance to detect whether the CPUID instruction is available. */
f = getflags();
- if (!(setflags(f | EFLAGS_ID) & EFLAGS_ID)) return;
- if ( setflags(f & ~EFLAGS_ID) & EFLAGS_ID ) return;
+ if (!(setflags(f | EFLAGS_ID) & EFLAGS_ID) ||
+ setflags(f & ~EFLAGS_ID) & EFLAGS_ID) {
+ dispatch_debug("CPUID instruction not available");
+ return;
+ }
setflags(f);
/* Alas, EBX is magical in PIC code, so abuse ESI instead. This isn't
__asm__ ("pushl %%ebx; cpuid; movl %%ebx, %%esi; popl %%ebx"
: "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d)
: "a" (a) , "c" (c));
+#else
+ dispatch_debug("GNU inline assembler not available; can't CPUID");
#endif
}
: "%ecx", "%edx");
return (f);
#else
+ dispatch_debug("GNU inline assembler not available; can't check for XMM");
return (0);
#endif
}
/*----- External interface ------------------------------------------------*/
+/* --- @dispatch_debug@ --- *
+ *
+ * Arguments: @const char *fmt@ = a format string
+ * @...@ = additional arguments
+ *
+ * Returns: ---
+ *
+ * Use: Writes a formatted message to standard output if dispatch
+ * debugging is enabled.
+ */
+
+void dispatch_debug(const char *fmt, ...)
+{
+ va_list ap;
+ const char *e = getenv("CATACOMB_CPUDISPATCH_DEBUG");
+
+ if (e && *e != 'n' && *e != '0') {
+ va_start(ap, fmt);
+ fputs("Catacomb CPUDISPATCH: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+ }
+}
+
/* --- @check_env@ --- *
*
* Arguments: @const char *ftok@ = feature token
#include <stdio.h>
+static int IGNORABLE
+ feat_debug(const char *ftok, const char *check, int verdict)
+{
+ if (verdict >= 0) {
+ dispatch_debug("feature `%s': %s -> %s", ftok, check,
+ verdict ? "available" : "absent");
+ }
+ return (verdict);
+}
+
int cpu_feature_p(int feat)
{
int IGNORABLE f;
IGNORE(f);
-#define CHECK_ENV(ftok) \
- do { if ((f = check_env(ftok)) >= 0) return (f); } while (0)
+#define CASE_CPUFEAT(feat, ftok, cond) case CPUFEAT_##feat: \
+ if ((f = feat_debug(ftok, "environment override", \
+ check_env(ftok))) >= 0) \
+ return (f); \
+ else \
+ return (feat_debug(ftok, "runtime probe", cond));
switch (feat) {
#ifdef CPUFAM_X86
- case CPUFEAT_X86_SSE2: {
- CHECK_ENV("x86:sse2");
- return (xmm_registers_available_p() &&
- cpuid_features_p(CPUID1D_SSE2, 0));
- }
- case CPUFEAT_X86_AESNI: {
- check_env("x86:aesni");
- return (xmm_registers_available_p() &&
- cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI));
- }
+ CASE_CPUFEAT(X86_SSE2, "x86:sse2",
+ xmm_registers_available_p() &&
+ cpuid_features_p(CPUID1D_SSE2, 0));
+ CASE_CPUFEAT(X86_AESNI, "x86:aesni",
+ xmm_registers_available_p() &&
+ cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI));
#endif
default:
+ dispatch_debug("denying unknown feature %d", feat);
return (0);
}
-#undef CHECK_ENV
+#undef CASE_CPUFEAT
}
/*----- That's all, folks -------------------------------------------------*/