• 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 <stdbool.h>
17#include <string.h>
18
19#include "copy.inl"
20#include "cpuinfo_x86.h"
21#include "equals.inl"
22#include "internal/bit_utils.h"
23#include "internal/cpuid_x86.h"
24
25#if !defined(CPU_FEATURES_ARCH_X86)
26#error "Cannot compile cpuinfo_x86 on a non x86 platform."
27#endif
28
29////////////////////////////////////////////////////////////////////////////////
30// Definitions for CpuId and GetXCR0Eax.
31////////////////////////////////////////////////////////////////////////////////
32
33#if defined(CPU_FEATURES_MOCK_CPUID_X86)
34// Implementation will be provided by test/cpuinfo_x86_test.cc.
35#elif defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
36
37#include <cpuid.h>
38
39Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
40  Leaf leaf;
41  __cpuid_count(leaf_id, ecx, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
42  return leaf;
43}
44
45uint32_t GetXCR0Eax(void) {
46  uint32_t eax, edx;
47  /* named form of xgetbv not supported on OSX, so must use byte form, see:
48     https://github.com/asmjit/asmjit/issues/78
49   */
50  __asm(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0));
51  return eax;
52}
53
54#elif defined(CPU_FEATURES_COMPILER_MSC)
55
56#include <immintrin.h>
57#include <intrin.h>  // For __cpuidex()
58
59Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
60  Leaf leaf;
61  int data[4];
62  __cpuidex(data, leaf_id, ecx);
63  leaf.eax = data[0];
64  leaf.ebx = data[1];
65  leaf.ecx = data[2];
66  leaf.edx = data[3];
67  return leaf;
68}
69
70uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
71
72#else
73#error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
74#endif
75
76static const Leaf kEmptyLeaf;
77
78static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
79  if (leaf_id <= max_cpuid_leaf) {
80    return GetCpuidLeaf(leaf_id, ecx);
81  } else {
82    return kEmptyLeaf;
83  }
84}
85
86typedef struct {
87  uint32_t max_cpuid_leaf;
88  Leaf leaf_0;    // Root
89  Leaf leaf_1;    // Family, Model, Stepping
90  Leaf leaf_2;    // Intel cache info + features
91  Leaf leaf_7;    // Features
92  Leaf leaf_7_1;  // Features
93  uint32_t max_cpuid_leaf_ext;
94  Leaf leaf_80000000;  // Root for extended leaves
95  Leaf leaf_80000001;  // AMD features features and cache
96  Leaf leaf_80000002;  // brand string
97  Leaf leaf_80000003;  // brand string
98  Leaf leaf_80000004;  // brand string
99} Leaves;
100
101static Leaves ReadLeaves() {
102  const Leaf leaf_0 = GetCpuidLeaf(0, 0);
103  const uint32_t max_cpuid_leaf = leaf_0.eax;
104  const Leaf leaf_80000000 = GetCpuidLeaf(0x80000000, 0);
105  const uint32_t max_cpuid_leaf_ext = leaf_80000000.eax;
106  return (Leaves){
107      .max_cpuid_leaf = max_cpuid_leaf,
108      .leaf_0 = leaf_0,
109      .leaf_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000001, 0),
110      .leaf_2 = SafeCpuIdEx(max_cpuid_leaf, 0x00000002, 0),
111      .leaf_7 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 0),
112      .leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 1),
113      .max_cpuid_leaf_ext = max_cpuid_leaf_ext,
114      .leaf_80000000 = leaf_80000000,
115      .leaf_80000001 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000001, 0),
116      .leaf_80000002 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000002, 0),
117      .leaf_80000003 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000003, 0),
118      .leaf_80000004 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000004, 0),
119  };
120}
121
122////////////////////////////////////////////////////////////////////////////////
123// OS support
124// TODO: Add documentation
125////////////////////////////////////////////////////////////////////////////////
126
127#define MASK_XMM 0x2
128#define MASK_YMM 0x4
129#define MASK_MASKREG 0x20
130#define MASK_ZMM0_15 0x40
131#define MASK_ZMM16_31 0x80
132#define MASK_XTILECFG 0x20000
133#define MASK_XTILEDATA 0x40000
134
135static bool HasMask(uint32_t value, uint32_t mask) {
136  return (value & mask) == mask;
137}
138
139// Checks that operating system saves and restores xmm registers during context
140// switches.
141static bool HasXmmOsXSave(uint32_t xcr0_eax) {
142  return HasMask(xcr0_eax, MASK_XMM);
143}
144
145// Checks that operating system saves and restores ymm registers during context
146// switches.
147static bool HasYmmOsXSave(uint32_t xcr0_eax) {
148  return HasMask(xcr0_eax, MASK_XMM | MASK_YMM);
149}
150
151// Checks that operating system saves and restores zmm registers during context
152// switches.
153static bool HasZmmOsXSave(uint32_t xcr0_eax) {
154  return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
155                               MASK_ZMM16_31);
156}
157
158// Checks that operating system saves and restores AMX/TMUL state during context
159// switches.
160static bool HasTmmOsXSave(uint32_t xcr0_eax) {
161  return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
162                               MASK_ZMM16_31 | MASK_XTILECFG | MASK_XTILEDATA);
163}
164
165////////////////////////////////////////////////////////////////////////////////
166// Vendor
167////////////////////////////////////////////////////////////////////////////////
168
169static void SetVendor(const Leaf leaf, char* const vendor) {
170  *(uint32_t*)(vendor) = leaf.ebx;
171  *(uint32_t*)(vendor + 4) = leaf.edx;
172  *(uint32_t*)(vendor + 8) = leaf.ecx;
173  vendor[12] = '\0';
174}
175
176static int IsVendor(const Leaf leaf, const char* const name) {
177  const uint32_t ebx = *(const uint32_t*)(name);
178  const uint32_t edx = *(const uint32_t*)(name + 4);
179  const uint32_t ecx = *(const uint32_t*)(name + 8);
180  return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
181}
182
183static int IsVendorByX86Info(const X86Info* info, const char* const name) {
184  return equals(info->vendor, name, sizeof(info->vendor));
185}
186
187// TODO: Remove when deprecation period is over,
188void FillX86BrandString(char brand_string[49]) {
189  const Leaves leaves = ReadLeaves();
190  const Leaf packed[3] = {
191      leaves.leaf_80000002,
192      leaves.leaf_80000003,
193      leaves.leaf_80000004,
194  };
195#if __STDC_VERSION__ >= 201112L
196  _Static_assert(sizeof(packed) == 48, "Leaves must be packed");
197#endif
198  copy(brand_string, (const char*)(packed), 48);
199  brand_string[48] = '\0';
200}
201
202////////////////////////////////////////////////////////////////////////////////
203// CpuId
204////////////////////////////////////////////////////////////////////////////////
205
206static bool HasSecondFMA(const X86Info* info) {
207  // Skylake server
208  if (info->model == 0x55) {
209    // detect Xeon
210    if (info->brand_string[9] == 'X') {
211      // detect Silver or Bronze
212      if (info->brand_string[17] == 'S' || info->brand_string[17] == 'B')
213        return false;
214      // detect Gold 5_20 and below, except for Gold 53__
215      if (info->brand_string[17] == 'G' && info->brand_string[22] == '5')
216        return (
217            (info->brand_string[23] == '3') ||
218            (info->brand_string[24] == '2' && info->brand_string[25] == '2'));
219      // detect Xeon W 210x
220      if (info->brand_string[17] == 'W' && info->brand_string[21] == '0')
221        return false;
222      // detect Xeon D 2xxx
223      if (info->brand_string[17] == 'D' && info->brand_string[19] == '2' &&
224          info->brand_string[20] == '1')
225        return false;
226    }
227    return true;
228  }
229  // Cannon Lake client
230  if (info->model == 0x66) return false;
231  // Ice Lake client
232  if (info->model == 0x7d || info->model == 0x7e) return false;
233  // This is the right default...
234  return true;
235}
236
237// Internal structure to hold the OS support for vector operations.
238// Avoid to recompute them since each call to cpuid is ~100 cycles.
239typedef struct {
240  bool sse_registers;
241  bool avx_registers;
242  bool avx512_registers;
243  bool amx_registers;
244} OsPreserves;
245
246// These two functions have to be implemented by the OS, that is the file
247// including this file.
248static void OverrideOsPreserves(OsPreserves* os_preserves);
249static void DetectFeaturesFromOs(X86Info* info, X86Features* features);
250
251// Reference https://en.wikipedia.org/wiki/CPUID.
252static void ParseCpuId(const Leaves* leaves, X86Info* info,
253                       OsPreserves* os_preserves) {
254  const Leaf leaf_1 = leaves->leaf_1;
255  const Leaf leaf_7 = leaves->leaf_7;
256  const Leaf leaf_7_1 = leaves->leaf_7_1;
257
258  const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
259  const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
260  const bool have_xcr0 = have_xsave && have_osxsave;
261
262  const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
263  const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
264  const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
265  const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
266
267  X86Features* const features = &info->features;
268
269  // Fill Family, Model and Stepping.
270  info->family = extended_family + family;
271  info->model = (extended_model << 4) + model;
272  info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
273
274  // Fill Brand String.
275  const Leaf packed[3] = {
276      leaves->leaf_80000002,
277      leaves->leaf_80000003,
278      leaves->leaf_80000004,
279  };
280#if __STDC_VERSION__ >= 201112L
281  _Static_assert(sizeof(packed) == 48, "Leaves must be packed");
282#endif
283  copy(info->brand_string, (const char*)(packed), 48);
284  info->brand_string[48] = '\0';
285
286  // Fill cpu features.
287  features->fpu = IsBitSet(leaf_1.edx, 0);
288  features->tsc = IsBitSet(leaf_1.edx, 4);
289  features->cx8 = IsBitSet(leaf_1.edx, 8);
290  features->clfsh = IsBitSet(leaf_1.edx, 19);
291  features->mmx = IsBitSet(leaf_1.edx, 23);
292  features->ss = IsBitSet(leaf_1.edx, 27);
293  features->pclmulqdq = IsBitSet(leaf_1.ecx, 1);
294  features->smx = IsBitSet(leaf_1.ecx, 6);
295  features->cx16 = IsBitSet(leaf_1.ecx, 13);
296  features->dca = IsBitSet(leaf_1.ecx, 18);
297  features->movbe = IsBitSet(leaf_1.ecx, 22);
298  features->popcnt = IsBitSet(leaf_1.ecx, 23);
299  features->aes = IsBitSet(leaf_1.ecx, 25);
300  features->f16c = IsBitSet(leaf_1.ecx, 29);
301  features->rdrnd = IsBitSet(leaf_1.ecx, 30);
302  features->sgx = IsBitSet(leaf_7.ebx, 2);
303  features->bmi1 = IsBitSet(leaf_7.ebx, 3);
304  features->hle = IsBitSet(leaf_7.ebx, 4);
305  features->bmi2 = IsBitSet(leaf_7.ebx, 8);
306  features->erms = IsBitSet(leaf_7.ebx, 9);
307  features->rtm = IsBitSet(leaf_7.ebx, 11);
308  features->rdseed = IsBitSet(leaf_7.ebx, 18);
309  features->clflushopt = IsBitSet(leaf_7.ebx, 23);
310  features->clwb = IsBitSet(leaf_7.ebx, 24);
311  features->sha = IsBitSet(leaf_7.ebx, 29);
312  features->vaes = IsBitSet(leaf_7.ecx, 9);
313  features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
314  features->adx = IsBitSet(leaf_7.ebx, 19);
315
316  /////////////////////////////////////////////////////////////////////////////
317  // The following section is devoted to Vector Extensions.
318  /////////////////////////////////////////////////////////////////////////////
319
320  // CPU with AVX expose XCR0 which enables checking vector extensions OS
321  // support through cpuid.
322  if (have_xcr0) {
323    // Here we rely exclusively on cpuid for both CPU and OS support of vector
324    // extensions.
325    const uint32_t xcr0_eax = GetXCR0Eax();
326    os_preserves->sse_registers = HasXmmOsXSave(xcr0_eax);
327    os_preserves->avx_registers = HasYmmOsXSave(xcr0_eax);
328    os_preserves->avx512_registers = HasZmmOsXSave(xcr0_eax);
329    os_preserves->amx_registers = HasTmmOsXSave(xcr0_eax);
330    OverrideOsPreserves(os_preserves);
331
332    if (os_preserves->sse_registers) {
333      features->sse = IsBitSet(leaf_1.edx, 25);
334      features->sse2 = IsBitSet(leaf_1.edx, 26);
335      features->sse3 = IsBitSet(leaf_1.ecx, 0);
336      features->ssse3 = IsBitSet(leaf_1.ecx, 9);
337      features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
338      features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
339    }
340    if (os_preserves->avx_registers) {
341      features->fma3 = IsBitSet(leaf_1.ecx, 12);
342      features->avx = IsBitSet(leaf_1.ecx, 28);
343      features->avx2 = IsBitSet(leaf_7.ebx, 5);
344    }
345    if (os_preserves->avx512_registers) {
346      features->avx512f = IsBitSet(leaf_7.ebx, 16);
347      features->avx512cd = IsBitSet(leaf_7.ebx, 28);
348      features->avx512er = IsBitSet(leaf_7.ebx, 27);
349      features->avx512pf = IsBitSet(leaf_7.ebx, 26);
350      features->avx512bw = IsBitSet(leaf_7.ebx, 30);
351      features->avx512dq = IsBitSet(leaf_7.ebx, 17);
352      features->avx512vl = IsBitSet(leaf_7.ebx, 31);
353      features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
354      features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
355      features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
356      features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
357      features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
358      features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
359      features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
360      features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
361      features->avx512_second_fma = HasSecondFMA(info);
362      features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3);
363      features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5);
364      features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8);
365    }
366    if (os_preserves->amx_registers) {
367      features->amx_bf16 = IsBitSet(leaf_7.edx, 22);
368      features->amx_tile = IsBitSet(leaf_7.edx, 24);
369      features->amx_int8 = IsBitSet(leaf_7.edx, 25);
370    }
371  } else {
372    // When XCR0 is not available (Atom based or older cpus) we need to defer to
373    // the OS via custom code.
374    DetectFeaturesFromOs(info, features);
375    // Now that we have queried the OS for SSE support, we report this back to
376    // os_preserves. This is needed in case of AMD CPU's to enable testing of
377    // sse4a (See ParseExtraAMDCpuId below).
378    if (features->sse) os_preserves->sse_registers = true;
379  }
380}
381
382static void ParseExtraAMDCpuId(const Leaves* leaves, X86Info* info,
383                               OsPreserves os_preserves) {
384  const Leaf leaf_80000001 = leaves->leaf_80000001;
385
386  X86Features* const features = &info->features;
387
388  if (os_preserves.sse_registers) {
389    features->sse4a = IsBitSet(leaf_80000001.ecx, 6);
390  }
391
392  if (os_preserves.avx_registers) {
393    features->fma4 = IsBitSet(leaf_80000001.ecx, 16);
394  }
395}
396
397static const X86Info kEmptyX86Info;
398static const OsPreserves kEmptyOsPreserves;
399
400X86Info GetX86Info(void) {
401  X86Info info = kEmptyX86Info;
402  const Leaves leaves = ReadLeaves();
403  const bool is_intel =
404      IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
405  const bool is_amd =
406      IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
407  const bool is_hygon =
408      IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
409  const bool is_zhaoxin =
410      (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) ||
411       IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI));
412  SetVendor(leaves.leaf_0, info.vendor);
413  if (is_intel || is_amd || is_hygon || is_zhaoxin) {
414    OsPreserves os_preserves = kEmptyOsPreserves;
415    ParseCpuId(&leaves, &info, &os_preserves);
416    if (is_amd || is_hygon) {
417      ParseExtraAMDCpuId(&leaves, &info, os_preserves);
418    }
419  }
420  return info;
421}
422
423////////////////////////////////////////////////////////////////////////////////
424// Microarchitecture
425////////////////////////////////////////////////////////////////////////////////
426
427#define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
428
429X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
430  if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_GENUINE_INTEL)) {
431    switch (CPUID(info->family, info->model)) {
432      case CPUID(0x04, 0x01):
433      case CPUID(0x04, 0x02):
434      case CPUID(0x04, 0x03):
435      case CPUID(0x04, 0x04):
436      case CPUID(0x04, 0x05):
437      case CPUID(0x04, 0x07):
438      case CPUID(0x04, 0x08):
439      case CPUID(0x04, 0x09):
440        // https://en.wikichip.org/wiki/intel/microarchitectures/80486
441        return INTEL_80486;
442      case CPUID(0x05, 0x01):
443      case CPUID(0x05, 0x02):
444      case CPUID(0x05, 0x04):
445      case CPUID(0x05, 0x07):
446      case CPUID(0x05, 0x08):
447        // https://en.wikichip.org/wiki/intel/microarchitectures/p5
448        return INTEL_P5;
449      case CPUID(0x05, 0x09):
450      case CPUID(0x05, 0x0A):
451        // https://en.wikichip.org/wiki/intel/quark
452        return INTEL_LAKEMONT;
453      case CPUID(0x06, 0x1C):  // Intel(R) Atom(TM) CPU 230 @ 1.60GHz
454      case CPUID(0x06, 0x35):
455      case CPUID(0x06, 0x36):
456      case CPUID(0x06, 0x70):  // https://en.wikichip.org/wiki/intel/atom/230
457        // https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
458        return INTEL_ATOM_BNL;
459      case CPUID(0x06, 0x37):
460      case CPUID(0x06, 0x4C):
461        // https://en.wikipedia.org/wiki/Silvermont
462        return INTEL_ATOM_SMT;
463      case CPUID(0x06, 0x5C):
464        // https://en.wikipedia.org/wiki/Goldmont
465        return INTEL_ATOM_GMT;
466      case CPUID(0x06, 0x0F):
467      case CPUID(0x06, 0x16):
468        // https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
469        return INTEL_CORE;
470      case CPUID(0x06, 0x17):
471      case CPUID(0x06, 0x1D):
472        // https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
473        return INTEL_PNR;
474      case CPUID(0x06, 0x1A):
475      case CPUID(0x06, 0x1E):
476      case CPUID(0x06, 0x1F):
477      case CPUID(0x06, 0x2E):
478        // https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
479        return INTEL_NHM;
480      case CPUID(0x06, 0x25):
481      case CPUID(0x06, 0x2C):
482      case CPUID(0x06, 0x2F):
483        // https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
484        return INTEL_WSM;
485      case CPUID(0x06, 0x2A):
486      case CPUID(0x06, 0x2D):
487        // https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
488        return INTEL_SNB;
489      case CPUID(0x06, 0x3A):
490      case CPUID(0x06, 0x3E):
491        // https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
492        return INTEL_IVB;
493      case CPUID(0x06, 0x3C):
494      case CPUID(0x06, 0x3F):
495      case CPUID(0x06, 0x45):
496      case CPUID(0x06, 0x46):
497        // https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
498        return INTEL_HSW;
499      case CPUID(0x06, 0x3D):
500      case CPUID(0x06, 0x47):
501      case CPUID(0x06, 0x4F):
502      case CPUID(0x06, 0x56):
503        // https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
504        return INTEL_BDW;
505      case CPUID(0x06, 0x4E):
506      case CPUID(0x06, 0x55):
507      case CPUID(0x06, 0x5E):
508        // https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
509        return INTEL_SKL;
510      case CPUID(0x06, 0x66):
511        // https://en.wikipedia.org/wiki/Cannon_Lake_(microarchitecture)
512        return INTEL_CNL;
513      case CPUID(0x06, 0x7D):  // client
514      case CPUID(0x06, 0x7E):  // client
515      case CPUID(0x06, 0x9D):  // NNP-I
516      case CPUID(0x06, 0x6A):  // server
517      case CPUID(0x06, 0x6C):  // server
518        // https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)
519        return INTEL_ICL;
520      case CPUID(0x06, 0x8C):
521      case CPUID(0x06, 0x8D):
522        // https://en.wikipedia.org/wiki/Tiger_Lake_(microarchitecture)
523        return INTEL_TGL;
524      case CPUID(0x06, 0x8F):
525        // https://en.wikipedia.org/wiki/Sapphire_Rapids
526        return INTEL_SPR;
527      case CPUID(0x06, 0x8E):
528        switch (info->stepping) {
529          case 9:
530            return INTEL_KBL;  // https://en.wikipedia.org/wiki/Kaby_Lake
531          case 10:
532            return INTEL_CFL;  // https://en.wikipedia.org/wiki/Coffee_Lake
533          case 11:
534            return INTEL_WHL;  // https://en.wikipedia.org/wiki/Whiskey_Lake_(microarchitecture)
535          default:
536            return X86_UNKNOWN;
537        }
538      case CPUID(0x06, 0x9E):
539        if (info->stepping > 9) {
540          // https://en.wikipedia.org/wiki/Coffee_Lake
541          return INTEL_CFL;
542        } else {
543          // https://en.wikipedia.org/wiki/Kaby_Lake
544          return INTEL_KBL;
545        }
546      case CPUID(0x06, 0x97):
547      case CPUID(0x06, 0x9A):
548        // https://en.wikichip.org/wiki/intel/microarchitectures/alder_lake
549        return INTEL_ADL;
550      case CPUID(0x06, 0xA7):
551        // https://en.wikichip.org/wiki/intel/microarchitectures/rocket_lake
552        return INTEL_RCL;
553      case CPUID(0x06, 0x85):
554        // https://en.wikichip.org/wiki/intel/microarchitectures/knights_mill
555        return INTEL_KNIGHTS_M;
556      case CPUID(0x06, 0x57):
557        // https://en.wikichip.org/wiki/intel/microarchitectures/knights_landing
558        return INTEL_KNIGHTS_L;
559      case CPUID(0x0B, 0x00):
560        // https://en.wikichip.org/wiki/intel/microarchitectures/knights_ferry
561        return INTEL_KNIGHTS_F;
562      case CPUID(0x0B, 0x01):
563        // https://en.wikichip.org/wiki/intel/microarchitectures/knights_corner
564        return INTEL_KNIGHTS_C;
565      case CPUID(0x0F, 0x01):
566      case CPUID(0x0F, 0x02):
567      case CPUID(0x0F, 0x03):
568      case CPUID(0x0F, 0x04):
569      case CPUID(0x0F, 0x06):
570        // https://en.wikichip.org/wiki/intel/microarchitectures/netburst
571        return INTEL_NETBURST;
572      default:
573        return X86_UNKNOWN;
574    }
575  }
576  if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_CENTAUR_HAULS)) {
577    switch (CPUID(info->family, info->model)) {
578      case CPUID(0x06, 0x0F):
579      case CPUID(0x06, 0x19):
580        // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang
581        return ZHAOXIN_ZHANGJIANG;
582      case CPUID(0x07, 0x1B):
583	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
584	return ZHAOXIN_WUDAOKOU;
585      case CPUID(0x07, 0x3B):
586	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
587	return ZHAOXIN_LUJIAZUI;
588      case CPUID(0x07, 0x5B):
589	return ZHAOXIN_YONGFENG;
590      default:
591	return X86_UNKNOWN;
592    }
593  }
594  if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_SHANGHAI)) {
595    switch (CPUID(info->family, info->model)) {
596      case CPUID(0x06, 0x0F):
597      case CPUID(0x06, 0x19):
598        // https://en.wikichip.org/wiki/zhaoxin/microarchitectures/zhangjiang
599        return ZHAOXIN_ZHANGJIANG;
600      case CPUID(0x07, 0x1B):
601	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/wudaokou
602	return ZHAOXIN_WUDAOKOU;
603      case CPUID(0x07, 0x3B):
604	// https://en.wikichip.org/wiki/zhaoxin/microarchitectures/lujiazui
605	return ZHAOXIN_LUJIAZUI;
606      case CPUID(0x07, 0x5B):
607	return ZHAOXIN_YONGFENG;
608      default:
609	return X86_UNKNOWN;
610    }
611  }
612  if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD)) {
613    switch (CPUID(info->family, info->model)) {
614      // https://en.wikichip.org/wiki/amd/cpuid
615      case CPUID(0xF, 0x04):
616      case CPUID(0xF, 0x05):
617      case CPUID(0xF, 0x07):
618      case CPUID(0xF, 0x08):
619      case CPUID(0xF, 0x0C):
620      case CPUID(0xF, 0x0E):
621      case CPUID(0xF, 0x0F):
622      case CPUID(0xF, 0x14):
623      case CPUID(0xF, 0x15):
624      case CPUID(0xF, 0x17):
625      case CPUID(0xF, 0x18):
626      case CPUID(0xF, 0x1B):
627      case CPUID(0xF, 0x1C):
628      case CPUID(0xF, 0x1F):
629      case CPUID(0xF, 0x21):
630      case CPUID(0xF, 0x23):
631      case CPUID(0xF, 0x24):
632      case CPUID(0xF, 0x25):
633      case CPUID(0xF, 0x27):
634      case CPUID(0xF, 0x2B):
635      case CPUID(0xF, 0x2C):
636      case CPUID(0xF, 0x2F):
637      case CPUID(0xF, 0x41):
638      case CPUID(0xF, 0x43):
639      case CPUID(0xF, 0x48):
640      case CPUID(0xF, 0x4B):
641      case CPUID(0xF, 0x4C):
642      case CPUID(0xF, 0x4F):
643      case CPUID(0xF, 0x5D):
644      case CPUID(0xF, 0x5F):
645      case CPUID(0xF, 0x68):
646      case CPUID(0xF, 0x6B):
647      case CPUID(0xF, 0x6F):
648      case CPUID(0xF, 0x7F):
649      case CPUID(0xF, 0xC1):
650        return AMD_HAMMER;
651      case CPUID(0x10, 0x02):
652      case CPUID(0x10, 0x04):
653      case CPUID(0x10, 0x05):
654      case CPUID(0x10, 0x06):
655      case CPUID(0x10, 0x08):
656      case CPUID(0x10, 0x09):
657      case CPUID(0x10, 0x0A):
658        return AMD_K10;
659      case CPUID(0x11, 0x03):
660        // http://developer.amd.com/wordpress/media/2012/10/41788.pdf
661        return AMD_K11;
662      case CPUID(0x12, 0x01):
663        // https://www.amd.com/system/files/TechDocs/44739_12h_Rev_Gd.pdf
664        return AMD_K12;
665      case CPUID(0x14, 0x00):
666      case CPUID(0x14, 0x01):
667      case CPUID(0x14, 0x02):
668        // https://www.amd.com/system/files/TechDocs/47534_14h_Mod_00h-0Fh_Rev_Guide.pdf
669        return AMD_BOBCAT;
670      case CPUID(0x15, 0x01):
671        // https://en.wikichip.org/wiki/amd/microarchitectures/bulldozer
672        return AMD_BULLDOZER;
673      case CPUID(0x15, 0x02):
674      case CPUID(0x15, 0x11):
675      case CPUID(0x15, 0x13):
676        // https://en.wikichip.org/wiki/amd/microarchitectures/piledriver
677        return AMD_PILEDRIVER;
678      case CPUID(0x15, 0x30):
679      case CPUID(0x15, 0x38):
680        // https://en.wikichip.org/wiki/amd/microarchitectures/steamroller
681        return AMD_STREAMROLLER;
682      case CPUID(0x15, 0x60):
683      case CPUID(0x15, 0x65):
684      case CPUID(0x15, 0x70):
685        // https://en.wikichip.org/wiki/amd/microarchitectures/excavator
686        return AMD_EXCAVATOR;
687      case CPUID(0x16, 0x00):
688        return AMD_JAGUAR;
689      case CPUID(0x16, 0x30):
690        return AMD_PUMA;
691      case CPUID(0x17, 0x01):
692      case CPUID(0x17, 0x11):
693      case CPUID(0x17, 0x18):
694      case CPUID(0x17, 0x20):
695        // https://en.wikichip.org/wiki/amd/microarchitectures/zen
696        return AMD_ZEN;
697      case CPUID(0x17, 0x08):
698        // https://en.wikichip.org/wiki/amd/microarchitectures/zen%2B
699        return AMD_ZEN_PLUS;
700      case CPUID(0x17, 0x31):
701      case CPUID(0x17, 0x47):
702      case CPUID(0x17, 0x60):
703      case CPUID(0x17, 0x68):
704      case CPUID(0x17, 0x71):
705      case CPUID(0x17, 0x90):
706      case CPUID(0x17, 0x98):
707        // https://en.wikichip.org/wiki/amd/microarchitectures/zen_2
708        return AMD_ZEN2;
709      case CPUID(0x19, 0x01):
710      case CPUID(0x19, 0x21):
711      case CPUID(0x19, 0x30):
712      case CPUID(0x19, 0x40):
713      case CPUID(0x19, 0x50):
714        // https://en.wikichip.org/wiki/amd/microarchitectures/zen_3
715        return AMD_ZEN3;
716      default:
717        return X86_UNKNOWN;
718    }
719  }
720  if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
721    switch (CPUID(info->family, info->model)) {
722      case CPUID(0x18, 0x00):
723        return AMD_ZEN;
724    }
725  }
726  return X86_UNKNOWN;
727}
728
729////////////////////////////////////////////////////////////////////////////////
730// CacheInfo
731////////////////////////////////////////////////////////////////////////////////
732
733static const CacheLevelInfo kEmptyCacheLevelInfo;
734
735static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
736  const int UNDEF = -1;
737  const int KiB = 1024;
738  const int MiB = 1024 * KiB;
739  switch (reg) {
740    case 0x01:
741      return (CacheLevelInfo){.level = UNDEF,
742                              .cache_type = CPU_FEATURE_CACHE_TLB,
743                              .cache_size = 4 * KiB,
744                              .ways = 4,
745                              .line_size = UNDEF,
746                              .tlb_entries = 32,
747                              .partitioning = 0};
748    case 0x02:
749      return (CacheLevelInfo){.level = UNDEF,
750                              .cache_type = CPU_FEATURE_CACHE_TLB,
751                              .cache_size = 4 * MiB,
752                              .ways = 0xFF,
753                              .line_size = UNDEF,
754                              .tlb_entries = 2,
755                              .partitioning = 0};
756    case 0x03:
757      return (CacheLevelInfo){.level = UNDEF,
758                              .cache_type = CPU_FEATURE_CACHE_TLB,
759                              .cache_size = 4 * KiB,
760                              .ways = 4,
761                              .line_size = UNDEF,
762                              .tlb_entries = 64,
763                              .partitioning = 0};
764    case 0x04:
765      return (CacheLevelInfo){.level = UNDEF,
766                              .cache_type = CPU_FEATURE_CACHE_TLB,
767                              .cache_size = 4 * MiB,
768                              .ways = 4,
769                              .line_size = UNDEF,
770                              .tlb_entries = 8,
771                              .partitioning = 0};
772    case 0x05:
773      return (CacheLevelInfo){.level = UNDEF,
774                              .cache_type = CPU_FEATURE_CACHE_TLB,
775                              .cache_size = 4 * MiB,
776                              .ways = 4,
777                              .line_size = UNDEF,
778                              .tlb_entries = 32,
779                              .partitioning = 0};
780    case 0x06:
781      return (CacheLevelInfo){.level = 1,
782                              .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
783                              .cache_size = 8 * KiB,
784                              .ways = 4,
785                              .line_size = 32,
786                              .tlb_entries = UNDEF,
787                              .partitioning = 0};
788    case 0x08:
789      return (CacheLevelInfo){.level = 1,
790                              .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
791                              .cache_size = 16 * KiB,
792                              .ways = 4,
793                              .line_size = 32,
794                              .tlb_entries = UNDEF,
795                              .partitioning = 0};
796    case 0x09:
797      return (CacheLevelInfo){.level = 1,
798                              .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
799                              .cache_size = 32 * KiB,
800                              .ways = 4,
801                              .line_size = 64,
802                              .tlb_entries = UNDEF,
803                              .partitioning = 0};
804    case 0x0A:
805      return (CacheLevelInfo){.level = 1,
806                              .cache_type = CPU_FEATURE_CACHE_DATA,
807                              .cache_size = 8 * KiB,
808                              .ways = 2,
809                              .line_size = 32,
810                              .tlb_entries = UNDEF,
811                              .partitioning = 0};
812    case 0x0B:
813      return (CacheLevelInfo){.level = UNDEF,
814                              .cache_type = CPU_FEATURE_CACHE_TLB,
815                              .cache_size = 4 * MiB,
816                              .ways = 4,
817                              .line_size = UNDEF,
818                              .tlb_entries = 4,
819                              .partitioning = 0};
820    case 0x0C:
821      return (CacheLevelInfo){.level = 1,
822                              .cache_type = CPU_FEATURE_CACHE_DATA,
823                              .cache_size = 16 * KiB,
824                              .ways = 4,
825                              .line_size = 32,
826                              .tlb_entries = UNDEF,
827                              .partitioning = 0};
828    case 0x0D:
829      return (CacheLevelInfo){.level = 1,
830                              .cache_type = CPU_FEATURE_CACHE_DATA,
831                              .cache_size = 16 * KiB,
832                              .ways = 4,
833                              .line_size = 64,
834                              .tlb_entries = UNDEF,
835                              .partitioning = 0};
836    case 0x0E:
837      return (CacheLevelInfo){.level = 1,
838                              .cache_type = CPU_FEATURE_CACHE_DATA,
839                              .cache_size = 24 * KiB,
840                              .ways = 6,
841                              .line_size = 64,
842                              .tlb_entries = UNDEF,
843                              .partitioning = 0};
844    case 0x1D:
845      return (CacheLevelInfo){.level = 2,
846                              .cache_type = CPU_FEATURE_CACHE_DATA,
847                              .cache_size = 128 * KiB,
848                              .ways = 2,
849                              .line_size = 64,
850                              .tlb_entries = UNDEF,
851                              .partitioning = 0};
852    case 0x21:
853      return (CacheLevelInfo){.level = 2,
854                              .cache_type = CPU_FEATURE_CACHE_DATA,
855                              .cache_size = 256 * KiB,
856                              .ways = 8,
857                              .line_size = 64,
858                              .tlb_entries = UNDEF,
859                              .partitioning = 0};
860    case 0x22:
861      return (CacheLevelInfo){.level = 3,
862                              .cache_type = CPU_FEATURE_CACHE_DATA,
863                              .cache_size = 512 * KiB,
864                              .ways = 4,
865                              .line_size = 64,
866                              .tlb_entries = UNDEF,
867                              .partitioning = 2};
868    case 0x23:
869      return (CacheLevelInfo){.level = 3,
870                              .cache_type = CPU_FEATURE_CACHE_DATA,
871                              .cache_size = 1 * MiB,
872                              .ways = 8,
873                              .line_size = 64,
874                              .tlb_entries = UNDEF,
875                              .partitioning = 2};
876    case 0x24:
877      return (CacheLevelInfo){.level = 2,
878                              .cache_type = CPU_FEATURE_CACHE_DATA,
879                              .cache_size = 1 * MiB,
880                              .ways = 16,
881                              .line_size = 64,
882                              .tlb_entries = UNDEF,
883                              .partitioning = 0};
884    case 0x25:
885      return (CacheLevelInfo){.level = 3,
886                              .cache_type = CPU_FEATURE_CACHE_DATA,
887                              .cache_size = 2 * MiB,
888                              .ways = 8,
889                              .line_size = 64,
890                              .tlb_entries = UNDEF,
891                              .partitioning = 2};
892    case 0x29:
893      return (CacheLevelInfo){.level = 3,
894                              .cache_type = CPU_FEATURE_CACHE_DATA,
895                              .cache_size = 4 * MiB,
896                              .ways = 8,
897                              .line_size = 64,
898                              .tlb_entries = UNDEF,
899                              .partitioning = 2};
900    case 0x2C:
901      return (CacheLevelInfo){.level = 1,
902                              .cache_type = CPU_FEATURE_CACHE_DATA,
903                              .cache_size = 32 * KiB,
904                              .ways = 8,
905                              .line_size = 64,
906                              .tlb_entries = UNDEF,
907                              .partitioning = 0};
908    case 0x30:
909      return (CacheLevelInfo){.level = 1,
910                              .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
911                              .cache_size = 32 * KiB,
912                              .ways = 8,
913                              .line_size = 64,
914                              .tlb_entries = UNDEF,
915                              .partitioning = 0};
916    case 0x40:
917      return (CacheLevelInfo){.level = UNDEF,
918                              .cache_type = CPU_FEATURE_CACHE_DATA,
919                              .cache_size = UNDEF,
920                              .ways = UNDEF,
921                              .line_size = UNDEF,
922                              .tlb_entries = UNDEF,
923                              .partitioning = 0};
924    case 0x41:
925      return (CacheLevelInfo){.level = 2,
926                              .cache_type = CPU_FEATURE_CACHE_DATA,
927                              .cache_size = 128 * KiB,
928                              .ways = 4,
929                              .line_size = 32,
930                              .tlb_entries = UNDEF,
931                              .partitioning = 0};
932    case 0x42:
933      return (CacheLevelInfo){.level = 2,
934                              .cache_type = CPU_FEATURE_CACHE_DATA,
935                              .cache_size = 256 * KiB,
936                              .ways = 4,
937                              .line_size = 32,
938                              .tlb_entries = UNDEF,
939                              .partitioning = 0};
940    case 0x43:
941      return (CacheLevelInfo){.level = 2,
942                              .cache_type = CPU_FEATURE_CACHE_DATA,
943                              .cache_size = 512 * KiB,
944                              .ways = 4,
945                              .line_size = 32,
946                              .tlb_entries = UNDEF,
947                              .partitioning = 0};
948    case 0x44:
949      return (CacheLevelInfo){.level = 2,
950                              .cache_type = CPU_FEATURE_CACHE_DATA,
951                              .cache_size = 1 * MiB,
952                              .ways = 4,
953                              .line_size = 32,
954                              .tlb_entries = UNDEF,
955                              .partitioning = 0};
956    case 0x45:
957      return (CacheLevelInfo){.level = 2,
958                              .cache_type = CPU_FEATURE_CACHE_DATA,
959                              .cache_size = 2 * MiB,
960                              .ways = 4,
961                              .line_size = 32,
962                              .tlb_entries = UNDEF,
963                              .partitioning = 0};
964    case 0x46:
965      return (CacheLevelInfo){.level = 3,
966                              .cache_type = CPU_FEATURE_CACHE_DATA,
967                              .cache_size = 4 * MiB,
968                              .ways = 4,
969                              .line_size = 64,
970                              .tlb_entries = UNDEF,
971                              .partitioning = 0};
972    case 0x47:
973      return (CacheLevelInfo){.level = 3,
974                              .cache_type = CPU_FEATURE_CACHE_DATA,
975                              .cache_size = 8 * MiB,
976                              .ways = 8,
977                              .line_size = 64,
978                              .tlb_entries = UNDEF,
979                              .partitioning = 0};
980    case 0x48:
981      return (CacheLevelInfo){.level = 2,
982                              .cache_type = CPU_FEATURE_CACHE_DATA,
983                              .cache_size = 3 * MiB,
984                              .ways = 12,
985                              .line_size = 64,
986                              .tlb_entries = UNDEF,
987                              .partitioning = 0};
988    case 0x49:
989      return (CacheLevelInfo){.level = 2,
990                              .cache_type = CPU_FEATURE_CACHE_DATA,
991                              .cache_size = 4 * MiB,
992                              .ways = 16,
993                              .line_size = 64,
994                              .tlb_entries = UNDEF,
995                              .partitioning = 0};
996    case (0x49 | (1 << 8)):
997      return (CacheLevelInfo){.level = 3,
998                              .cache_type = CPU_FEATURE_CACHE_DATA,
999                              .cache_size = 4 * MiB,
1000                              .ways = 16,
1001                              .line_size = 64,
1002                              .tlb_entries = UNDEF,
1003                              .partitioning = 0};
1004    case 0x4A:
1005      return (CacheLevelInfo){.level = 3,
1006                              .cache_type = CPU_FEATURE_CACHE_DATA,
1007                              .cache_size = 6 * MiB,
1008                              .ways = 12,
1009                              .line_size = 64,
1010                              .tlb_entries = UNDEF,
1011                              .partitioning = 0};
1012    case 0x4B:
1013      return (CacheLevelInfo){.level = 3,
1014                              .cache_type = CPU_FEATURE_CACHE_DATA,
1015                              .cache_size = 8 * MiB,
1016                              .ways = 16,
1017                              .line_size = 64,
1018                              .tlb_entries = UNDEF,
1019                              .partitioning = 0};
1020    case 0x4C:
1021      return (CacheLevelInfo){.level = 3,
1022                              .cache_type = CPU_FEATURE_CACHE_DATA,
1023                              .cache_size = 12 * MiB,
1024                              .ways = 12,
1025                              .line_size = 64,
1026                              .tlb_entries = UNDEF,
1027                              .partitioning = 0};
1028    case 0x4D:
1029      return (CacheLevelInfo){.level = 3,
1030                              .cache_type = CPU_FEATURE_CACHE_DATA,
1031                              .cache_size = 16 * MiB,
1032                              .ways = 16,
1033                              .line_size = 64,
1034                              .tlb_entries = UNDEF,
1035                              .partitioning = 0};
1036    case 0x4E:
1037      return (CacheLevelInfo){.level = 2,
1038                              .cache_type = CPU_FEATURE_CACHE_DATA,
1039                              .cache_size = 6 * MiB,
1040                              .ways = 24,
1041                              .line_size = 64,
1042                              .tlb_entries = UNDEF,
1043                              .partitioning = 0};
1044    case 0x4F:
1045      return (CacheLevelInfo){.level = UNDEF,
1046                              .cache_type = CPU_FEATURE_CACHE_TLB,
1047                              .cache_size = 4 * KiB,
1048                              .ways = UNDEF,
1049                              .line_size = UNDEF,
1050                              .tlb_entries = 32,
1051                              .partitioning = 0};
1052    case 0x50:
1053      return (CacheLevelInfo){.level = UNDEF,
1054                              .cache_type = CPU_FEATURE_CACHE_TLB,
1055                              .cache_size = 4 * KiB,
1056                              .ways = UNDEF,
1057                              .line_size = UNDEF,
1058                              .tlb_entries = 64,
1059                              .partitioning = 0};
1060    case 0x51:
1061      return (CacheLevelInfo){.level = UNDEF,
1062                              .cache_type = CPU_FEATURE_CACHE_TLB,
1063                              .cache_size = 4 * KiB,
1064                              .ways = UNDEF,
1065                              .line_size = UNDEF,
1066                              .tlb_entries = 128,
1067                              .partitioning = 0};
1068    case 0x52:
1069      return (CacheLevelInfo){.level = UNDEF,
1070                              .cache_type = CPU_FEATURE_CACHE_TLB,
1071                              .cache_size = 4 * KiB,
1072                              .ways = UNDEF,
1073                              .line_size = UNDEF,
1074                              .tlb_entries = 256,
1075                              .partitioning = 0};
1076    case 0x55:
1077      return (CacheLevelInfo){.level = UNDEF,
1078                              .cache_type = CPU_FEATURE_CACHE_TLB,
1079                              .cache_size = 2 * MiB,
1080                              .ways = 0xFF,
1081                              .line_size = UNDEF,
1082                              .tlb_entries = 7,
1083                              .partitioning = 0};
1084    case 0x56:
1085      return (CacheLevelInfo){.level = UNDEF,
1086                              .cache_type = CPU_FEATURE_CACHE_TLB,
1087                              .cache_size = 4 * MiB,
1088                              .ways = 4,
1089                              .line_size = UNDEF,
1090                              .tlb_entries = 16,
1091                              .partitioning = 0};
1092    case 0x57:
1093      return (CacheLevelInfo){.level = UNDEF,
1094                              .cache_type = CPU_FEATURE_CACHE_TLB,
1095                              .cache_size = 4 * KiB,
1096                              .ways = 4,
1097                              .line_size = UNDEF,
1098                              .tlb_entries = 16,
1099                              .partitioning = 0};
1100    case 0x59:
1101      return (CacheLevelInfo){.level = UNDEF,
1102                              .cache_type = CPU_FEATURE_CACHE_TLB,
1103                              .cache_size = 4 * KiB,
1104                              .ways = 0xFF,
1105                              .line_size = UNDEF,
1106                              .tlb_entries = 16,
1107                              .partitioning = 0};
1108    case 0x5A:
1109      return (CacheLevelInfo){.level = UNDEF,
1110                              .cache_type = CPU_FEATURE_CACHE_TLB,
1111                              .cache_size = 2 * MiB,
1112                              .ways = 4,
1113                              .line_size = UNDEF,
1114                              .tlb_entries = 32,
1115                              .partitioning = 0};
1116    case 0x5B:
1117      return (CacheLevelInfo){.level = UNDEF,
1118                              .cache_type = CPU_FEATURE_CACHE_TLB,
1119                              .cache_size = 4 * KiB,
1120                              .ways = UNDEF,
1121                              .line_size = UNDEF,
1122                              .tlb_entries = 64,
1123                              .partitioning = 0};
1124    case 0x5C:
1125      return (CacheLevelInfo){.level = UNDEF,
1126                              .cache_type = CPU_FEATURE_CACHE_TLB,
1127                              .cache_size = 4 * KiB,
1128                              .ways = UNDEF,
1129                              .line_size = UNDEF,
1130                              .tlb_entries = 128,
1131                              .partitioning = 0};
1132    case 0x5D:
1133      return (CacheLevelInfo){.level = UNDEF,
1134                              .cache_type = CPU_FEATURE_CACHE_TLB,
1135                              .cache_size = 4,
1136                              .ways = UNDEF,
1137                              .line_size = UNDEF,
1138                              .tlb_entries = 256,
1139                              .partitioning = 0};
1140    case 0x60:
1141      return (CacheLevelInfo){.level = 1,
1142                              .cache_type = CPU_FEATURE_CACHE_DATA,
1143                              .cache_size = 16 * KiB,
1144                              .ways = 8,
1145                              .line_size = 64,
1146                              .tlb_entries = UNDEF,
1147                              .partitioning = 0};
1148    case 0x61:
1149      return (CacheLevelInfo){.level = UNDEF,
1150                              .cache_type = CPU_FEATURE_CACHE_TLB,
1151                              .cache_size = 4 * KiB,
1152                              .ways = 0xFF,
1153                              .line_size = UNDEF,
1154                              .tlb_entries = 48,
1155                              .partitioning = 0};
1156    case 0x63:
1157      return (CacheLevelInfo){.level = UNDEF,
1158                              .cache_type = CPU_FEATURE_CACHE_TLB,
1159                              .cache_size = 2 * MiB,
1160                              .ways = 4,
1161                              .line_size = UNDEF,
1162                              .tlb_entries = 4,
1163                              .partitioning = 0};
1164    case 0x66:
1165      return (CacheLevelInfo){.level = 1,
1166                              .cache_type = CPU_FEATURE_CACHE_DATA,
1167                              .cache_size = 8 * KiB,
1168                              .ways = 4,
1169                              .line_size = 64,
1170                              .tlb_entries = UNDEF,
1171                              .partitioning = 0};
1172    case 0x67:
1173      return (CacheLevelInfo){.level = 1,
1174                              .cache_type = CPU_FEATURE_CACHE_DATA,
1175                              .cache_size = 16 * KiB,
1176                              .ways = 4,
1177                              .line_size = 64,
1178                              .tlb_entries = UNDEF,
1179                              .partitioning = 0};
1180    case 0x68:
1181      return (CacheLevelInfo){.level = 1,
1182                              .cache_type = CPU_FEATURE_CACHE_DATA,
1183                              .cache_size = 32 * KiB,
1184                              .ways = 4,
1185                              .line_size = 64,
1186                              .tlb_entries = UNDEF,
1187                              .partitioning = 0};
1188    case 0x70:
1189      return (CacheLevelInfo){.level = 1,
1190                              .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
1191                              .cache_size = 12 * KiB,
1192                              .ways = 8,
1193                              .line_size = UNDEF,
1194                              .tlb_entries = UNDEF,
1195                              .partitioning = 0};
1196    case 0x71:
1197      return (CacheLevelInfo){.level = 1,
1198                              .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
1199                              .cache_size = 16 * KiB,
1200                              .ways = 8,
1201                              .line_size = UNDEF,
1202                              .tlb_entries = UNDEF,
1203                              .partitioning = 0};
1204    case 0x72:
1205      return (CacheLevelInfo){.level = 1,
1206                              .cache_type = CPU_FEATURE_CACHE_INSTRUCTION,
1207                              .cache_size = 32 * KiB,
1208                              .ways = 8,
1209                              .line_size = UNDEF,
1210                              .tlb_entries = UNDEF,
1211                              .partitioning = 0};
1212    case 0x76:
1213      return (CacheLevelInfo){.level = UNDEF,
1214                              .cache_type = CPU_FEATURE_CACHE_TLB,
1215                              .cache_size = 2 * MiB,
1216                              .ways = 0xFF,
1217                              .line_size = UNDEF,
1218                              .tlb_entries = 8,
1219                              .partitioning = 0};
1220    case 0x78:
1221      return (CacheLevelInfo){.level = 2,
1222                              .cache_type = CPU_FEATURE_CACHE_DATA,
1223                              .cache_size = 1 * MiB,
1224                              .ways = 4,
1225                              .line_size = 64,
1226                              .tlb_entries = UNDEF,
1227                              .partitioning = 0};
1228    case 0x79:
1229      return (CacheLevelInfo){.level = 2,
1230                              .cache_type = CPU_FEATURE_CACHE_DATA,
1231                              .cache_size = 128 * KiB,
1232                              .ways = 8,
1233                              .line_size = 64,
1234                              .tlb_entries = UNDEF,
1235                              .partitioning = 2};
1236    case 0x7A:
1237      return (CacheLevelInfo){.level = 2,
1238                              .cache_type = CPU_FEATURE_CACHE_DATA,
1239                              .cache_size = 256 * KiB,
1240                              .ways = 8,
1241                              .line_size = 64,
1242                              .tlb_entries = UNDEF,
1243                              .partitioning = 2};
1244    case 0x7B:
1245      return (CacheLevelInfo){.level = 2,
1246                              .cache_type = CPU_FEATURE_CACHE_DATA,
1247                              .cache_size = 512 * KiB,
1248                              .ways = 8,
1249                              .line_size = 64,
1250                              .tlb_entries = UNDEF,
1251                              .partitioning = 2};
1252    case 0x7C:
1253      return (CacheLevelInfo){.level = 2,
1254                              .cache_type = CPU_FEATURE_CACHE_DATA,
1255                              .cache_size = 1 * MiB,
1256                              .ways = 8,
1257                              .line_size = 64,
1258                              .tlb_entries = UNDEF,
1259                              .partitioning = 2};
1260    case 0x7D:
1261      return (CacheLevelInfo){.level = 2,
1262                              .cache_type = CPU_FEATURE_CACHE_DATA,
1263                              .cache_size = 2 * MiB,
1264                              .ways = 8,
1265                              .line_size = 64,
1266                              .tlb_entries = UNDEF,
1267                              .partitioning = 0};
1268    case 0x7F:
1269      return (CacheLevelInfo){.level = 2,
1270                              .cache_type = CPU_FEATURE_CACHE_DATA,
1271                              .cache_size = 512 * KiB,
1272                              .ways = 2,
1273                              .line_size = 64,
1274                              .tlb_entries = UNDEF,
1275                              .partitioning = 0};
1276    case 0x80:
1277      return (CacheLevelInfo){.level = 2,
1278                              .cache_type = CPU_FEATURE_CACHE_DATA,
1279                              .cache_size = 512 * KiB,
1280                              .ways = 8,
1281                              .line_size = 64,
1282                              .tlb_entries = UNDEF,
1283                              .partitioning = 0};
1284    case 0x82:
1285      return (CacheLevelInfo){.level = 2,
1286                              .cache_type = CPU_FEATURE_CACHE_DATA,
1287                              .cache_size = 256 * KiB,
1288                              .ways = 8,
1289                              .line_size = 32,
1290                              .tlb_entries = UNDEF,
1291                              .partitioning = 0};
1292    case 0x83:
1293      return (CacheLevelInfo){.level = 2,
1294                              .cache_type = CPU_FEATURE_CACHE_DATA,
1295                              .cache_size = 512 * KiB,
1296                              .ways = 8,
1297                              .line_size = 32,
1298                              .tlb_entries = UNDEF,
1299                              .partitioning = 0};
1300    case 0x84:
1301      return (CacheLevelInfo){.level = 2,
1302                              .cache_type = CPU_FEATURE_CACHE_DATA,
1303                              .cache_size = 1 * MiB,
1304                              .ways = 8,
1305                              .line_size = 32,
1306                              .tlb_entries = UNDEF,
1307                              .partitioning = 0};
1308    case 0x85:
1309      return (CacheLevelInfo){.level = 2,
1310                              .cache_type = CPU_FEATURE_CACHE_DATA,
1311                              .cache_size = 2 * MiB,
1312                              .ways = 8,
1313                              .line_size = 32,
1314                              .tlb_entries = UNDEF,
1315                              .partitioning = 0};
1316    case 0x86:
1317      return (CacheLevelInfo){.level = 2,
1318                              .cache_type = CPU_FEATURE_CACHE_DATA,
1319                              .cache_size = 512 * KiB,
1320                              .ways = 4,
1321                              .line_size = 32,
1322                              .tlb_entries = UNDEF,
1323                              .partitioning = 0};
1324    case 0x87:
1325      return (CacheLevelInfo){.level = 2,
1326                              .cache_type = CPU_FEATURE_CACHE_DATA,
1327                              .cache_size = 1 * MiB,
1328                              .ways = 8,
1329                              .line_size = 64,
1330                              .tlb_entries = UNDEF,
1331                              .partitioning = 0};
1332    case 0xA0:
1333      return (CacheLevelInfo){.level = UNDEF,
1334                              .cache_type = CPU_FEATURE_CACHE_DTLB,
1335                              .cache_size = 4 * KiB,
1336                              .ways = 0xFF,
1337                              .line_size = UNDEF,
1338                              .tlb_entries = 32,
1339                              .partitioning = 0};
1340    case 0xB0:
1341      return (CacheLevelInfo){.level = UNDEF,
1342                              .cache_type = CPU_FEATURE_CACHE_TLB,
1343                              .cache_size = 4 * KiB,
1344                              .ways = 4,
1345                              .line_size = UNDEF,
1346                              .tlb_entries = 128,
1347                              .partitioning = 0};
1348    case 0xB1:
1349      return (CacheLevelInfo){.level = UNDEF,
1350                              .cache_type = CPU_FEATURE_CACHE_TLB,
1351                              .cache_size = 2 * MiB,
1352                              .ways = 4,
1353                              .line_size = UNDEF,
1354                              .tlb_entries = 8,
1355                              .partitioning = 0};
1356    case 0xB2:
1357      return (CacheLevelInfo){.level = UNDEF,
1358                              .cache_type = CPU_FEATURE_CACHE_TLB,
1359                              .cache_size = 4 * KiB,
1360                              .ways = 4,
1361                              .line_size = UNDEF,
1362                              .tlb_entries = 64,
1363                              .partitioning = 0};
1364    case 0xB3:
1365      return (CacheLevelInfo){.level = UNDEF,
1366                              .cache_type = CPU_FEATURE_CACHE_TLB,
1367                              .cache_size = 4 * KiB,
1368                              .ways = 4,
1369                              .line_size = UNDEF,
1370                              .tlb_entries = 128,
1371                              .partitioning = 0};
1372    case 0xB4:
1373      return (CacheLevelInfo){.level = UNDEF,
1374                              .cache_type = CPU_FEATURE_CACHE_TLB,
1375                              .cache_size = 4 * KiB,
1376                              .ways = 4,
1377                              .line_size = UNDEF,
1378                              .tlb_entries = 256,
1379                              .partitioning = 0};
1380    case 0xB5:
1381      return (CacheLevelInfo){.level = UNDEF,
1382                              .cache_type = CPU_FEATURE_CACHE_TLB,
1383                              .cache_size = 4 * KiB,
1384                              .ways = 8,
1385                              .line_size = UNDEF,
1386                              .tlb_entries = 64,
1387                              .partitioning = 0};
1388    case 0xB6:
1389      return (CacheLevelInfo){.level = UNDEF,
1390                              .cache_type = CPU_FEATURE_CACHE_TLB,
1391                              .cache_size = 4 * KiB,
1392                              .ways = 8,
1393                              .line_size = UNDEF,
1394                              .tlb_entries = 128,
1395                              .partitioning = 0};
1396    case 0xBA:
1397      return (CacheLevelInfo){.level = UNDEF,
1398                              .cache_type = CPU_FEATURE_CACHE_TLB,
1399                              .cache_size = 4 * KiB,
1400                              .ways = 4,
1401                              .line_size = UNDEF,
1402                              .tlb_entries = 64,
1403                              .partitioning = 0};
1404    case 0xC0:
1405      return (CacheLevelInfo){.level = UNDEF,
1406                              .cache_type = CPU_FEATURE_CACHE_TLB,
1407                              .cache_size = 4 * KiB,
1408                              .ways = 4,
1409                              .line_size = UNDEF,
1410                              .tlb_entries = 8,
1411                              .partitioning = 0};
1412    case 0xC1:
1413      return (CacheLevelInfo){.level = UNDEF,
1414                              .cache_type = CPU_FEATURE_CACHE_STLB,
1415                              .cache_size = 4 * KiB,
1416                              .ways = 8,
1417                              .line_size = UNDEF,
1418                              .tlb_entries = 1024,
1419                              .partitioning = 0};
1420    case 0xC2:
1421      return (CacheLevelInfo){.level = UNDEF,
1422                              .cache_type = CPU_FEATURE_CACHE_DTLB,
1423                              .cache_size = 4 * KiB,
1424                              .ways = 4,
1425                              .line_size = UNDEF,
1426                              .tlb_entries = 16,
1427                              .partitioning = 0};
1428    case 0xC3:
1429      return (CacheLevelInfo){.level = UNDEF,
1430                              .cache_type = CPU_FEATURE_CACHE_STLB,
1431                              .cache_size = 4 * KiB,
1432                              .ways = 6,
1433                              .line_size = UNDEF,
1434                              .tlb_entries = 1536,
1435                              .partitioning = 0};
1436    case 0xCA:
1437      return (CacheLevelInfo){.level = UNDEF,
1438                              .cache_type = CPU_FEATURE_CACHE_STLB,
1439                              .cache_size = 4 * KiB,
1440                              .ways = 4,
1441                              .line_size = UNDEF,
1442                              .tlb_entries = 512,
1443                              .partitioning = 0};
1444    case 0xD0:
1445      return (CacheLevelInfo){.level = 3,
1446                              .cache_type = CPU_FEATURE_CACHE_DATA,
1447                              .cache_size = 512 * KiB,
1448                              .ways = 4,
1449                              .line_size = 64,
1450                              .tlb_entries = UNDEF,
1451                              .partitioning = 0};
1452    case 0xD1:
1453      return (CacheLevelInfo){.level = 3,
1454                              .cache_type = CPU_FEATURE_CACHE_DATA,
1455                              .cache_size = 1 * MiB,
1456                              .ways = 4,
1457                              .line_size = 64,
1458                              .tlb_entries = UNDEF,
1459                              .partitioning = 0};
1460    case 0xD2:
1461      return (CacheLevelInfo){.level = 3,
1462                              .cache_type = CPU_FEATURE_CACHE_DATA,
1463                              .cache_size = 2 * MiB,
1464                              .ways = 4,
1465                              .line_size = 64,
1466                              .tlb_entries = UNDEF,
1467                              .partitioning = 0};
1468    case 0xD6:
1469      return (CacheLevelInfo){.level = 3,
1470                              .cache_type = CPU_FEATURE_CACHE_DATA,
1471                              .cache_size = 1 * MiB,
1472                              .ways = 8,
1473                              .line_size = 64,
1474                              .tlb_entries = UNDEF,
1475                              .partitioning = 0};
1476    case 0xD7:
1477      return (CacheLevelInfo){.level = 3,
1478                              .cache_type = CPU_FEATURE_CACHE_DATA,
1479                              .cache_size = 2 * MiB,
1480                              .ways = 8,
1481                              .line_size = 64,
1482                              .tlb_entries = UNDEF,
1483                              .partitioning = 0};
1484    case 0xD8:
1485      return (CacheLevelInfo){.level = 3,
1486                              .cache_type = CPU_FEATURE_CACHE_DATA,
1487                              .cache_size = 4 * MiB,
1488                              .ways = 8,
1489                              .line_size = 64,
1490                              .tlb_entries = UNDEF,
1491                              .partitioning = 0};
1492    case 0xDC:
1493      return (CacheLevelInfo){.level = 3,
1494                              .cache_type = CPU_FEATURE_CACHE_DATA,
1495                              .cache_size = 1 * 1536 * KiB,
1496                              .ways = 12,
1497                              .line_size = 64,
1498                              .tlb_entries = UNDEF,
1499                              .partitioning = 0};
1500    case 0xDD:
1501      return (CacheLevelInfo){.level = 3,
1502                              .cache_type = CPU_FEATURE_CACHE_DATA,
1503                              .cache_size = 3 * MiB,
1504                              .ways = 12,
1505                              .line_size = 64,
1506                              .tlb_entries = UNDEF,
1507                              .partitioning = 0};
1508    case 0xDE:
1509      return (CacheLevelInfo){.level = 3,
1510                              .cache_type = CPU_FEATURE_CACHE_DATA,
1511                              .cache_size = 6 * MiB,
1512                              .ways = 12,
1513                              .line_size = 64,
1514                              .tlb_entries = UNDEF,
1515                              .partitioning = 0};
1516    case 0xE2:
1517      return (CacheLevelInfo){.level = 3,
1518                              .cache_type = CPU_FEATURE_CACHE_DATA,
1519                              .cache_size = 2 * MiB,
1520                              .ways = 16,
1521                              .line_size = 64,
1522                              .tlb_entries = UNDEF,
1523                              .partitioning = 0};
1524    case 0xE3:
1525      return (CacheLevelInfo){.level = 3,
1526                              .cache_type = CPU_FEATURE_CACHE_DATA,
1527                              .cache_size = 4 * MiB,
1528                              .ways = 16,
1529                              .line_size = 64,
1530                              .tlb_entries = UNDEF,
1531                              .partitioning = 0};
1532    case 0xE4:
1533      return (CacheLevelInfo){.level = 3,
1534                              .cache_type = CPU_FEATURE_CACHE_DATA,
1535                              .cache_size = 8 * MiB,
1536                              .ways = 16,
1537                              .line_size = 64,
1538                              .tlb_entries = UNDEF,
1539                              .partitioning = 0};
1540    case 0xEA:
1541      return (CacheLevelInfo){.level = 3,
1542                              .cache_type = CPU_FEATURE_CACHE_DATA,
1543                              .cache_size = 12 * MiB,
1544                              .ways = 24,
1545                              .line_size = 64,
1546                              .tlb_entries = UNDEF,
1547                              .partitioning = 0};
1548    case 0xEB:
1549      return (CacheLevelInfo){.level = 3,
1550                              .cache_type = CPU_FEATURE_CACHE_DATA,
1551                              .cache_size = 18 * MiB,
1552                              .ways = 24,
1553                              .line_size = 64,
1554                              .tlb_entries = UNDEF,
1555                              .partitioning = 0};
1556    case 0xEC:
1557      return (CacheLevelInfo){.level = 3,
1558                              .cache_type = CPU_FEATURE_CACHE_DATA,
1559                              .cache_size = 24 * MiB,
1560                              .ways = 24,
1561                              .line_size = 64,
1562                              .tlb_entries = UNDEF,
1563                              .partitioning = 0};
1564    case 0xF0:
1565      return (CacheLevelInfo){.level = UNDEF,
1566                              .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1567                              .cache_size = 64 * KiB,
1568                              .ways = UNDEF,
1569                              .line_size = UNDEF,
1570                              .tlb_entries = UNDEF,
1571                              .partitioning = 0};
1572    case 0xF1:
1573      return (CacheLevelInfo){.level = UNDEF,
1574                              .cache_type = CPU_FEATURE_CACHE_PREFETCH,
1575                              .cache_size = 128 * KiB,
1576                              .ways = UNDEF,
1577                              .line_size = UNDEF,
1578                              .tlb_entries = UNDEF,
1579                              .partitioning = 0};
1580    case 0xFF:
1581      return (CacheLevelInfo){.level = UNDEF,
1582                              .cache_type = CPU_FEATURE_CACHE_NULL,
1583                              .cache_size = UNDEF,
1584                              .ways = UNDEF,
1585                              .line_size = UNDEF,
1586                              .tlb_entries = UNDEF,
1587                              .partitioning = 0};
1588    default:
1589      return kEmptyCacheLevelInfo;
1590  }
1591}
1592
1593// From https://www.felixcloutier.com/x86/cpuid#tbl-3-12
1594static void ParseLeaf2(const Leaves* leaves, CacheInfo* info) {
1595  Leaf leaf = leaves->leaf_2;
1596  // The least-significant byte in register EAX (register AL) will always return
1597  // 01H. Software should ignore this value and not interpret it as an
1598  // informational descriptor.
1599  leaf.eax &= 0xFFFFFF00;  // Zeroing out AL. 0 is the empty descriptor.
1600  // The most significant bit (bit 31) of each register indicates whether the
1601  // register contains valid information (set to 0) or is reserved (set to 1).
1602  if (IsBitSet(leaf.eax, 31)) leaf.eax = 0;
1603  if (IsBitSet(leaf.ebx, 31)) leaf.ebx = 0;
1604  if (IsBitSet(leaf.ecx, 31)) leaf.ecx = 0;
1605  if (IsBitSet(leaf.edx, 31)) leaf.edx = 0;
1606
1607  uint8_t data[16];
1608#if __STDC_VERSION__ >= 201112L
1609  _Static_assert(sizeof(Leaf) == sizeof(data), "Leaf must be 16 bytes");
1610#endif
1611  copy((char*)(data), (const char*)(&leaf), sizeof(data));
1612  for (size_t i = 0; i < sizeof(data); ++i) {
1613    const uint8_t descriptor = data[i];
1614    if (descriptor == 0) continue;
1615    info->levels[info->size] = GetCacheLevelInfo(descriptor);
1616    info->size++;
1617  }
1618}
1619
1620static const CacheInfo kEmptyCacheInfo;
1621
1622// For newer Intel CPUs uses "CPUID, eax=0x00000004".
1623// https://www.felixcloutier.com/x86/cpuid#input-eax-=-04h--returns-deterministic-cache-parameters-for-each-level
1624// For newer AMD CPUs uses "CPUID, eax=0x8000001D"
1625static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id,
1626                           CacheInfo* old_info) {
1627  CacheInfo info = kEmptyCacheInfo;
1628  for (int index = 0; info.size < CPU_FEATURES_MAX_CACHE_LEVEL; ++index) {
1629    const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, leaf_id, index);
1630    int cache_type_field = ExtractBitRange(leaf.eax, 4, 0);
1631    CacheType cache_type;
1632    if (cache_type_field == 0)
1633      break;
1634    else if (cache_type_field == 1)
1635      cache_type = CPU_FEATURE_CACHE_DATA;
1636    else if (cache_type_field == 2)
1637      cache_type = CPU_FEATURE_CACHE_INSTRUCTION;
1638    else if (cache_type_field == 3)
1639      cache_type = CPU_FEATURE_CACHE_UNIFIED;
1640    else
1641      break;  // Should not occur as per documentation.
1642    int level = ExtractBitRange(leaf.eax, 7, 5);
1643    int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
1644    int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
1645    int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
1646    int tlb_entries = leaf.ecx + 1;
1647    int cache_size = ways * partitioning * line_size * tlb_entries;
1648    info.levels[info.size] = (CacheLevelInfo){.level = level,
1649                                              .cache_type = cache_type,
1650                                              .cache_size = cache_size,
1651                                              .ways = ways,
1652                                              .line_size = line_size,
1653                                              .tlb_entries = tlb_entries,
1654                                              .partitioning = partitioning};
1655    ++info.size;
1656  }
1657  // Override CacheInfo if we successfully extracted Deterministic Cache
1658  // Parameters.
1659  if (info.size > 0) *old_info = info;
1660}
1661
1662CacheInfo GetX86CacheInfo(void) {
1663  CacheInfo info = kEmptyCacheInfo;
1664  const Leaves leaves = ReadLeaves();
1665  if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL) ||
1666      IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_CENTAUR_HAULS) ||
1667      IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_SHANGHAI)) {
1668    ParseLeaf2(&leaves, &info);
1669    ParseCacheInfo(leaves.max_cpuid_leaf, 4, &info);
1670  } else if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
1671             IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
1672    // If CPUID Fn8000_0001_ECX[TopologyExtensions]==0
1673    // then CPUID Fn8000_0001_E[D,C,B,A]X is reserved.
1674    // https://www.amd.com/system/files/TechDocs/25481.pdf
1675    if (IsBitSet(leaves.leaf_80000001.ecx, 22)) {
1676      ParseCacheInfo(leaves.max_cpuid_leaf_ext, 0x8000001D, &info);
1677    }
1678  }
1679  return info;
1680}
1681
1682////////////////////////////////////////////////////////////////////////////////
1683// Definitions for introspection.
1684////////////////////////////////////////////////////////////////////////////////
1685#define INTROSPECTION_TABLE                                \
1686  LINE(X86_FPU, fpu, , , )                                 \
1687  LINE(X86_TSC, tsc, , , )                                 \
1688  LINE(X86_CX8, cx8, , , )                                 \
1689  LINE(X86_CLFSH, clfsh, , , )                             \
1690  LINE(X86_MMX, mmx, , , )                                 \
1691  LINE(X86_AES, aes, , , )                                 \
1692  LINE(X86_ERMS, erms, , , )                               \
1693  LINE(X86_F16C, f16c, , , )                               \
1694  LINE(X86_FMA4, fma4, , , )                               \
1695  LINE(X86_FMA3, fma3, , , )                               \
1696  LINE(X86_VAES, vaes, , , )                               \
1697  LINE(X86_VPCLMULQDQ, vpclmulqdq, , , )                   \
1698  LINE(X86_BMI1, bmi1, , , )                               \
1699  LINE(X86_HLE, hle, , , )                                 \
1700  LINE(X86_BMI2, bmi2, , , )                               \
1701  LINE(X86_RTM, rtm, , , )                                 \
1702  LINE(X86_RDSEED, rdseed, , , )                           \
1703  LINE(X86_CLFLUSHOPT, clflushopt, , , )                   \
1704  LINE(X86_CLWB, clwb, , , )                               \
1705  LINE(X86_SSE, sse, , , )                                 \
1706  LINE(X86_SSE2, sse2, , , )                               \
1707  LINE(X86_SSE3, sse3, , , )                               \
1708  LINE(X86_SSSE3, ssse3, , , )                             \
1709  LINE(X86_SSE4_1, sse4_1, , , )                           \
1710  LINE(X86_SSE4_2, sse4_2, , , )                           \
1711  LINE(X86_SSE4A, sse4a, , , )                             \
1712  LINE(X86_AVX, avx, , , )                                 \
1713  LINE(X86_AVX2, avx2, , , )                               \
1714  LINE(X86_AVX512F, avx512f, , , )                         \
1715  LINE(X86_AVX512CD, avx512cd, , , )                       \
1716  LINE(X86_AVX512ER, avx512er, , , )                       \
1717  LINE(X86_AVX512PF, avx512pf, , , )                       \
1718  LINE(X86_AVX512BW, avx512bw, , , )                       \
1719  LINE(X86_AVX512DQ, avx512dq, , , )                       \
1720  LINE(X86_AVX512VL, avx512vl, , , )                       \
1721  LINE(X86_AVX512IFMA, avx512ifma, , , )                   \
1722  LINE(X86_AVX512VBMI, avx512vbmi, , , )                   \
1723  LINE(X86_AVX512VBMI2, avx512vbmi2, , , )                 \
1724  LINE(X86_AVX512VNNI, avx512vnni, , , )                   \
1725  LINE(X86_AVX512BITALG, avx512bitalg, , , )               \
1726  LINE(X86_AVX512VPOPCNTDQ, avx512vpopcntdq, , , )         \
1727  LINE(X86_AVX512_4VNNIW, avx512_4vnniw, , , )             \
1728  LINE(X86_AVX512_4VBMI2, avx512_4vbmi2, , , )             \
1729  LINE(X86_AVX512_SECOND_FMA, avx512_second_fma, , , )     \
1730  LINE(X86_AVX512_4FMAPS, avx512_4fmaps, , , )             \
1731  LINE(X86_AVX512_BF16, avx512_bf16, , , )                 \
1732  LINE(X86_AVX512_VP2INTERSECT, avx512_vp2intersect, , , ) \
1733  LINE(X86_AMX_BF16, amx_bf16, , , )                       \
1734  LINE(X86_AMX_TILE, amx_tile, , , )                       \
1735  LINE(X86_AMX_INT8, amx_int8, , , )                       \
1736  LINE(X86_PCLMULQDQ, pclmulqdq, , , )                     \
1737  LINE(X86_SMX, smx, , , )                                 \
1738  LINE(X86_SGX, sgx, , , )                                 \
1739  LINE(X86_CX16, cx16, , , )                               \
1740  LINE(X86_SHA, sha, , , )                                 \
1741  LINE(X86_POPCNT, popcnt, , , )                           \
1742  LINE(X86_MOVBE, movbe, , , )                             \
1743  LINE(X86_RDRND, rdrnd, , , )                             \
1744  LINE(X86_DCA, dca, , , )                                 \
1745  LINE(X86_SS, ss, , , )                                   \
1746  LINE(X86_ADX, adx, , , )
1747#define INTROSPECTION_PREFIX X86
1748#define INTROSPECTION_ENUM_PREFIX X86
1749#include "define_introspection.inl"
1750
1751#define X86_MICROARCHITECTURE_NAMES \
1752  LINE(X86_UNKNOWN)                 \
1753  LINE(ZHAOXIN_ZHANGJIANG)          \
1754  LINE(ZHAOXIN_WUDAOKOU)            \
1755  LINE(ZHAOXIN_LUJIAZUI)            \
1756  LINE(ZHAOXIN_YONGFENG)            \
1757  LINE(INTEL_80486)                 \
1758  LINE(INTEL_P5)                    \
1759  LINE(INTEL_LAKEMONT)              \
1760  LINE(INTEL_CORE)                  \
1761  LINE(INTEL_PNR)                   \
1762  LINE(INTEL_NHM)                   \
1763  LINE(INTEL_ATOM_BNL)              \
1764  LINE(INTEL_WSM)                   \
1765  LINE(INTEL_SNB)                   \
1766  LINE(INTEL_IVB)                   \
1767  LINE(INTEL_ATOM_SMT)              \
1768  LINE(INTEL_HSW)                   \
1769  LINE(INTEL_BDW)                   \
1770  LINE(INTEL_SKL)                   \
1771  LINE(INTEL_ATOM_GMT)              \
1772  LINE(INTEL_KBL)                   \
1773  LINE(INTEL_CFL)                   \
1774  LINE(INTEL_WHL)                   \
1775  LINE(INTEL_CNL)                   \
1776  LINE(INTEL_ICL)                   \
1777  LINE(INTEL_TGL)                   \
1778  LINE(INTEL_SPR)                   \
1779  LINE(INTEL_ADL)                   \
1780  LINE(INTEL_RCL)                   \
1781  LINE(INTEL_KNIGHTS_M)             \
1782  LINE(INTEL_KNIGHTS_L)             \
1783  LINE(INTEL_KNIGHTS_F)             \
1784  LINE(INTEL_KNIGHTS_C)             \
1785  LINE(INTEL_NETBURST)              \
1786  LINE(AMD_HAMMER)                  \
1787  LINE(AMD_K10)                     \
1788  LINE(AMD_K11)                     \
1789  LINE(AMD_K12)                     \
1790  LINE(AMD_BOBCAT)                  \
1791  LINE(AMD_PILEDRIVER)              \
1792  LINE(AMD_STREAMROLLER)            \
1793  LINE(AMD_EXCAVATOR)               \
1794  LINE(AMD_BULLDOZER)               \
1795  LINE(AMD_JAGUAR)                  \
1796  LINE(AMD_PUMA)                    \
1797  LINE(AMD_ZEN)                     \
1798  LINE(AMD_ZEN_PLUS)                \
1799  LINE(AMD_ZEN2)                    \
1800  LINE(AMD_ZEN3)
1801
1802const char* GetX86MicroarchitectureName(X86Microarchitecture value) {
1803#define LINE(ENUM) [ENUM] = STRINGIZE(ENUM),
1804  static const char* kMicroarchitectureNames[] = {X86_MICROARCHITECTURE_NAMES};
1805#undef LINE
1806  if (value >= X86_MICROARCHITECTURE_LAST_) return "unknown microarchitecture";
1807  return kMicroarchitectureNames[value];
1808}
1809