chiark / gitweb /
math/t/{mpx,mpmont}: Add some extra tests for flushing out `mul4' bugs.
[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 entropy source */
184   CPUFEAT_ARM_AES                       /* AES instructions */
185 };
186
187 extern int cpu_feature_p(int /*feat*/);
188
189 /*----- That's all, folks -------------------------------------------------*/
190
191 #ifdef __cplusplus
192   }
193 #endif
194
195 #endif