1*e0c1b49fSNick Terrell /*
2*e0c1b49fSNick Terrell * Copyright (c) Facebook, Inc.
3*e0c1b49fSNick Terrell * All rights reserved.
4*e0c1b49fSNick Terrell *
5*e0c1b49fSNick Terrell * This source code is licensed under both the BSD-style license (found in the
6*e0c1b49fSNick Terrell * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*e0c1b49fSNick Terrell * in the COPYING file in the root directory of this source tree).
8*e0c1b49fSNick Terrell * You may select, at your option, one of the above-listed licenses.
9*e0c1b49fSNick Terrell */
10*e0c1b49fSNick Terrell
11*e0c1b49fSNick Terrell #ifndef ZSTD_COMMON_CPU_H
12*e0c1b49fSNick Terrell #define ZSTD_COMMON_CPU_H
13*e0c1b49fSNick Terrell
14*e0c1b49fSNick Terrell /*
15*e0c1b49fSNick Terrell * Implementation taken from folly/CpuId.h
16*e0c1b49fSNick Terrell * https://github.com/facebook/folly/blob/master/folly/CpuId.h
17*e0c1b49fSNick Terrell */
18*e0c1b49fSNick Terrell
19*e0c1b49fSNick Terrell #include "mem.h"
20*e0c1b49fSNick Terrell
21*e0c1b49fSNick Terrell
22*e0c1b49fSNick Terrell typedef struct {
23*e0c1b49fSNick Terrell U32 f1c;
24*e0c1b49fSNick Terrell U32 f1d;
25*e0c1b49fSNick Terrell U32 f7b;
26*e0c1b49fSNick Terrell U32 f7c;
27*e0c1b49fSNick Terrell } ZSTD_cpuid_t;
28*e0c1b49fSNick Terrell
ZSTD_cpuid(void)29*e0c1b49fSNick Terrell MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) {
30*e0c1b49fSNick Terrell U32 f1c = 0;
31*e0c1b49fSNick Terrell U32 f1d = 0;
32*e0c1b49fSNick Terrell U32 f7b = 0;
33*e0c1b49fSNick Terrell U32 f7c = 0;
34*e0c1b49fSNick Terrell #if defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__)
35*e0c1b49fSNick Terrell /* The following block like the normal cpuid branch below, but gcc
36*e0c1b49fSNick Terrell * reserves ebx for use of its pic register so we must specially
37*e0c1b49fSNick Terrell * handle the save and restore to avoid clobbering the register
38*e0c1b49fSNick Terrell */
39*e0c1b49fSNick Terrell U32 n;
40*e0c1b49fSNick Terrell __asm__(
41*e0c1b49fSNick Terrell "pushl %%ebx\n\t"
42*e0c1b49fSNick Terrell "cpuid\n\t"
43*e0c1b49fSNick Terrell "popl %%ebx\n\t"
44*e0c1b49fSNick Terrell : "=a"(n)
45*e0c1b49fSNick Terrell : "a"(0)
46*e0c1b49fSNick Terrell : "ecx", "edx");
47*e0c1b49fSNick Terrell if (n >= 1) {
48*e0c1b49fSNick Terrell U32 f1a;
49*e0c1b49fSNick Terrell __asm__(
50*e0c1b49fSNick Terrell "pushl %%ebx\n\t"
51*e0c1b49fSNick Terrell "cpuid\n\t"
52*e0c1b49fSNick Terrell "popl %%ebx\n\t"
53*e0c1b49fSNick Terrell : "=a"(f1a), "=c"(f1c), "=d"(f1d)
54*e0c1b49fSNick Terrell : "a"(1));
55*e0c1b49fSNick Terrell }
56*e0c1b49fSNick Terrell if (n >= 7) {
57*e0c1b49fSNick Terrell __asm__(
58*e0c1b49fSNick Terrell "pushl %%ebx\n\t"
59*e0c1b49fSNick Terrell "cpuid\n\t"
60*e0c1b49fSNick Terrell "movl %%ebx, %%eax\n\t"
61*e0c1b49fSNick Terrell "popl %%ebx"
62*e0c1b49fSNick Terrell : "=a"(f7b), "=c"(f7c)
63*e0c1b49fSNick Terrell : "a"(7), "c"(0)
64*e0c1b49fSNick Terrell : "edx");
65*e0c1b49fSNick Terrell }
66*e0c1b49fSNick Terrell #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__)
67*e0c1b49fSNick Terrell U32 n;
68*e0c1b49fSNick Terrell __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
69*e0c1b49fSNick Terrell if (n >= 1) {
70*e0c1b49fSNick Terrell U32 f1a;
71*e0c1b49fSNick Terrell __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx");
72*e0c1b49fSNick Terrell }
73*e0c1b49fSNick Terrell if (n >= 7) {
74*e0c1b49fSNick Terrell U32 f7a;
75*e0c1b49fSNick Terrell __asm__("cpuid"
76*e0c1b49fSNick Terrell : "=a"(f7a), "=b"(f7b), "=c"(f7c)
77*e0c1b49fSNick Terrell : "a"(7), "c"(0)
78*e0c1b49fSNick Terrell : "edx");
79*e0c1b49fSNick Terrell }
80*e0c1b49fSNick Terrell #endif
81*e0c1b49fSNick Terrell {
82*e0c1b49fSNick Terrell ZSTD_cpuid_t cpuid;
83*e0c1b49fSNick Terrell cpuid.f1c = f1c;
84*e0c1b49fSNick Terrell cpuid.f1d = f1d;
85*e0c1b49fSNick Terrell cpuid.f7b = f7b;
86*e0c1b49fSNick Terrell cpuid.f7c = f7c;
87*e0c1b49fSNick Terrell return cpuid;
88*e0c1b49fSNick Terrell }
89*e0c1b49fSNick Terrell }
90*e0c1b49fSNick Terrell
91*e0c1b49fSNick Terrell #define X(name, r, bit) \
92*e0c1b49fSNick Terrell MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \
93*e0c1b49fSNick Terrell return ((cpuid.r) & (1U << bit)) != 0; \
94*e0c1b49fSNick Terrell }
95*e0c1b49fSNick Terrell
96*e0c1b49fSNick Terrell /* cpuid(1): Processor Info and Feature Bits. */
97*e0c1b49fSNick Terrell #define C(name, bit) X(name, f1c, bit)
98*e0c1b49fSNick Terrell C(sse3, 0)
99*e0c1b49fSNick Terrell C(pclmuldq, 1)
100*e0c1b49fSNick Terrell C(dtes64, 2)
101*e0c1b49fSNick Terrell C(monitor, 3)
102*e0c1b49fSNick Terrell C(dscpl, 4)
103*e0c1b49fSNick Terrell C(vmx, 5)
104*e0c1b49fSNick Terrell C(smx, 6)
105*e0c1b49fSNick Terrell C(eist, 7)
106*e0c1b49fSNick Terrell C(tm2, 8)
107*e0c1b49fSNick Terrell C(ssse3, 9)
108*e0c1b49fSNick Terrell C(cnxtid, 10)
109*e0c1b49fSNick Terrell C(fma, 12)
110*e0c1b49fSNick Terrell C(cx16, 13)
111*e0c1b49fSNick Terrell C(xtpr, 14)
112*e0c1b49fSNick Terrell C(pdcm, 15)
113*e0c1b49fSNick Terrell C(pcid, 17)
114*e0c1b49fSNick Terrell C(dca, 18)
115*e0c1b49fSNick Terrell C(sse41, 19)
116*e0c1b49fSNick Terrell C(sse42, 20)
117*e0c1b49fSNick Terrell C(x2apic, 21)
118*e0c1b49fSNick Terrell C(movbe, 22)
119*e0c1b49fSNick Terrell C(popcnt, 23)
120*e0c1b49fSNick Terrell C(tscdeadline, 24)
121*e0c1b49fSNick Terrell C(aes, 25)
122*e0c1b49fSNick Terrell C(xsave, 26)
123*e0c1b49fSNick Terrell C(osxsave, 27)
124*e0c1b49fSNick Terrell C(avx, 28)
125*e0c1b49fSNick Terrell C(f16c, 29)
126*e0c1b49fSNick Terrell C(rdrand, 30)
127*e0c1b49fSNick Terrell #undef C
128*e0c1b49fSNick Terrell #define D(name, bit) X(name, f1d, bit)
129*e0c1b49fSNick Terrell D(fpu, 0)
130*e0c1b49fSNick Terrell D(vme, 1)
131*e0c1b49fSNick Terrell D(de, 2)
132*e0c1b49fSNick Terrell D(pse, 3)
133*e0c1b49fSNick Terrell D(tsc, 4)
134*e0c1b49fSNick Terrell D(msr, 5)
135*e0c1b49fSNick Terrell D(pae, 6)
136*e0c1b49fSNick Terrell D(mce, 7)
137*e0c1b49fSNick Terrell D(cx8, 8)
138*e0c1b49fSNick Terrell D(apic, 9)
139*e0c1b49fSNick Terrell D(sep, 11)
140*e0c1b49fSNick Terrell D(mtrr, 12)
141*e0c1b49fSNick Terrell D(pge, 13)
142*e0c1b49fSNick Terrell D(mca, 14)
143*e0c1b49fSNick Terrell D(cmov, 15)
144*e0c1b49fSNick Terrell D(pat, 16)
145*e0c1b49fSNick Terrell D(pse36, 17)
146*e0c1b49fSNick Terrell D(psn, 18)
147*e0c1b49fSNick Terrell D(clfsh, 19)
148*e0c1b49fSNick Terrell D(ds, 21)
149*e0c1b49fSNick Terrell D(acpi, 22)
150*e0c1b49fSNick Terrell D(mmx, 23)
151*e0c1b49fSNick Terrell D(fxsr, 24)
152*e0c1b49fSNick Terrell D(sse, 25)
153*e0c1b49fSNick Terrell D(sse2, 26)
154*e0c1b49fSNick Terrell D(ss, 27)
155*e0c1b49fSNick Terrell D(htt, 28)
156*e0c1b49fSNick Terrell D(tm, 29)
157*e0c1b49fSNick Terrell D(pbe, 31)
158*e0c1b49fSNick Terrell #undef D
159*e0c1b49fSNick Terrell
160*e0c1b49fSNick Terrell /* cpuid(7): Extended Features. */
161*e0c1b49fSNick Terrell #define B(name, bit) X(name, f7b, bit)
162*e0c1b49fSNick Terrell B(bmi1, 3)
163*e0c1b49fSNick Terrell B(hle, 4)
164*e0c1b49fSNick Terrell B(avx2, 5)
165*e0c1b49fSNick Terrell B(smep, 7)
166*e0c1b49fSNick Terrell B(bmi2, 8)
167*e0c1b49fSNick Terrell B(erms, 9)
168*e0c1b49fSNick Terrell B(invpcid, 10)
169*e0c1b49fSNick Terrell B(rtm, 11)
170*e0c1b49fSNick Terrell B(mpx, 14)
171*e0c1b49fSNick Terrell B(avx512f, 16)
172*e0c1b49fSNick Terrell B(avx512dq, 17)
173*e0c1b49fSNick Terrell B(rdseed, 18)
174*e0c1b49fSNick Terrell B(adx, 19)
175*e0c1b49fSNick Terrell B(smap, 20)
176*e0c1b49fSNick Terrell B(avx512ifma, 21)
177*e0c1b49fSNick Terrell B(pcommit, 22)
178*e0c1b49fSNick Terrell B(clflushopt, 23)
179*e0c1b49fSNick Terrell B(clwb, 24)
180*e0c1b49fSNick Terrell B(avx512pf, 26)
181*e0c1b49fSNick Terrell B(avx512er, 27)
182*e0c1b49fSNick Terrell B(avx512cd, 28)
183*e0c1b49fSNick Terrell B(sha, 29)
184*e0c1b49fSNick Terrell B(avx512bw, 30)
185*e0c1b49fSNick Terrell B(avx512vl, 31)
186*e0c1b49fSNick Terrell #undef B
187*e0c1b49fSNick Terrell #define C(name, bit) X(name, f7c, bit)
188*e0c1b49fSNick Terrell C(prefetchwt1, 0)
189*e0c1b49fSNick Terrell C(avx512vbmi, 1)
190*e0c1b49fSNick Terrell #undef C
191*e0c1b49fSNick Terrell
192*e0c1b49fSNick Terrell #undef X
193*e0c1b49fSNick Terrell
194*e0c1b49fSNick Terrell #endif /* ZSTD_COMMON_CPU_H */
195