Patchwork Support for Runtime CPU type detection via builtins (issue5754058)

login
register
mail settings
Submitter Sriraman Tallam
Date June 5, 2012, 10 p.m.
Message ID <CAAs8Hmz4vqAF7TBmew=m2jnrG4MyqkhhKq11nqzo6j2J_E6n8g@mail.gmail.com>
Download mbox | patch
Permalink /patch/163180/
State New
Headers show

Comments

Sriraman Tallam - June 5, 2012, 10 p.m.
Hi H.J.,

I am attaching a patch to add __cpu_indicator_init to the list of
symbols to be versioned and exported in libgcc_s.so. Also, updating
builtin_target.c test to explicitly do a CPUID and check if the
features are identified correctly like you had suggested earlier.

Patch ok?


	* config/i386/libgcc-bsd.ver: Version symbol __cpu_indicator_init.
	* config/i386/libgcc-sol2.ver: Ditto.
	* config/i386/libgcc-glibc.ver: Ditto.


	* gcc.target/i386/builtin_target.c (vendor_signatures): New enum.
	(check_intel_cpu_model): New function.
	(check_amd_cpu_model): New function.
	(check_features): New function.
	(__get_cpuid_output): New function.
	(check_detailed): New function.
	(fn1): Rename to quick_check.
	(main): Update to call quick_check and call check_detailed.

Thanks,
-Sri.

On Wed, Apr 25, 2012 at 5:52 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> Patch committed.
>
> Thanks,
> -Sri.
>
> On Wed, Apr 25, 2012 at 4:52 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Wed, Apr 25, 2012 at 4:38 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>>> Hi H.J,
>>>
>>>   Could you please review this patch for AVX2 check?
>>>
>>>        * config/i386/i386-cpuinfo.c (FEATURE_AVX2): New enum value.
>>>        (get_available_features): New argument. Check for AVX2.
>>>        (__cpu_indicator_init): Modify call to get_available_features
>>> .
>>>        * doc/extend.texi: Document avx2 support.
>>>        * testsuite/gcc.target/i386/builtin_target.c: Check avx2.
>>>        * config/i386/i386.c (fold_builtin_cpu): Add avx2.
>>>
>>
>> It looks good to me.
>>
>> Thanks.
>>
>> --
>> H.J.
H.J. Lu - June 6, 2012, 1:52 p.m.
On Tue, Jun 5, 2012 at 3:00 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> Hi H.J.,
>
> I am attaching a patch to add __cpu_indicator_init to the list of
> symbols to be versioned and exported in libgcc_s.so. Also, updating
> builtin_target.c test to explicitly do a CPUID and check if the
> features are identified correctly like you had suggested earlier.
>
> Patch ok?
>
>
>        * config/i386/libgcc-bsd.ver: Version symbol __cpu_indicator_init.
>        * config/i386/libgcc-sol2.ver: Ditto.
>        * config/i386/libgcc-glibc.ver: Ditto.
>
>
>        * gcc.target/i386/builtin_target.c (vendor_signatures): New enum.
>        (check_intel_cpu_model): New function.
>        (check_amd_cpu_model): New function.
>        (check_features): New function.
>        (__get_cpuid_output): New function.
>        (check_detailed): New function.
>        (fn1): Rename to quick_check.
>        (main): Update to call quick_check and call check_detailed.
>

It looks good.  The only problem is for C programs,  __cpu_model and
__cpu_indicator_init in libgcc_s.so aren't used at all.  I suggested
in

http://gcc.gnu.org/ml/gcc-patches/2012-05/msg01816.html

We can do one
of 3 things:

1. Abuse libgcc_eh.a by moving __cpu_model and __cpu_indicator_init
from libgcc.a to libgcc_eh.a.
2. Rename libgcc_eh.a to libgcc_static.a and move __cpu_model and
__cpu_indicator_init from libgcc.a to libgcc_static.a.
3. Add  libgcc_static.a and move __cpu_model and __cpu_indicator_ini
 from libgcc.a to libgcc_static.a.  We treat libgcc_static.a similar to
libgcc_eh.a.
Sriraman Tallam - June 12, 2012, 2:56 a.m.
On Wed, Jun 6, 2012 at 6:52 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Tue, Jun 5, 2012 at 3:00 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>> Hi H.J.,
>>
>> I am attaching a patch to add __cpu_indicator_init to the list of
>> symbols to be versioned and exported in libgcc_s.so. Also, updating
>> builtin_target.c test to explicitly do a CPUID and check if the
>> features are identified correctly like you had suggested earlier.
>>
>> Patch ok?
>>
>>
>>        * config/i386/libgcc-bsd.ver: Version symbol __cpu_indicator_init.
>>        * config/i386/libgcc-sol2.ver: Ditto.
>>        * config/i386/libgcc-glibc.ver: Ditto.
>>
>>
>>        * gcc.target/i386/builtin_target.c (vendor_signatures): New enum.
>>        (check_intel_cpu_model): New function.
>>        (check_amd_cpu_model): New function.
>>        (check_features): New function.
>>        (__get_cpuid_output): New function.
>>        (check_detailed): New function.
>>        (fn1): Rename to quick_check.
>>        (main): Update to call quick_check and call check_detailed.
>>
>
> It looks good.

I submitted this patch. I am working on fixing the problem mentioned
below about cpu indicator symbols from libgcc_s.so being used in C
programs.

Thanks,
-Sri.


The only problem is for C programs,  __cpu_model and
> __cpu_indicator_init in libgcc_s.so aren't used at all.  I suggested
> in
>
> http://gcc.gnu.org/ml/gcc-patches/2012-05/msg01816.html
>
> We can do one
> of 3 things:
>
> 1. Abuse libgcc_eh.a by moving __cpu_model and __cpu_indicator_init
> from libgcc.a to libgcc_eh.a.
> 2. Rename libgcc_eh.a to libgcc_static.a and move __cpu_model and
> __cpu_indicator_init from libgcc.a to libgcc_static.a.
> 3. Add  libgcc_static.a and move __cpu_model and __cpu_indicator_ini
>  from libgcc.a to libgcc_static.a.  We treat libgcc_static.a similar to
> libgcc_eh.a.
>
>
> --
> H.J.

Patch

Index: libgcc/config/i386/libgcc-bsd.ver
===================================================================
--- libgcc/config/i386/libgcc-bsd.ver	(revision 188246)
+++ libgcc/config/i386/libgcc-bsd.ver	(working copy)
@@ -109,4 +109,5 @@  GCC_4.6.0 {
 
 GCC_4.8.0 {
   __cpu_model
+  __cpu_indicator_init
 }
Index: libgcc/config/i386/libgcc-sol2.ver
===================================================================
--- libgcc/config/i386/libgcc-sol2.ver	(revision 188246)
+++ libgcc/config/i386/libgcc-sol2.ver	(working copy)
@@ -109,4 +109,5 @@  GCC_4.5.0 {
 
 GCC_4.8.0 {
   __cpu_model
+  __cpu_indicator_init
 }
Index: libgcc/config/i386/libgcc-glibc.ver
===================================================================
--- libgcc/config/i386/libgcc-glibc.ver	(revision 188246)
+++ libgcc/config/i386/libgcc-glibc.ver	(working copy)
@@ -150,6 +150,7 @@  GCC_4.3.0 {
 
 GCC_4.8.0 {
   __cpu_model
+  __cpu_indicator_init
 }
 %else
 GCC_4.4.0 {
@@ -190,5 +191,6 @@  GCC_4.5.0 {
 
 GCC_4.8.0 {
   __cpu_model
+  __cpu_indicator_init
 }
 %endif
Index: gcc/testsuite/gcc.target/i386/builtin_target.c
===================================================================
--- gcc/testsuite/gcc.target/i386/builtin_target.c	(revision 188246)
+++ gcc/testsuite/gcc.target/i386/builtin_target.c	(working copy)
@@ -1,13 +1,229 @@ 
 /* This test checks if the __builtin_cpu_is and __builtin_cpu_supports calls
-   are recognized. */
+   are recognized.  It also independently uses CPUID to get cpu type and
+   features supported and checks if the builtins correctly identify the
+   platform.  The code to do the identification is adapted from
+   libgcc/config/i386/cpuinfo.c.  */
 
 /* { dg-do run } */
 
 #include <assert.h>
+#include "cpuid.h"
 
-int
-fn1 ()
+enum vendor_signatures
 {
+  SIG_INTEL =	0x756e6547 /* Genu */,
+  SIG_AMD =	0x68747541 /* Auth */
+};
+
+/* Check if the Intel CPU model and sub-model are identified.  */
+static void
+check_intel_cpu_model (unsigned int family, unsigned int model,
+		       unsigned int brand_id)
+{
+  /* Parse family and model only if brand ID is 0. */
+  if (brand_id == 0)
+    {
+      switch (family)
+	{
+	case 0x5:
+	  /* Pentium.  */
+	  break;
+	case 0x6:
+	  switch (model)
+	    {
+	    case 0x1c:
+	    case 0x26:
+	      /* Atom.  */
+	      assert (__builtin_cpu_is ("atom"));
+	      break;
+	    case 0x1a:
+	    case 0x1e:
+	    case 0x1f:
+	    case 0x2e:
+	      /* Nehalem.  */
+	      assert (__builtin_cpu_is ("corei7"));
+	      assert (__builtin_cpu_is ("nehalem"));
+	      break;
+	    case 0x25:
+	    case 0x2c:
+	    case 0x2f:
+	      /* Westmere.  */
+	      assert (__builtin_cpu_is ("corei7"));
+	      assert (__builtin_cpu_is ("westmere"));
+	      break;
+	    case 0x2a:
+	      /* Sandy Bridge.  */
+	      assert (__builtin_cpu_is ("corei7"));
+	      assert (__builtin_cpu_is ("sandybridge"));
+	      break;
+	    case 0x17:
+	    case 0x1d:
+	      /* Penryn.  */
+	    case 0x0f:
+	      /* Merom.  */
+	      assert (__builtin_cpu_is ("core2"));
+	      break;
+	    default:
+	      break;
+	    }
+	  break;
+	default:
+	  /* We have no idea.  */
+	  break;
+	}
+    }
+}
+
+/* Check if the AMD CPU model and sub-model are identified.  */
+static void
+check_amd_cpu_model (unsigned int family, unsigned int model)
+{
+  switch (family)
+    {
+    /* AMD Family 10h.  */
+    case 0x10:
+      switch (model)
+	{
+	case 0x2:
+	  /* Barcelona.  */
+	  assert (__builtin_cpu_is ("amdfam10h"));
+	  assert (__builtin_cpu_is ("barcelona"));
+	  break;
+	case 0x4:
+	  /* Shanghai.  */
+	  assert (__builtin_cpu_is ("amdfam10h"));
+	  assert (__builtin_cpu_is ("shanghai"));
+	  break;
+	case 0x8:
+	  /* Istanbul.  */
+	  assert (__builtin_cpu_is ("amdfam10h"));
+	  assert (__builtin_cpu_is ("istanbul"));
+	  break;
+	default:
+	  break;
+	}
+      break;
+    /* AMD Family 15h.  */
+    case 0x15:
+      assert (__builtin_cpu_is ("amdfam15h"));
+      /* Bulldozer version 1.  */
+      if ( model <= 0xf)
+	assert (__builtin_cpu_is ("bdver1"));
+      /* Bulldozer version 2.  */
+      if (model >= 0x10 && model <= 0x1f)
+	assert (__builtin_cpu_is ("bdver2"));
+      break;
+    default:
+      break;
+    }
+}
+
+/* Check if the ISA features are identified.  */
+static void
+check_features (unsigned int ecx, unsigned int edx,
+		int max_cpuid_level)
+{
+  if (edx & bit_CMOV)
+    assert (__builtin_cpu_supports ("cmov"));
+  if (edx & bit_MMX)
+    assert (__builtin_cpu_supports ("mmx"));
+  if (edx & bit_SSE)
+    assert (__builtin_cpu_supports ("sse"));
+  if (edx & bit_SSE2)
+    assert (__builtin_cpu_supports ("sse2"));
+  if (ecx & bit_POPCNT)
+    assert (__builtin_cpu_supports ("popcnt"));
+  if (ecx & bit_SSE3)
+    assert (__builtin_cpu_supports ("sse3"));
+  if (ecx & bit_SSSE3)
+    assert (__builtin_cpu_supports ("ssse3"));
+  if (ecx & bit_SSE4_1)
+    assert (__builtin_cpu_supports ("sse4.1"));
+  if (ecx & bit_SSE4_2)
+    assert (__builtin_cpu_supports ("sse4.2"));
+  if (ecx & bit_AVX)
+    assert (__builtin_cpu_supports ("avx"));
+
+  /* Get advanced features at level 7 (eax = 7, ecx = 0).  */
+  if (max_cpuid_level >= 7)
+    {
+      unsigned int eax, ebx, ecx, edx;
+      __cpuid_count (7, 0, eax, ebx, ecx, edx);
+      if (ebx & bit_AVX2)
+	assert (__builtin_cpu_supports ("avx2"));
+    }
+}
+
+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);
+}
+
+static int
+check_detailed ()
+{
+  unsigned int eax, ebx, ecx, edx;
+
+  int max_level; 
+  unsigned int vendor;
+  unsigned int model, family, brand_id;
+  unsigned int extended_model, extended_family;
+
+  /* Assume cpuid insn present. Run in level 0 to get vendor id. */
+  if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  vendor = ebx;
+  max_level = eax;
+
+  if (max_level < 1)
+    return 0;
+
+  if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
+    return 0;
+
+  model = (eax >> 4) & 0x0f;
+  family = (eax >> 8) & 0x0f;
+  brand_id = ebx & 0xff;
+  extended_model = (eax >> 12) & 0xf0;
+  extended_family = (eax >> 20) & 0xff;
+
+  if (vendor == SIG_INTEL)
+    {
+      assert (__builtin_cpu_is ("intel"));
+      /* Adjust family and model for Intel CPUs.  */
+      if (family == 0x0f)
+	{
+	  family += extended_family;
+	  model += extended_model;
+	}
+      else if (family == 0x06)
+	model += extended_model;
+      check_intel_cpu_model (family, model, brand_id);
+      check_features (ecx, edx, max_level);
+    }
+  else if (vendor == SIG_AMD)
+    {
+      assert (__builtin_cpu_is ("amd"));
+      /* Adjust model and family for AMD CPUS. */
+      if (family == 0x0f)
+	{
+	  family += extended_family;
+	  model += (extended_model << 4);
+	}
+      check_amd_cpu_model (family, model);
+      check_features (ecx, edx, max_level);
+    }
+
+  return 0;
+}
+
+static int
+quick_check ()
+{
   /* Check CPU Features.  */
   assert (__builtin_cpu_supports ("cmov") >= 0);
 
@@ -68,5 +284,7 @@ 
 int main ()
 {
   __builtin_cpu_init ();
-  return fn1 ();
+  quick_check ();
+  check_detailed ();
+  return 0;
 }