• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 Google LLC
2 // Copyright 2020 Intel Corporation
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 #include "cpuinfo_x86.h"
17 
18 #include <stdbool.h>
19 #include <string.h>
20 
21 #include "internal/bit_utils.h"
22 #include "internal/cpuid_x86.h"
23 
24 #if !defined(CPU_FEATURES_ARCH_X86)
25 #error "Cannot compile cpuinfo_x86 on a non x86 platform."
26 #endif
27 
28 // Generation of feature's getters/setters functions and kGetters, kSetters,
29 // kCpuInfoFlags global tables.
30 #define DEFINE_TABLE_FEATURES                                                  \
31   FEATURE(X86_FPU, fpu, "fpu", 0, 0)                                           \
32   FEATURE(X86_TSC, tsc, "tsc", 0, 0)                                           \
33   FEATURE(X86_CX8, cx8, "cx8", 0, 0)                                           \
34   FEATURE(X86_CLFSH, clfsh, "clfsh", 0, 0)                                     \
35   FEATURE(X86_MMX, mmx, "mmx", 0, 0)                                           \
36   FEATURE(X86_AES, aes, "aes", 0, 0)                                           \
37   FEATURE(X86_ERMS, erms, "erms", 0, 0)                                        \
38   FEATURE(X86_F16C, f16c, "f16c", 0, 0)                                        \
39   FEATURE(X86_FMA4, fma4, "fma4", 0, 0)                                        \
40   FEATURE(X86_FMA3, fma3, "fma3", 0, 0)                                        \
41   FEATURE(X86_VAES, vaes, "vaes", 0, 0)                                        \
42   FEATURE(X86_VPCLMULQDQ, vpclmulqdq, "vpclmulqdq", 0, 0)                      \
43   FEATURE(X86_BMI1, bmi1, "bmi1", 0, 0)                                        \
44   FEATURE(X86_HLE, hle, "hle", 0, 0)                                           \
45   FEATURE(X86_BMI2, bmi2, "bmi2", 0, 0)                                        \
46   FEATURE(X86_RTM, rtm, "rtm", 0, 0)                                           \
47   FEATURE(X86_RDSEED, rdseed, "rdseed", 0, 0)                                  \
48   FEATURE(X86_CLFLUSHOPT, clflushopt, "clflushopt", 0, 0)                      \
49   FEATURE(X86_CLWB, clwb, "clwb", 0, 0)                                        \
50   FEATURE(X86_SSE, sse, "sse", 0, 0)                                           \
51   FEATURE(X86_SSE2, sse2, "sse2", 0, 0)                                        \
52   FEATURE(X86_SSE3, sse3, "sse3", 0, 0)                                        \
53   FEATURE(X86_SSSE3, ssse3, "ssse3", 0, 0)                                     \
54   FEATURE(X86_SSE4_1, sse4_1, "sse4_1", 0, 0)                                  \
55   FEATURE(X86_SSE4_2, sse4_2, "sse4_2", 0, 0)                                  \
56   FEATURE(X86_SSE4A, sse4a, "sse4a", 0, 0)                                     \
57   FEATURE(X86_AVX, avx, "avx", 0, 0)                                           \
58   FEATURE(X86_AVX2, avx2, "avx2", 0, 0)                                        \
59   FEATURE(X86_AVX512F, avx512f, "avx512f", 0, 0)                               \
60   FEATURE(X86_AVX512CD, avx512cd, "avx512cd", 0, 0)                            \
61   FEATURE(X86_AVX512ER, avx512er, "avx512er", 0, 0)                            \
62   FEATURE(X86_AVX512PF, avx512pf, "avx512pf", 0, 0)                            \
63   FEATURE(X86_AVX512BW, avx512bw, "avx512bw", 0, 0)                            \
64   FEATURE(X86_AVX512DQ, avx512dq, "avx512dq", 0, 0)                            \
65   FEATURE(X86_AVX512VL, avx512vl, "avx512vl", 0, 0)                            \
66   FEATURE(X86_AVX512IFMA, avx512ifma, "avx512ifma", 0, 0)                      \
67   FEATURE(X86_AVX512VBMI, avx512vbmi, "avx512vbmi", 0, 0)                      \
68   FEATURE(X86_AVX512VBMI2, avx512vbmi2, "avx512vbmi2", 0, 0)                   \
69   FEATURE(X86_AVX512VNNI, avx512vnni, "avx512vnni", 0, 0)                      \
70   FEATURE(X86_AVX512BITALG, avx512bitalg, "avx512bitalg", 0, 0)                \
71   FEATURE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, "avx512vpopcntdq", 0, 0)       \
72   FEATURE(X86_AVX512_4VNNIW, avx512_4vnniw, "avx512_4vnniw", 0, 0)             \
73   FEATURE(X86_AVX512_4VBMI2, avx512_4vbmi2, "avx512_4vbmi2", 0, 0)             \
74   FEATURE(X86_AVX512_SECOND_FMA, avx512_second_fma, "avx512_second_fma", 0, 0) \
75   FEATURE(X86_AVX512_4FMAPS, avx512_4fmaps, "avx512_4fmaps", 0, 0)             \
76   FEATURE(X86_AVX512_BF16, avx512_bf16, "avx512_bf16", 0, 0)                   \
77   FEATURE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, "avx512_vp2intersect", \
78           0, 0)                                                                \
79   FEATURE(X86_AMX_BF16, amx_bf16, "amx_bf16", 0, 0)                            \
80   FEATURE(X86_AMX_TILE, amx_tile, "amx_tile", 0, 0)                            \
81   FEATURE(X86_AMX_INT8, amx_int8, "amx_int8", 0, 0)                            \
82   FEATURE(X86_PCLMULQDQ, pclmulqdq, "pclmulqdq", 0, 0)                         \
83   FEATURE(X86_SMX, smx, "smx", 0, 0)                                           \
84   FEATURE(X86_SGX, sgx, "sgx", 0, 0)                                           \
85   FEATURE(X86_CX16, cx16, "cx16", 0, 0)                                        \
86   FEATURE(X86_SHA, sha, "sha", 0, 0)                                           \
87   FEATURE(X86_POPCNT, popcnt, "popcnt", 0, 0)                                  \
88   FEATURE(X86_MOVBE, movbe, "movbe", 0, 0)                                     \
89   FEATURE(X86_RDRND, rdrnd, "rdrnd", 0, 0)                                     \
90   FEATURE(X86_DCA, dca, "dca", 0, 0)                                           \
91   FEATURE(X86_SS, ss, "ss", 0, 0)
92 #define DEFINE_TABLE_FEATURE_TYPE X86Features
93 #define DEFINE_TABLE_DONT_GENERATE_HWCAPS
94 #include "define_tables.h"
95 
96 // The following includes are necessary to provide SSE detections on pre-AVX
97 // microarchitectures.
98 #if defined(CPU_FEATURES_OS_WINDOWS)
99 #include <windows.h>  // IsProcessorFeaturePresent
100 #elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
101 #include "internal/filesystem.h"         // Needed to parse /proc/cpuinfo
102 #include "internal/stack_line_reader.h"  // Needed to parse /proc/cpuinfo
103 #include "internal/string_view.h"        // Needed to parse /proc/cpuinfo
104 #elif defined(CPU_FEATURES_OS_DARWIN)
105 #if !defined(HAVE_SYSCTLBYNAME)
106 #error "Darwin needs support for sysctlbyname"
107 #endif
108 #include <sys/sysctl.h>
109 #else
110 #error "Unsupported OS"
111 #endif  // CPU_FEATURES_OS
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 // Definitions for CpuId and GetXCR0Eax.
115 ////////////////////////////////////////////////////////////////////////////////
116 
117 #if defined(CPU_FEATURES_MOCK_CPUID_X86)
118 // Implementation will be provided by test/cpuinfo_x86_test.cc.
119 #elif defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
120 
121 #include <cpuid.h>
122 
GetCpuidLeaf(uint32_t leaf_id,int ecx)123 Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
124   Leaf leaf;
125   __cpuid_count(leaf_id, ecx, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
126   return leaf;
127 }
128 
GetXCR0Eax(void)129 uint32_t GetXCR0Eax(void) {
130   uint32_t eax, edx;
131   /* named form of xgetbv not supported on OSX, so must use byte form, see:
132      https://github.com/asmjit/asmjit/issues/78
133    */
134   __asm(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0));
135   return eax;
136 }
137 
138 #elif defined(CPU_FEATURES_COMPILER_MSC)
139 
140 #include <immintrin.h>
141 #include <intrin.h>  // For __cpuidex()
142 
GetCpuidLeaf(uint32_t leaf_id,int ecx)143 Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
144   Leaf leaf;
145   int data[4];
146   __cpuidex(data, leaf_id, ecx);
147   leaf.eax = data[0];
148   leaf.ebx = data[1];
149   leaf.ecx = data[2];
150   leaf.edx = data[3];
151   return leaf;
152 }
153 
GetXCR0Eax(void)154 uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
155 
156 #else
157 #error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
158 #endif
159 
CpuId(uint32_t leaf_id)160 static Leaf CpuId(uint32_t leaf_id) { return GetCpuidLeaf(leaf_id, 0); }
161 
162 static const Leaf kEmptyLeaf;
163 
SafeCpuIdEx(uint32_t max_cpuid_leaf,uint32_t leaf_id,int ecx)164 static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
165   if (leaf_id <= max_cpuid_leaf) {
166     return GetCpuidLeaf(leaf_id, ecx);
167   } else {
168     return kEmptyLeaf;
169   }
170 }
171 
SafeCpuId(uint32_t max_cpuid_leaf,uint32_t leaf_id)172 static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
173   return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0);
174 }
175 
176 #define MASK_XMM 0x2
177 #define MASK_YMM 0x4
178 #define MASK_MASKREG 0x20
179 #define MASK_ZMM0_15 0x40
180 #define MASK_ZMM16_31 0x80
181 #define MASK_XTILECFG 0x20000
182 #define MASK_XTILEDATA 0x40000
183 
HasMask(uint32_t value,uint32_t mask)184 static bool HasMask(uint32_t value, uint32_t mask) {
185   return (value & mask) == mask;
186 }
187 
188 // Checks that operating system saves and restores xmm registers during context
189 // switches.
HasXmmOsXSave(uint32_t xcr0_eax)190 static bool HasXmmOsXSave(uint32_t xcr0_eax) {
191   return HasMask(xcr0_eax, MASK_XMM);
192 }
193 
194 // Checks that operating system saves and restores ymm registers during context
195 // switches.
HasYmmOsXSave(uint32_t xcr0_eax)196 static bool HasYmmOsXSave(uint32_t xcr0_eax) {
197   return HasMask(xcr0_eax, MASK_XMM | MASK_YMM);
198 }
199 
200 // Checks that operating system saves and restores zmm registers during context
201 // switches.
HasZmmOsXSave(uint32_t xcr0_eax)202 static bool HasZmmOsXSave(uint32_t xcr0_eax) {
203   return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
204                                MASK_ZMM16_31);
205 }
206 
207 // Checks that operating system saves and restores AMX/TMUL state during context
208 // switches.
HasTmmOsXSave(uint32_t xcr0_eax)209 static bool HasTmmOsXSave(uint32_t xcr0_eax) {
210   return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
211                                MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA);
212 }
213 
HasSecondFMA(uint32_t model)214 static bool HasSecondFMA(uint32_t model) {
215   // Skylake server
216   if (model == 0x55) {
217     char proc_name[49] = {0};
218     FillX86BrandString(proc_name);
219     // detect Xeon
220     if (proc_name[9] == 'X') {
221       // detect Silver or Bronze
222       if (proc_name[17] == 'S' || proc_name[17] == 'B') return false;
223       // detect Gold 5_20 and below, except for Gold 53__
224       if (proc_name[17] == 'G' && proc_name[22] == '5')
225         return ((proc_name[23] == '3') ||
226                 (proc_name[24] == '2' && proc_name[25] == '2'));
227       // detect Xeon W 210x
228       if (proc_name[17] == 'W' && proc_name[21] == '0') return false;
229       // detect Xeon D 2xxx
230       if (proc_name[17] == 'D' && proc_name[19] == '2' && proc_name[20] == '1')
231         return false;
232     }
233     return true;
234   }
235   // Cannon Lake client
236   if (model == 0x66) return false;
237   // Ice Lake client
238   if (model == 0x7d || model == 0x7e) return false;
239   // This is the right default...
240   return true;
241 }
242 
SetVendor(const Leaf leaf,char * const vendor)243 static void SetVendor(const Leaf leaf, char* const vendor) {
244   *(uint32_t*)(vendor) = leaf.ebx;
245   *(uint32_t*)(vendor + 4) = leaf.edx;
246   *(uint32_t*)(vendor + 8) = leaf.ecx;
247   vendor[12] = '\0';
248 }
249 
IsVendor(const Leaf leaf,const char * const name)250 static int IsVendor(const Leaf leaf, const char* const name) {
251   const uint32_t ebx = *(const uint32_t*)(name);
252   const uint32_t edx = *(const uint32_t*)(name + 4);
253   const uint32_t ecx = *(const uint32_t*)(name + 8);
254   return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
255 }
256 
257 static const CacheLevelInfo kEmptyCacheLevelInfo;
258 
GetCacheLevelInfo(const uint32_t reg)259 static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
260   const int UNDEF = -1;
261   const int KiB = 1024;
262   const int MiB = 1024 * KiB;
263   switch (reg) {
264     case 0x01:
265       return (CacheLevelInfo){.level = UNDEF,
266                               .cache_type = CPU_FEATURE_CACHE_TLB,
267                               .cache_size = 4 * KiB,
268                               .ways = 4,
269                               .line_size = UNDEF,
270                               .tlb_entries = 32,
271                               .partitioning = 0};
272     case 0x02:
273       return (CacheLevelInfo){.level = UNDEF,
274                               .cache_type = CPU_FEATURE_CACHE_TLB,
275                               .cache_size = 4 * MiB,
276                               .ways = 0xFF,
277                               .line_size = UNDEF,
278                               .tlb_entries = 2,
279                               .partitioning = 0};
280     case 0x03:
281       return (CacheLevelInfo){.level = UNDEF,
282                               .cache_type = CPU_FEATURE_CACHE_TLB,
283                               .cache_size = 4 * KiB,
284                               .ways = 4,
285                               .line_size = UNDEF,
286                               .tlb_entries = 64,
287                               .partitioning = 0};
288     case 0x04:
289       return (CacheLevelInfo){.level = UNDEF,
290                               .cache_type = CPU_FEATURE_CACHE_TLB,
291                               .cache_size = 4 * MiB,
292                               .ways = 4,
293                               .line_size = UNDEF,
294                               .tlb_entries = 8,
295                               .partitioning = 0};
296     case 0x05:
297       return (CacheLevelInfo){.level = UNDEF,
298                               .cache_type = CPU_FEATURE_CACHE_TLB,
299                               .cache_size = 4 * MiB,
300                               .ways = 4,
301                               .line_size = UNDEF,
302                               .tlb_entries = 32,
303                               .partitioning = 0};
304     case 0x06:
305       return (CacheLevelInfo){.level = 1,
306                               .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
307                               .cache_size = 8 * KiB,
308                               .ways = 4,
309                               .line_size = 32,
310                               .tlb_entries = UNDEF,
311                               .partitioning = 0};
312     case 0x08:
313       return (CacheLevelInfo){.level = 1,
314                               .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
315                               .cache_size = 16 * KiB,
316                               .ways = 4,
317                               .line_size = 32,
318                               .tlb_entries = UNDEF,
319                               .partitioning = 0};
320     case 0x09:
321       return (CacheLevelInfo){.level = 1,
322                               .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
323                               .cache_size = 32 * KiB,
324                               .ways = 4,
325                               .line_size = 64,
326                               .tlb_entries = UNDEF,
327                               .partitioning = 0};
328     case 0x0A:
329       return (CacheLevelInfo){.level = 1,
330                               .cache_type = CPU_FEATURE_CACHE_DATA,
331                               .cache_size = 8 * KiB,
332                               .ways = 2,
333                               .line_size = 32,
334                               .tlb_entries = UNDEF,
335                               .partitioning = 0};
336     case 0x0B:
337       return (CacheLevelInfo){.level = UNDEF,
338                               .cache_type = CPU_FEATURE_CACHE_TLB,
339                               .cache_size = 4 * MiB,
340                               .ways = 4,
341                               .line_size = UNDEF,
342                               .tlb_entries = 4,
343                               .partitioning = 0};
344     case 0x0C:
345       return (CacheLevelInfo){.level = 1,
346                               .cache_type = CPU_FEATURE_CACHE_DATA,
347                               .cache_size = 16 * KiB,
348                               .ways = 4,
349                               .line_size = 32,
350                               .tlb_entries = UNDEF,
351                               .partitioning = 0};
352     case 0x0D:
353       return (CacheLevelInfo){.level = 1,
354                               .cache_type = CPU_FEATURE_CACHE_DATA,
355                               .cache_size = 16 * KiB,
356                               .ways = 4,
357                               .line_size = 64,
358                               .tlb_entries = UNDEF,
359                               .partitioning = 0};
360     case 0x0E:
361       return (CacheLevelInfo){.level = 1,
362                               .cache_type = CPU_FEATURE_CACHE_DATA,
363                               .cache_size = 24 * KiB,
364                               .ways = 6,
365                               .line_size = 64,
366                               .tlb_entries = UNDEF,
367                               .partitioning = 0};
368     case 0x1D:
369       return (CacheLevelInfo){.level = 2,
370                               .cache_type = CPU_FEATURE_CACHE_DATA,
371                               .cache_size = 128 * KiB,
372                               .ways = 2,
373                               .line_size = 64,
374                               .tlb_entries = UNDEF,
375                               .partitioning = 0};
376     case 0x21:
377       return (CacheLevelInfo){.level = 2,
378                               .cache_type = CPU_FEATURE_CACHE_DATA,
379                               .cache_size = 256 * KiB,
380                               .ways = 8,
381                               .line_size = 64,
382                               .tlb_entries = UNDEF,
383                               .partitioning = 0};
384     case 0x22:
385       return (CacheLevelInfo){.level = 3,
386                               .cache_type = CPU_FEATURE_CACHE_DATA,
387                               .cache_size = 512 * KiB,
388                               .ways = 4,
389                               .line_size = 64,
390                               .tlb_entries = UNDEF,
391                               .partitioning = 2};
392     case 0x23:
393       return (CacheLevelInfo){.level = 3,
394                               .cache_type = CPU_FEATURE_CACHE_DATA,
395                               .cache_size = 1 * MiB,
396                               .ways = 8,
397                               .line_size = 64,
398                               .tlb_entries = UNDEF,
399                               .partitioning = 2};
400     case 0x24:
401       return (CacheLevelInfo){.level = 2,
402                               .cache_type = CPU_FEATURE_CACHE_DATA,
403                               .cache_size = 1 * MiB,
404                               .ways = 16,
405                               .line_size = 64,
406                               .tlb_entries = UNDEF,
407                               .partitioning = 0};
408     case 0x25:
409       return (CacheLevelInfo){.level = 3,
410                               .cache_type = CPU_FEATURE_CACHE_DATA,
411                               .cache_size = 2 * MiB,
412                               .ways = 8,
413                               .line_size = 64,
414                               .tlb_entries = UNDEF,
415                               .partitioning = 2};
416     case 0x29:
417       return (CacheLevelInfo){.level = 3,
418                               .cache_type = CPU_FEATURE_CACHE_DATA,
419                               .cache_size = 4 * MiB,
420                               .ways = 8,
421                               .line_size = 64,
422                               .tlb_entries = UNDEF,
423                               .partitioning = 2};
424     case 0x2C:
425       return (CacheLevelInfo){.level = 1,
426                               .cache_type = CPU_FEATURE_CACHE_DATA,
427                               .cache_size = 32 * KiB,
428                               .ways = 8,
429                               .line_size = 64,
430                               .tlb_entries = UNDEF,
431                               .partitioning = 0};
432     case 0x30:
433       return (CacheLevelInfo){.level = 1,
434                               .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
435                               .cache_size = 32 * KiB,
436                               .ways = 8,
437                               .line_size = 64,
438                               .tlb_entries = UNDEF,
439                               .partitioning = 0};
440     case 0x40:
441       return (CacheLevelInfo){.level = UNDEF,
442                               .cache_type = CPU_FEATURE_CACHE_DATA,
443                               .cache_size = UNDEF,
444                               .ways = UNDEF,
445                               .line_size = UNDEF,
446                               .tlb_entries = UNDEF,
447                               .partitioning = 0};
448     case 0x41:
449       return (CacheLevelInfo){.level = 2,
450                               .cache_type = CPU_FEATURE_CACHE_DATA,
451                               .cache_size = 128 * KiB,
452                               .ways = 4,
453                               .line_size = 32,
454                               .tlb_entries = UNDEF,
455                               .partitioning = 0};
456     case 0x42:
457       return (CacheLevelInfo){.level = 2,
458                               .cache_type = CPU_FEATURE_CACHE_DATA,
459                               .cache_size = 256 * KiB,
460                               .ways = 4,
461                               .line_size = 32,
462                               .tlb_entries = UNDEF,
463                               .partitioning = 0};
464     case 0x43:
465       return (CacheLevelInfo){.level = 2,
466                               .cache_type = CPU_FEATURE_CACHE_DATA,
467                               .cache_size = 512 * KiB,
468                               .ways = 4,
469                               .line_size = 32,
470                               .tlb_entries = UNDEF,
471                               .partitioning = 0};
472     case 0x44:
473       return (CacheLevelInfo){.level = 2,
474                               .cache_type = CPU_FEATURE_CACHE_DATA,
475                               .cache_size = 1 * MiB,
476                               .ways = 4,
477                               .line_size = 32,
478                               .tlb_entries = UNDEF,
479                               .partitioning = 0};
480     case 0x45:
481       return (CacheLevelInfo){.level = 2,
482                               .cache_type = CPU_FEATURE_CACHE_DATA,
483                               .cache_size = 2 * MiB,
484                               .ways = 4,
485                               .line_size = 32,
486                               .tlb_entries = UNDEF,
487                               .partitioning = 0};
488     case 0x46:
489       return (CacheLevelInfo){.level = 3,
490                               .cache_type = CPU_FEATURE_CACHE_DATA,
491                               .cache_size = 4 * MiB,
492                               .ways = 4,
493                               .line_size = 64,
494                               .tlb_entries = UNDEF,
495                               .partitioning = 0};
496     case 0x47:
497       return (CacheLevelInfo){.level = 3,
498                               .cache_type = CPU_FEATURE_CACHE_DATA,
499                               .cache_size = 8 * MiB,
500                               .ways = 8,
501                               .line_size = 64,
502                               .tlb_entries = UNDEF,
503                               .partitioning = 0};
504     case 0x48:
505       return (CacheLevelInfo){.level = 2,
506                               .cache_type = CPU_FEATURE_CACHE_DATA,
507                               .cache_size = 3 * MiB,
508                               .ways = 12,
509                               .line_size = 64,
510                               .tlb_entries = UNDEF,
511                               .partitioning = 0};
512     case 0x49:
513       return (CacheLevelInfo){.level = 2,
514                               .cache_type = CPU_FEATURE_CACHE_DATA,
515                               .cache_size = 4 * MiB,
516                               .ways = 16,
517                               .line_size = 64,
518                               .tlb_entries = UNDEF,
519                               .partitioning = 0};
520     case (0x49 | (1 << 8)):
521       return (CacheLevelInfo){.level = 3,
522                               .cache_type = CPU_FEATURE_CACHE_DATA,
523                               .cache_size = 4 * MiB,
524                               .ways = 16,
525                               .line_size = 64,
526                               .tlb_entries = UNDEF,
527                               .partitioning = 0};
528     case 0x4A:
529       return (CacheLevelInfo){.level = 3,
530                               .cache_type = CPU_FEATURE_CACHE_DATA,
531                               .cache_size = 6 * MiB,
532                               .ways = 12,
533                               .line_size = 64,
534                               .tlb_entries = UNDEF,
535                               .partitioning = 0};
536     case 0x4B:
537       return (CacheLevelInfo){.level = 3,
538                               .cache_type = CPU_FEATURE_CACHE_DATA,
539                               .cache_size = 8 * MiB,
540                               .ways = 16,
541                               .line_size = 64,
542                               .tlb_entries = UNDEF,
543                               .partitioning = 0};
544     case 0x4C:
545       return (CacheLevelInfo){.level = 3,
546                               .cache_type = CPU_FEATURE_CACHE_DATA,
547                               .cache_size = 12 * MiB,
548                               .ways = 12,
549                               .line_size = 64,
550                               .tlb_entries = UNDEF,
551                               .partitioning = 0};
552     case 0x4D:
553       return (CacheLevelInfo){.level = 3,
554                               .cache_type = CPU_FEATURE_CACHE_DATA,
555                               .cache_size = 16 * MiB,
556                               .ways = 16,
557                               .line_size = 64,
558                               .tlb_entries = UNDEF,
559                               .partitioning = 0};
560     case 0x4E:
561       return (CacheLevelInfo){.level = 2,
562                               .cache_type = CPU_FEATURE_CACHE_DATA,
563                               .cache_size = 6 * MiB,
564                               .ways = 24,
565                               .line_size = 64,
566                               .tlb_entries = UNDEF,
567                               .partitioning = 0};
568     case 0x4F:
569       return (CacheLevelInfo){.level = UNDEF,
570                               .cache_type = CPU_FEATURE_CACHE_TLB,
571                               .cache_size = 4 * KiB,
572                               .ways = UNDEF,
573                               .line_size = UNDEF,
574                               .tlb_entries = 32,
575                               .partitioning = 0};
576     case 0x50:
577       return (CacheLevelInfo){.level = UNDEF,
578                               .cache_type = CPU_FEATURE_CACHE_TLB,
579                               .cache_size = 4 * KiB,
580                               .ways = UNDEF,
581                               .line_size = UNDEF,
582                               .tlb_entries = 64,
583                               .partitioning = 0};
584     case 0x51:
585       return (CacheLevelInfo){.level = UNDEF,
586                               .cache_type = CPU_FEATURE_CACHE_TLB,
587                               .cache_size = 4 * KiB,
588                               .ways = UNDEF,
589                               .line_size = UNDEF,
590                               .tlb_entries = 128,
591                               .partitioning = 0};
592     case 0x52:
593       return (CacheLevelInfo){.level = UNDEF,
594                               .cache_type = CPU_FEATURE_CACHE_TLB,
595                               .cache_size = 4 * KiB,
596                               .ways = UNDEF,
597                               .line_size = UNDEF,
598                               .tlb_entries = 256,
599                               .partitioning = 0};
600     case 0x55:
601       return (CacheLevelInfo){.level = UNDEF,
602                               .cache_type = CPU_FEATURE_CACHE_TLB,
603                               .cache_size = 2 * MiB,
604                               .ways = 0xFF,
605                               .line_size = UNDEF,
606                               .tlb_entries = 7,
607                               .partitioning = 0};
608     case 0x56:
609       return (CacheLevelInfo){.level = UNDEF,
610                               .cache_type = CPU_FEATURE_CACHE_TLB,
611                               .cache_size = 4 * MiB,
612                               .ways = 4,
613                               .line_size = UNDEF,
614                               .tlb_entries = 16,
615                               .partitioning = 0};
616     case 0x57:
617       return (CacheLevelInfo){.level = UNDEF,
618                               .cache_type = CPU_FEATURE_CACHE_TLB,
619                               .cache_size = 4 * KiB,
620                               .ways = 4,
621                               .line_size = UNDEF,
622                               .tlb_entries = 16,
623                               .partitioning = 0};
624     case 0x59:
625       return (CacheLevelInfo){.level = UNDEF,
626                               .cache_type = CPU_FEATURE_CACHE_TLB,
627                               .cache_size = 4 * KiB,
628                               .ways = 0xFF,
629                               .line_size = UNDEF,
630                               .tlb_entries = 16,
631                               .partitioning = 0};
632     case 0x5A:
633       return (CacheLevelInfo){.level = UNDEF,
634                               .cache_type = CPU_FEATURE_CACHE_TLB,
635                               .cache_size = 2 * MiB,
636                               .ways = 4,
637                               .line_size = UNDEF,
638                               .tlb_entries = 32,
639                               .partitioning = 0};
640     case 0x5B:
641       return (CacheLevelInfo){.level = UNDEF,
642                               .cache_type = CPU_FEATURE_CACHE_TLB,
643                               .cache_size = 4 * KiB,
644                               .ways = UNDEF,
645                               .line_size = UNDEF,
646                               .tlb_entries = 64,
647                               .partitioning = 0};
648     case 0x5C:
649       return (CacheLevelInfo){.level = UNDEF,
650                               .cache_type = CPU_FEATURE_CACHE_TLB,
651                               .cache_size = 4 * KiB,
652                               .ways = UNDEF,
653                               .line_size = UNDEF,
654                               .tlb_entries = 128,
655                               .partitioning = 0};
656     case 0x5D:
657       return (CacheLevelInfo){.level = UNDEF,
658                               .cache_type = CPU_FEATURE_CACHE_TLB,
659                               .cache_size = 4,
660                               .ways = UNDEF,
661                               .line_size = UNDEF,
662                               .tlb_entries = 256,
663                               .partitioning = 0};
664     case 0x60:
665       return (CacheLevelInfo){.level = 1,
666                               .cache_type = CPU_FEATURE_CACHE_DATA,
667                               .cache_size = 16 * KiB,
668                               .ways = 8,
669                               .line_size = 64,
670                               .tlb_entries = UNDEF,
671                               .partitioning = 0};
672     case 0x61:
673       return (CacheLevelInfo){.level = UNDEF,
674                               .cache_type = CPU_FEATURE_CACHE_TLB,
675                               .cache_size = 4 * KiB,
676                               .ways = 0xFF,
677                               .line_size = UNDEF,
678                               .tlb_entries = 48,
679                               .partitioning = 0};
680     case 0x63:
681       return (CacheLevelInfo){.level = UNDEF,
682                               .cache_type = CPU_FEATURE_CACHE_TLB,
683                               .cache_size = 2 * MiB,
684                               .ways = 4,
685                               .line_size = UNDEF,
686                               .tlb_entries = 4,
687                               .partitioning = 0};
688     case 0x66:
689       return (CacheLevelInfo){.level = 1,
690                               .cache_type = CPU_FEATURE_CACHE_DATA,
691                               .cache_size = 8 * KiB,
692                               .ways = 4,
693                               .line_size = 64,
694                               .tlb_entries = UNDEF,
695                               .partitioning = 0};
696     case 0x67:
697       return (CacheLevelInfo){.level = 1,
698                               .cache_type = CPU_FEATURE_CACHE_DATA,
699                               .cache_size = 16 * KiB,
700                               .ways = 4,
701                               .line_size = 64,
702                               .tlb_entries = UNDEF,
703                               .partitioning = 0};
704     case 0x68:
705       return (CacheLevelInfo){.level = 1,
706                               .cache_type = CPU_FEATURE_CACHE_DATA,
707                               .cache_size = 32 * KiB,
708                               .ways = 4,
709                               .line_size = 64,
710                               .tlb_entries = UNDEF,
711                               .partitioning = 0};
712     case 0x70:
713       return (CacheLevelInfo){.level = 1,
714                               .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
715                               .cache_size = 12 * KiB,
716                               .ways = 8,
717                               .line_size = UNDEF,
718                               .tlb_entries = UNDEF,
719                               .partitioning = 0};
720     case 0x71:
721       return (CacheLevelInfo){.level = 1,
722                               .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
723                               .cache_size = 16 * KiB,
724                               .ways = 8,
725                               .line_size = UNDEF,
726                               .tlb_entries = UNDEF,
727                               .partitioning = 0};
728     case 0x72:
729       return (CacheLevelInfo){.level = 1,
730                               .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
731                               .cache_size = 32 * KiB,
732                               .ways = 8,
733                               .line_size = UNDEF,
734                               .tlb_entries = UNDEF,
735                               .partitioning = 0};
736     case 0x76:
737       return (CacheLevelInfo){.level = UNDEF,
738                               .cache_type = CPU_FEATURE_CACHE_TLB,
739                               .cache_size = 2 * MiB,
740                               .ways = 0xFF,
741                               .line_size = UNDEF,
742                               .tlb_entries = 8,
743                               .partitioning = 0};
744     case 0x78:
745       return (CacheLevelInfo){.level = 2,
746                               .cache_type = CPU_FEATURE_CACHE_DATA,
747                               .cache_size = 1 * MiB,
748                               .ways = 4,
749                               .line_size = 64,
750                               .tlb_entries = UNDEF,
751                               .partitioning = 0};
752     case 0x79:
753       return (CacheLevelInfo){.level = 2,
754                               .cache_type = CPU_FEATURE_CACHE_DATA,
755                               .cache_size = 128 * KiB,
756                               .ways = 8,
757                               .line_size = 64,
758                               .tlb_entries = UNDEF,
759                               .partitioning = 2};
760     case 0x7A:
761       return (CacheLevelInfo){.level = 2,
762                               .cache_type = CPU_FEATURE_CACHE_DATA,
763                               .cache_size = 256 * KiB,
764                               .ways = 8,
765                               .line_size = 64,
766                               .tlb_entries = UNDEF,
767                               .partitioning = 2};
768     case 0x7B:
769       return (CacheLevelInfo){.level = 2,
770                               .cache_type = CPU_FEATURE_CACHE_DATA,
771                               .cache_size = 512 * KiB,
772                               .ways = 8,
773                               .line_size = 64,
774                               .tlb_entries = UNDEF,
775                               .partitioning = 2};
776     case 0x7C:
777       return (CacheLevelInfo){.level = 2,
778                               .cache_type = CPU_FEATURE_CACHE_DATA,
779                               .cache_size = 1 * MiB,
780                               .ways = 8,
781                               .line_size = 64,
782                               .tlb_entries = UNDEF,
783                               .partitioning = 2};
784     case 0x7D:
785       return (CacheLevelInfo){.level = 2,
786                               .cache_type = CPU_FEATURE_CACHE_DATA,
787                               .cache_size = 2 * MiB,
788                               .ways = 8,
789                               .line_size = 64,
790                               .tlb_entries = UNDEF,
791                               .partitioning = 0};
792     case 0x7F:
793       return (CacheLevelInfo){.level = 2,
794                               .cache_type = CPU_FEATURE_CACHE_DATA,
795                               .cache_size = 512 * KiB,
796                               .ways = 2,
797                               .line_size = 64,
798                               .tlb_entries = UNDEF,
799                               .partitioning = 0};
800     case 0x80:
801       return (CacheLevelInfo){.level = 2,
802                               .cache_type = CPU_FEATURE_CACHE_DATA,
803                               .cache_size = 512 * KiB,
804                               .ways = 8,
805                               .line_size = 64,
806                               .tlb_entries = UNDEF,
807                               .partitioning = 0};
808     case 0x82:
809       return (CacheLevelInfo){.level = 2,
810                               .cache_type = CPU_FEATURE_CACHE_DATA,
811                               .cache_size = 256 * KiB,
812                               .ways = 8,
813                               .line_size = 32,
814                               .tlb_entries = UNDEF,
815                               .partitioning = 0};
816     case 0x83:
817       return (CacheLevelInfo){.level = 2,
818                               .cache_type = CPU_FEATURE_CACHE_DATA,
819                               .cache_size = 512 * KiB,
820                               .ways = 8,
821                               .line_size = 32,
822                               .tlb_entries = UNDEF,
823                               .partitioning = 0};
824     case 0x84:
825       return (CacheLevelInfo){.level = 2,
826                               .cache_type = CPU_FEATURE_CACHE_DATA,
827                               .cache_size = 1 * MiB,
828                               .ways = 8,
829                               .line_size = 32,
830                               .tlb_entries = UNDEF,
831                               .partitioning = 0};
832     case 0x85:
833       return (CacheLevelInfo){.level = 2,
834                               .cache_type = CPU_FEATURE_CACHE_DATA,
835                               .cache_size = 2 * MiB,
836                               .ways = 8,
837                               .line_size = 32,
838                               .tlb_entries = UNDEF,
839                               .partitioning = 0};
840     case 0x86:
841       return (CacheLevelInfo){.level = 2,
842                               .cache_type = CPU_FEATURE_CACHE_DATA,
843                               .cache_size = 512 * KiB,
844                               .ways = 4,
845                               .line_size = 32,
846                               .tlb_entries = UNDEF,
847                               .partitioning = 0};
848     case 0x87:
849       return (CacheLevelInfo){.level = 2,
850                               .cache_type = CPU_FEATURE_CACHE_DATA,
851                               .cache_size = 1 * MiB,
852                               .ways = 8,
853                               .line_size = 64,
854                               .tlb_entries = UNDEF,
855                               .partitioning = 0};
856     case 0xA0:
857       return (CacheLevelInfo){.level = UNDEF,
858                               .cache_type = CPU_FEATURE_CACHE_DTLB,
859                               .cache_size = 4 * KiB,
860                               .ways = 0xFF,
861                               .line_size = UNDEF,
862                               .tlb_entries = 32,
863                               .partitioning = 0};
864     case 0xB0:
865       return (CacheLevelInfo){.level = UNDEF,
866                               .cache_type = CPU_FEATURE_CACHE_TLB,
867                               .cache_size = 4 * KiB,
868                               .ways = 4,
869                               .line_size = UNDEF,
870                               .tlb_entries = 128,
871                               .partitioning = 0};
872     case 0xB1:
873       return (CacheLevelInfo){.level = UNDEF,
874                               .cache_type = CPU_FEATURE_CACHE_TLB,
875                               .cache_size = 2 * MiB,
876                               .ways = 4,
877                               .line_size = UNDEF,
878                               .tlb_entries = 8,
879                               .partitioning = 0};
880     case 0xB2:
881       return (CacheLevelInfo){.level = UNDEF,
882                               .cache_type = CPU_FEATURE_CACHE_TLB,
883                               .cache_size = 4 * KiB,
884                               .ways = 4,
885                               .line_size = UNDEF,
886                               .tlb_entries = 64,
887                               .partitioning = 0};
888     case 0xB3:
889       return (CacheLevelInfo){.level = UNDEF,
890                               .cache_type = CPU_FEATURE_CACHE_TLB,
891                               .cache_size = 4 * KiB,
892                               .ways = 4,
893                               .line_size = UNDEF,
894                               .tlb_entries = 128,
895                               .partitioning = 0};
896     case 0xB4:
897       return (CacheLevelInfo){.level = UNDEF,
898                               .cache_type = CPU_FEATURE_CACHE_TLB,
899                               .cache_size = 4 * KiB,
900                               .ways = 4,
901                               .line_size = UNDEF,
902                               .tlb_entries = 256,
903                               .partitioning = 0};
904     case 0xB5:
905       return (CacheLevelInfo){.level = UNDEF,
906                               .cache_type = CPU_FEATURE_CACHE_TLB,
907                               .cache_size = 4 * KiB,
908                               .ways = 8,
909                               .line_size = UNDEF,
910                               .tlb_entries = 64,
911                               .partitioning = 0};
912     case 0xB6:
913       return (CacheLevelInfo){.level = UNDEF,
914                               .cache_type = CPU_FEATURE_CACHE_TLB,
915                               .cache_size = 4 * KiB,
916                               .ways = 8,
917                               .line_size = UNDEF,
918                               .tlb_entries = 128,
919                               .partitioning = 0};
920     case 0xBA:
921       return (CacheLevelInfo){.level = UNDEF,
922                               .cache_type = CPU_FEATURE_CACHE_TLB,
923                               .cache_size = 4 * KiB,
924                               .ways = 4,
925                               .line_size = UNDEF,
926                               .tlb_entries = 64,
927                               .partitioning = 0};
928     case 0xC0:
929       return (CacheLevelInfo){.level = UNDEF,
930                               .cache_type = CPU_FEATURE_CACHE_TLB,
931                               .cache_size = 4 * KiB,
932                               .ways = 4,
933                               .line_size = UNDEF,
934                               .tlb_entries = 8,
935                               .partitioning = 0};
936     case 0xC1:
937       return (CacheLevelInfo){.level = UNDEF,
938                               .cache_type = CPU_FEATURE_CACHE_STLB,
939                               .cache_size = 4 * KiB,
940                               .ways = 8,
941                               .line_size = UNDEF,
942                               .tlb_entries = 1024,
943                               .partitioning = 0};
944     case 0xC2:
945       return (CacheLevelInfo){.level = UNDEF,
946                               .cache_type = CPU_FEATURE_CACHE_DTLB,
947                               .cache_size = 4 * KiB,
948                               .ways = 4,
949                               .line_size = UNDEF,
950                               .tlb_entries = 16,
951                               .partitioning = 0};
952     case 0xC3:
953       return (CacheLevelInfo){.level = UNDEF,
954                               .cache_type = CPU_FEATURE_CACHE_STLB,
955                               .cache_size = 4 * KiB,
956                               .ways = 6,
957                               .line_size = UNDEF,
958                               .tlb_entries = 1536,
959                               .partitioning = 0};
960     case 0xCA:
961       return (CacheLevelInfo){.level = UNDEF,
962                               .cache_type = CPU_FEATURE_CACHE_STLB,
963                               .cache_size = 4 * KiB,
964                               .ways = 4,
965                               .line_size = UNDEF,
966                               .tlb_entries = 512,
967                               .partitioning = 0};
968     case 0xD0:
969       return (CacheLevelInfo){.level = 3,
970                               .cache_type = CPU_FEATURE_CACHE_DATA,
971                               .cache_size = 512 * KiB,
972                               .ways = 4,
973                               .line_size = 64,
974                               .tlb_entries = UNDEF,
975                               .partitioning = 0};
976     case 0xD1:
977       return (CacheLevelInfo){.level = 3,
978                               .cache_type = CPU_FEATURE_CACHE_DATA,
979                               .cache_size = 1 * MiB,
980                               .ways = 4,
981                               .line_size = 64,
982                               .tlb_entries = UNDEF,
983                               .partitioning = 0};
984     case 0xD2:
985       return (CacheLevelInfo){.level = 3,
986                               .cache_type = CPU_FEATURE_CACHE_DATA,
987                               .cache_size = 2 * MiB,
988                               .ways = 4,
989                               .line_size = 64,
990                               .tlb_entries = UNDEF,
991                               .partitioning = 0};
992     case 0xD6:
993       return (CacheLevelInfo){.level = 3,
994                               .cache_type = CPU_FEATURE_CACHE_DATA,
995                               .cache_size = 1 * MiB,
996                               .ways = 8,
997                               .line_size = 64,
998                               .tlb_entries = UNDEF,
999                               .partitioning = 0};
1000     case 0xD7:
1001       return (CacheLevelInfo){.level = 3,
1002                               .cache_type = CPU_FEATURE_CACHE_DATA,
1003                               .cache_size = 2 * MiB,
1004                               .ways = 8,
1005                               .line_size = 64,
1006                               .tlb_entries = UNDEF,
1007                               .partitioning = 0};
1008     case 0xD8:
1009       return (CacheLevelInfo){.level = 3,
1010                               .cache_type = CPU_FEATURE_CACHE_DATA,
1011                               .cache_size = 4 * MiB,
1012                               .ways = 8,
1013                               .line_size = 64,
1014                               .tlb_entries = UNDEF,
1015                               .partitioning = 0};
1016     case 0xDC:
1017       return (CacheLevelInfo){.level = 3,
1018                               .cache_type = CPU_FEATURE_CACHE_DATA,
1019                               .cache_size = 1 * 1536 * KiB,
1020                               .ways = 12,
1021                               .line_size = 64,
1022                               .tlb_entries = UNDEF,
1023                               .partitioning = 0};
1024     case 0xDD:
1025       return (CacheLevelInfo){.level = 3,
1026                               .cache_type = CPU_FEATURE_CACHE_DATA,
1027                               .cache_size = 3 * MiB,
1028                               .ways = 12,
1029                               .line_size = 64,
1030                               .tlb_entries = UNDEF,
1031                               .partitioning = 0};
1032     case 0xDE:
1033       return (CacheLevelInfo){.level = 3,
1034                               .cache_type = CPU_FEATURE_CACHE_DATA,
1035                               .cache_size = 6 * MiB,
1036                               .ways = 12,
1037                               .line_size = 64,
1038                               .tlb_entries = UNDEF,
1039                               .partitioning = 0};
1040     case 0xE2:
1041       return (CacheLevelInfo){.level = 3,
1042                               .cache_type = CPU_FEATURE_CACHE_DATA,
1043                               .cache_size = 2 * MiB,
1044                               .ways = 16,
1045                               .line_size = 64,
1046                               .tlb_entries = UNDEF,
1047                               .partitioning = 0};
1048     case 0xE3:
1049       return (CacheLevelInfo){.level = 3,
1050                               .cache_type = CPU_FEATURE_CACHE_DATA,
1051                               .cache_size = 4 * MiB,
1052                               .ways = 16,
1053                               .line_size = 64,
1054                               .tlb_entries = UNDEF,
1055                               .partitioning = 0};
1056     case 0xE4:
1057       return (CacheLevelInfo){.level = 3,
1058                               .cache_type = CPU_FEATURE_CACHE_DATA,
1059                               .cache_size = 8 * MiB,
1060                               .ways = 16,
1061                               .line_size = 64,
1062                               .tlb_entries = UNDEF,
1063                               .partitioning = 0};
1064     case 0xEA:
1065       return (CacheLevelInfo){.level = 3,
1066                               .cache_type = CPU_FEATURE_CACHE_DATA,
1067                               .cache_size = 12 * MiB,
1068                               .ways = 24,
1069                               .line_size = 64,
1070                               .tlb_entries = UNDEF,
1071                               .partitioning = 0};
1072     case 0xEB:
1073       return (CacheLevelInfo){.level = 3,
1074                               .cache_type = CPU_FEATURE_CACHE_DATA,
1075                               .cache_size = 18 * MiB,
1076                               .ways = 24,
1077                               .line_size = 64,
1078                               .tlb_entries = UNDEF,
1079                               .partitioning = 0};
1080     case 0xEC:
1081       return (CacheLevelInfo){.level = 3,
1082                               .cache_type = CPU_FEATURE_CACHE_DATA,
1083                               .cache_size = 24 * MiB,
1084                               .ways = 24,
1085                               .line_size = 64,
1086                               .tlb_entries = UNDEF,
1087                               .partitioning = 0};
1088     case 0xF0:
1089       return (CacheLevelInfo){.level = UNDEF,
1090                               .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1091                               .cache_size = 64 * KiB,
1092                               .ways = UNDEF,
1093                               .line_size = UNDEF,
1094                               .tlb_entries = UNDEF,
1095                               .partitioning = 0};
1096     case 0xF1:
1097       return (CacheLevelInfo){.level = UNDEF,
1098                               .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1099                               .cache_size = 128 * KiB,
1100                               .ways = UNDEF,
1101                               .line_size = UNDEF,
1102                               .tlb_entries = UNDEF,
1103                               .partitioning = 0};
1104     case 0xFF:
1105       return (CacheLevelInfo){.level = UNDEF,
1106                               .cache_type = CPU_FEATURE_CACHE_NULL,
1107                               .cache_size = UNDEF,
1108                               .ways = UNDEF,
1109                               .line_size = UNDEF,
1110                               .tlb_entries = UNDEF,
1111                               .partitioning = 0};
1112     default:
1113       return kEmptyCacheLevelInfo;
1114   }
1115 }
1116 
GetByteArrayFromRegister(uint32_t result[4],const uint32_t reg)1117 static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg) {
1118   for (int i = 0; i < 4; ++i) {
1119     result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
1120   }
1121 }
1122 
ParseLeaf2(const int max_cpuid_leaf,CacheInfo * info)1123 static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
1124   Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
1125   uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx};
1126   for (int i = 0; i < 4; ++i) {
1127     if (registers[i] & (1U << 31)) {
1128       continue;  // register does not contains valid information
1129     }
1130     uint32_t bytes[4];
1131     GetByteArrayFromRegister(bytes, registers[i]);
1132     for (int j = 0; j < 4; ++j) {
1133       if (bytes[j] == 0xFF)
1134         break;  // leaf 4 should be used to fetch cache information
1135       info->levels[info->size] = GetCacheLevelInfo(bytes[j]);
1136     }
1137     info->size++;
1138   }
1139 }
1140 
ParseLeaf4(const int max_cpuid_leaf,CacheInfo * info)1141 static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) {
1142   info->size = 0;
1143   for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) {
1144     const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id);
1145     CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
1146     if (cache_type == CPU_FEATURE_CACHE_NULL) {
1147       info->levels[cache_id] = kEmptyCacheLevelInfo;
1148       continue;
1149     }
1150     int level = ExtractBitRange(leaf.eax, 7, 5);
1151     int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
1152     int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
1153     int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
1154     int tlb_entries = leaf.ecx + 1;
1155     int cache_size = (ways * partitioning * line_size * (tlb_entries));
1156     info->levels[cache_id] = (CacheLevelInfo){.level = level,
1157                                               .cache_type = cache_type,
1158                                               .cache_size = cache_size,
1159                                               .ways = ways,
1160                                               .line_size = line_size,
1161                                               .tlb_entries = tlb_entries,
1162                                               .partitioning = partitioning};
1163     info->size++;
1164   }
1165 }
1166 
1167 // Internal structure to hold the OS support for vector operations.
1168 // Avoid to recompute them since each call to cpuid is ~100 cycles.
1169 typedef struct {
1170   bool have_sse_via_os;
1171   bool have_sse_via_cpuid;
1172   bool have_avx;
1173   bool have_avx512;
1174   bool have_amx;
1175 } OsSupport;
1176 
1177 static const OsSupport kEmptyOsSupport;
1178 
CheckOsSupport(const uint32_t max_cpuid_leaf)1179 static OsSupport CheckOsSupport(const uint32_t max_cpuid_leaf) {
1180   const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
1181   const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
1182   const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
1183   const bool have_xcr0 = have_xsave && have_osxsave;
1184 
1185   OsSupport os_support = kEmptyOsSupport;
1186 
1187   if (have_xcr0) {
1188     // AVX capable cpu will expose XCR0.
1189     const uint32_t xcr0_eax = GetXCR0Eax();
1190     os_support.have_sse_via_cpuid = HasXmmOsXSave(xcr0_eax);
1191     os_support.have_avx = HasYmmOsXSave(xcr0_eax);
1192     os_support.have_avx512 = HasZmmOsXSave(xcr0_eax);
1193     os_support.have_amx = HasTmmOsXSave(xcr0_eax);
1194   } else {
1195     // Atom based or older cpus need to ask the OS for sse support.
1196     os_support.have_sse_via_os = true;
1197   }
1198 
1199   return os_support;
1200 }
1201 
1202 #if defined(CPU_FEATURES_OS_WINDOWS)
1203 #if defined(CPU_FEATURES_MOCK_CPUID_X86)
1204 extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
1205 #else  // CPU_FEATURES_MOCK_CPUID_X86
GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature)1206 static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
1207   return IsProcessorFeaturePresent(ProcessorFeature);
1208 }
1209 #endif
1210 #endif  // CPU_FEATURES_OS_WINDOWS
1211 
1212 #if defined(CPU_FEATURES_OS_DARWIN)
1213 #if defined(CPU_FEATURES_MOCK_CPUID_X86)
1214 extern bool GetDarwinSysCtlByName(const char*);
1215 #else  // CPU_FEATURES_MOCK_CPUID_X86
GetDarwinSysCtlByName(const char * name)1216 static bool GetDarwinSysCtlByName(const char* name) {
1217   int enabled;
1218   size_t enabled_len = sizeof(enabled);
1219   const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
1220   return failure ? false : enabled;
1221 }
1222 #endif
1223 #endif  // CPU_FEATURES_OS_DARWIN
1224 
DetectSseViaOs(X86Features * features)1225 static void DetectSseViaOs(X86Features* features) {
1226 #if defined(CPU_FEATURES_OS_WINDOWS)
1227   // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
1228   features->sse =
1229       GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
1230   features->sse2 =
1231       GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
1232   features->sse3 =
1233       GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
1234 #elif defined(CPU_FEATURES_OS_DARWIN)
1235   // Handling Darwin platform through sysctlbyname.
1236   features->sse = GetDarwinSysCtlByName("hw.optional.sse");
1237   features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2");
1238   features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3");
1239   features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
1240   features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
1241   features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
1242 #elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
1243   // Handling Linux platform through /proc/cpuinfo.
1244   const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
1245   if (fd >= 0) {
1246     StackLineReader reader;
1247     StackLineReader_Initialize(&reader, fd);
1248     for (;;) {
1249       const LineResult result = StackLineReader_NextLine(&reader);
1250       const StringView line = result.line;
1251       StringView key, value;
1252       if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
1253         if (CpuFeatures_StringView_IsEquals(key, str("flags"))) {
1254           features->sse = CpuFeatures_StringView_HasWord(value, "sse");
1255           features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2");
1256           features->sse3 = CpuFeatures_StringView_HasWord(value, "sse3");
1257           features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3");
1258           features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1");
1259           features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2");
1260           break;
1261         }
1262       }
1263       if (result.eof) break;
1264     }
1265     CpuFeatures_CloseFile(fd);
1266   }
1267 #else
1268 #error "Unsupported fallback detection of SSE OS support."
1269 #endif
1270 }
1271 
1272 // Reference https://en.wikipedia.org/wiki/CPUID.
ParseCpuId(const uint32_t max_cpuid_leaf,const OsSupport os_support,X86Info * info)1273 static void ParseCpuId(const uint32_t max_cpuid_leaf,
1274                        const OsSupport os_support, X86Info* info) {
1275   const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
1276   const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
1277   const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1);
1278 
1279   const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
1280   const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
1281   const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
1282   const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
1283 
1284   X86Features* const features = &info->features;
1285 
1286   info->family = extended_family + family;
1287   info->model = (extended_model << 4) + model;
1288   info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
1289 
1290   features->fpu = IsBitSet(leaf_1.edx, 0);
1291   features->tsc = IsBitSet(leaf_1.edx, 4);
1292   features->cx8 = IsBitSet(leaf_1.edx, 8);
1293   features->clfsh = IsBitSet(leaf_1.edx, 19);
1294   features->mmx = IsBitSet(leaf_1.edx, 23);
1295   features->ss = IsBitSet(leaf_1.edx, 27);
1296   features->pclmulqdq = IsBitSet(leaf_1.ecx, 1);
1297   features->smx = IsBitSet(leaf_1.ecx, 6);
1298   features->cx16 = IsBitSet(leaf_1.ecx, 13);
1299   features->dca = IsBitSet(leaf_1.ecx, 18);
1300   features->movbe = IsBitSet(leaf_1.ecx, 22);
1301   features->popcnt = IsBitSet(leaf_1.ecx, 23);
1302   features->aes = IsBitSet(leaf_1.ecx, 25);
1303   features->f16c = IsBitSet(leaf_1.ecx, 29);
1304   features->rdrnd = IsBitSet(leaf_1.ecx, 30);
1305   features->sgx = IsBitSet(leaf_7.ebx, 2);
1306   features->bmi1 = IsBitSet(leaf_7.ebx, 3);
1307   features->hle = IsBitSet(leaf_7.ebx, 4);
1308   features->bmi2 = IsBitSet(leaf_7.ebx, 8);
1309   features->erms = IsBitSet(leaf_7.ebx, 9);
1310   features->rtm = IsBitSet(leaf_7.ebx, 11);
1311   features->rdseed = IsBitSet(leaf_7.ebx, 18);
1312   features->clflushopt = IsBitSet(leaf_7.ebx, 23);
1313   features->clwb = IsBitSet(leaf_7.ebx, 24);
1314   features->sha = IsBitSet(leaf_7.ebx, 29);
1315   features->vaes = IsBitSet(leaf_7.ecx, 9);
1316   features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
1317 
1318   if (os_support.have_sse_via_os) {
1319     DetectSseViaOs(features);
1320   } else if (os_support.have_sse_via_cpuid) {
1321     features->sse = IsBitSet(leaf_1.edx, 25);
1322     features->sse2 = IsBitSet(leaf_1.edx, 26);
1323     features->sse3 = IsBitSet(leaf_1.ecx, 0);
1324     features->ssse3 = IsBitSet(leaf_1.ecx, 9);
1325     features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
1326     features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
1327   }
1328 
1329   if (os_support.have_avx) {
1330     features->fma3 = IsBitSet(leaf_1.ecx, 12);
1331     features->avx = IsBitSet(leaf_1.ecx, 28);
1332     features->avx2 = IsBitSet(leaf_7.ebx, 5);
1333   }
1334 
1335   if (os_support.have_avx512) {
1336     features->avx512f = IsBitSet(leaf_7.ebx, 16);
1337     features->avx512cd = IsBitSet(leaf_7.ebx, 28);
1338     features->avx512er = IsBitSet(leaf_7.ebx, 27);
1339     features->avx512pf = IsBitSet(leaf_7.ebx, 26);
1340     features->avx512bw = IsBitSet(leaf_7.ebx, 30);
1341     features->avx512dq = IsBitSet(leaf_7.ebx, 17);
1342     features->avx512vl = IsBitSet(leaf_7.ebx, 31);
1343     features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
1344     features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
1345     features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
1346     features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
1347     features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
1348     features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
1349     features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
1350     features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
1351     features->avx512_second_fma = HasSecondFMA(info->model);
1352     features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
1353     features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
1354     features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
1355   }
1356 
1357   if (os_support.have_amx) {
1358     features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
1359     features->amx_tile = IsBitSet(leaf_7.edx, 24);
1360     features->amx_int8 = IsBitSet(leaf_7.edx, 25);
1361   }
1362 }
1363 
1364 // Reference
1365 // https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
ParseExtraAMDCpuId(X86Info * info,OsSupport os_support)1366 static void ParseExtraAMDCpuId(X86Info* info, OsSupport os_support) {
1367   const Leaf leaf_80000000 = CpuId(0x80000000);
1368   const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
1369   const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
1370 
1371   X86Features* const features = &info->features;
1372 
1373   if (os_support.have_sse_via_cpuid) {
1374     features->sse4a = IsBitSet(leaf_80000001.ecx, 6);
1375   }
1376 
1377   if (os_support.have_avx) {
1378     features->fma4 = IsBitSet(leaf_80000001.ecx, 16);
1379   }
1380 }
1381 
1382 static const X86Info kEmptyX86Info;
1383 static const CacheInfo kEmptyCacheInfo;
1384 
GetX86Info(void)1385 X86Info GetX86Info(void) {
1386   X86Info info = kEmptyX86Info;
1387   const Leaf leaf_0 = CpuId(0);
1388   const bool is_intel = IsVendor(leaf_0, "GenuineIntel");
1389   const bool is_amd = IsVendor(leaf_0, "AuthenticAMD");
1390   SetVendor(leaf_0, info.vendor);
1391   if (is_intel || is_amd) {
1392     const uint32_t max_cpuid_leaf = leaf_0.eax;
1393     const OsSupport os_support = CheckOsSupport(max_cpuid_leaf);
1394     ParseCpuId(max_cpuid_leaf, os_support, &info);
1395     if (is_amd) {
1396       ParseExtraAMDCpuId(&info, os_support);
1397     }
1398   }
1399   return info;
1400 }
1401 
GetX86CacheInfo(void)1402 CacheInfo GetX86CacheInfo(void) {
1403   CacheInfo info = kEmptyCacheInfo;
1404   const Leaf leaf_0 = CpuId(0);
1405   const uint32_t max_cpuid_leaf = leaf_0.eax;
1406   if (IsVendor(leaf_0, "GenuineIntel")) {
1407     ParseLeaf2(max_cpuid_leaf, &info);
1408     ParseLeaf4(max_cpuid_leaf, &info);
1409   }
1410   return info;
1411 }
1412 
1413 #define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
1414 
GetX86Microarchitecture(const X86Info * info)1415 X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
1416   if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
1417     switch (CPUID(info->family, info->model)) {
1418       case CPUID(0x06, 0x35):
1419       case CPUID(0x06, 0x36):
1420         // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
1421         return INTEL_ATOM_BNL;
1422       case CPUID(0x06, 0x37):
1423       case CPUID(0x06, 0x4C):
1424         // https://en.wikipedia.org/wiki/Silvermont
1425         return INTEL_ATOM_SMT;
1426       case CPUID(0x06, 0x5C):
1427         // https://en.wikipedia.org/wiki/Goldmont
1428         return INTEL_ATOM_GMT;
1429       case CPUID(0x06, 0x0F):
1430       case CPUID(0x06, 0x16):
1431         // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
1432         return INTEL_CORE;
1433       case CPUID(0x06, 0x17):
1434       case CPUID(0x06, 0x1D):
1435         // https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
1436         return INTEL_PNR;
1437       case CPUID(0x06, 0x1A):
1438       case CPUID(0x06, 0x1E):
1439       case CPUID(0x06, 0x1F):
1440       case CPUID(0x06, 0x2E):
1441         // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
1442         return INTEL_NHM;
1443       case CPUID(0x06, 0x25):
1444       case CPUID(0x06, 0x2C):
1445       case CPUID(0x06, 0x2F):
1446         // https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
1447         return INTEL_WSM;
1448       case CPUID(0x06, 0x2A):
1449       case CPUID(0x06, 0x2D):
1450         // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
1451         return INTEL_SNB;
1452       case CPUID(0x06, 0x3A):
1453       case CPUID(0x06, 0x3E):
1454         // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
1455         return INTEL_IVB;
1456       case CPUID(0x06, 0x3C):
1457       case CPUID(0x06, 0x3F):
1458       case CPUID(0x06, 0x45):
1459       case CPUID(0x06, 0x46):
1460         // https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
1461         return INTEL_HSW;
1462       case CPUID(0x06, 0x3D):
1463       case CPUID(0x06, 0x47):
1464       case CPUID(0x06, 0x4F):
1465       case CPUID(0x06, 0x56):
1466         // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
1467         return INTEL_BDW;
1468       case CPUID(0x06, 0x4E):
1469       case CPUID(0x06, 0x55):
1470       case CPUID(0x06, 0x5E):
1471         // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
1472         return INTEL_SKL;
1473       case CPUID(0x06, 0x66):
1474         // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
1475         return INTEL_CNL;
1476       case CPUID(0x06, 0x7D):  // client
1477       case CPUID(0x06, 0x7E):  // client
1478       case CPUID(0x06, 0x9D):  // NNP-I
1479       case CPUID(0x06, 0x6A):  // server
1480       case CPUID(0x06, 0x6C):  // server
1481         // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)
1482         return INTEL_ICL;
1483       case CPUID(0x06, 0x8C):
1484       case CPUID(0x06, 0x8D):
1485         // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture)
1486         return INTEL_TGL;
1487       case CPUID(0x06, 0x8F):
1488         // https://en.wikipedia.org/wiki/Sapphire_Rapids
1489         return INTEL_SPR;
1490       case CPUID(0x06, 0x8E):
1491         switch (info->stepping) {
1492           case 9:
1493             return INTEL_KBL;  // https://en.wikipedia.org/wiki/Kaby_Lake
1494           case 10:
1495             return INTEL_CFL;  // https://en.wikipedia.org/wiki/Coffee_Lake
1496           case 11:
1497             return INTEL_WHL;  // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture)
1498           default:
1499             return X86_UNKNOWN;
1500         }
1501       case CPUID(0x06, 0x9E):
1502         if (info->stepping > 9) {
1503           // https://en.wikipedia.org/wiki/Coffee_Lake
1504           return INTEL_CFL;
1505         } else {
1506           // https://en.wikipedia.org/wiki/Kaby_Lake
1507           return INTEL_KBL;
1508         }
1509       default:
1510         return X86_UNKNOWN;
1511     }
1512   }
1513   if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
1514     switch (info->family) {
1515         // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
1516       case 0x0F:
1517         return AMD_HAMMER;
1518       case 0x10:
1519         return AMD_K10;
1520       case 0x14:
1521         return AMD_BOBCAT;
1522       case 0x15:
1523         return AMD_BULLDOZER;
1524       case 0x16:
1525         return AMD_JAGUAR;
1526       case 0x17:
1527         return AMD_ZEN;
1528       default:
1529         return X86_UNKNOWN;
1530     }
1531   }
1532   return X86_UNKNOWN;
1533 }
1534 
SetString(const uint32_t max_cpuid_ext_leaf,const uint32_t leaf_id,char * buffer)1535 static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
1536                       char* buffer) {
1537   const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
1538   // We allow calling memcpy from SetString which is only called when requesting
1539   // X86BrandString.
1540   memcpy(buffer, &leaf, sizeof(Leaf));
1541 }
1542 
FillX86BrandString(char brand_string[49])1543 void FillX86BrandString(char brand_string[49]) {
1544   const Leaf leaf_ext_0 = CpuId(0x80000000);
1545   const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
1546   SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
1547   SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
1548   SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
1549   brand_string[48] = '\0';
1550 }
1551 
1552 ////////////////////////////////////////////////////////////////////////////////
1553 // Introspection functions
1554 
GetX86FeaturesEnumValue(const X86Features * features,X86FeaturesEnum value)1555 int GetX86FeaturesEnumValue(const X86Features* features,
1556                             X86FeaturesEnum value) {
1557   if (value >= X86_LAST_) return false;
1558   return kGetters[value](features);
1559 }
1560 
GetX86FeaturesEnumName(X86FeaturesEnum value)1561 const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
1562   if (value >= X86_LAST_) return "unknown_feature";
1563   return kCpuInfoFlags[value];
1564 }
1565 
GetX86MicroarchitectureName(X86Microarchitecture uarch)1566 const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) {
1567   switch (uarch) {
1568     case X86_UNKNOWN:
1569       return "X86_UNKNOWN";
1570     case INTEL_CORE:
1571       return "INTEL_CORE";
1572     case INTEL_PNR:
1573       return "INTEL_PNR";
1574     case INTEL_NHM:
1575       return "INTEL_NHM";
1576     case INTEL_ATOM_BNL:
1577       return "INTEL_ATOM_BNL";
1578     case INTEL_WSM:
1579       return "INTEL_WSM";
1580     case INTEL_SNB:
1581       return "INTEL_SNB";
1582     case INTEL_IVB:
1583       return "INTEL_IVB";
1584     case INTEL_ATOM_SMT:
1585       return "INTEL_ATOM_SMT";
1586     case INTEL_HSW:
1587       return "INTEL_HSW";
1588     case INTEL_BDW:
1589       return "INTEL_BDW";
1590     case INTEL_SKL:
1591       return "INTEL_SKL";
1592     case INTEL_ATOM_GMT:
1593       return "INTEL_ATOM_GMT";
1594     case INTEL_KBL:
1595       return "INTEL_KBL";
1596     case INTEL_CFL:
1597       return "INTEL_CFL";
1598     case INTEL_WHL:
1599       return "INTEL_WHL";
1600     case INTEL_CNL:
1601       return "INTEL_CNL";
1602     case INTEL_ICL:
1603       return "INTEL_ICL";
1604     case INTEL_TGL:
1605       return "INTEL_TGL";
1606     case INTEL_SPR:
1607       return "INTEL_SPR";
1608     case AMD_HAMMER:
1609       return "AMD_HAMMER";
1610     case AMD_K10:
1611       return "AMD_K10";
1612     case AMD_BOBCAT:
1613       return "AMD_BOBCAT";
1614     case AMD_BULLDOZER:
1615       return "AMD_BULLDOZER";
1616     case AMD_JAGUAR:
1617       return "AMD_JAGUAR";
1618     case AMD_ZEN:
1619       return "AMD_ZEN";
1620   }
1621   return "unknown microarchitecture";
1622 }
1623