symm/: New SSE2 implementations of Salsa20 and ChaCha.
[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
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
150enum {
151 CPUFEAT_X86_SSE2 /* Streaming SIMD Extensions 2 */
152};
153
154extern int cpu_feature_p(int /*feat*/);
155
156/*----- That's all, folks -------------------------------------------------*/
157
158#ifdef __cplusplus
159 }
160#endif
161
162#endif