MMgr v1.0.0
Zero-heap memory manager in C11. One borrowed buffer, carved by asserted offset.
Loading...
Searching...
No Matches
mmgr_compiler_directives.h
1/**
2 * @brief Preprocessor definitions; declares no type and defines no function.
3 */
4#ifndef MMGR_COMPILER_DIRECTIVES_H
5#define MMGR_COMPILER_DIRECTIVES_H
6
7#include <stddef.h>
8
9/**
10 * @brief Set to 1 when __clang__ is defined, 0 otherwise.
11 *
12 * @note Defined on both branches, and so #ifdef MMGR_CC_CLANG is always true.
13 */
14#if defined(__clang__)
15#define MMGR_CC_CLANG 1
16#else
17
18#define MMGR_CC_CLANG 0
19#endif
20
21/**
22 * @brief Set to 1 when __GNUC__ is defined and __clang__ is not, 0 otherwise.
23 */
24#if defined(__GNUC__) && !defined(__clang__)
25#define MMGR_CC_GNU 1
26#else
27
28#define MMGR_CC_GNU 0
29#endif
30
31/**
32 * @brief Set to 1 when __GNUC__ or __clang__ is defined, 0 otherwise.
33 *
34 * @note Used as the fallback value of MMGR_HAS_ATTRIBUTE.
35 */
36#if defined(__GNUC__) || defined(__clang__)
37#define MMGR_CC_GNU_ATTRS 1
38#else
39
40#define MMGR_CC_GNU_ATTRS 0
41#endif
42
43/**
44 * @brief Expands to __has_attribute(x) where __has_attribute is defined.
45 *
46 * @param[in] x Attribute name, as passed to __has_attribute.
47 * @return The value __has_attribute gives for x.
48 * @warning Expands to MMGR_CC_GNU_ATTRS where __has_attribute is undefined, ignoring x.
49 */
50#if defined(__has_attribute)
51#define MMGR_HAS_ATTRIBUTE(x) __has_attribute(x)
52#else
53
54#define MMGR_HAS_ATTRIBUTE(x) MMGR_CC_GNU_ATTRS
55#endif
56
57/**
58 * @brief Expands to __has_builtin(x) where __has_builtin is defined.
59 *
60 * @param[in] x Builtin name, as passed to __has_builtin.
61 * @return The value __has_builtin gives for x.
62 * @warning Expands to 0 where __has_builtin is undefined, ignoring x.
63 */
64#if defined(__has_builtin)
65#define MMGR_HAS_BUILTIN(x) __has_builtin(x)
66#else
67
68#define MMGR_HAS_BUILTIN(x) 0
69#endif
70
71/**
72 * @brief Expands to a two-operand static assertion.
73 *
74 * @param[in] cond Constant expression passed through unchanged.
75 * @param[in] msg Message operand passed through unchanged.
76 * @note static_assert where __cplusplus is defined or __STDC_VERSION__ >= 202311L.
77 * @note _Static_assert otherwise.
78 */
79#if defined(__cplusplus)
80#define MMGR_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
81#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
82#define MMGR_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
83#else
84
85#define MMGR_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
86#endif
87
88/**
89 * @brief Expands to extern "C" { where __cplusplus is defined.
90 *
91 * @warning The expansion contains an open {; MMGR_FINIS_DECLS supplies the }.
92 * @note Expands to nothing where __cplusplus is undefined.
93 */
94#ifdef __cplusplus
95#define MMGR_INCIPE_DECLS \
96 extern "C" \
97 {
98
99/** @brief Expands to } where __cplusplus is defined, closing MMGR_INCIPE_DECLS. */
100#define MMGR_FINIS_DECLS }
101#else
102
103#define MMGR_INCIPE_DECLS
104
105/** @brief Expands to nothing where __cplusplus is undefined. */
106#define MMGR_FINIS_DECLS
107#endif
108
109/**
110 * @brief Expands to a##b.
111 *
112 * @param[in] a Left operand of ##.
113 * @param[in] b Right operand of ##.
114 * @return The single token formed by joining a and b.
115 * @note Called by MMGR_CAT.
116 */
117#define MMGR_CAT_(a, b) a##b
118
119/**
120 * @brief Expands to MMGR_CAT_(a, b).
121 *
122 * @param[in] a Left operand, forwarded to MMGR_CAT_.
123 * @param[in] b Right operand, forwarded to MMGR_CAT_.
124 * @return The single token formed by joining a and b.
125 * @note Builds a macro name from a count, as in MMGR_NS_LAYOUT and mmgr_carcer_init.
126 */
127#define MMGR_CAT(a, b) MMGR_CAT_(a, b)
128
129/**
130 * @brief Expands to MMGR_NARG_ with __VA_ARGS__ followed by the constants 24 down to 0.
131 *
132 * @param[in] ... The list to count.
133 * @return The number of arguments, for one to twenty-four arguments.
134 * @warning An empty list gives 1.
135 * @warning Twenty-five or more arguments make MMGR_ARG_N select an argument instead of a constant.
136 */
137#define MMGR_NARG(...) \
138 MMGR_NARG_(__VA_ARGS__, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
139/**
140 * @brief Expands to MMGR_ARG_N(__VA_ARGS__).
141 *
142 * @param[in] ... The list from MMGR_NARG, followed by the constants 24 down to 0.
143 * @return The value MMGR_ARG_N selects.
144 * @note Called by MMGR_NARG.
145 */
146#define MMGR_NARG_(...) MMGR_ARG_N(__VA_ARGS__)
147
148/**
149 * @brief Expands to its twenty-fifth argument.
150 *
151 * @param[in] _1 Arguments one through twenty-four, discarded.
152 * @param[in] N The twenty-fifth argument.
153 * @param[in] ... Arguments beyond the twenty-fifth, discarded.
154 * @return N.
155 */
156#define MMGR_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, \
157 _22, _23, _24, N, ...) \
158 N
159
160/**
161 * @brief Expands to backend(&(ArgsType){__VA_ARGS__}).
162 *
163 * @param[in] backend Function called with the address of the literal.
164 * @param[in] ArgsType Type of the compound literal.
165 * @param[in] ... Initializers for the compound literal.
166 * @return The value backend returns.
167 * @warning backend receives the address of the literal [BORROWS].
168 */
169#define MMGR_CALL(backend, ArgsType, ...) backend(&(ArgsType){__VA_ARGS__})
170
171/**
172 * @brief Expands to sizeof(void (*)(void)).
173 *
174 * @note Multiplied by a loculus index in MMGR_NS_LOCULUS, and by the member count in the two layout macros.
175 */
176#define MMGR_FP_SIZE (sizeof(void (*)(void)))
177
178/**
179 * @brief Expands to MMGR_STATIC_ASSERT that offsetof(T, member) equals loculus * MMGR_FP_SIZE.
180 *
181 * @param[in] T Struct type passed to offsetof.
182 * @param[in] member Member name passed to offsetof.
183 * @param[in] loculus Index, cast to size_t and multiplied by MMGR_FP_SIZE.
184 * @note T, member and loculus are stringized into the assertion message.
185 */
186#define MMGR_NS_LOCULUS(T, member, loculus) \
187 MMGR_STATIC_ASSERT(offsetof(T, member) == (size_t)(loculus) * MMGR_FP_SIZE, \
188 #T "." #member " is not at dispatch loculus " #loculus)
189
190/**
191 * @brief MMGR_NS_L1 to MMGR_NS_L24 expand to one MMGR_NS_LOCULUS per member, at indices 0 upward.
192 *
193 * @param[in] T Struct type forwarded to MMGR_NS_LOCULUS.
194 * @param[in] a Member names in order; a takes index 0, b takes index 1.
195 * @note MMGR_NS_L<n> expands MMGR_NS_L<n-1> before its own MMGR_NS_LOCULUS.
196 * @warning Selected by MMGR_NS_LAYOUT through MMGR_CAT on the argument count.
197 */
198#define MMGR_NS_L1(T, a) MMGR_NS_LOCULUS(T, a, 0);
199#define MMGR_NS_L2(T, a, b) MMGR_NS_L1(T, a) MMGR_NS_LOCULUS(T, b, 1);
200#define MMGR_NS_L3(T, a, b, c) MMGR_NS_L2(T, a, b) MMGR_NS_LOCULUS(T, c, 2);
201#define MMGR_NS_L4(T, a, b, c, d) MMGR_NS_L3(T, a, b, c) MMGR_NS_LOCULUS(T, d, 3);
202#define MMGR_NS_L5(T, a, b, c, d, e) MMGR_NS_L4(T, a, b, c, d) MMGR_NS_LOCULUS(T, e, 4);
203#define MMGR_NS_L6(T, a, b, c, d, e, f) MMGR_NS_L5(T, a, b, c, d, e) MMGR_NS_LOCULUS(T, f, 5);
204#define MMGR_NS_L7(T, a, b, c, d, e, f, g) MMGR_NS_L6(T, a, b, c, d, e, f) MMGR_NS_LOCULUS(T, g, 6);
205#define MMGR_NS_L8(T, a, b, c, d, e, f, g, h) MMGR_NS_L7(T, a, b, c, d, e, f, g) MMGR_NS_LOCULUS(T, h, 7);
206#define MMGR_NS_L9(T, a, b, c, d, e, f, g, h, i) MMGR_NS_L8(T, a, b, c, d, e, f, g, h) MMGR_NS_LOCULUS(T, i, 8);
207#define MMGR_NS_L10(T, a, b, c, d, e, f, g, h, i, j) MMGR_NS_L9(T, a, b, c, d, e, f, g, h, i) MMGR_NS_LOCULUS(T, j, 9);
208#define MMGR_NS_L11(T, a, b, c, d, e, f, g, h, i, j, k) \
209 MMGR_NS_L10(T, a, b, c, d, e, f, g, h, i, j) MMGR_NS_LOCULUS(T, k, 10);
210#define MMGR_NS_L12(T, a, b, c, d, e, f, g, h, i, j, k, l) \
211 MMGR_NS_L11(T, a, b, c, d, e, f, g, h, i, j, k) MMGR_NS_LOCULUS(T, l, 11);
212#define MMGR_NS_L13(T, a, b, c, d, e, f, g, h, i, j, k, l, m) \
213 MMGR_NS_L12(T, a, b, c, d, e, f, g, h, i, j, k, l) MMGR_NS_LOCULUS(T, m, 12);
214#define MMGR_NS_L14(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
215 MMGR_NS_L13(T, a, b, c, d, e, f, g, h, i, j, k, l, m) MMGR_NS_LOCULUS(T, n, 13);
216#define MMGR_NS_L15(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
217 MMGR_NS_L14(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n) MMGR_NS_LOCULUS(T, o, 14);
218#define MMGR_NS_L16(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
219 MMGR_NS_L15(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) MMGR_NS_LOCULUS(T, p, 15);
220#define MMGR_NS_L17(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) \
221 MMGR_NS_L16(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) MMGR_NS_LOCULUS(T, q, 16);
222#define MMGR_NS_L18(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) \
223 MMGR_NS_L17(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) MMGR_NS_LOCULUS(T, r, 17);
224#define MMGR_NS_L19(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) \
225 MMGR_NS_L18(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) MMGR_NS_LOCULUS(T, s, 18);
226#define MMGR_NS_L20(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) \
227 MMGR_NS_L19(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) MMGR_NS_LOCULUS(T, t, 19);
228#define MMGR_NS_L21(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) \
229 MMGR_NS_L20(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) MMGR_NS_LOCULUS(T, u, 20);
230#define MMGR_NS_L22(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) \
231 MMGR_NS_L21(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) MMGR_NS_LOCULUS(T, v, 21);
232#define MMGR_NS_L23(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w) \
233 MMGR_NS_L22(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) MMGR_NS_LOCULUS(T, w, 22);
234#define MMGR_NS_L24(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x) \
235 MMGR_NS_L23(T, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w) MMGR_NS_LOCULUS(T, x, 23);
236
237/**
238 * @brief Expands the matching MMGR_NS_L, then asserts sizeof(T) equals the member count times MMGR_FP_SIZE.
239 *
240 * @param[in] T Struct type forwarded to MMGR_NS_L and to sizeof.
241 * @param[in] ... Member names in loculus order, one to twenty-four.
242 * @note MMGR_NARG(__VA_ARGS__) is cast to size_t before the multiply.
243 * @warning Any size other than the member count times MMGR_FP_SIZE fails the assertion.
244 */
245#define MMGR_NS_LAYOUT(T, ...) \
246 MMGR_CAT(MMGR_NS_L, MMGR_NARG(__VA_ARGS__))(T, __VA_ARGS__) \
247 MMGR_STATIC_ASSERT(sizeof(T) == (size_t)MMGR_NARG(__VA_ARGS__) * MMGR_FP_SIZE, \
248 #T " has a member that is not in its dispatch list, or is padded")
249
250/**
251 * @brief Expands to static const.
252 *
253 * @note Used to declare the dispatch tables, such as ascii, spat and clz.
254 */
255#define MMGR_NS static const
256
257/**
258 * @brief Expands to __attribute__((flatten)) where MMGR_HAS_ATTRIBUTE(flatten) is non-zero.
259 *
260 * @note For a caller and not for the library. It asks the compiler to inline everything the function it
261 * marks calls, which reaches an entry body that the inliner would otherwise leave out of line
262 * on size. The entries are large enough that it does leave them: measured on an ESP32-S3, a
263 * cellul.len over eight bytes costs 112 cycles called and 80 inlined, and so the call is 32 of
264 * them - a third of the work at that length, and it is paid on every entry.
265 * @note Worth it where an extent is short and settled before the build, as this library
266 * is for. A long scan amortizes the call and will not notice: the same measurement at 64 bytes
267 * is 253 against 240.
268 * @note Costs the walk's code at every site that takes it, and so it belongs on the one hot function a
269 * caller cares about and not on a translation unit.
270 * @warning Needs the entry body visible. A build without link-time optimization gets nothing from
271 * it. See MMGR_LTO.
272 * @warning Expands to nothing where MMGR_HAS_ATTRIBUTE(flatten) is 0, which costs speed and never
273 * correctness.
274 */
275#if MMGR_HAS_ATTRIBUTE(flatten)
276#define MMGR_FLATTEN __attribute__((flatten))
277#else
278
279#define MMGR_FLATTEN
280#endif
281
282/**
283 * @brief Expands to __attribute__((packed)) where MMGR_HAS_ATTRIBUTE(packed) is non-zero, and to the
284 * fixed underlying type `: unsigned char` for a C++ compiler without it.
285 *
286 * @note The C++ arm is nvcc over MSVC, which a .cu reaching MMgr on Windows compiles under. C++11 made
287 * the fixed underlying type standard.
288 * @warning On the C++ arm the width is one byte whatever the range, and therefore an enumerator past 255 or below
289 * 0 fails the build there.
290 * @warning Expands to nothing where MMGR_HAS_ATTRIBUTE(packed) is 0 in C.
291 * @note mmgr_types.h asserts sizeof(MmgrEnumProbe) == 1 to catch that case.
292 */
293#if MMGR_HAS_ATTRIBUTE(packed)
294#define MMGR_ENUM_PACKED __attribute__((packed))
295#elif defined(__cplusplus)
296#define MMGR_ENUM_PACKED : unsigned char
297#else
298
299#define MMGR_ENUM_PACKED
300#endif
301
302/**
303 * @brief Expands to __attribute__((aligned(n))) where MMGR_HAS_ATTRIBUTE(aligned) is non-zero.
304 *
305 * @param[in] n Alignment operand passed to the attribute.
306 * @warning Expands to nothing where MMGR_HAS_ATTRIBUTE(aligned) is 0, ignoring n.
307 */
308#if MMGR_HAS_ATTRIBUTE(aligned)
309#define MMGR_ALIGN(n) __attribute__((aligned(n)))
310#else
311
312#define MMGR_ALIGN(n)
313#endif
314
315/**
316 * @brief Expands to __attribute__((may_alias)) where MMGR_HAS_ATTRIBUTE(may_alias) is non-zero.
317 *
318 * @warning Expands to nothing where MMGR_HAS_ATTRIBUTE(may_alias) is 0.
319 */
320#if MMGR_HAS_ATTRIBUTE(may_alias)
321#define MMGR_ALIAS __attribute__((may_alias))
322#else
323
324#define MMGR_ALIAS
325#endif
326
327/**
328 * @brief Expands to __attribute__((unused)) where MMGR_HAS_ATTRIBUTE(unused) is non-zero.
329 *
330 * @warning Expands to nothing where MMGR_HAS_ATTRIBUTE(unused) is 0.
331 */
332#if MMGR_HAS_ATTRIBUTE(unused)
333#define MMGR_UNUSED __attribute__((unused))
334#else
335
336#define MMGR_UNUSED
337#endif
338
339/**
340 * @brief Expands to __attribute__((weak)) where MMGR_HAS_ATTRIBUTE(weak) is non-zero.
341 *
342 * @warning Expands to nothing where MMGR_HAS_ATTRIBUTE(weak) is 0.
343 */
344#if MMGR_HAS_ATTRIBUTE(weak)
345#define MMGR_WEAK __attribute__((weak))
346#else
347
348#define MMGR_WEAK
349#endif
350
351/**
352 * @brief Expands to static inline __attribute__((always_inline)).
353 *
354 * @note Expands to static inline where MMGR_HAS_ATTRIBUTE(always_inline) is 0.
355 * @warning Neither definition is made when MMGR_INLINE is already defined.
356 */
357#ifndef MMGR_INLINE
358#if MMGR_HAS_ATTRIBUTE(always_inline)
359#define MMGR_INLINE static inline __attribute__((always_inline))
360#else
361#define MMGR_INLINE static inline
362#endif
363#endif
364
365/**
366 * @brief Expands to _Pragma(#directive) where MMGR_CC_GNU is non-zero.
367 *
368 * @param[in] directive Pragma text, stringized by #.
369 * @warning Expands to nothing where MMGR_CC_GNU is 0, ignoring directive.
370 */
371#if MMGR_CC_GNU
372#define MMGR_TU_PRAGMA(directive) _Pragma(#directive)
373#else
374
375#define MMGR_TU_PRAGMA(directive)
376#endif
377
378/**
379 * @brief Expands to MMGR_TU_PRAGMA(GCC optimize("O2")).
380 *
381 * @warning Expands to nothing where MMGR_CC_GNU is 0, through MMGR_TU_PRAGMA.
382 */
383#define MMGR_OPTIMIZE_O2 MMGR_TU_PRAGMA(GCC optimize("O2"))
384
385#if defined(__clang__)
386/** @brief Expands to _Pragma("clang diagnostic push") where __clang__ is defined. */
387#define MMGR_DIAG_PUSH _Pragma("clang diagnostic push")
388
389/** @brief Expands to _Pragma("clang diagnostic pop") where __clang__ is defined. */
390#define MMGR_DIAG_POP _Pragma("clang diagnostic pop")
391
392/**
393 * @brief Expands to _Pragma(MMGR_DIAG_STR(clang diagnostic ignored w)) where __clang__ is defined.
394 *
395 * @param[in] w Warning name as a string literal, such as "-Wpadded".
396 * @note MMGR_DIAG_STR stringizes the whole pragma text, including w.
397 */
398#define MMGR_DIAG_IGNORE(w) _Pragma(MMGR_DIAG_STR(clang diagnostic ignored w))
399
400/**
401 * @brief Expands to #x.
402 *
403 * @param[in] x Token sequence to stringize.
404 * @return x as a string literal.
405 * @note Called by MMGR_DIAG_IGNORE.
406 */
407#define MMGR_DIAG_STR(x) #x
408#elif defined(__GNUC__)
409/** @brief Expands to _Pragma("GCC diagnostic push") where __GNUC__ is defined and __clang__ is not. */
410#define MMGR_DIAG_PUSH _Pragma("GCC diagnostic push")
411
412/** @brief Expands to _Pragma("GCC diagnostic pop") where __GNUC__ is defined and __clang__ is not. */
413#define MMGR_DIAG_POP _Pragma("GCC diagnostic pop")
414
415/**
416 * @brief Expands to #x.
417 *
418 * @param[in] x Token sequence to stringize.
419 * @return x as a string literal.
420 * @note Called by MMGR_DIAG_IGNORE.
421 */
422#define MMGR_DIAG_STR(x) #x
423
424/**
425 * @brief Expands to _Pragma(MMGR_DIAG_STR(GCC diagnostic ignored w)).
426 *
427 * @param[in] w Warning name as a string literal, such as "-Wpadded".
428 * @note Selected where __GNUC__ is defined and __clang__ is not.
429 * @note MMGR_DIAG_STR stringizes the whole pragma text, including w.
430 */
431#define MMGR_DIAG_IGNORE(w) _Pragma(MMGR_DIAG_STR(GCC diagnostic ignored w))
432#else
433
434/** @brief Expands to nothing when __clang__ and __GNUC__ are both undefined. */
435#define MMGR_DIAG_PUSH
436
437/** @brief Expands to nothing when __clang__ and __GNUC__ are both undefined. */
438#define MMGR_DIAG_POP
439
440/**
441 * @brief Expands to nothing when __clang__ and __GNUC__ are both undefined.
442 *
443 * @param[in] w Warning name as a string literal, discarded.
444 */
445#define MMGR_DIAG_IGNORE(w)
446#endif
447
448/**
449 * @brief Set to 1 when __BYTE_ORDER__ and __ORDER_BIG_ENDIAN__ are both defined and equal, 0 otherwise.
450 *
451 * @warning Neither definition is made when MMGR_HW_BIG_ENDIAN is already defined.
452 */
453#ifndef MMGR_HW_BIG_ENDIAN
454#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
455#define MMGR_HW_BIG_ENDIAN 1
456#else
457
458#define MMGR_HW_BIG_ENDIAN 0
459#endif
460#endif
461
462/**
463 * @brief Set to 1 when the target loads a word from any address in one instruction, 0 otherwise.
464 *
465 * @note Not whether an unaligned load compiles - every target here accepts one through
466 * mmgr_proxim_word_t, which carries MMGR_ALIGN(1). It is whether the hardware does it, or the
467 * compiler assembles it out of byte loads and shifts. Measured on one such load: ARMv7-M emits
468 * a single ldr, Xtensa twelve instructions and RISC-V eleven.
469 * @note The difference decides which of two shapes is faster in a scan that needs the word at an
470 * offset of one. Where a load is a single instruction, take it; where it is a dozen, derive
471 * the word from the one already in hand and a byte.
472 * @note __ARM_FEATURE_UNALIGNED is the compiler's own answer for ARM, and is switched off by
473 * -mno-unaligned-access. x86 is stated directly, having no equivalent macro.
474 * @warning Neither definition is made when MMGR_HW_FAST_UNALIGNED is already defined.
475 */
476#ifndef MMGR_HW_FAST_UNALIGNED
477#if defined(__ARM_FEATURE_UNALIGNED) || defined(__x86_64__) || defined(__i386__)
478#define MMGR_HW_FAST_UNALIGNED 1
479#else
480
481#define MMGR_HW_FAST_UNALIGNED 0
482#endif
483#endif
484
485#endif