| 1 | #ifndef _CPUSUPPORT_H_ |
| 2 | #define _CPUSUPPORT_H_ |
| 3 | |
| 4 | /* |
| 5 | * To enable support for non-portable CPU features at compile time, one or |
| 6 | * more CPUSUPPORT_ARCH_FEATURE macros should be defined. This can be done |
| 7 | * directly on the compiler command line via -D CPUSUPPORT_ARCH_FEATURE or |
| 8 | * -D CPUSUPPORT_ARCH_FEATURE=1; or a file can be created with the |
| 9 | * necessary #define lines and then -D CPUSUPPORT_CONFIG_FILE=cpuconfig.h |
| 10 | * (or similar) can be provided to include that file here. |
| 11 | */ |
| 12 | #ifdef CPUSUPPORT_CONFIG_FILE |
| 13 | #include CPUSUPPORT_CONFIG_FILE |
| 14 | #endif |
| 15 | |
| 16 | /** |
| 17 | * The CPUSUPPORT_FEATURE macro declares the necessary variables and |
| 18 | * functions for detecting CPU feature support at run time. The function |
| 19 | * defined in the macro acts to cache the result of the ..._detect function |
| 20 | * using the ..._present and ..._init variables. The _detect function and the |
| 21 | * _present and _init variables are turn defined by CPUSUPPORT_FEATURE_DECL in |
| 22 | * appropriate cpusupport_foo_bar.c file. |
| 23 | * |
| 24 | * In order to allow CPUSUPPORT_FEATURE to be used for features which do not |
| 25 | * have corresponding CPUSUPPORT_FEATURE_DECL blocks in another source file, |
| 26 | * we abuse the C preprocessor: If CPUSUPPORT_${enabler} is defined to 1, then |
| 27 | * we access _present_1, _init_1, and _detect_1; but if it is not defined, we |
| 28 | * access _present_CPUSUPPORT_${enabler} etc., which we define as static, thus |
| 29 | * preventing the compiler from emitting a reference to an external symbol. |
| 30 | * |
| 31 | * In this way, it becomes possible to issue CPUSUPPORT_FEATURE invocations |
| 32 | * for nonexistent features without running afoul of the requirement that |
| 33 | * "If an identifier declared with external linkage is used... in the entire |
| 34 | * program there shall be exactly one external definition" (C99 standard, 6.9 |
| 35 | * paragraph 5). In practice, this means that users of the cpusupport code |
| 36 | * can omit build and runtime detection files without changing the framework |
| 37 | * code. |
| 38 | */ |
| 39 | #define CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) \ |
| 40 | static int cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \ |
| 41 | static int cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \ |
| 42 | static inline int cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler(void) { return (0); } \ |
| 43 | extern int cpusupport_ ## arch_feature ## _present_ ## enabled; \ |
| 44 | extern int cpusupport_ ## arch_feature ## _init_ ## enabled; \ |
| 45 | int cpusupport_ ## arch_feature ## _detect_ ## enabled(void); \ |
| 46 | \ |
| 47 | static inline int \ |
| 48 | cpusupport_ ## arch_feature(void) \ |
| 49 | { \ |
| 50 | \ |
| 51 | if (cpusupport_ ## arch_feature ## _present_ ## enabled) \ |
| 52 | return (1); \ |
| 53 | else if (cpusupport_ ## arch_feature ## _init_ ## enabled) \ |
| 54 | return (0); \ |
| 55 | cpusupport_ ## arch_feature ## _present_ ## enabled = \ |
| 56 | cpusupport_ ## arch_feature ## _detect_ ## enabled(); \ |
| 57 | cpusupport_ ## arch_feature ## _init_ ## enabled = 1; \ |
| 58 | return (cpusupport_ ## arch_feature ## _present_ ## enabled); \ |
| 59 | } \ |
| 60 | static void (* cpusupport_ ## arch_feature ## _dummyptr)(void); \ |
| 61 | static inline void \ |
| 62 | cpusupport_ ## arch_feature ## _dummyfunc(void) \ |
| 63 | { \ |
| 64 | \ |
| 65 | (void)cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \ |
| 66 | (void)cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \ |
| 67 | (void)cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler; \ |
| 68 | (void)cpusupport_ ## arch_feature ## _present_ ## enabled; \ |
| 69 | (void)cpusupport_ ## arch_feature ## _init_ ## enabled; \ |
| 70 | (void)cpusupport_ ## arch_feature ## _detect_ ## enabled; \ |
| 71 | (void)cpusupport_ ## arch_feature ## _dummyptr; \ |
| 72 | } \ |
| 73 | static void (* cpusupport_ ## arch_feature ## _dummyptr)(void) = cpusupport_ ## arch_feature ## _dummyfunc; \ |
| 74 | struct cpusupport_ ## arch_feature ## _dummy |
| 75 | #define CPUSUPPORT_FEATURE_(arch_feature, enabler, enabled) \ |
| 76 | CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) |
| 77 | #define CPUSUPPORT_FEATURE(arch, feature, enabler) \ |
| 78 | CPUSUPPORT_FEATURE_(arch ## _ ## feature, enabler, CPUSUPPORT_ ## enabler) |
| 79 | |
| 80 | /* |
| 81 | * CPUSUPPORT_FEATURE_DECL(arch, feature): |
| 82 | * Macro which defines variables and provides a function declaration for |
| 83 | * detecting the presence of "feature" on the "arch" architecture. The |
| 84 | * function body following this macro expansion must return nonzero if the |
| 85 | * feature is present, or zero if the feature is not present or the detection |
| 86 | * fails for any reason. |
| 87 | */ |
| 88 | #define CPUSUPPORT_FEATURE_DECL(arch, feature) \ |
| 89 | int cpusupport_ ## arch ## _ ## feature ## _present_1 = 0; \ |
| 90 | int cpusupport_ ## arch ## _ ## feature ## _init_1 = 0; \ |
| 91 | int cpusupport_ ## arch ## _ ## feature ## _detect_1(void); \ |
| 92 | int \ |
| 93 | cpusupport_ ## arch ## _ ## feature ## _detect_1(void) |
| 94 | |
| 95 | /* |
| 96 | * List of features. If a feature here is not enabled by the appropriate |
| 97 | * CPUSUPPORT_ARCH_FEATURE macro being defined, it has no effect; but if the |
| 98 | * relevant macro may be defined (e.g., by Build/cpusupport.sh successfully |
| 99 | * compiling Build/cpusupport-ARCH-FEATURE.c) then the C file containing the |
| 100 | * corresponding run-time detection code (cpusupport_arch_feature.c) must be |
| 101 | * compiled and linked in. |
| 102 | */ |
| 103 | CPUSUPPORT_FEATURE(x86, aesni, X86_AESNI); |
| 104 | CPUSUPPORT_FEATURE(x86, sse2, X86_SSE2); |
| 105 | |
| 106 | #endif /* !_CPUSUPPORT_H_ */ |