cpuinfo.c revision 1.1.1.1
1/* Get CPU type and Features for x86 processors.
2   Copyright (C) 2012-2013 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
39enum vendor_signatures
40{
41  SIG_INTEL =	0x756e6547 /* Genu */,
42  SIG_AMD =	0x68747541 /* Auth */
43};
44
45/* Processor Vendor and Models. */
46
47enum processor_vendor
48{
49  VENDOR_INTEL = 1,
50  VENDOR_AMD,
51  VENDOR_OTHER,
52  VENDOR_MAX
53};
54
55enum processor_types
56{
57  INTEL_ATOM = 1,
58  INTEL_CORE2,
59  INTEL_COREI7,
60  AMDFAM10H,
61  AMDFAM15H,
62  CPU_TYPE_MAX
63};
64
65enum processor_subtypes
66{
67  INTEL_COREI7_NEHALEM = 1,
68  INTEL_COREI7_WESTMERE,
69  INTEL_COREI7_SANDYBRIDGE,
70  AMDFAM10H_BARCELONA,
71  AMDFAM10H_SHANGHAI,
72  AMDFAM10H_ISTANBUL,
73  AMDFAM15H_BDVER1,
74  AMDFAM15H_BDVER2,
75  CPU_SUBTYPE_MAX
76};
77
78/* ISA Features supported. */
79
80enum processor_features
81{
82  FEATURE_CMOV = 0,
83  FEATURE_MMX,
84  FEATURE_POPCNT,
85  FEATURE_SSE,
86  FEATURE_SSE2,
87  FEATURE_SSE3,
88  FEATURE_SSSE3,
89  FEATURE_SSE4_1,
90  FEATURE_SSE4_2,
91  FEATURE_AVX,
92  FEATURE_AVX2
93};
94
95struct __processor_model
96{
97  unsigned int __cpu_vendor;
98  unsigned int __cpu_type;
99  unsigned int __cpu_subtype;
100  unsigned int __cpu_features[1];
101} __cpu_model;
102
103
104/* Get the specific type of AMD CPU.  */
105
106static void
107get_amd_cpu (unsigned int family, unsigned int model)
108{
109  switch (family)
110    {
111    /* AMD Family 10h.  */
112    case 0x10:
113      switch (model)
114	{
115	case 0x2:
116	  /* Barcelona.  */
117	  __cpu_model.__cpu_type = AMDFAM10H;
118	  __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA;
119	  break;
120	case 0x4:
121	  /* Shanghai.  */
122	  __cpu_model.__cpu_type = AMDFAM10H;
123	  __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI;
124	  break;
125	case 0x8:
126	  /* Istanbul.  */
127	  __cpu_model.__cpu_type = AMDFAM10H;
128	  __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL;
129	  break;
130	default:
131	  break;
132	}
133      break;
134    /* AMD Family 15h.  */
135    case 0x15:
136      __cpu_model.__cpu_type = AMDFAM15H;
137      /* Bulldozer version 1.  */
138      if ( model <= 0xf)
139	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER1;
140      /* Bulldozer version 2.  */
141      if (model >= 0x10 && model <= 0x1f)
142	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
143      break;
144    default:
145      break;
146    }
147}
148
149/* Get the specific type of Intel CPU.  */
150
151static void
152get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
153{
154  /* Parse family and model only if brand ID is 0. */
155  if (brand_id == 0)
156    {
157      switch (family)
158	{
159	case 0x5:
160	  /* Pentium.  */
161	  break;
162	case 0x6:
163	  switch (model)
164	    {
165	    case 0x1c:
166	    case 0x26:
167	      /* Atom.  */
168	      __cpu_model.__cpu_type = INTEL_ATOM;
169	      break;
170	    case 0x1a:
171	    case 0x1e:
172	    case 0x1f:
173	    case 0x2e:
174	      /* Nehalem.  */
175	      __cpu_model.__cpu_type = INTEL_COREI7;
176	      __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM;
177	      break;
178	    case 0x25:
179	    case 0x2c:
180	    case 0x2f:
181	      /* Westmere.  */
182	      __cpu_model.__cpu_type = INTEL_COREI7;
183	      __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE;
184	      break;
185	    case 0x2a:
186	    case 0x2d:
187	      /* Sandy Bridge.  */
188	      __cpu_model.__cpu_type = INTEL_COREI7;
189	      __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
190	      break;
191	    case 0x17:
192	    case 0x1d:
193	      /* Penryn.  */
194	    case 0x0f:
195	      /* Merom.  */
196	      __cpu_model.__cpu_type = INTEL_CORE2;
197	      break;
198	    default:
199	      break;
200	    }
201	  break;
202	default:
203	  /* We have no idea.  */
204	  break;
205	}
206    }
207}
208
209/* ECX and EDX are output of CPUID at level one.  MAX_CPUID_LEVEL is
210   the max possible level of CPUID insn.  */
211static void
212get_available_features (unsigned int ecx, unsigned int edx,
213			int max_cpuid_level)
214{
215  unsigned int features = 0;
216
217  if (edx & bit_CMOV)
218    features |= (1 << FEATURE_CMOV);
219  if (edx & bit_MMX)
220    features |= (1 << FEATURE_MMX);
221  if (edx & bit_SSE)
222    features |= (1 << FEATURE_SSE);
223  if (edx & bit_SSE2)
224    features |= (1 << FEATURE_SSE2);
225  if (ecx & bit_POPCNT)
226    features |= (1 << FEATURE_POPCNT);
227  if (ecx & bit_SSE3)
228    features |= (1 << FEATURE_SSE3);
229  if (ecx & bit_SSSE3)
230    features |= (1 << FEATURE_SSSE3);
231  if (ecx & bit_SSE4_1)
232    features |= (1 << FEATURE_SSE4_1);
233  if (ecx & bit_SSE4_2)
234    features |= (1 << FEATURE_SSE4_2);
235  if (ecx & bit_AVX)
236    features |= (1 << FEATURE_AVX);
237
238  /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */
239  if (max_cpuid_level >= 7)
240    {
241      unsigned int eax, ebx, ecx, edx;
242      __cpuid_count (7, 0, eax, ebx, ecx, edx);
243      if (ebx & bit_AVX2)
244	features |= (1 << FEATURE_AVX2);
245    }
246
247  __cpu_model.__cpu_features[0] = features;
248}
249
250/* A noinline function calling __get_cpuid. Having many calls to
251   cpuid in one function in 32-bit mode causes GCC to complain:
252   "can't find a register in class CLOBBERED_REGS".  This is
253   related to PR rtl-optimization 44174. */
254
255static int __attribute__ ((noinline))
256__get_cpuid_output (unsigned int __level,
257		    unsigned int *__eax, unsigned int *__ebx,
258		    unsigned int *__ecx, unsigned int *__edx)
259{
260  return __get_cpuid (__level, __eax, __ebx, __ecx, __edx);
261}
262
263
264/* A constructor function that is sets __cpu_model and __cpu_features with
265   the right values.  This needs to run only once.  This constructor is
266   given the highest priority and it should run before constructors without
267   the priority set.  However, it still runs after ifunc initializers and
268   needs to be called explicitly there.  */
269
270int __attribute__ ((constructor CONSTRUCTOR_PRIORITY))
271__cpu_indicator_init (void)
272{
273  unsigned int eax, ebx, ecx, edx;
274
275  int max_level = 5;
276  unsigned int vendor;
277  unsigned int model, family, brand_id;
278  unsigned int extended_model, extended_family;
279
280  /* This function needs to run just once.  */
281  if (__cpu_model.__cpu_vendor)
282    return 0;
283
284  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
285  if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
286    {
287      __cpu_model.__cpu_vendor = VENDOR_OTHER;
288      return -1;
289    }
290
291  vendor = ebx;
292  max_level = eax;
293
294  if (max_level < 1)
295    {
296      __cpu_model.__cpu_vendor = VENDOR_OTHER;
297      return -1;
298    }
299
300  if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
301    {
302      __cpu_model.__cpu_vendor = VENDOR_OTHER;
303      return -1;
304    }
305
306  model = (eax >> 4) & 0x0f;
307  family = (eax >> 8) & 0x0f;
308  brand_id = ebx & 0xff;
309  extended_model = (eax >> 12) & 0xf0;
310  extended_family = (eax >> 20) & 0xff;
311
312  if (vendor == SIG_INTEL)
313    {
314      /* Adjust model and family for Intel CPUS. */
315      if (family == 0x0f)
316	{
317	  family += extended_family;
318	  model += extended_model;
319	}
320      else if (family == 0x06)
321	model += extended_model;
322
323      /* Get CPU type.  */
324      get_intel_cpu (family, model, brand_id);
325      /* Find available features. */
326      get_available_features (ecx, edx, max_level);
327      __cpu_model.__cpu_vendor = VENDOR_INTEL;
328    }
329  else if (vendor == SIG_AMD)
330    {
331      /* Adjust model and family for AMD CPUS. */
332      if (family == 0x0f)
333	{
334	  family += extended_family;
335	  model += (extended_model << 4);
336	}
337
338      /* Get CPU type.  */
339      get_amd_cpu (family, model);
340      /* Find available features. */
341      get_available_features (ecx, edx, max_level);
342      __cpu_model.__cpu_vendor = VENDOR_AMD;
343    }
344  else
345    __cpu_model.__cpu_vendor = VENDOR_OTHER;
346
347  gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX);
348  gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX);
349  gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
350
351  return 0;
352}
353