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