chiark / gitweb /
Support Intel's AES Native Instructions where available on x86 hardware.
[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 /*----- Functions provided ------------------------------------------------*/
142
143 /* --- @cpu_feature_p@ --- *
144  *
145  * Arguments:   @unsigned feat@ = a @CPUFEAT_...@ code
146  *
147  * Returns:     Nonzero if the feature is available.
148  */
149
150 enum {
151   CPUFEAT_X86_SSE2,                     /* Streaming SIMD Extensions 2 */
152   CPUFEAT_X86_AESNI                     /* AES Native Instructions */
153 };
154
155 extern int cpu_feature_p(int /*feat*/);
156
157 /*----- That's all, folks -------------------------------------------------*/
158
159 #ifdef __cplusplus
160   }
161 #endif
162
163 #endif