xref: /php-src/Zend/zend_cpuinfo.h (revision 6bd54646)
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 	/* intentionally don't support		= (1<<30 | ZEND_CPU_EBX_MASK) */
68 	/* intentionally don't support		= (1<<31 | ZEND_CPU_EBX_MASK) */
69 
70 	/* EDX */
71 	ZEND_CPU_FEATURE_FPU			= (1<<0 | ZEND_CPU_EDX_MASK),
72 	ZEND_CPU_FEATURE_VME			= (1<<1 | ZEND_CPU_EDX_MASK),
73 	ZEND_CPU_FEATURE_DE				= (1<<2 | ZEND_CPU_EDX_MASK),
74 	ZEND_CPU_FEATURE_PSE			= (1<<3 | ZEND_CPU_EDX_MASK),
75 	ZEND_CPU_FEATURE_TSC			= (1<<4 | ZEND_CPU_EDX_MASK),
76 	ZEND_CPU_FEATURE_MSR			= (1<<5 | ZEND_CPU_EDX_MASK),
77 	ZEND_CPU_FEATURE_PAE			= (1<<6 | ZEND_CPU_EDX_MASK),
78 	ZEND_CPU_FEATURE_MCE			= (1<<7 | ZEND_CPU_EDX_MASK),
79 	ZEND_CPU_FEATURE_CX8			= (1<<8 | ZEND_CPU_EDX_MASK),
80 	ZEND_CPU_FEATURE_APIC			= (1<<9 | ZEND_CPU_EDX_MASK),
81 	/* reserved						= (1<<10 | ZEND_CPU_EDX_MASK),*/
82 	ZEND_CPU_FEATURE_SEP			= (1<<11 | ZEND_CPU_EDX_MASK),
83 	ZEND_CPU_FEATURE_MTRR			= (1<<12 | ZEND_CPU_EDX_MASK),
84 	ZEND_CPU_FEATURE_PGE			= (1<<13 | ZEND_CPU_EDX_MASK),
85 	ZEND_CPU_FEATURE_MCA			= (1<<14 | ZEND_CPU_EDX_MASK),
86 	ZEND_CPU_FEATURE_CMOV			= (1<<15 | ZEND_CPU_EDX_MASK),
87 	ZEND_CPU_FEATURE_PAT			= (1<<16 | ZEND_CPU_EDX_MASK),
88 	ZEND_CPU_FEATURE_PSE36			= (1<<17 | ZEND_CPU_EDX_MASK),
89 	ZEND_CPU_FEATURE_PN				= (1<<18 | ZEND_CPU_EDX_MASK),
90 	ZEND_CPU_FEATURE_CLFLUSH		= (1<<19 | ZEND_CPU_EDX_MASK),
91 	/* reserved						= (1<<20 | ZEND_CPU_EDX_MASK),*/
92 	ZEND_CPU_FEATURE_DS				= (1<<21 | ZEND_CPU_EDX_MASK),
93 	ZEND_CPU_FEATURE_ACPI			= (1<<22 | ZEND_CPU_EDX_MASK),
94 	ZEND_CPU_FEATURE_MMX			= (1<<23 | ZEND_CPU_EDX_MASK),
95 	ZEND_CPU_FEATURE_FXSR			= (1<<24 | ZEND_CPU_EDX_MASK),
96 	ZEND_CPU_FEATURE_SSE			= (1<<25 | ZEND_CPU_EDX_MASK),
97 	ZEND_CPU_FEATURE_SSE2			= (1<<26 | ZEND_CPU_EDX_MASK),
98 	ZEND_CPU_FEATURE_SS				= (1<<27 | ZEND_CPU_EDX_MASK),
99 	ZEND_CPU_FEATURE_HT				= (1<<28 | ZEND_CPU_EDX_MASK),
100 	ZEND_CPU_FEATURE_TM				= (1<<29 | ZEND_CPU_EDX_MASK)
101 	/*intentionally don't support   = (1<<30 | ZEND_CPU_EDX_MASK)*/
102 	/*intentionally don't support   = (1<<31 | ZEND_CPU_EDX_MASK)*/
103 } zend_cpu_feature;
104 
105 void zend_cpu_startup(void);
106 ZEND_API int zend_cpu_supports(zend_cpu_feature feature);
107 
108 #ifndef __has_attribute
109 # define __has_attribute(x) 0
110 #endif
111 
112 /* Address sanitizer is incompatible with ifunc resolvers, so exclude the
113  * CPU support helpers from asan.
114  * See also https://github.com/google/sanitizers/issues/342. */
115 #if __has_attribute(no_sanitize_address)
116 # define ZEND_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
117 #else
118 # define ZEND_NO_SANITIZE_ADDRESS
119 #endif
120 
121 #if PHP_HAVE_BUILTIN_CPU_SUPPORTS
122 /* NOTE: you should use following inline function in
123  * resolver functions (ifunc), as it could be called
124  * before all PLT symbols are resolved. in other words,
125  * resolver functions should not depend on any external
126  * functions */
127 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse2(void)128 static inline int zend_cpu_supports_sse2(void) {
129 #if PHP_HAVE_BUILTIN_CPU_INIT
130 	__builtin_cpu_init();
131 #endif
132 	return __builtin_cpu_supports("sse2");
133 }
134 
135 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse3(void)136 static inline int zend_cpu_supports_sse3(void) {
137 #if PHP_HAVE_BUILTIN_CPU_INIT
138 	__builtin_cpu_init();
139 #endif
140 	return __builtin_cpu_supports("sse3");
141 }
142 
143 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_ssse3(void)144 static inline int zend_cpu_supports_ssse3(void) {
145 #if PHP_HAVE_BUILTIN_CPU_INIT
146 	__builtin_cpu_init();
147 #endif
148 	return __builtin_cpu_supports("ssse3");
149 }
150 
151 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse41(void)152 static inline int zend_cpu_supports_sse41(void) {
153 #if PHP_HAVE_BUILTIN_CPU_INIT
154 	__builtin_cpu_init();
155 #endif
156 	return __builtin_cpu_supports("sse4.1");
157 }
158 
159 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_sse42(void)160 static inline int zend_cpu_supports_sse42(void) {
161 #if PHP_HAVE_BUILTIN_CPU_INIT
162 	__builtin_cpu_init();
163 #endif
164 	return __builtin_cpu_supports("sse4.2");
165 }
166 
167 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx(void)168 static inline int zend_cpu_supports_avx(void) {
169 #if PHP_HAVE_BUILTIN_CPU_INIT
170 	__builtin_cpu_init();
171 #endif
172 	return __builtin_cpu_supports("avx");
173 }
174 
175 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx2(void)176 static inline int zend_cpu_supports_avx2(void) {
177 #if PHP_HAVE_BUILTIN_CPU_INIT
178 	__builtin_cpu_init();
179 #endif
180 	return __builtin_cpu_supports("avx2");
181 }
182 
183 #if PHP_HAVE_AVX512_SUPPORTS
184 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx512(void)185 static inline int zend_cpu_supports_avx512(void) {
186 #if PHP_HAVE_BUILTIN_CPU_INIT
187 	__builtin_cpu_init();
188 #endif
189 	return __builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq")
190 		&& __builtin_cpu_supports("avx512cd") && __builtin_cpu_supports("avx512bw")
191 		&& __builtin_cpu_supports("avx512vl");
192 }
193 #endif
194 
195 #if PHP_HAVE_AVX512_VBMI_SUPPORTS
196 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_avx512_vbmi(void)197 static inline int zend_cpu_supports_avx512_vbmi(void) {
198 #if PHP_HAVE_BUILTIN_CPU_INIT
199 	__builtin_cpu_init();
200 #endif
201 	return zend_cpu_supports_avx512() && __builtin_cpu_supports("avx512vbmi");
202 }
203 #endif
204 
205 #else
206 
zend_cpu_supports_sse2(void)207 static inline int zend_cpu_supports_sse2(void) {
208 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE2);
209 }
210 
zend_cpu_supports_sse3(void)211 static inline int zend_cpu_supports_sse3(void) {
212 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE3);
213 }
214 
zend_cpu_supports_ssse3(void)215 static inline int zend_cpu_supports_ssse3(void) {
216 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSSE3);
217 }
218 
zend_cpu_supports_sse41(void)219 static inline int zend_cpu_supports_sse41(void) {
220 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE41);
221 }
222 
zend_cpu_supports_sse42(void)223 static inline int zend_cpu_supports_sse42(void) {
224 	return zend_cpu_supports(ZEND_CPU_FEATURE_SSE42);
225 }
226 
zend_cpu_supports_avx(void)227 static inline int zend_cpu_supports_avx(void) {
228 	return zend_cpu_supports(ZEND_CPU_FEATURE_AVX);
229 }
230 
zend_cpu_supports_avx2(void)231 static inline int zend_cpu_supports_avx2(void) {
232 	return zend_cpu_supports(ZEND_CPU_FEATURE_AVX2);
233 }
234 
zend_cpu_supports_avx512(void)235 static inline int zend_cpu_supports_avx512(void) {
236 	/* TODO: avx512_bw/avx512_vl use bit 30/31 which are reserved for mask */
237 	return 0;
238 }
239 
zend_cpu_supports_avx512_vbmi(void)240 static zend_always_inline int zend_cpu_supports_avx512_vbmi(void) {
241 	/* TODO: avx512_vbmi use ECX of cpuid 7 */
242 	return 0;
243 }
244 #endif
245 
246 /* __builtin_cpu_supports has pclmul from gcc9 */
247 #if PHP_HAVE_BUILTIN_CPU_SUPPORTS && (!defined(__GNUC__) || (ZEND_GCC_VERSION >= 9000))
248 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_pclmul(void)249 static inline int zend_cpu_supports_pclmul(void) {
250 #if PHP_HAVE_BUILTIN_CPU_INIT
251 	__builtin_cpu_init();
252 #endif
253 	return __builtin_cpu_supports("pclmul");
254 }
255 #else
zend_cpu_supports_pclmul(void)256 static inline int zend_cpu_supports_pclmul(void) {
257 	return zend_cpu_supports(ZEND_CPU_FEATURE_PCLMULQDQ);
258 }
259 #endif
260 
261 /* __builtin_cpu_supports has cldemote from gcc11 */
262 #if PHP_HAVE_BUILTIN_CPU_SUPPORTS && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000)
263 ZEND_NO_SANITIZE_ADDRESS
zend_cpu_supports_cldemote(void)264 static inline int zend_cpu_supports_cldemote(void) {
265 #if PHP_HAVE_BUILTIN_CPU_INIT
266 	__builtin_cpu_init();
267 #endif
268 	return __builtin_cpu_supports("cldemote");
269 }
270 #endif
271 
272 #endif
273