/src/php-src/Zend/zend_cpuinfo.c
Line | Count | Source (jump to first uncovered line) |
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 <xinchen.h@zend.com> | |
16 | | +----------------------------------------------------------------------+ |
17 | | */ |
18 | | |
19 | | #include "zend_cpuinfo.h" |
20 | | |
21 | | typedef struct _zend_cpu_info { |
22 | | uint32_t eax; |
23 | | uint32_t ebx; |
24 | | uint32_t ecx; |
25 | | uint32_t edx; |
26 | | uint32_t initialized; |
27 | | } zend_cpu_info; |
28 | | |
29 | | static zend_cpu_info cpuinfo = {0}; |
30 | | |
31 | | #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) |
32 | | # if defined(HAVE_CPUID_H) && defined(HAVE_CPUID_COUNT) |
33 | | # include <cpuid.h> |
34 | 12.2k | static void __zend_cpuid(uint32_t func, uint32_t subfunc, zend_cpu_info *cpuinfo) { |
35 | 12.2k | __cpuid_count(func, subfunc, cpuinfo->eax, cpuinfo->ebx, cpuinfo->ecx, cpuinfo->edx); |
36 | 12.2k | } |
37 | | # else |
38 | | static void __zend_cpuid(uint32_t func, uint32_t subfunc, zend_cpu_info *cpuinfo) { |
39 | | #if defined(__i386__) && (defined(__pic__) || defined(__PIC__)) |
40 | | /* PIC on i386 uses %ebx, so preserve it. */ |
41 | | __asm__ __volatile__ ( |
42 | | "pushl %%ebx\n" |
43 | | "cpuid\n" |
44 | | "mov %%ebx,%1\n" |
45 | | "popl %%ebx" |
46 | | : "=a"(cpuinfo->eax), "=r"(cpuinfo->ebx), "=c"(cpuinfo->ecx), "=d"(cpuinfo->edx) |
47 | | : "a"(func), "c"(subfunc) |
48 | | ); |
49 | | #else |
50 | | __asm__ __volatile__ ( |
51 | | "cpuid" |
52 | | : "=a"(cpuinfo->eax), "=b"(cpuinfo->ebx), "=c"(cpuinfo->ecx), "=d"(cpuinfo->edx) |
53 | | : "a"(func), "c"(subfunc) |
54 | | ); |
55 | | #endif |
56 | | } |
57 | | # endif |
58 | | #elif defined(ZEND_WIN32) && !defined(__clang__) |
59 | | # include <intrin.h> |
60 | | static void __zend_cpuid(uint32_t func, uint32_t subfunc, zend_cpu_info *cpuinfo) { |
61 | | int regs[4]; |
62 | | |
63 | | __cpuidex(regs, func, subfunc); |
64 | | |
65 | | cpuinfo->eax = regs[0]; |
66 | | cpuinfo->ebx = regs[1]; |
67 | | cpuinfo->ecx = regs[2]; |
68 | | cpuinfo->edx = regs[3]; |
69 | | } |
70 | | #else |
71 | | static void __zend_cpuid(uint32_t func, uint32_t subfunc, zend_cpu_info *cpuinfo) { |
72 | | cpuinfo->eax = 0; |
73 | | } |
74 | | #endif |
75 | | |
76 | | void zend_cpu_startup(void) |
77 | 4.06k | { |
78 | 4.06k | if (!cpuinfo.initialized) { |
79 | 4.06k | zend_cpu_info ebx; |
80 | 4.06k | int max_feature; |
81 | | |
82 | 4.06k | cpuinfo.initialized = 1; |
83 | 4.06k | __zend_cpuid(0, 0, &cpuinfo); |
84 | 4.06k | max_feature = cpuinfo.eax; |
85 | 4.06k | if (max_feature == 0) { |
86 | 0 | return; |
87 | 0 | } |
88 | | |
89 | 4.06k | __zend_cpuid(1, 0, &cpuinfo); |
90 | | |
91 | | /* for avx2 */ |
92 | 4.06k | if (max_feature >= 7) { |
93 | 4.06k | __zend_cpuid(7, 0, &ebx); |
94 | 4.06k | cpuinfo.ebx = ebx.ebx; |
95 | 0 | } else { |
96 | 0 | cpuinfo.ebx = 0; |
97 | 0 | } |
98 | 4.06k | } |
99 | 4.06k | } |
100 | | |
101 | 0 | ZEND_API int zend_cpu_supports(zend_cpu_feature feature) { |
102 | 0 | if (feature & ZEND_CPU_EDX_MASK) { |
103 | 0 | return (cpuinfo.edx & (feature & ~ZEND_CPU_EDX_MASK)); |
104 | 0 | } else if (feature & ZEND_CPU_EBX_MASK) { |
105 | 0 | return (cpuinfo.ebx & (feature & ~ZEND_CPU_EBX_MASK)); |
106 | 0 | } else { |
107 | 0 | return (cpuinfo.ecx & feature); |
108 | 0 | } |
109 | 0 | } |