1/* Get CPU type and Features for x86 processors.
2   Copyright (C) 2012-2015 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
30#ifdef HAVE_INIT_PRIORITY
31#define CONSTRUCTOR_PRIORITY (101)
32#else
33#define CONSTRUCTOR_PRIORITY
34#endif
35
36int __cpu_indicator_init (void)
37  __attribute__ ((constructor CONSTRUCTOR_PRIORITY));
38
39/* Processor Vendor and Models. */
40
41enum processor_vendor
42{
43  VENDOR_INTEL = 1,
44  VENDOR_AMD,
45  VENDOR_OTHER,
46  VENDOR_MAX
47};
48
49/* Any new types or subtypes have to be inserted at the end. */
50
51enum processor_types
52{
53  INTEL_BONNELL = 1,
54  INTEL_CORE2,
55  INTEL_COREI7,
56  AMDFAM10H,
57  AMDFAM15H,
58  INTEL_SILVERMONT,
59  AMD_BTVER1,
60  AMD_BTVER2,
61  CPU_TYPE_MAX
62};
63
64enum processor_subtypes
65{
66  INTEL_COREI7_NEHALEM = 1,
67  INTEL_COREI7_WESTMERE,
68  INTEL_COREI7_SANDYBRIDGE,
69  AMDFAM10H_BARCELONA,
70  AMDFAM10H_SHANGHAI,
71  AMDFAM10H_ISTANBUL,
72  AMDFAM15H_BDVER1,
73  AMDFAM15H_BDVER2,
74  AMDFAM15H_BDVER3,
75  AMDFAM15H_BDVER4,
76  INTEL_COREI7_IVYBRIDGE,
77  INTEL_COREI7_HASWELL,
78  INTEL_COREI7_BROADWELL,
79  CPU_SUBTYPE_MAX
80};
81
82/* ISA Features supported. */
83
84enum processor_features
85{
86  FEATURE_CMOV = 0,
87  FEATURE_MMX,
88  FEATURE_POPCNT,
89  FEATURE_SSE,
90  FEATURE_SSE2,
91  FEATURE_SSE3,
92  FEATURE_SSSE3,
93  FEATURE_SSE4_1,
94  FEATURE_SSE4_2,
95  FEATURE_AVX,
96  FEATURE_AVX2,
97  FEATURE_SSE4_A,
98  FEATURE_FMA4,
99  FEATURE_XOP,
100  FEATURE_FMA,
101  FEATURE_AVX512F,
102  FEATURE_BMI,
103  FEATURE_BMI2
104};
105
106struct __processor_model
107{
108  unsigned int __cpu_vendor;
109  unsigned int __cpu_type;
110  unsigned int __cpu_subtype;
111  unsigned int __cpu_features[1];
112} __cpu_model;
113
114
115/* Get the specific type of AMD CPU.  */
116
117static void
118get_amd_cpu (unsigned int family, unsigned int model)
119{
120  switch (family)
121    {
122    /* AMD Family 10h.  */
123    case 0x10:
124      __cpu_model.__cpu_type = AMDFAM10H;
125      switch (model)
126	{
127	case 0x2:
128	  /* Barcelona.  */
129	  __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA;
130	  break;
131	case 0x4:
132	  /* Shanghai.  */
133	  __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI;
134	  break;
135	case 0x8:
136	  /* Istanbul.  */
137	  __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL;
138	  break;
139	default:
140	  break;
141	}
142      break;
143    /* AMD Family 14h "btver1". */
144    case 0x14:
145      __cpu_model.__cpu_type = AMD_BTVER1;
146      break;
147    /* AMD Family 15h "Bulldozer".  */
148    case 0x15:
149      __cpu_model.__cpu_type = AMDFAM15H;
150      /* Bulldozer version 1.  */
151      if ( model <= 0xf)
152	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER1;
153      /* Bulldozer version 2 "Piledriver" */
154      if (model >= 0x10 && model <= 0x2f)
155	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
156      /* Bulldozer version 3 "Steamroller"  */
157      if (model >= 0x30 && model <= 0x4f)
158	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER3;
159      /* Bulldozer version 4 "Excavator"   */
160      if (model >= 0x60 && model <= 0x7f)
161	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER4;
162      break;
163    /* AMD Family 16h "btver2" */
164    case 0x16:
165      __cpu_model.__cpu_type = AMD_BTVER2;
166      break;
167    default:
168      break;
169    }
170}
171
172/* Get the specific type of Intel CPU.  */
173
174static void
175get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
176{
177  /* Parse family and model only if brand ID is 0. */
178  if (brand_id == 0)
179    {
180      switch (family)
181	{
182	case 0x5:
183	  /* Pentium.  */
184	  break;
185	case 0x6:
186	  switch (model)
187	    {
188	    case 0x1c:
189	    case 0x26:
190	      /* Bonnell.  */
191	      __cpu_model.__cpu_type = INTEL_BONNELL;
192	      break;
193	    case 0x37:
194	    case 0x4a:
195	    case 0x4d:
196	    case 0x5a:
197	    case 0x5d:
198	      /* Silvermont.  */
199	      __cpu_model.__cpu_type = INTEL_SILVERMONT;
200	      break;
201	    case 0x1a:
202	    case 0x1e:
203	    case 0x1f:
204	    case 0x2e:
205	      /* Nehalem.  */
206	      __cpu_model.__cpu_type = INTEL_COREI7;
207	      __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM;
208	      break;
209	    case 0x25:
210	    case 0x2c:
211	    case 0x2f:
212	      /* Westmere.  */
213	      __cpu_model.__cpu_type = INTEL_COREI7;
214	      __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE;
215	      break;
216	    case 0x2a:
217	    case 0x2d:
218	      /* Sandy Bridge.  */
219	      __cpu_model.__cpu_type = INTEL_COREI7;
220	      __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
221	      break;
222	    case 0x3a:
223	    case 0x3e:
224	      /* Ivy Bridge.  */
225	      __cpu_model.__cpu_type = INTEL_COREI7;
226	      __cpu_model.__cpu_subtype = INTEL_COREI7_IVYBRIDGE;
227	      break;
228	    case 0x3c:
229	    case 0x3f:
230	    case 0x45:
231	    case 0x46:
232	      /* Haswell.  */
233	      __cpu_model.__cpu_type = INTEL_COREI7;
234	      __cpu_model.__cpu_subtype = INTEL_COREI7_HASWELL;
235	      break;
236	    case 0x3d:
237	    case 0x4f:
238	    case 0x56:
239	      /* Broadwell.  */
240	      __cpu_model.__cpu_type = INTEL_COREI7;
241	      __cpu_model.__cpu_subtype = INTEL_COREI7_BROADWELL;
242	      break;
243	    case 0x17:
244	    case 0x1d:
245	      /* Penryn.  */
246	    case 0x0f:
247	      /* Merom.  */
248	      __cpu_model.__cpu_type = INTEL_CORE2;
249	      break;
250	    default:
251	      break;
252	    }
253	  break;
254	default:
255	  /* We have no idea.  */
256	  break;
257	}
258    }
259}
260
261/* ECX and EDX are output of CPUID at level one.  MAX_CPUID_LEVEL is
262   the max possible level of CPUID insn.  */
263static void
264get_available_features (unsigned int ecx, unsigned int edx,
265			int max_cpuid_level)
266{
267  unsigned int features = 0;
268
269  if (edx & bit_CMOV)
270    features |= (1 << FEATURE_CMOV);
271  if (edx & bit_MMX)
272    features |= (1 << FEATURE_MMX);
273  if (edx & bit_SSE)
274    features |= (1 << FEATURE_SSE);
275  if (edx & bit_SSE2)
276    features |= (1 << FEATURE_SSE2);
277  if (ecx & bit_POPCNT)
278    features |= (1 << FEATURE_POPCNT);
279  if (ecx & bit_SSE3)
280    features |= (1 << FEATURE_SSE3);
281  if (ecx & bit_SSSE3)
282    features |= (1 << FEATURE_SSSE3);
283  if (ecx & bit_SSE4_1)
284    features |= (1 << FEATURE_SSE4_1);
285  if (ecx & bit_SSE4_2)
286    features |= (1 << FEATURE_SSE4_2);
287  if (ecx & bit_AVX)
288    features |= (1 << FEATURE_AVX);
289  if (ecx & bit_FMA)
290    features |= (1 << FEATURE_FMA);
291
292  /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */
293  if (max_cpuid_level >= 7)
294    {
295      unsigned int eax, ebx, ecx, edx;
296      __cpuid_count (7, 0, eax, ebx, ecx, edx);
297      if (ebx & bit_BMI)
298        features |= (1 << FEATURE_BMI);
299      if (ebx & bit_AVX2)
300	features |= (1 << FEATURE_AVX2);
301      if (ebx & bit_BMI2)
302        features |= (1 << FEATURE_BMI2);
303      if (ebx & bit_AVX512F)
304	features |= (1 << FEATURE_AVX512F);
305    }
306
307  unsigned int ext_level;
308  unsigned int eax, ebx;
309  /* Check cpuid level of extended features.  */
310  __cpuid (0x80000000, ext_level, ebx, ecx, edx);
311
312  if (ext_level > 0x80000000)
313    {
314      __cpuid (0x80000001, eax, ebx, ecx, edx);
315
316      if (ecx & bit_SSE4a)
317	features |= (1 << FEATURE_SSE4_A);
318      if (ecx & bit_FMA4)
319	features |= (1 << FEATURE_FMA4);
320      if (ecx & bit_XOP)
321	features |= (1 << FEATURE_XOP);
322    }
323
324  __cpu_model.__cpu_features[0] = features;
325}
326
327/* A noinline function calling __get_cpuid. Having many calls to
328   cpuid in one function in 32-bit mode causes GCC to complain:
329   "can't find a register in class CLOBBERED_REGS".  This is
330   related to PR rtl-optimization 44174. */
331
332static int __attribute__ ((noinline))
333__get_cpuid_output (unsigned int __level,
334		    unsigned int *__eax, unsigned int *__ebx,
335		    unsigned int *__ecx, unsigned int *__edx)
336{
337  return __get_cpuid (__level, __eax, __ebx, __ecx, __edx);
338}
339
340
341/* A constructor function that is sets __cpu_model and __cpu_features with
342   the right values.  This needs to run only once.  This constructor is
343   given the highest priority and it should run before constructors without
344   the priority set.  However, it still runs after ifunc initializers and
345   needs to be called explicitly there.  */
346
347int __attribute__ ((constructor CONSTRUCTOR_PRIORITY))
348__cpu_indicator_init (void)
349{
350  unsigned int eax, ebx, ecx, edx;
351
352  int max_level = 5;
353  unsigned int vendor;
354  unsigned int model, family, brand_id;
355  unsigned int extended_model, extended_family;
356
357  /* This function needs to run just once.  */
358  if (__cpu_model.__cpu_vendor)
359    return 0;
360
361  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
362  if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
363    {
364      __cpu_model.__cpu_vendor = VENDOR_OTHER;
365      return -1;
366    }
367
368  vendor = ebx;
369  max_level = eax;
370
371  if (max_level < 1)
372    {
373      __cpu_model.__cpu_vendor = VENDOR_OTHER;
374      return -1;
375    }
376
377  if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
378    {
379      __cpu_model.__cpu_vendor = VENDOR_OTHER;
380      return -1;
381    }
382
383  model = (eax >> 4) & 0x0f;
384  family = (eax >> 8) & 0x0f;
385  brand_id = ebx & 0xff;
386  extended_model = (eax >> 12) & 0xf0;
387  extended_family = (eax >> 20) & 0xff;
388
389  if (vendor == signature_INTEL_ebx)
390    {
391      /* Adjust model and family for Intel CPUS. */
392      if (family == 0x0f)
393	{
394	  family += extended_family;
395	  model += extended_model;
396	}
397      else if (family == 0x06)
398	model += extended_model;
399
400      /* Get CPU type.  */
401      get_intel_cpu (family, model, brand_id);
402      /* Find available features. */
403      get_available_features (ecx, edx, max_level);
404      __cpu_model.__cpu_vendor = VENDOR_INTEL;
405    }
406  else if (vendor == signature_AMD_ebx)
407    {
408      /* Adjust model and family for AMD CPUS. */
409      if (family == 0x0f)
410	{
411	  family += extended_family;
412	  model += extended_model;
413	}
414
415      /* Get CPU type.  */
416      get_amd_cpu (family, model);
417      /* Find available features. */
418      get_available_features (ecx, edx, max_level);
419      __cpu_model.__cpu_vendor = VENDOR_AMD;
420    }
421  else
422    __cpu_model.__cpu_vendor = VENDOR_OTHER;
423
424  gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX);
425  gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX);
426  gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
427
428  return 0;
429}
430