]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libgcc/config/i386/cpuinfo.c
Enable support for bfloat16 which will be in Future Cooper Lake.
[thirdparty/gcc.git] / libgcc / config / i386 / cpuinfo.c
index 40ed84cf6cbcb36e6f067c4ede5f7a9d3ff81be6..5659ec89546a3fecd0990c88ba00afe486719219 100644 (file)
@@ -1,5 +1,5 @@
 /* Get CPU type and Features for x86 processors.
-   Copyright (C) 2012-2015 Free Software Foundation, Inc.
+   Copyright (C) 2012-2019 Free Software Foundation, Inc.
    Contributed by Sriraman Tallam (tmsriram@google.com)
 
 This file is part of GCC.
@@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include "cpuid.h"
 #include "tsystem.h"
 #include "auto-target.h"
+#include "cpuinfo.h"
 
 #ifdef HAVE_INIT_PRIORITY
 #define CONSTRUCTOR_PRIORITY (101)
@@ -36,92 +37,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 int __cpu_indicator_init (void)
   __attribute__ ((constructor CONSTRUCTOR_PRIORITY));
 
-/* Processor Vendor and Models. */
 
-enum processor_vendor
-{
-  VENDOR_INTEL = 1,
-  VENDOR_AMD,
-  VENDOR_OTHER,
-  VENDOR_MAX
-};
-
-/* Any new types or subtypes have to be inserted at the end. */
-
-enum processor_types
-{
-  INTEL_BONNELL = 1,
-  INTEL_CORE2,
-  INTEL_COREI7,
-  AMDFAM10H,
-  AMDFAM15H,
-  INTEL_SILVERMONT,
-  INTEL_KNL,
-  AMD_BTVER1,
-  AMD_BTVER2,  
-  CPU_TYPE_MAX
-};
-
-enum processor_subtypes
-{
-  INTEL_COREI7_NEHALEM = 1,
-  INTEL_COREI7_WESTMERE,
-  INTEL_COREI7_SANDYBRIDGE,
-  AMDFAM10H_BARCELONA,
-  AMDFAM10H_SHANGHAI,
-  AMDFAM10H_ISTANBUL,
-  AMDFAM15H_BDVER1,
-  AMDFAM15H_BDVER2,
-  AMDFAM15H_BDVER3,
-  AMDFAM15H_BDVER4,
-  INTEL_COREI7_IVYBRIDGE,
-  INTEL_COREI7_HASWELL,
-  INTEL_COREI7_BROADWELL,
-  INTEL_COREI7_SKYLAKE,
-  CPU_SUBTYPE_MAX
-};
-
-/* ISA Features supported. New features have to be inserted at the end.  */
-
-enum processor_features
-{
-  FEATURE_CMOV = 0,
-  FEATURE_MMX,
-  FEATURE_POPCNT,
-  FEATURE_SSE,
-  FEATURE_SSE2,
-  FEATURE_SSE3,
-  FEATURE_SSSE3,
-  FEATURE_SSE4_1,
-  FEATURE_SSE4_2,
-  FEATURE_AVX,
-  FEATURE_AVX2,
-  FEATURE_SSE4_A,
-  FEATURE_FMA4,
-  FEATURE_XOP,
-  FEATURE_FMA,
-  FEATURE_AVX512F,
-  FEATURE_BMI,
-  FEATURE_BMI2,
-  FEATURE_AES,
-  FEATURE_PCLMUL,
-  FEATURE_AVX512VL,
-  FEATURE_AVX512BW,
-  FEATURE_AVX512DQ,
-  FEATURE_AVX512CD,
-  FEATURE_AVX512ER,
-  FEATURE_AVX512PF,
-  FEATURE_AVX512VBMI,
-  FEATURE_AVX512IFMA
-};
-
-struct __processor_model
-{
-  unsigned int __cpu_vendor;
-  unsigned int __cpu_type;
-  unsigned int __cpu_subtype;
-  unsigned int __cpu_features[1];
-} __cpu_model = { };
+struct __processor_model __cpu_model = { };
+#ifndef SHARED
+/* We want to move away from __cpu_model in libgcc_s.so.1 and the
+   size of __cpu_model is part of ABI.  So, new features that don't
+   fit into __cpu_model.__cpu_features[0] go into extra variables
+   in libgcc.a only, preferrably hidden.  */
+unsigned int __cpu_features2;
+#endif
 
 
 /* Get the specific type of AMD CPU.  */
@@ -159,20 +83,34 @@ get_amd_cpu (unsigned int family, unsigned int model)
     /* AMD Family 15h "Bulldozer".  */
     case 0x15:
       __cpu_model.__cpu_type = AMDFAM15H;
+
+      if (model == 0x2)
+       __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;      
       /* Bulldozer version 1.  */
-      if ( model <= 0xf)
+      else if (model <= 0xf)
        __cpu_model.__cpu_subtype = AMDFAM15H_BDVER1;
       /* Bulldozer version 2 "Piledriver" */
-      if (model >= 0x10 && model <= 0x2f)
+      else if (model <= 0x2f)
        __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2;      
       /* Bulldozer version 3 "Steamroller"  */
-      if (model >= 0x30 && model <= 0x4f)
+      else if (model <= 0x4f)
        __cpu_model.__cpu_subtype = AMDFAM15H_BDVER3;
+      /* Bulldozer version 4 "Excavator"   */
+      else if (model <= 0x7f)
+       __cpu_model.__cpu_subtype = AMDFAM15H_BDVER4;
       break;
     /* AMD Family 16h "btver2" */
     case 0x16:
       __cpu_model.__cpu_type = AMD_BTVER2;
       break;
+    case 0x17:
+      __cpu_model.__cpu_type = AMDFAM17H;
+      /* AMD family 17h version 1.  */
+      if (model <= 0x1f)
+       __cpu_model.__cpu_subtype = AMDFAM17H_ZNVER1;
+      if (model >= 0x30)
+        __cpu_model.__cpu_subtype = AMDFAM17H_ZNVER2;
+      break;
     default:
       break;
     }
@@ -207,10 +145,23 @@ get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
              /* Silvermont.  */
              __cpu_model.__cpu_type = INTEL_SILVERMONT;
              break;
+           case 0x5c:
+           case 0x5f:
+             /* Goldmont.  */
+             __cpu_model.__cpu_type = INTEL_GOLDMONT;
+             break;
+           case 0x7a:
+             /* Goldmont Plus.  */
+             __cpu_model.__cpu_type = INTEL_GOLDMONT_PLUS;
+             break;
            case 0x57:
              /* Knights Landing.  */
              __cpu_model.__cpu_type = INTEL_KNL;
              break;
+           case 0x85:
+             /* Knights Mill. */
+             __cpu_model.__cpu_type = INTEL_KNM;
+             break;
            case 0x1a:
            case 0x1e:
            case 0x1f:
@@ -257,9 +208,30 @@ get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
            case 0x4e:
            case 0x5e:
              /* Skylake.  */
+           case 0x8e:
+           case 0x9e:
+             /* Kaby Lake.  */
              __cpu_model.__cpu_type = INTEL_COREI7;
              __cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE;
              break;
+           case 0x55:
+             {
+               unsigned int eax, ebx, ecx, edx;
+               __cpu_model.__cpu_type = INTEL_COREI7;
+               __cpuid_count (7, 0, eax, ebx, ecx, edx);
+               if (ecx & bit_AVX512VNNI)
+                 /* Cascade Lake.  */
+                 __cpu_model.__cpu_subtype = INTEL_COREI7_CASCADELAKE;
+               else
+                 /* Skylake with AVX-512 support.  */
+                 __cpu_model.__cpu_subtype = INTEL_COREI7_SKYLAKE_AVX512;
+             }
+             break;
+           case 0x66:
+             /* Cannon Lake.  */
+             __cpu_model.__cpu_type = INTEL_COREI7;
+             __cpu_model.__cpu_subtype = INTEL_COREI7_CANNONLAKE;
+             break;
            case 0x17:
            case 0x1d:
              /* Penryn.  */
@@ -284,100 +256,168 @@ static void
 get_available_features (unsigned int ecx, unsigned int edx,
                        int max_cpuid_level)
 {
+  unsigned int eax, ebx;
+  unsigned int ext_level;
+
   unsigned int features = 0;
+  unsigned int features2 = 0;
+
+  /* Get XCR_XFEATURE_ENABLED_MASK register with xgetbv.  */
+#define XCR_XFEATURE_ENABLED_MASK      0x0
+#define XSTATE_FP                      0x1
+#define XSTATE_SSE                     0x2
+#define XSTATE_YMM                     0x4
+#define XSTATE_OPMASK                  0x20
+#define XSTATE_ZMM                     0x40
+#define XSTATE_HI_ZMM                  0x80
+
+#define XCR_AVX_ENABLED_MASK \
+  (XSTATE_SSE | XSTATE_YMM)
+#define XCR_AVX512F_ENABLED_MASK \
+  (XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM)
+
+  /* Check if AVX and AVX512 are usable.  */
+  int avx_usable = 0;
+  int avx512_usable = 0;
+  if ((ecx & bit_OSXSAVE))
+    {
+      /* Check if XMM, YMM, OPMASK, upper 256 bits of ZMM0-ZMM15 and
+         ZMM16-ZMM31 states are supported by OSXSAVE.  */
+      unsigned int xcrlow;
+      unsigned int xcrhigh;
+      asm (".byte 0x0f, 0x01, 0xd0"
+          : "=a" (xcrlow), "=d" (xcrhigh)
+          : "c" (XCR_XFEATURE_ENABLED_MASK));
+      if ((xcrlow & XCR_AVX_ENABLED_MASK) == XCR_AVX_ENABLED_MASK)
+       {
+         avx_usable = 1;
+         avx512_usable = ((xcrlow & XCR_AVX512F_ENABLED_MASK)
+                          == XCR_AVX512F_ENABLED_MASK);
+       }
+    }
+
+#define set_feature(f) \
+  do                                           \
+    {                                          \
+      if (f < 32)                              \
+       features |= (1U << (f & 31));           \
+      else                                     \
+       features2 |= (1U << ((f - 32) & 31));   \
+    }                                          \
+  while (0)
 
   if (edx & bit_CMOV)
-    features |= (1 << FEATURE_CMOV);
+    set_feature (FEATURE_CMOV);
   if (edx & bit_MMX)
-    features |= (1 << FEATURE_MMX);
+    set_feature (FEATURE_MMX);
   if (edx & bit_SSE)
-    features |= (1 << FEATURE_SSE);
+    set_feature (FEATURE_SSE);
   if (edx & bit_SSE2)
-    features |= (1 << FEATURE_SSE2);
+    set_feature (FEATURE_SSE2);
   if (ecx & bit_POPCNT)
-    features |= (1 << FEATURE_POPCNT);
+    set_feature (FEATURE_POPCNT);
   if (ecx & bit_AES)
-    features |= (1 << FEATURE_AES);
+    set_feature (FEATURE_AES);
   if (ecx & bit_PCLMUL)
-    features |= (1 << FEATURE_PCLMUL);
+    set_feature (FEATURE_PCLMUL);
   if (ecx & bit_SSE3)
-    features |= (1 << FEATURE_SSE3);
+    set_feature (FEATURE_SSE3);
   if (ecx & bit_SSSE3)
-    features |= (1 << FEATURE_SSSE3);
+    set_feature (FEATURE_SSSE3);
   if (ecx & bit_SSE4_1)
-    features |= (1 << FEATURE_SSE4_1);
+    set_feature (FEATURE_SSE4_1);
   if (ecx & bit_SSE4_2)
-    features |= (1 << FEATURE_SSE4_2);
-  if (ecx & bit_AVX)
-    features |= (1 << FEATURE_AVX);
-  if (ecx & bit_FMA)
-    features |= (1 << FEATURE_FMA);
+    set_feature (FEATURE_SSE4_2);
+  if (avx_usable)
+    {
+      if (ecx & bit_AVX)
+       set_feature (FEATURE_AVX);
+      if (ecx & bit_FMA)
+       set_feature (FEATURE_FMA);
+    }
 
-  /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */
+  /* Get Advanced Features at level 7 (eax = 7, ecx = 0/1). */
   if (max_cpuid_level >= 7)
     {
-      unsigned int eax, ebx, ecx, edx;
       __cpuid_count (7, 0, eax, ebx, ecx, edx);
       if (ebx & bit_BMI)
-        features |= (1 << FEATURE_BMI);
-      if (ebx & bit_AVX2)
-       features |= (1 << FEATURE_AVX2);
+       set_feature (FEATURE_BMI);
+      if (avx_usable)
+       {
+         if (ebx & bit_AVX2)
+           set_feature (FEATURE_AVX2);
+       }
       if (ebx & bit_BMI2)
-        features |= (1 << FEATURE_BMI2);
-      if (ebx & bit_AVX512F)
-       features |= (1 << FEATURE_AVX512F);
-      if (ebx & bit_AVX512VL)
-       features |= (1 << FEATURE_AVX512VL);
-      if (ebx & bit_AVX512BW)
-       features |= (1 << FEATURE_AVX512BW);
-      if (ebx & bit_AVX512DQ)
-       features |= (1 << FEATURE_AVX512DQ);
-      if (ebx & bit_AVX512CD)
-       features |= (1 << FEATURE_AVX512CD);
-      if (ebx & bit_AVX512PF)
-       features |= (1 << FEATURE_AVX512PF);
-      if (ebx & bit_AVX512ER)
-       features |= (1 << FEATURE_AVX512ER);
-      if (ebx & bit_AVX512IFMA)
-       features |= (1 << FEATURE_AVX512IFMA);
-      if (ecx & bit_AVX512VBMI)
-       features |= (1 << FEATURE_AVX512VBMI);
+       set_feature (FEATURE_BMI2);
+      if (avx512_usable)
+       {
+         if (ebx & bit_AVX512F)
+           set_feature (FEATURE_AVX512F);
+         if (ebx & bit_AVX512VL)
+           set_feature (FEATURE_AVX512VL);
+         if (ebx & bit_AVX512BW)
+           set_feature (FEATURE_AVX512BW);
+         if (ebx & bit_AVX512DQ)
+           set_feature (FEATURE_AVX512DQ);
+         if (ebx & bit_AVX512CD)
+           set_feature (FEATURE_AVX512CD);
+         if (ebx & bit_AVX512PF)
+           set_feature (FEATURE_AVX512PF);
+         if (ebx & bit_AVX512ER)
+           set_feature (FEATURE_AVX512ER);
+         if (ebx & bit_AVX512IFMA)
+           set_feature (FEATURE_AVX512IFMA);
+         if (ecx & bit_AVX512VBMI)
+           set_feature (FEATURE_AVX512VBMI);
+         if (ecx & bit_AVX512VBMI2)
+           set_feature (FEATURE_AVX512VBMI2);
+         if (ecx & bit_GFNI)
+           set_feature (FEATURE_GFNI);
+         if (ecx & bit_VPCLMULQDQ)
+           set_feature (FEATURE_VPCLMULQDQ);
+         if (ecx & bit_AVX512VNNI)
+           set_feature (FEATURE_AVX512VNNI);
+         if (ecx & bit_AVX512BITALG)
+           set_feature (FEATURE_AVX512BITALG);
+         if (ecx & bit_AVX512VPOPCNTDQ)
+           set_feature (FEATURE_AVX512VPOPCNTDQ);
+         if (edx & bit_AVX5124VNNIW)
+           set_feature (FEATURE_AVX5124VNNIW);
+         if (edx & bit_AVX5124FMAPS)
+           set_feature (FEATURE_AVX5124FMAPS);
+
+         __cpuid_count (7, 1, eax, ebx, ecx, edx);
+         if (eax & bit_AVX512BF16)
+           set_feature (FEATURE_AVX512BF16);
+       }
     }
 
-  unsigned int ext_level;
-  unsigned int eax, ebx;
   /* Check cpuid level of extended features.  */
   __cpuid (0x80000000, ext_level, ebx, ecx, edx);
 
-  if (ext_level > 0x80000000)
+  if (ext_level >= 0x80000001)
     {
       __cpuid (0x80000001, eax, ebx, ecx, edx);
 
       if (ecx & bit_SSE4a)
-       features |= (1 << FEATURE_SSE4_A);
-      if (ecx & bit_FMA4)
-       features |= (1 << FEATURE_FMA4);
-      if (ecx & bit_XOP)
-       features |= (1 << FEATURE_XOP);
+       set_feature (FEATURE_SSE4_A);
+      if (avx_usable)
+       {
+         if (ecx & bit_FMA4)
+           set_feature (FEATURE_FMA4);
+         if (ecx & bit_XOP)
+           set_feature (FEATURE_XOP);
+       }
     }
     
   __cpu_model.__cpu_features[0] = features;
+#ifndef SHARED
+  __cpu_features2 = features2;
+#else
+  (void) features2;
+#endif
 }
 
-/* A noinline function calling __get_cpuid. Having many calls to
-   cpuid in one function in 32-bit mode causes GCC to complain:
-   "can't find a register in class CLOBBERED_REGS".  This is
-   related to PR rtl-optimization 44174. */
-
-static int __attribute__ ((noinline))
-__get_cpuid_output (unsigned int __level,
-                   unsigned int *__eax, unsigned int *__ebx,
-                   unsigned int *__ecx, unsigned int *__edx)
-{
-  return __get_cpuid (__level, __eax, __ebx, __ecx, __edx);
-}
-
-
 /* A constructor function that is sets __cpu_model and __cpu_features with
    the right values.  This needs to run only once.  This constructor is
    given the highest priority and it should run before constructors without
@@ -389,7 +429,7 @@ __cpu_indicator_init (void)
 {
   unsigned int eax, ebx, ecx, edx;
 
-  int max_level = 5;
+  int max_level;
   unsigned int vendor;
   unsigned int model, family, brand_id;
   unsigned int extended_model, extended_family;
@@ -399,7 +439,7 @@ __cpu_indicator_init (void)
     return 0;
 
   /* Assume cpuid insn present. Run in level 0 to get vendor id. */
-  if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
+  if (!__get_cpuid (0, &eax, &ebx, &ecx, &edx))
     {
       __cpu_model.__cpu_vendor = VENDOR_OTHER;
       return -1;
@@ -414,7 +454,7 @@ __cpu_indicator_init (void)
       return -1;
     }
 
-  if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
+  if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
     {
       __cpu_model.__cpu_vendor = VENDOR_OTHER;
       return -1;
@@ -449,7 +489,7 @@ __cpu_indicator_init (void)
       if (family == 0x0f)
        {
          family += extended_family;
-         model += (extended_model << 4);
+         model += extended_model;
        }
 
       /* Get CPU type.  */