| Index: libgcc/config/i386/i386-cpuinfo.c |
| =================================================================== |
| --- libgcc/config/i386/i386-cpuinfo.c (revision 0) |
| +++ libgcc/config/i386/i386-cpuinfo.c (revision 0) |
| @@ -0,0 +1,275 @@ |
| +/* Copyright (C) 2011 Free Software Foundation, Inc. |
| + * Contributed by Sriraman Tallam <tmsriram@google.com>. |
| + * |
| + * This file 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. |
| + * |
| + * This file 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. |
| + * |
| + * Under Section 7 of GPL version 3, you are granted additional |
| + * permissions described in the GCC Runtime Library Exception, version |
| + * 3.1, as published by the Free Software Foundation. |
| + * |
| + * You should have received a copy of the GNU General Public License and |
| + * a copy of the GCC Runtime Library Exception along with this program; |
| + * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| + * <http://www.gnu.org/licenses/>. |
| + * |
| + * |
| + * This code is adapted from gcc/config/i386/driver-i386.c. The CPUID |
| + * instruction is used to figure out the cpu type and supported features. |
| + * GCC runs __cpu_indicator_init from a constructor which sets the members |
| + * of __cpu_model and __cpu_features. |
| + */ |
| + |
| +#include <string.h> |
| + |
| +#ifdef __GNUC__ |
| +#include "cpuid.h" |
| + |
| +enum processor_type |
| +{ |
| + PROCESSOR_PENTIUM = 0, |
| + PROCESSOR_CORE2, |
| + PROCESSOR_COREI7_NEHALEM, |
| + PROCESSOR_COREI7_WESTMERE, |
| + PROCESSOR_COREI7_SANDYBRIDGE, |
| + PROCESSOR_INTEL_GENERIC, |
| + PROCESSOR_AMDFAM10_BARCELONA, |
| + PROCESSOR_AMDFAM10_SHANGHAI, |
| + PROCESSOR_AMDFAM10_ISTANBUL, |
| + PROCESSOR_AMDFAM10_GENERIC, |
| + PROCESSOR_AMD_GENERIC, |
| + PROCESSOR_GENERIC, |
| + PROCESSOR_max |
| +}; |
| + |
| +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; |
| +}; |
| + |
| +/* Flags exported. */ |
| + |
| +struct __processor_model |
| +{ |
| + unsigned int __cpu_is_amd : 1; |
| + unsigned int __cpu_is_intel : 1; |
| + unsigned int __cpu_is_corei7_nehalem : 1; |
| + unsigned int __cpu_is_corei7_westmere : 1; |
| + unsigned int __cpu_is_corei7_sandybridge : 1; |
| + unsigned int __cpu_is_amdfam10_barcelona : 1; |
| + unsigned int __cpu_is_amdfam10_shanghai : 1; |
| + unsigned int __cpu_is_amdfam10_istanbul : 1; |
| +}; |
| + |
| +enum processor_type __cpu_type = PROCESSOR_GENERIC; |
| +struct __processor_features __cpu_features; |
| +struct __processor_model __cpu_model; |
| + |
| +static void |
| +get_amd_cpu (unsigned int family, unsigned int model) |
| +{ |
| + switch (family) |
| + { |
| + case 0x10: |
| + switch (model) |
| + { |
| + case 0x2: |
| + __cpu_type = PROCESSOR_AMDFAM10_BARCELONA; |
| + __cpu_model.__cpu_is_amdfam10_barcelona = 1; |
| + break; |
| + case 0x4: |
| + __cpu_type = PROCESSOR_AMDFAM10_SHANGHAI; |
| + __cpu_model.__cpu_is_amdfam10_shanghai = 1; |
| + break; |
| + case 0x8: |
| + __cpu_type = PROCESSOR_AMDFAM10_ISTANBUL; |
| + __cpu_model.__cpu_is_amdfam10_istanbul = 1; |
| + break; |
| + default: |
| + __cpu_type = PROCESSOR_AMDFAM10_GENERIC; |
| + break; |
| + } |
| + break; |
| + default: |
| + __cpu_type = PROCESSOR_AMD_GENERIC; |
| + } |
| +} |
| + |
| +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: |
| + __cpu_type = PROCESSOR_PENTIUM; |
| + break; |
| + case 0x6: |
| + switch (model) |
| + { |
| + case 0x1a: |
| + case 0x1e: |
| + case 0x1f: |
| + case 0x2e: |
| + /* Nehalem. */ |
| + __cpu_type = PROCESSOR_COREI7_NEHALEM; |
| + __cpu_model.__cpu_is_corei7_nehalem = 1; |
| + break; |
| + case 0x25: |
| + case 0x2c: |
| + case 0x2f: |
| + /* Westmere. */ |
| + __cpu_type = PROCESSOR_COREI7_WESTMERE; |
| + __cpu_model.__cpu_is_corei7_westmere = 1; |
| + break; |
| + case 0x2a: |
| + /* Sandy Bridge. */ |
| + __cpu_type = PROCESSOR_COREI7_SANDYBRIDGE; |
| + __cpu_model.__cpu_is_corei7_sandybridge = 1; |
| + break; |
| + case 0x17: |
| + case 0x1d: |
| + /* Penryn. */ |
| + case 0x0f: |
| + /* Merom. */ |
| + __cpu_type = PROCESSOR_CORE2; |
| + break; |
| + default: |
| + __cpu_type = PROCESSOR_INTEL_GENERIC; |
| + break; |
| + } |
| + break; |
| + default: |
| + /* We have no idea. */ |
| + __cpu_type = PROCESSOR_INTEL_GENERIC; |
| + 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; |
| +} |
| + |
| +/* 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); |
| +} |
| + |
| +/* This function will be linked in to binaries that need to look up |
| + CPU information. */ |
| + |
| +void |
| +__cpu_indicator_init(void) |
| +{ |
| + unsigned int eax, ebx, ecx, edx; |
| + |
| + int max_level = 5; |
| + unsigned int vendor; |
| + unsigned int model, family, brand_id; |
| + |
| + memset (&__cpu_features, 0, sizeof (struct __processor_features)); |
| + memset (&__cpu_model, 0, sizeof (struct __processor_model)); |
| + |
| + /* Assume cpuid insn present. Run in level 0 to get vendor id. */ |
| + if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx)) |
| + return; |
| + |
| + vendor = ebx; |
| + max_level = eax; |
| + |
| + if (max_level < 1) |
| + return; |
| + |
| + if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx)) |
| + return; |
| + |
| + model = (eax >> 4) & 0x0f; |
| + family = (eax >> 8) & 0x0f; |
| + brand_id = ebx & 0xff; |
| + |
| + /* Adjust model and family for Intel CPUS. */ |
| + if (vendor == SIG_INTEL) |
| + { |
| + unsigned int extended_model, extended_family; |
| + |
| + extended_model = (eax >> 12) & 0xf0; |
| + extended_family = (eax >> 20) & 0xff; |
| + if (family == 0x0f) |
| + { |
| + family += extended_family; |
| + model += extended_model; |
| + } |
| + else if (family == 0x06) |
| + model += extended_model; |
| + } |
| + |
| + /* Find CPU model. */ |
| + |
| + if (vendor == SIG_AMD) |
| + { |
| + __cpu_model.__cpu_is_amd = 1; |
| + get_amd_cpu (family, model); |
| + } |
| + else if (vendor == SIG_INTEL) |
| + { |
| + __cpu_model.__cpu_is_intel = 1; |
| + get_intel_cpu (family, model, brand_id); |
| + } |
| + |
| + /* Find available features. */ |
| + get_available_features (ecx, edx); |
| +} |
| + |
| +#else |
| + |
| +void |
| +__cpu_indicator_init(void) |
| +{ |
| +} |
| + |
| +#endif /* __GNUC__ */ |