xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/config/i386/cpuinfo.c (revision fc4f42693f9b1c31f39f9cf50af1bf2010325808)
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 
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 /* Processor Vendor and Models. */
40 
41 enum 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 
51 enum 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 
64 enum 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 
84 enum 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 
106 struct __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 
117 static void
118 get_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 
174 static void
175 get_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.  */
263 static void
264 get_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 
332 static 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 
347 int __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