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