aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.6/libgcc/config/i386/i386-cpuinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.6/libgcc/config/i386/i386-cpuinfo.c')
-rw-r--r--gcc-4.6/libgcc/config/i386/i386-cpuinfo.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/gcc-4.6/libgcc/config/i386/i386-cpuinfo.c b/gcc-4.6/libgcc/config/i386/i386-cpuinfo.c
new file mode 100644
index 0000000..362bfc4
--- /dev/null
+++ b/gcc-4.6/libgcc/config/i386/i386-cpuinfo.c
@@ -0,0 +1,307 @@
+/* Get CPU type and Features for x86 processors.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+ Contributed by Sriraman Tallam (tmsriram@google.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "cpuid.h"
+#include "tsystem.h"
+
+int __cpu_indicator_init (void) __attribute__ ((constructor));
+
+enum vendor_signatures
+{
+ SIG_INTEL = 0x756e6547 /* Genu */,
+ SIG_AMD = 0x68747541 /* Auth */
+};
+
+
+/* Features supported. */
+
+struct __processor_features
+{
+ unsigned int __cpu_cmov : 1;
+ unsigned int __cpu_mmx : 1;
+ unsigned int __cpu_popcnt : 1;
+ unsigned int __cpu_sse : 1;
+ unsigned int __cpu_sse2 : 1;
+ unsigned int __cpu_sse3 : 1;
+ unsigned int __cpu_ssse3 : 1;
+ unsigned int __cpu_sse4_1 : 1;
+ unsigned int __cpu_sse4_2 : 1;
+} __cpu_features;
+
+/* Processor Model. */
+
+struct __processor_model
+{
+ /* Vendor. */
+ unsigned int __cpu_is_amd : 1;
+ unsigned int __cpu_is_intel : 1;
+ /* CPU type. */
+ unsigned int __cpu_is_intel_atom : 1;
+ unsigned int __cpu_is_intel_core2 : 1;
+ unsigned int __cpu_is_intel_corei7 : 1;
+ unsigned int __cpu_is_intel_corei7_nehalem : 1;
+ unsigned int __cpu_is_intel_corei7_westmere : 1;
+ unsigned int __cpu_is_intel_corei7_sandybridge : 1;
+ unsigned int __cpu_is_amdfam10h : 1;
+ unsigned int __cpu_is_amdfam10h_barcelona : 1;
+ unsigned int __cpu_is_amdfam10h_shanghai : 1;
+ unsigned int __cpu_is_amdfam10h_istanbul : 1;
+ unsigned int __cpu_is_amdfam15h_bdver1 : 1;
+ unsigned int __cpu_is_amdfam15h_bdver2 : 1;
+} __cpu_model;
+
+/* Get the specific type of AMD CPU. */
+
+static void
+get_amd_cpu (unsigned int family, unsigned int model)
+{
+ switch (family)
+ {
+ /* AMD Family 10h. */
+ case 0x10:
+ switch (model)
+ {
+ case 0x2:
+ /* Barcelona. */
+ __cpu_model.__cpu_is_amdfam10h = 1;
+ __cpu_model.__cpu_is_amdfam10h_barcelona = 1;
+ break;
+ case 0x4:
+ /* Shanghai. */
+ __cpu_model.__cpu_is_amdfam10h = 1;
+ __cpu_model.__cpu_is_amdfam10h_shanghai = 1;
+ break;
+ case 0x8:
+ /* Istanbul. */
+ __cpu_model.__cpu_is_amdfam10h = 1;
+ __cpu_model.__cpu_is_amdfam10h_istanbul = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ /* AMD Family 15h. */
+ case 0x15:
+ /* Bulldozer version 1. */
+ if (model >= 0 && model <= 0xf)
+ __cpu_model.__cpu_is_amdfam15h_bdver1 = 1;
+ /* Bulldozer version 2. */
+ if (model >= 0x10 && model <= 0x1f)
+ __cpu_model.__cpu_is_amdfam15h_bdver2 = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+/* Get the specific type of Intel CPU. */
+
+static void
+get_intel_cpu (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. */
+ __cpu_model.__cpu_is_intel_atom = 1;
+ break;
+ case 0x1a:
+ case 0x1e:
+ case 0x1f:
+ case 0x2e:
+ /* Nehalem. */
+ __cpu_model.__cpu_is_intel_corei7 = 1;
+ __cpu_model.__cpu_is_intel_corei7_nehalem = 1;
+ break;
+ case 0x25:
+ case 0x2c:
+ case 0x2f:
+ /* Westmere. */
+ __cpu_model.__cpu_is_intel_corei7 = 1;
+ __cpu_model.__cpu_is_intel_corei7_westmere = 1;
+ break;
+ case 0x2a:
+ /* Sandy Bridge. */
+ __cpu_model.__cpu_is_intel_corei7 = 1;
+ __cpu_model.__cpu_is_intel_corei7_sandybridge = 1;
+ break;
+ case 0x17:
+ case 0x1d:
+ /* Penryn. */
+ case 0x0f:
+ /* Merom. */
+ __cpu_model.__cpu_is_intel_core2 = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ /* We have no idea. */
+ break;
+ }
+ }
+}
+
+static void
+get_available_features (unsigned int ecx, unsigned int edx)
+{
+ __cpu_features.__cpu_cmov = (edx & bit_CMOV) ? 1 : 0;
+ __cpu_features.__cpu_mmx = (edx & bit_MMX) ? 1 : 0;
+ __cpu_features.__cpu_sse = (edx & bit_SSE) ? 1 : 0;
+ __cpu_features.__cpu_sse2 = (edx & bit_SSE2) ? 1 : 0;
+ __cpu_features.__cpu_popcnt = (ecx & bit_POPCNT) ? 1 : 0;
+ __cpu_features.__cpu_sse3 = (ecx & bit_SSE3) ? 1 : 0;
+ __cpu_features.__cpu_ssse3 = (ecx & bit_SSSE3) ? 1 : 0;
+ __cpu_features.__cpu_sse4_1 = (ecx & bit_SSE4_1) ? 1 : 0;
+ __cpu_features.__cpu_sse4_2 = (ecx & bit_SSE4_2) ? 1 : 0;
+}
+
+
+/* Sanity check for the vendor and cpu type flags. */
+
+static int
+sanity_check (void)
+{
+ unsigned int one_type = 0;
+
+ /* Vendor cannot be Intel and AMD. */
+ gcc_assert((__cpu_model.__cpu_is_intel == 0)
+ || (__cpu_model.__cpu_is_amd == 0));
+
+ /* Only one CPU type can be set. */
+ one_type = (__cpu_model.__cpu_is_intel_atom
+ + __cpu_model.__cpu_is_intel_core2
+ + __cpu_model.__cpu_is_intel_corei7_nehalem
+ + __cpu_model.__cpu_is_intel_corei7_westmere
+ + __cpu_model.__cpu_is_intel_corei7_sandybridge
+ + __cpu_model.__cpu_is_amdfam10h_barcelona
+ + __cpu_model.__cpu_is_amdfam10h_shanghai
+ + __cpu_model.__cpu_is_amdfam10h_istanbul
+ + __cpu_model.__cpu_is_amdfam15h_bdver1
+ + __cpu_model.__cpu_is_amdfam15h_bdver2);
+
+ gcc_assert (one_type <= 1);
+ return 0;
+}
+
+/* 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.
+ If another constructor needs to use these values, explicitly call this
+ function from the other constructor. Otherwise, the ordering of
+ constructors could make this constructor run later. */
+
+int __attribute__ ((constructor))
+__cpu_indicator_init (void)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ int max_level = 5;
+ unsigned int vendor;
+ unsigned int model, family, brand_id;
+ unsigned int extended_model, extended_family;
+ static int called = 0;
+
+ /* This function needs to run just once. */
+ if (called)
+ return 0;
+ else
+ called = 1;
+
+ /* Assume cpuid insn present. Run in level 0 to get vendor id. */
+ if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx))
+ return -1;
+
+ vendor = ebx;
+ max_level = eax;
+
+ if (max_level < 1)
+ return -1;
+
+ if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx))
+ return -1;
+
+ 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)
+ {
+ /* Adjust model and family for Intel CPUS. */
+ if (family == 0x0f)
+ {
+ family += extended_family;
+ model += extended_model;
+ }
+ else if (family == 0x06)
+ model += extended_model;
+
+ /* Get CPU type. */
+ __cpu_model.__cpu_is_intel = 1;
+ get_intel_cpu (family, model, brand_id);
+ }
+
+ if (vendor == SIG_AMD)
+ {
+ /* Adjust model and family for AMD CPUS. */
+ if (family == 0x0f)
+ {
+ family += extended_family;
+ model += (extended_model << 4);
+ }
+
+ /* Get CPU type. */
+ __cpu_model.__cpu_is_amd = 1;
+ get_amd_cpu (family, model);
+ }
+
+ /* Find available features. */
+ get_available_features (ecx, edx);
+
+ sanity_check ();
+
+ return 0;
+}