progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / base / dispatch.h
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 \
109 typedef ret ext##__functype argdecls; \
110 static ret dflt argdecls; \
111 static ret ext##__dispatch argdecls; \
112 static ext##__functype *pick(void); \
113 static ext##__functype *ext##__ptr = ext##__dispatch; \
114 \
115 static ret ext##__dispatch argdecls \
116 { \
117 ext##__functype *f = pick(); \
118 DISPATCH_STORE(ext##__ptr, f); \
119 rtn f args; \
120 } \
121 \
122 stcls 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 \
133 typedef ret ext##__functype argdecls; \
134 static ret dflt argdecls; \
135 static ext##__functype *pick(void) IGNORABLE; \
136 \
137 stcls ret ext argdecls { rtn dflt args; }
138
139 #endif
140
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
154 /*----- Functions provided ------------------------------------------------*/
155
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
167 extern void dispatch_debug(const char */*fmt*/, ...);
168
169 /* --- @cpu_feature_p@ --- *
170 *
171 * Arguments: @unsigned feat@ = a @CPUFEAT_...@ code
172 *
173 * Returns: Nonzero if the feature is available.
174 */
175
176 enum {
177 CPUFEAT_X86_SSE2, /* Streaming SIMD Extensions 2 */
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 */
182 CPUFEAT_ARM_D32, /* 32 double registers, not 16 */
183 CPUFEAT_X86_RDRAND, /* Built-in cooked entropy source */
184 CPUFEAT_ARM_AES, /* AES instructions */
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 */
188 CPUFEAT_ARM_PMULL, /* Polynomial multiplication */
189 CPUFEAT_X86_RDSEED, /* Built-in raw entropy source */
190 CPUFEAT_X86_AVX2 /* AVX 2 (256-bit integer ops) */
191 };
192
193 extern int cpu_feature_p(int /*feat*/);
194
195 /*----- That's all, folks -------------------------------------------------*/
196
197 #ifdef __cplusplus
198 }
199 #endif
200
201 #endif