configure.ac, base/dispatch.[ch]: CPU-specific implementations.
[catacomb] / base / dispatch.h
diff --git a/base/dispatch.h b/base/dispatch.h
new file mode 100644 (file)
index 0000000..bcf9a13
--- /dev/null
@@ -0,0 +1,162 @@
+/* -*-c-*-
+ *
+ * CPU-specific dispatch
+ *
+ * (c) 2015 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_DISPATCH_H
+#define CATACOMB_DISPATCH_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/macros.h>
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- Atomic data access machinery --- *
+ *
+ * If they're available, use GCC's `__atomic_*' intrinsics.  If that doesn't
+ * work and we're using one of a small number of processors I'm sure won't
+ * mind, then just stick with simple memory access.  Otherwise turn
+ * dispatching off, because it probably isn't thread-safe.
+ */
+
+#if GCC_VERSION_P(4, 7)
+#  define CPU_DISPATCH_P 1
+#  define DISPATCH_LOAD(g, v)                                          \
+       ((v) = __atomic_load_n(&(g), __ATOMIC_RELAXED))
+#  define DISPATCH_STORE(g, v)                                         \
+       (__atomic_store_n(&(g), (v), __ATOMIC_RELAXED))
+#elif defined(__i386__) || defined(__amd64__) ||                       \
+      defined(__arm__) || defined(__aarch64__) ||                      \
+      defined(__mips__)
+#  define CPU_DISPATCH_P 1
+#  define DISPATCH_LOAD(g, v) ((v) = (g))
+#  define DISPATCH_STORE(g, v) ((g) = (v))
+#endif
+
+/* --- A simple hack --- */
+
+#ifndef EMPTY
+#  define EMPTY
+#endif
+
+/* --- @CPU_DISPATCH@ --- *
+ *
+ * Arguments:  @stcls@ = storage class for the main @ext@ function
+ *                     (typically either @static@ or @EMPTY@)
+ *             @rtn@ = prefix for tail-calling a function of the appropriate
+ *                     type (either @(void)@ or @return@)
+ *             @ret@ = return type for the function
+ *             @ext@ = name for the main function (other named are derived
+ *                     from this)
+ *             @argdecls@ = parenthesis-enclosed list of argument types
+ *             @args@ = parenthesis-enclosed list of argument names only
+ *             @pick@ = function to select appropriate implementation
+ *             @dflt@ = fallback implementation
+ *
+ * Use:                Main machinery for CPU-specfic dispatching.
+ *
+ *             The macro defines a function
+ *
+ *                     @stcls ret ext argdcls@
+ *
+ *             The first time @ext@ is called, it will invoke @pick@ to
+ *             select and a return a pointer to an appropriate
+ *             implementation for the runtime environment.  Subsequent calls
+ *             to @ext@ will (usually) call this preferred implementation
+ *             directly.
+ *
+ *             Some target platforms may not be able to establish the
+ *             necessary function pointer in a threadsafe way.  On such
+ *             platforms, the dispatch machinery is disabled and @ext@ will
+ *             simply call @dflt@.
+ *
+ *             Some additional declarations are made.  As a convenience,
+ *             @ext__functype@ is the function type of @ext@.  Declarations
+ *             are made for @pick@ and @dflt@, as @static@ functions.
+ */
+
+#ifdef CPU_DISPATCH_P
+
+#define CPU_DISPATCH(stcls, rtn, ret, ext, argdecls, args, pick, dflt) \
+                                                                       \
+typedef ret ext##__functype argdecls;                                  \
+static ret dflt argdecls;                                              \
+static ret ext##__dispatch argdecls;                                   \
+static ext##__functype *pick(void);                                    \
+static ext##__functype *ext##__ptr = ext##__dispatch;                  \
+                                                                       \
+static ret ext##__dispatch argdecls                                    \
+{                                                                      \
+  ext##__functype *f = pick();                                         \
+  DISPATCH_STORE(ext##__ptr, f);                                       \
+  rtn f args;                                                          \
+}                                                                      \
+                                                                       \
+stcls ret ext argdecls                                                 \
+{                                                                      \
+  ext##__functype *f;                                                  \
+  DISPATCH_LOAD(ext##__ptr, f);                                                \
+  rtn f args;                                                          \
+}
+
+#else
+
+#define CPU_DISPATCH(stcls, rtn, ret, ext, argdecls, args, pick, dflt) \
+                                                                       \
+typedef ret ext##__functype argdecls;                                  \
+static ret dflt argdecls;                                              \
+static ext##__functype *pick(void) IGNORABLE;                          \
+                                                                       \
+stcls ret ext argdecls { rtn dflt args; }
+
+#endif
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @cpu_feature_p@ --- *
+ *
+ * Arguments:  @unsigned feat@ = a @CPUFEAT_...@ code
+ *
+ * Returns:    Nonzero if the feature is available.
+ */
+
+enum {
+  CPUFEAT_X86_SSE2                     /* Streaming SIMD Extensions 2 */
+};
+
+extern int cpu_feature_p(int /*feat*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif