]>
Commit | Line | Data |
---|---|---|
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_ */ |