base/dispatch.c, rand/rand.c, and asm: Support `rdseed' for quick noise.
[catacomb] / base / dispatch.h
CommitLineData
08e2be29
MW
1/* -*-c-*-
2 *
3 * CPU-specific dispatch
4 *
5 * (c) 2015 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28#ifndef CATACOMB_DISPATCH_H
29#define CATACOMB_DISPATCH_H
30
31#ifdef __cplusplus
32 extern "C" {
33#endif
34
35/*----- Header files ------------------------------------------------------*/
36
37#include <mLib/macros.h>
38
39/*----- Macros ------------------------------------------------------------*/
40
41/* --- Atomic data access machinery --- *
42 *
43 * If they're available, use GCC's `__atomic_*' intrinsics. If that doesn't
44 * work and we're using one of a small number of processors I'm sure won't
45 * mind, then just stick with simple memory access. Otherwise turn
46 * dispatching off, because it probably isn't thread-safe.
47 */
48
49#if GCC_VERSION_P(4, 7)
50# define CPU_DISPATCH_P 1
51# define DISPATCH_LOAD(g, v) \
52 ((v) = __atomic_load_n(&(g), __ATOMIC_RELAXED))
53# define DISPATCH_STORE(g, v) \
54 (__atomic_store_n(&(g), (v), __ATOMIC_RELAXED))
55#elif defined(__i386__) || defined(__amd64__) || \
56 defined(__arm__) || defined(__aarch64__) || \
57 defined(__mips__)
58# define CPU_DISPATCH_P 1
59# define DISPATCH_LOAD(g, v) ((v) = (g))
60# define DISPATCH_STORE(g, v) ((g) = (v))
61#endif
62
63/* --- A simple hack --- */
64
65#ifndef EMPTY
66# define EMPTY
67#endif
68
69/* --- @CPU_DISPATCH@ --- *
70 *
71 * Arguments: @stcls@ = storage class for the main @ext@ function
72 * (typically either @static@ or @EMPTY@)
73 * @rtn@ = prefix for tail-calling a function of the appropriate
74 * type (either @(void)@ or @return@)
75 * @ret@ = return type for the function
76 * @ext@ = name for the main function (other named are derived
77 * from this)
78 * @argdecls@ = parenthesis-enclosed list of argument types
79 * @args@ = parenthesis-enclosed list of argument names only
80 * @pick@ = function to select appropriate implementation
81 * @dflt@ = fallback implementation
82 *
83 * Use: Main machinery for CPU-specfic dispatching.
84 *
85 * The macro defines a function
86 *
87 * @stcls ret ext argdcls@
88 *
89 * The first time @ext@ is called, it will invoke @pick@ to
90 * select and a return a pointer to an appropriate
91 * implementation for the runtime environment. Subsequent calls
92 * to @ext@ will (usually) call this preferred implementation
93 * directly.
94 *
95 * Some target platforms may not be able to establish the
96 * necessary function pointer in a threadsafe way. On such
97 * platforms, the dispatch machinery is disabled and @ext@ will
98 * simply call @dflt@.
99 *
100 * Some additional declarations are made. As a convenience,
101 * @ext__functype@ is the function type of @ext@. Declarations
102 * are made for @pick@ and @dflt@, as @static@ functions.
103 */
104
105#ifdef CPU_DISPATCH_P
106
107#define CPU_DISPATCH(stcls, rtn, ret, ext, argdecls, args, pick, dflt) \
108 \
109typedef ret ext##__functype argdecls; \
110static ret dflt argdecls; \
111static ret ext##__dispatch argdecls; \
112static ext##__functype *pick(void); \
113static ext##__functype *ext##__ptr = ext##__dispatch; \
114 \
115static ret ext##__dispatch argdecls \
116{ \
117 ext##__functype *f = pick(); \
118 DISPATCH_STORE(ext##__ptr, f); \
119 rtn f args; \
120} \
121 \
122stcls ret ext argdecls \
123{ \
124 ext##__functype *f; \
125 DISPATCH_LOAD(ext##__ptr, f); \
126 rtn f args; \
127}
128
129#else
130
131#define CPU_DISPATCH(stcls, rtn, ret, ext, argdecls, args, pick, dflt) \
132 \
133typedef ret ext##__functype argdecls; \
134static ret dflt argdecls; \
135static ext##__functype *pick(void) IGNORABLE; \
136 \
137stcls ret ext argdecls { rtn dflt args; }
138
139#endif
140
fac645f7
MW
141/* --- Some macros for producing useful debugging --- */
142
143#define DISPATCH_PICK_COND(what, func, cond) do { \
144 if (cond) { \
145 dispatch_debug("picked `%s' for `%s'", #func, #what); \
146 return (func); \
147 } \
148} while (0)
149#define DISPATCH_PICK_FALLBACK(what, func) do { \
150 dispatch_debug("using default `%s'", #what); \
151 return (func); \
152} while (0)
153
08e2be29
MW
154/*----- Functions provided ------------------------------------------------*/
155
fac645f7
MW
156/* --- @dispatch_debug@ --- *
157 *
158 * Arguments: @const char *fmt@ = a format string
159 * @...@ = additional arguments
160 *
161 * Returns: ---
162 *
163 * Use: Writes a formatted message to standard output if dispatch
164 * debugging is enabled.
165 */
166
167extern void dispatch_debug(const char */*fmt*/, ...);
168
08e2be29
MW
169/* --- @cpu_feature_p@ --- *
170 *
171 * Arguments: @unsigned feat@ = a @CPUFEAT_...@ code
172 *
173 * Returns: Nonzero if the feature is available.
174 */
175
176enum {
226639f3 177 CPUFEAT_X86_SSE2, /* Streaming SIMD Extensions 2 */
61bd904b
MW
178 CPUFEAT_X86_AESNI, /* AES Native Instructions */
179 CPUFEAT_ARM_VFP, /* VFP floating-point (v3 or v4) */
180 CPUFEAT_ARM_NEON, /* Advanced SIMD (v1 or v2) */
181 CPUFEAT_ARM_V4, /* VFPv4 and/or SIMD v2 */
d25653be 182 CPUFEAT_ARM_D32, /* 32 double registers, not 16 */
6c0946ef 183 CPUFEAT_X86_RDRAND, /* Built-in cooked entropy source */
b9b279b4 184 CPUFEAT_ARM_AES, /* AES instructions */
9e6a4409
MW
185 CPUFEAT_X86_AVX, /* AVX 1 (i.e., 256-bit YMM regs) */
186 CPUFEAT_X86_SSSE3, /* Supplementary SSE 3 */
187 CPUFEAT_X86_PCLMUL, /* Carry-less multiplication */
6c0946ef
MW
188 CPUFEAT_ARM_PMULL, /* Polynomial multiplication */
189 CPUFEAT_X86_RDSEED /* Built-in raw entropy source */
08e2be29
MW
190};
191
192extern int cpu_feature_p(int /*feat*/);
193
194/*----- That's all, folks -------------------------------------------------*/
195
196#ifdef __cplusplus
197 }
198#endif
199
200#endif