xref: /dflybsd-src/contrib/gcc-8.0/libgcc/config/i386/cpuinfo.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* Get CPU type and Features for x86 processors.
238fd1498Szrj    Copyright (C) 2012-2018 Free Software Foundation, Inc.
338fd1498Szrj    Contributed by Sriraman Tallam (tmsriram@google.com)
438fd1498Szrj 
538fd1498Szrj This file is part of GCC.
638fd1498Szrj 
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj 
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj 
1738fd1498Szrj Under Section 7 of GPL version 3, you are granted additional
1838fd1498Szrj permissions described in the GCC Runtime Library Exception, version
1938fd1498Szrj 3.1, as published by the Free Software Foundation.
2038fd1498Szrj 
2138fd1498Szrj You should have received a copy of the GNU General Public License and
2238fd1498Szrj a copy of the GCC Runtime Library Exception along with this program;
2338fd1498Szrj see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2438fd1498Szrj <http://www.gnu.org/licenses/>.  */
2538fd1498Szrj 
2638fd1498Szrj #include "cpuid.h"
2738fd1498Szrj #include "tsystem.h"
2838fd1498Szrj #include "auto-target.h"
2938fd1498Szrj #include "cpuinfo.h"
3038fd1498Szrj 
3138fd1498Szrj #ifdef HAVE_INIT_PRIORITY
3238fd1498Szrj #define CONSTRUCTOR_PRIORITY (101)
3338fd1498Szrj #else
3438fd1498Szrj #define CONSTRUCTOR_PRIORITY
3538fd1498Szrj #endif
3638fd1498Szrj 
3738fd1498Szrj int __cpu_indicator_init (void)
3838fd1498Szrj   __attribute__ ((constructor CONSTRUCTOR_PRIORITY));
3938fd1498Szrj 
4038fd1498Szrj 
4138fd1498Szrj struct __processor_model __cpu_model = { };
4238fd1498Szrj #ifndef SHARED
4338fd1498Szrj /* We want to move away from __cpu_model in libgcc_s.so.1 and the
4438fd1498Szrj    size of __cpu_model is part of ABI.  So, new features that don't
4538fd1498Szrj    fit into __cpu_model.__cpu_features[0] go into extra variables
4638fd1498Szrj    in libgcc.a only, preferrably hidden.  */
4738fd1498Szrj unsigned int __cpu_features2;
4838fd1498Szrj #endif
4938fd1498Szrj 
5038fd1498Szrj 
5138fd1498Szrj /* Get the specific type of AMD CPU.  */
5238fd1498Szrj 
5338fd1498Szrj static void
get_amd_cpu(unsigned int family,unsigned int model)5438fd1498Szrj get_amd_cpu (unsigned int family, unsigned int model)
5538fd1498Szrj {
5638fd1498Szrj   switch (family)
5738fd1498Szrj     {
5838fd1498Szrj     /* AMD Family 10h.  */
5938fd1498Szrj     case 0x10:
6038fd1498Szrj       __cpu_model.__cpu_type = AMDFAM10H;
6138fd1498Szrj       switch (model)
6238fd1498Szrj 	{
6338fd1498Szrj 	case 0x2:
6438fd1498Szrj 	  /* Barcelona.  */
6538fd1498Szrj 	  __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA;
6638fd1498Szrj 	  break;
6738fd1498Szrj 	case 0x4:
6838fd1498Szrj 	  /* Shanghai.  */
6938fd1498Szrj 	  __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI;
7038fd1498Szrj 	  break;
7138fd1498Szrj 	case 0x8:
7238fd1498Szrj 	  /* Istanbul.  */
7338fd1498Szrj 	  __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL;
7438fd1498Szrj 	  break;
7538fd1498Szrj 	default:
7638fd1498Szrj 	  break;
7738fd1498Szrj 	}
7838fd1498Szrj       break;
7938fd1498Szrj     /* AMD Family 14h "btver1". */
8038fd1498Szrj     case 0x14:
8138fd1498Szrj       __cpu_model.__cpu_type = AMD_BTVER1;
8238fd1498Szrj       break;
8338fd1498Szrj     /* AMD Family 15h "Bulldozer".  */
8438fd1498Szrj     case 0x15:
8538fd1498Szrj       __cpu_model.__cpu_type = AMDFAM15H;
86*58e805e6Szrj 
87*58e805e6Szrj       if (model == 0x2)
88*58e805e6Szrj 	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
8938fd1498Szrj       /* Bulldozer version 1.  */
90*58e805e6Szrj       else if (model <= 0xf)
9138fd1498Szrj 	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER1;
9238fd1498Szrj       /* Bulldozer version 2 "Piledriver" */
93*58e805e6Szrj       else if (model <= 0x2f)
9438fd1498Szrj 	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;
9538fd1498Szrj       /* Bulldozer version 3 "Steamroller"  */
96*58e805e6Szrj       else if (model <= 0x4f)
9738fd1498Szrj 	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER3;
9838fd1498Szrj       /* Bulldozer version 4 "Excavator"   */
99*58e805e6Szrj       else if (model <= 0x7f)
10038fd1498Szrj 	__cpu_model.__cpu_subtype = AMDFAM15H_BDVER4;
10138fd1498Szrj       break;
10238fd1498Szrj     /* AMD Family 16h "btver2" */
10338fd1498Szrj     case 0x16:
10438fd1498Szrj       __cpu_model.__cpu_type = AMD_BTVER2;
10538fd1498Szrj       break;
10638fd1498Szrj     case 0x17:
10738fd1498Szrj       __cpu_model.__cpu_type = AMDFAM17H;
10838fd1498Szrj       /* AMD family 17h version 1.  */
10938fd1498Szrj       if (model <= 0x1f)
11038fd1498Szrj 	__cpu_model.__cpu_subtype = AMDFAM17H_ZNVER1;
11138fd1498Szrj       break;
11238fd1498Szrj     default:
11338fd1498Szrj       break;
11438fd1498Szrj     }
11538fd1498Szrj }
11638fd1498Szrj 
11738fd1498Szrj /* Get the specific type of Intel CPU.  */
11838fd1498Szrj 
11938fd1498Szrj static void
get_intel_cpu(unsigned int family,unsigned int model,unsigned int brand_id)12038fd1498Szrj get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
12138fd1498Szrj {
12238fd1498Szrj   /* Parse family and model only if brand ID is 0. */
12338fd1498Szrj   if (brand_id == 0)
12438fd1498Szrj     {
12538fd1498Szrj       switch (family)
12638fd1498Szrj 	{
12738fd1498Szrj 	case 0x5:
12838fd1498Szrj 	  /* Pentium.  */
12938fd1498Szrj 	  break;
13038fd1498Szrj 	case 0x6:
13138fd1498Szrj 	  switch (model)
13238fd1498Szrj 	    {
13338fd1498Szrj 	    case 0x1c:
13438fd1498Szrj 	    case 0x26:
13538fd1498Szrj 	      /* Bonnell.  */
13638fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_BONNELL;
13738fd1498Szrj 	      break;
13838fd1498Szrj 	    case 0x37:
13938fd1498Szrj 	    case 0x4a:
14038fd1498Szrj 	    case 0x4d:
14138fd1498Szrj 	    case 0x5a:
14238fd1498Szrj 	    case 0x5d:
14338fd1498Szrj 	      /* Silvermont.  */
14438fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_SILVERMONT;
14538fd1498Szrj 	      break;
14638fd1498Szrj 	    case 0x57:
14738fd1498Szrj 	      /* Knights Landing.  */
14838fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_KNL;
14938fd1498Szrj 	      break;
15038fd1498Szrj 	    case 0x85:
15138fd1498Szrj 	      /* Knights Mill. */
15238fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_KNM;
15338fd1498Szrj 	      break;
15438fd1498Szrj 	    case 0x1a:
15538fd1498Szrj 	    case 0x1e:
15638fd1498Szrj 	    case 0x1f:
15738fd1498Szrj 	    case 0x2e:
15838fd1498Szrj 	      /* Nehalem.  */
15938fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
16038fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM;
16138fd1498Szrj 	      break;
16238fd1498Szrj 	    case 0x25:
16338fd1498Szrj 	    case 0x2c:
16438fd1498Szrj 	    case 0x2f:
16538fd1498Szrj 	      /* Westmere.  */
16638fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
16738fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE;
16838fd1498Szrj 	      break;
16938fd1498Szrj 	    case 0x2a:
17038fd1498Szrj 	    case 0x2d:
17138fd1498Szrj 	      /* Sandy Bridge.  */
17238fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
17338fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE;
17438fd1498Szrj 	      break;
17538fd1498Szrj 	    case 0x3a:
17638fd1498Szrj 	    case 0x3e:
17738fd1498Szrj 	      /* Ivy Bridge.  */
17838fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
17938fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_IVYBRIDGE;
18038fd1498Szrj 	      break;
18138fd1498Szrj 	    case 0x3c:
18238fd1498Szrj 	    case 0x3f:
18338fd1498Szrj 	    case 0x45:
18438fd1498Szrj 	    case 0x46:
18538fd1498Szrj 	      /* Haswell.  */
18638fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
18738fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_HASWELL;
18838fd1498Szrj 	      break;
18938fd1498Szrj 	    case 0x3d:
19038fd1498Szrj 	    case 0x47:
19138fd1498Szrj 	    case 0x4f:
19238fd1498Szrj 	    case 0x56:
19338fd1498Szrj 	      /* Broadwell.  */
19438fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
19538fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_BROADWELL;
19638fd1498Szrj 	      break;
19738fd1498Szrj 	    case 0x4e:
19838fd1498Szrj 	    case 0x5e:
19938fd1498Szrj 	      /* Skylake.  */
20038fd1498Szrj 	    case 0x8e:
20138fd1498Szrj 	    case 0x9e:
20238fd1498Szrj 	      /* Kaby Lake.  */
20338fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
20438fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE;
20538fd1498Szrj 	      break;
20638fd1498Szrj 	    case 0x55:
20738fd1498Szrj 	      /* Skylake with AVX-512 support.  */
20838fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
20938fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE_AVX512;
21038fd1498Szrj 	      break;
21138fd1498Szrj 	    case 0x66:
21238fd1498Szrj 	      /* Cannon Lake.  */
21338fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_COREI7;
21438fd1498Szrj 	      __cpu_model.__cpu_subtype = INTEL_COREI7_CANNONLAKE;
21538fd1498Szrj 	      break;
21638fd1498Szrj 	    case 0x17:
21738fd1498Szrj 	    case 0x1d:
21838fd1498Szrj 	      /* Penryn.  */
21938fd1498Szrj 	    case 0x0f:
22038fd1498Szrj 	      /* Merom.  */
22138fd1498Szrj 	      __cpu_model.__cpu_type = INTEL_CORE2;
22238fd1498Szrj 	      break;
22338fd1498Szrj 	    default:
22438fd1498Szrj 	      break;
22538fd1498Szrj 	    }
22638fd1498Szrj 	  break;
22738fd1498Szrj 	default:
22838fd1498Szrj 	  /* We have no idea.  */
22938fd1498Szrj 	  break;
23038fd1498Szrj 	}
23138fd1498Szrj     }
23238fd1498Szrj }
23338fd1498Szrj 
23438fd1498Szrj /* ECX and EDX are output of CPUID at level one.  MAX_CPUID_LEVEL is
23538fd1498Szrj    the max possible level of CPUID insn.  */
23638fd1498Szrj static void
get_available_features(unsigned int ecx,unsigned int edx,int max_cpuid_level)23738fd1498Szrj get_available_features (unsigned int ecx, unsigned int edx,
23838fd1498Szrj 			int max_cpuid_level)
23938fd1498Szrj {
24038fd1498Szrj   unsigned int eax, ebx;
24138fd1498Szrj   unsigned int ext_level;
24238fd1498Szrj 
24338fd1498Szrj   unsigned int features = 0;
24438fd1498Szrj   unsigned int features2 = 0;
24538fd1498Szrj 
24638fd1498Szrj   /* Get XCR_XFEATURE_ENABLED_MASK register with xgetbv.  */
24738fd1498Szrj #define XCR_XFEATURE_ENABLED_MASK	0x0
24838fd1498Szrj #define XSTATE_FP			0x1
24938fd1498Szrj #define XSTATE_SSE			0x2
25038fd1498Szrj #define XSTATE_YMM			0x4
25138fd1498Szrj #define XSTATE_OPMASK			0x20
25238fd1498Szrj #define XSTATE_ZMM			0x40
25338fd1498Szrj #define XSTATE_HI_ZMM			0x80
25438fd1498Szrj 
25538fd1498Szrj #define XCR_AVX_ENABLED_MASK \
25638fd1498Szrj   (XSTATE_SSE | XSTATE_YMM)
25738fd1498Szrj #define XCR_AVX512F_ENABLED_MASK \
25838fd1498Szrj   (XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM)
25938fd1498Szrj 
26038fd1498Szrj   /* Check if AVX and AVX512 are usable.  */
26138fd1498Szrj   int avx_usable = 0;
26238fd1498Szrj   int avx512_usable = 0;
26338fd1498Szrj   if ((ecx & bit_OSXSAVE))
26438fd1498Szrj     {
26538fd1498Szrj       /* Check if XMM, YMM, OPMASK, upper 256 bits of ZMM0-ZMM15 and
26638fd1498Szrj          ZMM16-ZMM31 states are supported by OSXSAVE.  */
26738fd1498Szrj       unsigned int xcrlow;
26838fd1498Szrj       unsigned int xcrhigh;
26938fd1498Szrj       asm (".byte 0x0f, 0x01, 0xd0"
27038fd1498Szrj 	   : "=a" (xcrlow), "=d" (xcrhigh)
27138fd1498Szrj 	   : "c" (XCR_XFEATURE_ENABLED_MASK));
27238fd1498Szrj       if ((xcrlow & XCR_AVX_ENABLED_MASK) == XCR_AVX_ENABLED_MASK)
27338fd1498Szrj 	{
27438fd1498Szrj 	  avx_usable = 1;
27538fd1498Szrj 	  avx512_usable = ((xcrlow & XCR_AVX512F_ENABLED_MASK)
27638fd1498Szrj 			   == XCR_AVX512F_ENABLED_MASK);
27738fd1498Szrj 	}
27838fd1498Szrj     }
27938fd1498Szrj 
28038fd1498Szrj #define set_feature(f) \
28138fd1498Szrj   do						\
28238fd1498Szrj     {						\
28338fd1498Szrj       if (f < 32)				\
28438fd1498Szrj 	features |= (1U << (f & 31));		\
28538fd1498Szrj       else					\
28638fd1498Szrj 	features2 |= (1U << ((f - 32) & 31));	\
28738fd1498Szrj     }						\
28838fd1498Szrj   while (0)
28938fd1498Szrj 
29038fd1498Szrj   if (edx & bit_CMOV)
29138fd1498Szrj     set_feature (FEATURE_CMOV);
29238fd1498Szrj   if (edx & bit_MMX)
29338fd1498Szrj     set_feature (FEATURE_MMX);
29438fd1498Szrj   if (edx & bit_SSE)
29538fd1498Szrj     set_feature (FEATURE_SSE);
29638fd1498Szrj   if (edx & bit_SSE2)
29738fd1498Szrj     set_feature (FEATURE_SSE2);
29838fd1498Szrj   if (ecx & bit_POPCNT)
29938fd1498Szrj     set_feature (FEATURE_POPCNT);
30038fd1498Szrj   if (ecx & bit_AES)
30138fd1498Szrj     set_feature (FEATURE_AES);
30238fd1498Szrj   if (ecx & bit_PCLMUL)
30338fd1498Szrj     set_feature (FEATURE_PCLMUL);
30438fd1498Szrj   if (ecx & bit_SSE3)
30538fd1498Szrj     set_feature (FEATURE_SSE3);
30638fd1498Szrj   if (ecx & bit_SSSE3)
30738fd1498Szrj     set_feature (FEATURE_SSSE3);
30838fd1498Szrj   if (ecx & bit_SSE4_1)
30938fd1498Szrj     set_feature (FEATURE_SSE4_1);
31038fd1498Szrj   if (ecx & bit_SSE4_2)
31138fd1498Szrj     set_feature (FEATURE_SSE4_2);
31238fd1498Szrj   if (avx_usable)
31338fd1498Szrj     {
31438fd1498Szrj       if (ecx & bit_AVX)
31538fd1498Szrj 	set_feature (FEATURE_AVX);
31638fd1498Szrj       if (ecx & bit_FMA)
31738fd1498Szrj 	set_feature (FEATURE_FMA);
31838fd1498Szrj     }
31938fd1498Szrj 
32038fd1498Szrj   /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */
32138fd1498Szrj   if (max_cpuid_level >= 7)
32238fd1498Szrj     {
32338fd1498Szrj       __cpuid_count (7, 0, eax, ebx, ecx, edx);
32438fd1498Szrj       if (ebx & bit_BMI)
32538fd1498Szrj 	set_feature (FEATURE_BMI);
32638fd1498Szrj       if (avx_usable)
32738fd1498Szrj 	{
32838fd1498Szrj 	  if (ebx & bit_AVX2)
32938fd1498Szrj 	    set_feature (FEATURE_AVX2);
33038fd1498Szrj 	}
33138fd1498Szrj       if (ebx & bit_BMI2)
33238fd1498Szrj 	set_feature (FEATURE_BMI2);
33338fd1498Szrj       if (avx512_usable)
33438fd1498Szrj 	{
33538fd1498Szrj 	  if (ebx & bit_AVX512F)
33638fd1498Szrj 	    set_feature (FEATURE_AVX512F);
33738fd1498Szrj 	  if (ebx & bit_AVX512VL)
33838fd1498Szrj 	    set_feature (FEATURE_AVX512VL);
33938fd1498Szrj 	  if (ebx & bit_AVX512BW)
34038fd1498Szrj 	    set_feature (FEATURE_AVX512BW);
34138fd1498Szrj 	  if (ebx & bit_AVX512DQ)
34238fd1498Szrj 	    set_feature (FEATURE_AVX512DQ);
34338fd1498Szrj 	  if (ebx & bit_AVX512CD)
34438fd1498Szrj 	    set_feature (FEATURE_AVX512CD);
34538fd1498Szrj 	  if (ebx & bit_AVX512PF)
34638fd1498Szrj 	    set_feature (FEATURE_AVX512PF);
34738fd1498Szrj 	  if (ebx & bit_AVX512ER)
34838fd1498Szrj 	    set_feature (FEATURE_AVX512ER);
34938fd1498Szrj 	  if (ebx & bit_AVX512IFMA)
35038fd1498Szrj 	    set_feature (FEATURE_AVX512IFMA);
35138fd1498Szrj 	  if (ecx & bit_AVX512VBMI)
35238fd1498Szrj 	    set_feature (FEATURE_AVX512VBMI);
35338fd1498Szrj 	  if (ecx & bit_AVX512VBMI2)
35438fd1498Szrj 	    set_feature (FEATURE_AVX512VBMI2);
35538fd1498Szrj 	  if (ecx & bit_GFNI)
35638fd1498Szrj 	    set_feature (FEATURE_GFNI);
35738fd1498Szrj 	  if (ecx & bit_VPCLMULQDQ)
35838fd1498Szrj 	    set_feature (FEATURE_VPCLMULQDQ);
35938fd1498Szrj 	  if (ecx & bit_AVX512VNNI)
36038fd1498Szrj 	    set_feature (FEATURE_AVX512VNNI);
36138fd1498Szrj 	  if (ecx & bit_AVX512BITALG)
36238fd1498Szrj 	    set_feature (FEATURE_AVX512BITALG);
36338fd1498Szrj 	  if (ecx & bit_AVX512VPOPCNTDQ)
36438fd1498Szrj 	    set_feature (FEATURE_AVX512VPOPCNTDQ);
36538fd1498Szrj 	  if (edx & bit_AVX5124VNNIW)
36638fd1498Szrj 	    set_feature (FEATURE_AVX5124VNNIW);
36738fd1498Szrj 	  if (edx & bit_AVX5124FMAPS)
36838fd1498Szrj 	    set_feature (FEATURE_AVX5124FMAPS);
36938fd1498Szrj 	}
37038fd1498Szrj     }
37138fd1498Szrj 
37238fd1498Szrj   /* Check cpuid level of extended features.  */
37338fd1498Szrj   __cpuid (0x80000000, ext_level, ebx, ecx, edx);
37438fd1498Szrj 
37538fd1498Szrj   if (ext_level >= 0x80000001)
37638fd1498Szrj     {
37738fd1498Szrj       __cpuid (0x80000001, eax, ebx, ecx, edx);
37838fd1498Szrj 
37938fd1498Szrj       if (ecx & bit_SSE4a)
38038fd1498Szrj 	set_feature (FEATURE_SSE4_A);
38138fd1498Szrj       if (avx_usable)
38238fd1498Szrj 	{
38338fd1498Szrj 	  if (ecx & bit_FMA4)
38438fd1498Szrj 	    set_feature (FEATURE_FMA4);
38538fd1498Szrj 	  if (ecx & bit_XOP)
38638fd1498Szrj 	    set_feature (FEATURE_XOP);
38738fd1498Szrj 	}
38838fd1498Szrj     }
38938fd1498Szrj 
39038fd1498Szrj   __cpu_model.__cpu_features[0] = features;
39138fd1498Szrj #ifndef SHARED
39238fd1498Szrj   __cpu_features2 = features2;
39338fd1498Szrj #else
39438fd1498Szrj   (void) features2;
39538fd1498Szrj #endif
39638fd1498Szrj }
39738fd1498Szrj 
39838fd1498Szrj /* A constructor function that is sets __cpu_model and __cpu_features with
39938fd1498Szrj    the right values.  This needs to run only once.  This constructor is
40038fd1498Szrj    given the highest priority and it should run before constructors without
40138fd1498Szrj    the priority set.  However, it still runs after ifunc initializers and
40238fd1498Szrj    needs to be called explicitly there.  */
40338fd1498Szrj 
40438fd1498Szrj int __attribute__ ((constructor CONSTRUCTOR_PRIORITY))
__cpu_indicator_init(void)40538fd1498Szrj __cpu_indicator_init (void)
40638fd1498Szrj {
40738fd1498Szrj   unsigned int eax, ebx, ecx, edx;
40838fd1498Szrj 
40938fd1498Szrj   int max_level;
41038fd1498Szrj   unsigned int vendor;
41138fd1498Szrj   unsigned int model, family, brand_id;
41238fd1498Szrj   unsigned int extended_model, extended_family;
41338fd1498Szrj 
41438fd1498Szrj   /* This function needs to run just once.  */
41538fd1498Szrj   if (__cpu_model.__cpu_vendor)
41638fd1498Szrj     return 0;
41738fd1498Szrj 
41838fd1498Szrj   /* Assume cpuid insn present. Run in level 0 to get vendor id. */
41938fd1498Szrj   if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
42038fd1498Szrj     {
42138fd1498Szrj       __cpu_model.__cpu_vendor = VENDOR_OTHER;
42238fd1498Szrj       return -1;
42338fd1498Szrj     }
42438fd1498Szrj 
42538fd1498Szrj   vendor = ebx;
42638fd1498Szrj   max_level = eax;
42738fd1498Szrj 
42838fd1498Szrj   if (max_level < 1)
42938fd1498Szrj     {
43038fd1498Szrj       __cpu_model.__cpu_vendor = VENDOR_OTHER;
43138fd1498Szrj       return -1;
43238fd1498Szrj     }
43338fd1498Szrj 
43438fd1498Szrj   if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
43538fd1498Szrj     {
43638fd1498Szrj       __cpu_model.__cpu_vendor = VENDOR_OTHER;
43738fd1498Szrj       return -1;
43838fd1498Szrj     }
43938fd1498Szrj 
44038fd1498Szrj   model = (eax >> 4) & 0x0f;
44138fd1498Szrj   family = (eax >> 8) & 0x0f;
44238fd1498Szrj   brand_id = ebx & 0xff;
44338fd1498Szrj   extended_model = (eax >> 12) & 0xf0;
44438fd1498Szrj   extended_family = (eax >> 20) & 0xff;
44538fd1498Szrj 
44638fd1498Szrj   if (vendor == signature_INTEL_ebx)
44738fd1498Szrj     {
44838fd1498Szrj       /* Adjust model and family for Intel CPUS. */
44938fd1498Szrj       if (family == 0x0f)
45038fd1498Szrj 	{
45138fd1498Szrj 	  family += extended_family;
45238fd1498Szrj 	  model += extended_model;
45338fd1498Szrj 	}
45438fd1498Szrj       else if (family == 0x06)
45538fd1498Szrj 	model += extended_model;
45638fd1498Szrj 
45738fd1498Szrj       /* Get CPU type.  */
45838fd1498Szrj       get_intel_cpu (family, model, brand_id);
45938fd1498Szrj       /* Find available features. */
46038fd1498Szrj       get_available_features (ecx, edx, max_level);
46138fd1498Szrj       __cpu_model.__cpu_vendor = VENDOR_INTEL;
46238fd1498Szrj     }
46338fd1498Szrj   else if (vendor == signature_AMD_ebx)
46438fd1498Szrj     {
46538fd1498Szrj       /* Adjust model and family for AMD CPUS. */
46638fd1498Szrj       if (family == 0x0f)
46738fd1498Szrj 	{
46838fd1498Szrj 	  family += extended_family;
46938fd1498Szrj 	  model += extended_model;
47038fd1498Szrj 	}
47138fd1498Szrj 
47238fd1498Szrj       /* Get CPU type.  */
47338fd1498Szrj       get_amd_cpu (family, model);
47438fd1498Szrj       /* Find available features. */
47538fd1498Szrj       get_available_features (ecx, edx, max_level);
47638fd1498Szrj       __cpu_model.__cpu_vendor = VENDOR_AMD;
47738fd1498Szrj     }
47838fd1498Szrj   else
47938fd1498Szrj     __cpu_model.__cpu_vendor = VENDOR_OTHER;
48038fd1498Szrj 
48138fd1498Szrj   gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX);
48238fd1498Szrj   gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX);
48338fd1498Szrj   gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
48438fd1498Szrj 
48538fd1498Szrj   return 0;
48638fd1498Szrj }
48738fd1498Szrj 
48838fd1498Szrj #if defined SHARED && defined USE_ELF_SYMVER
48938fd1498Szrj __asm__ (".symver __cpu_indicator_init, __cpu_indicator_init@GCC_4.8.0");
49038fd1498Szrj __asm__ (".symver __cpu_model, __cpu_model@GCC_4.8.0");
49138fd1498Szrj #endif
492