Flesh out Optional members swap, reset, emplace, has_value
[folly.git] / folly / CpuId.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <cstdint>
20
21 #include <folly/Portability.h>
22
23 #ifdef _MSC_VER
24 #include <intrin.h>
25 #endif
26
27 namespace folly {
28
29 /**
30  * Identification of an Intel CPU.
31  * Supports CPUID feature flags (EAX=1) and extended features (EAX=7, ECX=0).
32  * Values from http://www.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html
33  */
34 class CpuId {
35  public:
36   // Always inline in order for this to be usable from a __ifunc__.
37   // In shared library mode, a __ifunc__ runs at relocation time, while the
38   // PLT hasn't been fully populated yet; thus, ifuncs cannot use symbols
39   // with potentially external linkage. (This issue is less likely in opt
40   // mode since inlining happens more likely, and it doesn't happen for
41   // statically linked binaries which don't depend on the PLT)
42   FOLLY_ALWAYS_INLINE CpuId() {
43 #ifdef _MSC_VER
44     int reg[4];
45     __cpuid(static_cast<int*>(reg), 0);
46     const int n = reg[0];
47     if (n >= 1) {
48       __cpuid(static_cast<int*>(reg), 1);
49       f1c_ = uint32_t(reg[2]);
50       f1d_ = uint32_t(reg[3]);
51     }
52     if (n >= 7) {
53       __cpuidex(static_cast<int*>(reg), 7, 0);
54       f7b_ = uint32_t(reg[1]);
55       f7c_ = uint32_t(reg[2]);
56     }
57 #elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && \
58     defined(__GNUC__)
59     // The following block like the normal cpuid branch below, but gcc
60     // reserves ebx for use of its pic register so we must specially
61     // handle the save and restore to avoid clobbering the register
62     uint32_t n;
63     __asm__(
64         "pushl %%ebx\n\t"
65         "cpuid\n\t"
66         "popl %%ebx\n\t"
67         : "=a"(n)
68         : "a"(0)
69         : "ecx", "edx");
70     if (n >= 1) {
71       uint32_t f1a;
72       __asm__(
73           "pushl %%ebx\n\t"
74           "cpuid\n\t"
75           "popl %%ebx\n\t"
76           : "=a"(f1a), "=c"(f1c_), "=d"(f1d_)
77           : "a"(1)
78           :);
79     }
80     if (n >= 7) {
81       __asm__(
82           "pushl %%ebx\n\t"
83           "cpuid\n\t"
84           "movl %%ebx, %%eax\n\r"
85           "popl %%ebx"
86           : "=a"(f7b_), "=c"(f7c_)
87           : "a"(7), "c"(0)
88           : "edx");
89     }
90 #elif FOLLY_X64 || defined(__i386__)
91     uint32_t n;
92     __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx");
93     if (n >= 1) {
94       uint32_t f1a;
95       __asm__("cpuid" : "=a"(f1a), "=c"(f1c_), "=d"(f1d_) : "a"(1) : "ebx");
96     }
97     if (n >= 7) {
98       uint32_t f7a;
99       __asm__("cpuid"
100               : "=a"(f7a), "=b"(f7b_), "=c"(f7c_)
101               : "a"(7), "c"(0)
102               : "edx");
103     }
104 #endif
105   }
106
107 #define X(name, r, bit)                   \
108   FOLLY_ALWAYS_INLINE bool name() const { \
109     return ((r) & (1U << bit)) != 0;      \
110   }
111
112 // cpuid(1): Processor Info and Feature Bits.
113 #define C(name, bit) X(name, f1c_, bit)
114   C(sse3, 0)
115   C(pclmuldq, 1)
116   C(dtes64, 2)
117   C(monitor, 3)
118   C(dscpl, 4)
119   C(vmx, 5)
120   C(smx, 6)
121   C(eist, 7)
122   C(tm2, 8)
123   C(ssse3, 9)
124   C(cnxtid, 10)
125   C(fma, 12)
126   C(cx16, 13)
127   C(xtpr, 14)
128   C(pdcm, 15)
129   C(pcid, 17)
130   C(dca, 18)
131   C(sse41, 19)
132   C(sse42, 20)
133   C(x2apic, 21)
134   C(movbe, 22)
135   C(popcnt, 23)
136   C(tscdeadline, 24)
137   C(aes, 25)
138   C(xsave, 26)
139   C(osxsave, 27)
140   C(avx, 28)
141   C(f16c, 29)
142   C(rdrand, 30)
143 #undef C
144 #define D(name, bit) X(name, f1d_, bit)
145   D(fpu, 0)
146   D(vme, 1)
147   D(de, 2)
148   D(pse, 3)
149   D(tsc, 4)
150   D(msr, 5)
151   D(pae, 6)
152   D(mce, 7)
153   D(cx8, 8)
154   D(apic, 9)
155   D(sep, 11)
156   D(mtrr, 12)
157   D(pge, 13)
158   D(mca, 14)
159   D(cmov, 15)
160   D(pat, 16)
161   D(pse36, 17)
162   D(psn, 18)
163   D(clfsh, 19)
164   D(ds, 21)
165   D(acpi, 22)
166   D(mmx, 23)
167   D(fxsr, 24)
168   D(sse, 25)
169   D(sse2, 26)
170   D(ss, 27)
171   D(htt, 28)
172   D(tm, 29)
173   D(pbe, 31)
174 #undef D
175
176   // cpuid(7): Extended Features.
177 #define B(name, bit) X(name, f7b_, bit)
178   B(bmi1, 3)
179   B(hle, 4)
180   B(avx2, 5)
181   B(smep, 7)
182   B(bmi2, 8)
183   B(erms, 9)
184   B(invpcid, 10)
185   B(rtm, 11)
186   B(mpx, 14)
187   B(avx512f, 16)
188   B(avx512dq, 17)
189   B(rdseed, 18)
190   B(adx, 19)
191   B(smap, 20)
192   B(avx512ifma, 21)
193   B(pcommit, 22)
194   B(clflushopt, 23)
195   B(clwb, 24)
196   B(avx512pf, 26)
197   B(avx512er, 27)
198   B(avx512cd, 28)
199   B(sha, 29)
200   B(avx512bw, 30)
201   B(avx512vl, 31)
202 #undef B
203 #define C(name, bit) X(name, f7c_, bit)
204   C(prefetchwt1, 0)
205   C(avx512vbmi, 1)
206 #undef C
207
208 #undef X
209
210  private:
211   uint32_t f1c_ = 0;
212   uint32_t f1d_ = 0;
213   uint32_t f7b_ = 0;
214   uint32_t f7c_ = 0;
215 };
216
217 } // namespace folly