xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/config/i386/cpuinfo.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
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 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20 
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see 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 
36 int __cpu_indicator_init (void)
37   __attribute__ ((constructor CONSTRUCTOR_PRIORITY));
38 
39 enum vendor_signatures
40 {
41   SIG_INTEL =	0x756e6547 /* Genu */,
42   SIG_AMD =	0x68747541 /* Auth */
43 };
44 
45 /* Processor Vendor and Models. */
46 
47 enum processor_vendor
48 {
49   VENDOR_INTEL = 1,
50   VENDOR_AMD,
51   VENDOR_OTHER,
52   VENDOR_MAX
53 };
54 
55 enum processor_types
56 {
57   INTEL_ATOM = 1,
58   INTEL_CORE2,
59   INTEL_COREI7,
60   AMDFAM10H,
61   AMDFAM15H,
62   CPU_TYPE_MAX
63 };
64 
65 enum 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 
80 enum 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 
95 struct __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 
106 static void
107 get_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 
151 static void
152 get_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.  */
211 static void
212 get_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 
255 static 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 
270 int __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