cpuinfo.c revision 1.1.1.8
1/* Get CPU type and Features for x86 processors.
2   Copyright (C) 2012-2018 Free Software Foundation, Inc.
3   Contributed by Sriraman Tallam (tmsriram@google.com)
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24<http://www.gnu.org/licenses/>.  */
25
26#include "cpuid.h"
27#include "tsystem.h"
28#include "auto-target.h"
29#include "cpuinfo.h"
30
31#ifdef HAVE_INIT_PRIORITY
32#define CONSTRUCTOR_PRIORITY (101)
33#else
34#define CONSTRUCTOR_PRIORITY
35#endif
36
37int __cpu_indicator_init (void)
38  __attribute__ ((constructor CONSTRUCTOR_PRIORITY));
39
40
41struct __processor_model __cpu_model = { };
42#ifndef SHARED
43/* We want to move away from __cpu_model in libgcc_s.so.1 and the
44   size of __cpu_model is part of ABI.  So, new features that don't
45   fit into __cpu_model.__cpu_features[0] go into extra variables
46   in libgcc.a only, preferrably hidden.  */
47unsigned int __cpu_features2;
48#endif
49
50
51/* Get the specific type of AMD CPU.  */
52
53static void
54get_amd_cpu (unsigned int family, unsigned int model)
55{
56  switch (family)
57    {
58    /* AMD Family 10h.  */
59    case 0x10:
60      __cpu_model.__cpu_type = AMDFAM10H;
61      switch (model)
62	{
63	case 0x2:
64	  /* Barcelona.  */
65	  __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA;
66	  break;
67	case 0x4:
68	  /* Shanghai.  */
69	  __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI;
70	  break;
71	case 0x8:
72	  /* Istanbul.  */
73	  __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL;
74	  break;
75	default:
76	  break;
77	}
78      break;
79    /* AMD Family 14h "btver1". */
80    case 0x14:
81      __cpu_model.__cpu_type = AMD_BTVER1;
82      break;
83    /* AMD Family 15h "Bulldozer".  */
84    case 0x15:
85      __cpu_model.__cpu_type = AMDFAM15H;
86
87      if (model == 0x2)
88	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
89      /* Bulldozer version 1.  */
90      else if (model <= 0xf)
91	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER1;
92      /* Bulldozer version 2 "Piledriver" */
93      else if (model <= 0x2f)
94	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
95      /* Bulldozer version 3 "Steamroller"  */
96      else if (model <= 0x4f)
97	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER3;
98      /* Bulldozer version 4 "Excavator"   */
99      else if (model <= 0x7f)
100	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER4;
101      break;
102    /* AMD Family 16h "btver2" */
103    case 0x16:
104      __cpu_model.__cpu_type = AMD_BTVER2;
105      break;
106    case 0x17:
107      __cpu_model.__cpu_type = AMDFAM17H;
108      /* AMD family 17h version 1.  */
109      if (model <= 0x1f)
110	__cpu_model.__cpu_subtype = AMDFAM17H_ZNVER1;
111      break;
112    default:
113      break;
114    }
115}
116
117/* Get the specific type of Intel CPU.  */
118
119static void
120get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
121{
122  /* Parse family and model only if brand ID is 0. */
123  if (brand_id == 0)
124    {
125      switch (family)
126	{
127	case 0x5:
128	  /* Pentium.  */
129	  break;
130	case 0x6:
131	  switch (model)
132	    {
133	    case 0x1c:
134	    case 0x26:
135	      /* Bonnell.  */
136	      __cpu_model.__cpu_type = INTEL_BONNELL;
137	      break;
138	    case 0x37:
139	    case 0x4a:
140	    case 0x4d:
141	    case 0x5a:
142	    case 0x5d:
143	      /* Silvermont.  */
144	      __cpu_model.__cpu_type = INTEL_SILVERMONT;
145	      break;
146	    case 0x57:
147	      /* Knights Landing.  */
148	      __cpu_model.__cpu_type = INTEL_KNL;
149	      break;
150	    case 0x85:
151	      /* Knights Mill. */
152	      __cpu_model.__cpu_type = INTEL_KNM;
153	      break;
154	    case 0x1a:
155	    case 0x1e:
156	    case 0x1f:
157	    case 0x2e:
158	      /* Nehalem.  */
159	      __cpu_model.__cpu_type = INTEL_COREI7;
160	      __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM;
161	      break;
162	    case 0x25:
163	    case 0x2c:
164	    case 0x2f:
165	      /* Westmere.  */
166	      __cpu_model.__cpu_type = INTEL_COREI7;
167	      __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE;
168	      break;
169	    case 0x2a:
170	    case 0x2d:
171	      /* Sandy Bridge.  */
172	      __cpu_model.__cpu_type = INTEL_COREI7;
173	      __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
174	      break;
175	    case 0x3a:
176	    case 0x3e:
177	      /* Ivy Bridge.  */
178	      __cpu_model.__cpu_type = INTEL_COREI7;
179	      __cpu_model.__cpu_subtype = INTEL_COREI7_IVYBRIDGE;
180	      break;
181	    case 0x3c:
182	    case 0x3f:
183	    case 0x45:
184	    case 0x46:
185	      /* Haswell.  */
186	      __cpu_model.__cpu_type = INTEL_COREI7;
187	      __cpu_model.__cpu_subtype = INTEL_COREI7_HASWELL;
188	      break;
189	    case 0x3d:
190	    case 0x47:
191	    case 0x4f:
192	    case 0x56:
193	      /* Broadwell.  */
194	      __cpu_model.__cpu_type = INTEL_COREI7;
195	      __cpu_model.__cpu_subtype = INTEL_COREI7_BROADWELL;
196	      break;
197	    case 0x4e:
198	    case 0x5e:
199	      /* Skylake.  */
200	    case 0x8e:
201	    case 0x9e:
202	      /* Kaby Lake.  */
203	      __cpu_model.__cpu_type = INTEL_COREI7;
204	      __cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE;
205	      break;
206	    case 0x55:
207	      /* Skylake with AVX-512 support.  */
208	      __cpu_model.__cpu_type = INTEL_COREI7;
209	      __cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE_AVX512;
210	      break;
211	    case 0x66:
212	      /* Cannon Lake.  */
213	      __cpu_model.__cpu_type = INTEL_COREI7;
214	      __cpu_model.__cpu_subtype = INTEL_COREI7_CANNONLAKE;
215	      break;
216	    case 0x17:
217	    case 0x1d:
218	      /* Penryn.  */
219	    case 0x0f:
220	      /* Merom.  */
221	      __cpu_model.__cpu_type = INTEL_CORE2;
222	      break;
223	    default:
224	      break;
225	    }
226	  break;
227	default:
228	  /* We have no idea.  */
229	  break;
230	}
231    }
232}
233
234/* ECX and EDX are output of CPUID at level one.  MAX_CPUID_LEVEL is
235   the max possible level of CPUID insn.  */
236static void
237get_available_features (unsigned int ecx, unsigned int edx,
238			int max_cpuid_level)
239{
240  unsigned int eax, ebx;
241  unsigned int ext_level;
242
243  unsigned int features = 0;
244  unsigned int features2 = 0;
245
246  /* Get XCR_XFEATURE_ENABLED_MASK register with xgetbv.  */
247#define XCR_XFEATURE_ENABLED_MASK	0x0
248#define XSTATE_FP			0x1
249#define XSTATE_SSE			0x2
250#define XSTATE_YMM			0x4
251#define XSTATE_OPMASK			0x20
252#define XSTATE_ZMM			0x40
253#define XSTATE_HI_ZMM			0x80
254
255#define XCR_AVX_ENABLED_MASK \
256  (XSTATE_SSE | XSTATE_YMM)
257#define XCR_AVX512F_ENABLED_MASK \
258  (XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM)
259
260  /* Check if AVX and AVX512 are usable.  */
261  int avx_usable = 0;
262  int avx512_usable = 0;
263  if ((ecx & bit_OSXSAVE))
264    {
265      /* Check if XMM, YMM, OPMASK, upper 256 bits of ZMM0-ZMM15 and
266         ZMM16-ZMM31 states are supported by OSXSAVE.  */
267      unsigned int xcrlow;
268      unsigned int xcrhigh;
269      asm (".byte 0x0f, 0x01, 0xd0"
270	   : "=a" (xcrlow), "=d" (xcrhigh)
271	   : "c" (XCR_XFEATURE_ENABLED_MASK));
272      if ((xcrlow & XCR_AVX_ENABLED_MASK) == XCR_AVX_ENABLED_MASK)
273	{
274	  avx_usable = 1;
275	  avx512_usable = ((xcrlow & XCR_AVX512F_ENABLED_MASK)
276			   == XCR_AVX512F_ENABLED_MASK);
277	}
278    }
279
280#define set_feature(f) \
281  do						\
282    {						\
283      if (f < 32)				\
284	features |= (1U << (f & 31));		\
285      else					\
286	features2 |= (1U << ((f - 32) & 31));	\
287    }						\
288  while (0)
289
290  if (edx & bit_CMOV)
291    set_feature (FEATURE_CMOV);
292  if (edx & bit_MMX)
293    set_feature (FEATURE_MMX);
294  if (edx & bit_SSE)
295    set_feature (FEATURE_SSE);
296  if (edx & bit_SSE2)
297    set_feature (FEATURE_SSE2);
298  if (ecx & bit_POPCNT)
299    set_feature (FEATURE_POPCNT);
300  if (ecx & bit_AES)
301    set_feature (FEATURE_AES);
302  if (ecx & bit_PCLMUL)
303    set_feature (FEATURE_PCLMUL);
304  if (ecx & bit_SSE3)
305    set_feature (FEATURE_SSE3);
306  if (ecx & bit_SSSE3)
307    set_feature (FEATURE_SSSE3);
308  if (ecx & bit_SSE4_1)
309    set_feature (FEATURE_SSE4_1);
310  if (ecx & bit_SSE4_2)
311    set_feature (FEATURE_SSE4_2);
312  if (avx_usable)
313    {
314      if (ecx & bit_AVX)
315	set_feature (FEATURE_AVX);
316      if (ecx & bit_FMA)
317	set_feature (FEATURE_FMA);
318    }
319
320  /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */
321  if (max_cpuid_level >= 7)
322    {
323      __cpuid_count (7, 0, eax, ebx, ecx, edx);
324      if (ebx & bit_BMI)
325	set_feature (FEATURE_BMI);
326      if (avx_usable)
327	{
328	  if (ebx & bit_AVX2)
329	    set_feature (FEATURE_AVX2);
330	}
331      if (ebx & bit_BMI2)
332	set_feature (FEATURE_BMI2);
333      if (avx512_usable)
334	{
335	  if (ebx & bit_AVX512F)
336	    set_feature (FEATURE_AVX512F);
337	  if (ebx & bit_AVX512VL)
338	    set_feature (FEATURE_AVX512VL);
339	  if (ebx & bit_AVX512BW)
340	    set_feature (FEATURE_AVX512BW);
341	  if (ebx & bit_AVX512DQ)
342	    set_feature (FEATURE_AVX512DQ);
343	  if (ebx & bit_AVX512CD)
344	    set_feature (FEATURE_AVX512CD);
345	  if (ebx & bit_AVX512PF)
346	    set_feature (FEATURE_AVX512PF);
347	  if (ebx & bit_AVX512ER)
348	    set_feature (FEATURE_AVX512ER);
349	  if (ebx & bit_AVX512IFMA)
350	    set_feature (FEATURE_AVX512IFMA);
351	  if (ecx & bit_AVX512VBMI)
352	    set_feature (FEATURE_AVX512VBMI);
353	  if (ecx & bit_AVX512VBMI2)
354	    set_feature (FEATURE_AVX512VBMI2);
355	  if (ecx & bit_GFNI)
356	    set_feature (FEATURE_GFNI);
357	  if (ecx & bit_VPCLMULQDQ)
358	    set_feature (FEATURE_VPCLMULQDQ);
359	  if (ecx & bit_AVX512VNNI)
360	    set_feature (FEATURE_AVX512VNNI);
361	  if (ecx & bit_AVX512BITALG)
362	    set_feature (FEATURE_AVX512BITALG);
363	  if (ecx & bit_AVX512VPOPCNTDQ)
364	    set_feature (FEATURE_AVX512VPOPCNTDQ);
365	  if (edx & bit_AVX5124VNNIW)
366	    set_feature (FEATURE_AVX5124VNNIW);
367	  if (edx & bit_AVX5124FMAPS)
368	    set_feature (FEATURE_AVX5124FMAPS);
369	}
370    }
371
372  /* Check cpuid level of extended features.  */
373  __cpuid (0x80000000, ext_level, ebx, ecx, edx);
374
375  if (ext_level >= 0x80000001)
376    {
377      __cpuid (0x80000001, eax, ebx, ecx, edx);
378
379      if (ecx & bit_SSE4a)
380	set_feature (FEATURE_SSE4_A);
381      if (avx_usable)
382	{
383	  if (ecx & bit_FMA4)
384	    set_feature (FEATURE_FMA4);
385	  if (ecx & bit_XOP)
386	    set_feature (FEATURE_XOP);
387	}
388    }
389
390  __cpu_model.__cpu_features[0] = features;
391#ifndef SHARED
392  __cpu_features2 = features2;
393#else
394  (void) features2;
395#endif
396}
397
398/* A constructor function that is sets __cpu_model and __cpu_features with
399   the right values.  This needs to run only once.  This constructor is
400   given the highest priority and it should run before constructors without
401   the priority set.  However, it still runs after ifunc initializers and
402   needs to be called explicitly there.  */
403
404int __attribute__ ((constructor CONSTRUCTOR_PRIORITY))
405__cpu_indicator_init (void)
406{
407  unsigned int eax, ebx, ecx, edx;
408
409  int max_level;
410  unsigned int vendor;
411  unsigned int model, family, brand_id;
412  unsigned int extended_model, extended_family;
413
414  /* This function needs to run just once.  */
415  if (__cpu_model.__cpu_vendor)
416    return 0;
417
418  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
419  if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
420    {
421      __cpu_model.__cpu_vendor = VENDOR_OTHER;
422      return -1;
423    }
424
425  vendor = ebx;
426  max_level = eax;
427
428  if (max_level < 1)
429    {
430      __cpu_model.__cpu_vendor = VENDOR_OTHER;
431      return -1;
432    }
433
434  if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
435    {
436      __cpu_model.__cpu_vendor = VENDOR_OTHER;
437      return -1;
438    }
439
440  model = (eax >> 4) & 0x0f;
441  family = (eax >> 8) & 0x0f;
442  brand_id = ebx & 0xff;
443  extended_model = (eax >> 12) & 0xf0;
444  extended_family = (eax >> 20) & 0xff;
445
446  if (vendor == signature_INTEL_ebx)
447    {
448      /* Adjust model and family for Intel CPUS. */
449      if (family == 0x0f)
450	{
451	  family += extended_family;
452	  model += extended_model;
453	}
454      else if (family == 0x06)
455	model += extended_model;
456
457      /* Get CPU type.  */
458      get_intel_cpu (family, model, brand_id);
459      /* Find available features. */
460      get_available_features (ecx, edx, max_level);
461      __cpu_model.__cpu_vendor = VENDOR_INTEL;
462    }
463  else if (vendor == signature_AMD_ebx)
464    {
465      /* Adjust model and family for AMD CPUS. */
466      if (family == 0x0f)
467	{
468	  family += extended_family;
469	  model += extended_model;
470	}
471
472      /* Get CPU type.  */
473      get_amd_cpu (family, model);
474      /* Find available features. */
475      get_available_features (ecx, edx, max_level);
476      __cpu_model.__cpu_vendor = VENDOR_AMD;
477    }
478  else
479    __cpu_model.__cpu_vendor = VENDOR_OTHER;
480
481  gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX);
482  gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX);
483  gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
484
485  return 0;
486}
487
488#if defined SHARED && defined USE_ELF_SYMVER
489__asm__ (".symver __cpu_indicator_init, __cpu_indicator_init@GCC_4.8.0");
490__asm__ (".symver __cpu_model, __cpu_model@GCC_4.8.0");
491#endif
492