xref: /php-src/Zend/zend_cpuinfo.h (revision 6eca7839)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Xinchen Hui <laruence@php.net>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 #ifndef ZEND_CPU_INFO_H
20 #define ZEND_CPU_INFO_H
21 
22 #include "zend.h"
23 
24 #define ZEND_CPU_EBX_MASK     (1<<30)
25 #define ZEND_CPU_EDX_MASK     (1U<<31)
26 
27 typedef enum _zend_cpu_feature {
28 	/* ECX */
29 	ZEND_CPU_FEATURE_SSE3			= (1<<0),
30 	ZEND_CPU_FEATURE_PCLMULQDQ		= (1<<1),
31 	ZEND_CPU_FEATURE_DTES64			= (1<<2),
32 	ZEND_CPU_FEATURE_MONITOR		= (1<<3),
33 	ZEND_CPU_FEATURE_DSCPL			= (1<<4),
34 	ZEND_CPU_FEATURE_VMX			= (1<<5),
35 	ZEND_CPU_FEATURE_SMX			= (1<<6),
36 	ZEND_CPU_FEATURE_EST			= (1<<7),
37 	ZEND_CPU_FEATURE_TM2			= (1<<8),
38 	ZEND_CPU_FEATURE_SSSE3			= (1<<9),
39 	ZEND_CPU_FEATURE_CID			= (1<<10),
40 	ZEND_CPU_FEATURE_SDBG			= (1<<11),
41 	ZEND_CPU_FEATURE_FMA			= (1<<12),
42 	ZEND_CPU_FEATURE_CX16			= (1<<13),
43 	ZEND_CPU_FEATURE_XTPR			= (1<<14),
44 	ZEND_CPU_FEATURE_PDCM			= (1<<15),
45 	/* reserved						= (1<<16),*/
46 	ZEND_CPU_FEATURE_PCID			= (1<<17),
47 	ZEND_CPU_FEATURE_DCA			= (1<<18),
48 	ZEND_CPU_FEATURE_SSE41			= (1<<19),
49 	ZEND_CPU_FEATURE_SSE42			= (1<<20),
50 	ZEND_CPU_FEATURE_X2APIC			= (1<<21),
51 	ZEND_CPU_FEATURE_MOVBE			= (1<<22),
52 	ZEND_CPU_FEATURE_POPCNT			= (1<<23),
53 	ZEND_CPU_FEATURE_TSC_DEADLINE 	= (1<<24),
54 	ZEND_CPU_FEATURE_AES			= (1<<25),
55 	ZEND_CPU_FEATURE_XSAVE			= (1<<26),
56 	ZEND_CPU_FEATURE_OSXSAVE		= (1<<27) ,
57 	ZEND_CPU_FEATURE_AVX			= (1<<28),
58 	ZEND_CPU_FEATURE_F16C			= (1<<29),
59 	/* intentionally don't support	= (1<<30) */
60 	/* intentionally don't support	= (1<<31) */
61 
62 	/* EBX */
63 	ZEND_CPU_FEATURE_AVX2			= (1<<5 | ZEND_CPU_EBX_MASK),
64 	ZEND_CPU_FEATURE_AVX512F		= (1<<16 | ZEND_CPU_EBX_MASK),
65 	ZEND_CPU_FEATURE_AVX512DQ		= (1<<17 | ZEND_CPU_EBX_MASK),
66 	ZEND_CPU_FEATURE_AVX512CD		= (1<<28 | ZEND_CPU_EBX_MASK),
67 	ZEND_CPU_FEATURE_SHA			= (1<<29 | ZEND_CPU_EBX_MASK),
68 	/* intentionally don't support		= (1<<30 | ZEND_CPU_EBX_MASK) */
69 	/* intentionally don't support		= (1<<31 | ZEND_CPU_EBX_MASK) */
70 
71 	/* EDX */
72 	ZEND_CPU_FEATURE_FPU			= (1<<0 | ZEND_CPU_EDX_MASK),
73 	ZEND_CPU_FEATURE_VME			= (1<<1 | ZEND_CPU_EDX_MASK),
74 	ZEND_CPU_FEATURE_DE				= (1<<2 | ZEND_CPU_EDX_MASK),
75 	ZEND_CPU_FEATURE_PSE			= (1<<3 | ZEND_CPU_EDX_MASK),
76 	ZEND_CPU_FEATURE_TSC			= (1<<4 | ZEND_CPU_EDX_MASK),
77 	ZEND_CPU_FEATURE_MSR			= (1<<5 | ZEND_CPU_EDX_MASK),
78 	ZEND_CPU_FEATURE_PAE			= (1<<6 | ZEND_CPU_EDX_MASK),
79 	ZEND_CPU_FEATURE_MCE			= (1<<7 | ZEND_CPU_EDX_MASK),
80 	ZEND_CPU_FEATURE_CX8			= (1<<8 | ZEND_CPU_EDX_MASK),
81 	ZEND_CPU_FEATURE_APIC			= (1<<9 | ZEND_CPU_EDX_MASK),
82 	/* reserved						= (1<<10 | ZEND_CPU_EDX_MASK),*/
83 	ZEND_CPU_FEATURE_SEP			= (1<<11 | ZEND_CPU_EDX_MASK),
84 	ZEND_CPU_FEATURE_MTRR			= (1<<12 | ZEND_CPU_EDX_MASK),
85 	ZEND_CPU_FEATURE_PGE			= (1<<13 | ZEND_CPU_EDX_MASK),
86 	ZEND_CPU_FEATURE_MCA			= (1<<14 | ZEND_CPU_EDX_MASK),
87 	ZEND_CPU_FEATURE_CMOV			= (1<<15 | ZEND_CPU_EDX_MASK),
88 	ZEND_CPU_FEATURE_PAT			= (1<<16 | ZEND_CPU_EDX_MASK),
89 	ZEND_CPU_FEATURE_PSE36			= (1<<17 | ZEND_CPU_EDX_MASK),
90 	ZEND_CPU_FEATURE_PN				= (1<<18 | ZEND_CPU_EDX_MASK),
91 	ZEND_CPU_FEATURE_CLFLUSH		= (1<<19 | ZEND_CPU_EDX_MASK),
92 	/* reserved						= (1<<20 | ZEND_CPU_EDX_MASK),*/
93 	ZEND_CPU_FEATURE_DS				= (1<<21 | ZEND_CPU_EDX_MASK),
94 	ZEND_CPU_FEATURE_ACPI			= (1<<22 | ZEND_CPU_EDX_MASK),
95 	ZEND_CPU_FEATURE_MMX			= (1<<23 | ZEND_CPU_EDX_MASK),
96 	ZEND_CPU_FEATURE_FXSR			= (1<<24 | ZEND_CPU_EDX_MASK),
97 	ZEND_CPU_FEATURE_SSE			= (1<<25 | ZEND_CPU_EDX_MASK),
98 	ZEND_CPU_FEATURE_SSE2			= (1<<26 | ZEND_CPU_EDX_MASK),
99 	ZEND_CPU_FEATURE_SS				= (1<<27 | ZEND_CPU_EDX_MASK),
100 	ZEND_CPU_FEATURE_HT				= (1<<28 | ZEND_CPU_EDX_MASK),
101 	ZEND_CPU_FEATURE_TM				= (1<<29 | ZEND_CPU_EDX_MASK)
102 	/*intentionally don't support   = (1<<30 | ZEND_CPU_EDX_MASK)*/
103 	/*intentionally don't support   = (1<<31 | ZEND_CPU_EDX_MASK)*/
104 } zend_cpu_feature;
105 
106 void zend_cpu_startup(void);
107 ZEND_API int zend_cpu_supports(zend_cpu_feature feature);
108 
109 #ifndef __has_attribute
110 # define __has_attribute(x) 0
111 #endif
112 
113 /* Address sanitizer is incompatible with ifunc resolvers, so exclude the
114  * CPU support helpers from asan.
115  * See also https://github.com/google/sanitizers/issues/342. */
116 #if __has_attribute(no_sanitize_address)
117 # define ZEND_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
118 #else
119 # define ZEND_NO_SANITIZE_ADDRESS
120 #endif
121 
122 #ifdef PHP_HAVE_BUILTIN_CPU_SUPPORTS
123 /* NOTE: you should use following inline function in
124  * resolver functions (ifunc), as it could be called
125  * before all PLT symbols are resolved. in other words,
126  * resolver functions should not depend on any external
127  * functions */
128 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse2(void)129 static inline int zend_cpu_supports_sse2(void) {
130 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
131 	__builtin_cpu_init();
132 #endif
133 	return __builtin_cpu_supports("sse2");
134 }
135 
136 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse3(void)137 static inline int zend_cpu_supports_sse3(void) {
138 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
139 	__builtin_cpu_init();
140 #endif
141 	return __builtin_cpu_supports("sse3");
142 }
143 
144 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_ssse3(void)145 static inline int zend_cpu_supports_ssse3(void) {
146 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
147 	__builtin_cpu_init();
148 #endif
149 	return __builtin_cpu_supports("ssse3");
150 }
151 
152 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse41(void)153 static inline int zend_cpu_supports_sse41(void) {
154 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
155 	__builtin_cpu_init();
156 #endif
157 	return __builtin_cpu_supports("sse4.1");
158 }
159 
160 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse42(void)161 static inline int zend_cpu_supports_sse42(void) {
162 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
163 	__builtin_cpu_init();
164 #endif
165 	return __builtin_cpu_supports("sse4.2");
166 }
167 
168 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx(void)169 static inline int zend_cpu_supports_avx(void) {
170 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
171 	__builtin_cpu_init();
172 #endif
173 	return __builtin_cpu_supports("avx");
174 }
175 
176 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx2(void)177 static inline int zend_cpu_supports_avx2(void) {
178 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
179 	__builtin_cpu_init();
180 #endif
181 	return __builtin_cpu_supports("avx2");
182 }
183 
184 #ifdef PHP_HAVE_AVX512_SUPPORTS
185 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx512(void)186 static inline int zend_cpu_supports_avx512(void) {
187 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
188 	__builtin_cpu_init();
189 #endif
190 	return __builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq")
191 		&& __builtin_cpu_supports("avx512cd") && __builtin_cpu_supports("avx512bw")
192 		&& __builtin_cpu_supports("avx512vl");
193 }
194 #endif
195 
196 #ifdef PHP_HAVE_AVX512_VBMI_SUPPORTS
197 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx512_vbmi(void)198 static inline int zend_cpu_supports_avx512_vbmi(void) {
199 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
200 	__builtin_cpu_init();
201 #endif
202 	return zend_cpu_supports_avx512() && __builtin_cpu_supports("avx512vbmi");
203 }
204 #endif
205 
206 #else
207 
zend_cpu_supports_sse2(void)208 static inline int zend_cpu_supports_sse2(void) {
209 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE2);
210 }
211 
zend_cpu_supports_sse3(void)212 static inline int zend_cpu_supports_sse3(void) {
213 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE3);
214 }
215 
zend_cpu_supports_ssse3(void)216 static inline int zend_cpu_supports_ssse3(void) {
217 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSSE3);
218 }
219 
zend_cpu_supports_sse41(void)220 static inline int zend_cpu_supports_sse41(void) {
221 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE41);
222 }
223 
zend_cpu_supports_sse42(void)224 static inline int zend_cpu_supports_sse42(void) {
225 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE42);
226 }
227 
zend_cpu_supports_avx(void)228 static inline int zend_cpu_supports_avx(void) {
229 	return zend_cpu_supports(ZEND_CPU_FEATURE_AVX);
230 }
231 
zend_cpu_supports_avx2(void)232 static inline int zend_cpu_supports_avx2(void) {
233 	return zend_cpu_supports(ZEND_CPU_FEATURE_AVX2);
234 }
235 
zend_cpu_supports_avx512(void)236 static inline int zend_cpu_supports_avx512(void) {
237 	/* TODO: avx512_bw/avx512_vl use bit 30/31 which are reserved for mask */
238 	return 0;
239 }
240 
zend_cpu_supports_avx512_vbmi(void)241 static zend_always_inline int zend_cpu_supports_avx512_vbmi(void) {
242 	/* TODO: avx512_vbmi use ECX of cpuid 7 */
243 	return 0;
244 }
245 #endif
246 
247 /* __builtin_cpu_supports has pclmul from gcc9 */
248 #if defined(PHP_HAVE_BUILTIN_CPU_SUPPORTS) && (!defined(__GNUC__) || (ZEND_GCC_VERSION >= 9000))
249 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_pclmul(void)250 static inline int zend_cpu_supports_pclmul(void) {
251 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
252 	__builtin_cpu_init();
253 #endif
254 	return __builtin_cpu_supports("pclmul");
255 }
256 #else
zend_cpu_supports_pclmul(void)257 static inline int zend_cpu_supports_pclmul(void) {
258 	return zend_cpu_supports(ZEND_CPU_FEATURE_PCLMULQDQ);
259 }
260 #endif
261 
262 /* __builtin_cpu_supports has cldemote from gcc11 */
263 #if defined(PHP_HAVE_BUILTIN_CPU_SUPPORTS) && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000)
264 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_cldemote(void)265 static inline int zend_cpu_supports_cldemote(void) {
266 #ifdef PHP_HAVE_BUILTIN_CPU_INIT
267 	__builtin_cpu_init();
268 #endif
269 	return __builtin_cpu_supports("cldemote");
270 }
271 #endif
272 
273 #endif
274