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