cpuinfo.c revision 1.1.1.1
1/* Get CPU type and Features for x86 processors. 2 Copyright (C) 2012-2013 Free Software Foundation, Inc. 3 Contributed by Sriraman Tallam (tmsriram@google.com) 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 3, or (at your option) any later 10version. 11 12GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17Under Section 7 of GPL version 3, you are granted additional 18permissions described in the GCC Runtime Library Exception, version 193.1, as published by the Free Software Foundation. 20 21You should have received a copy of the GNU General Public License and 22a copy of the GCC Runtime Library Exception along with this program; 23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24<http://www.gnu.org/licenses/>. */ 25 26#include "cpuid.h" 27#include "tsystem.h" 28#include "auto-target.h" 29 30#ifdef HAVE_INIT_PRIORITY 31#define CONSTRUCTOR_PRIORITY (101) 32#else 33#define CONSTRUCTOR_PRIORITY 34#endif 35 36int __cpu_indicator_init (void) 37 __attribute__ ((constructor CONSTRUCTOR_PRIORITY)); 38 39enum vendor_signatures 40{ 41 SIG_INTEL = 0x756e6547 /* Genu */, 42 SIG_AMD = 0x68747541 /* Auth */ 43}; 44 45/* Processor Vendor and Models. */ 46 47enum processor_vendor 48{ 49 VENDOR_INTEL = 1, 50 VENDOR_AMD, 51 VENDOR_OTHER, 52 VENDOR_MAX 53}; 54 55enum processor_types 56{ 57 INTEL_ATOM = 1, 58 INTEL_CORE2, 59 INTEL_COREI7, 60 AMDFAM10H, 61 AMDFAM15H, 62 CPU_TYPE_MAX 63}; 64 65enum processor_subtypes 66{ 67 INTEL_COREI7_NEHALEM = 1, 68 INTEL_COREI7_WESTMERE, 69 INTEL_COREI7_SANDYBRIDGE, 70 AMDFAM10H_BARCELONA, 71 AMDFAM10H_SHANGHAI, 72 AMDFAM10H_ISTANBUL, 73 AMDFAM15H_BDVER1, 74 AMDFAM15H_BDVER2, 75 CPU_SUBTYPE_MAX 76}; 77 78/* ISA Features supported. */ 79 80enum processor_features 81{ 82 FEATURE_CMOV = 0, 83 FEATURE_MMX, 84 FEATURE_POPCNT, 85 FEATURE_SSE, 86 FEATURE_SSE2, 87 FEATURE_SSE3, 88 FEATURE_SSSE3, 89 FEATURE_SSE4_1, 90 FEATURE_SSE4_2, 91 FEATURE_AVX, 92 FEATURE_AVX2 93}; 94 95struct __processor_model 96{ 97 unsigned int __cpu_vendor; 98 unsigned int __cpu_type; 99 unsigned int __cpu_subtype; 100 unsigned int __cpu_features[1]; 101} __cpu_model; 102 103 104/* Get the specific type of AMD CPU. */ 105 106static void 107get_amd_cpu (unsigned int family, unsigned int model) 108{ 109 switch (family) 110 { 111 /* AMD Family 10h. */ 112 case 0x10: 113 switch (model) 114 { 115 case 0x2: 116 /* Barcelona. */ 117 __cpu_model.__cpu_type = AMDFAM10H; 118 __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA; 119 break; 120 case 0x4: 121 /* Shanghai. */ 122 __cpu_model.__cpu_type = AMDFAM10H; 123 __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI; 124 break; 125 case 0x8: 126 /* Istanbul. */ 127 __cpu_model.__cpu_type = AMDFAM10H; 128 __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL; 129 break; 130 default: 131 break; 132 } 133 break; 134 /* AMD Family 15h. */ 135 case 0x15: 136 __cpu_model.__cpu_type = AMDFAM15H; 137 /* Bulldozer version 1. */ 138 if ( model <= 0xf) 139 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER1; 140 /* Bulldozer version 2. */ 141 if (model >= 0x10 && model <= 0x1f) 142 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2; 143 break; 144 default: 145 break; 146 } 147} 148 149/* Get the specific type of Intel CPU. */ 150 151static void 152get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id) 153{ 154 /* Parse family and model only if brand ID is 0. */ 155 if (brand_id == 0) 156 { 157 switch (family) 158 { 159 case 0x5: 160 /* Pentium. */ 161 break; 162 case 0x6: 163 switch (model) 164 { 165 case 0x1c: 166 case 0x26: 167 /* Atom. */ 168 __cpu_model.__cpu_type = INTEL_ATOM; 169 break; 170 case 0x1a: 171 case 0x1e: 172 case 0x1f: 173 case 0x2e: 174 /* Nehalem. */ 175 __cpu_model.__cpu_type = INTEL_COREI7; 176 __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM; 177 break; 178 case 0x25: 179 case 0x2c: 180 case 0x2f: 181 /* Westmere. */ 182 __cpu_model.__cpu_type = INTEL_COREI7; 183 __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE; 184 break; 185 case 0x2a: 186 case 0x2d: 187 /* Sandy Bridge. */ 188 __cpu_model.__cpu_type = INTEL_COREI7; 189 __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE; 190 break; 191 case 0x17: 192 case 0x1d: 193 /* Penryn. */ 194 case 0x0f: 195 /* Merom. */ 196 __cpu_model.__cpu_type = INTEL_CORE2; 197 break; 198 default: 199 break; 200 } 201 break; 202 default: 203 /* We have no idea. */ 204 break; 205 } 206 } 207} 208 209/* ECX and EDX are output of CPUID at level one. MAX_CPUID_LEVEL is 210 the max possible level of CPUID insn. */ 211static void 212get_available_features (unsigned int ecx, unsigned int edx, 213 int max_cpuid_level) 214{ 215 unsigned int features = 0; 216 217 if (edx & bit_CMOV) 218 features |= (1 << FEATURE_CMOV); 219 if (edx & bit_MMX) 220 features |= (1 << FEATURE_MMX); 221 if (edx & bit_SSE) 222 features |= (1 << FEATURE_SSE); 223 if (edx & bit_SSE2) 224 features |= (1 << FEATURE_SSE2); 225 if (ecx & bit_POPCNT) 226 features |= (1 << FEATURE_POPCNT); 227 if (ecx & bit_SSE3) 228 features |= (1 << FEATURE_SSE3); 229 if (ecx & bit_SSSE3) 230 features |= (1 << FEATURE_SSSE3); 231 if (ecx & bit_SSE4_1) 232 features |= (1 << FEATURE_SSE4_1); 233 if (ecx & bit_SSE4_2) 234 features |= (1 << FEATURE_SSE4_2); 235 if (ecx & bit_AVX) 236 features |= (1 << FEATURE_AVX); 237 238 /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */ 239 if (max_cpuid_level >= 7) 240 { 241 unsigned int eax, ebx, ecx, edx; 242 __cpuid_count (7, 0, eax, ebx, ecx, edx); 243 if (ebx & bit_AVX2) 244 features |= (1 << FEATURE_AVX2); 245 } 246 247 __cpu_model.__cpu_features[0] = features; 248} 249 250/* A noinline function calling __get_cpuid. Having many calls to 251 cpuid in one function in 32-bit mode causes GCC to complain: 252 "can't find a register in class CLOBBERED_REGS". This is 253 related to PR rtl-optimization 44174. */ 254 255static int __attribute__ ((noinline)) 256__get_cpuid_output (unsigned int __level, 257 unsigned int *__eax, unsigned int *__ebx, 258 unsigned int *__ecx, unsigned int *__edx) 259{ 260 return __get_cpuid (__level, __eax, __ebx, __ecx, __edx); 261} 262 263 264/* A constructor function that is sets __cpu_model and __cpu_features with 265 the right values. This needs to run only once. This constructor is 266 given the highest priority and it should run before constructors without 267 the priority set. However, it still runs after ifunc initializers and 268 needs to be called explicitly there. */ 269 270int __attribute__ ((constructor CONSTRUCTOR_PRIORITY)) 271__cpu_indicator_init (void) 272{ 273 unsigned int eax, ebx, ecx, edx; 274 275 int max_level = 5; 276 unsigned int vendor; 277 unsigned int model, family, brand_id; 278 unsigned int extended_model, extended_family; 279 280 /* This function needs to run just once. */ 281 if (__cpu_model.__cpu_vendor) 282 return 0; 283 284 /* Assume cpuid insn present. Run in level 0 to get vendor id. */ 285 if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx)) 286 { 287 __cpu_model.__cpu_vendor = VENDOR_OTHER; 288 return -1; 289 } 290 291 vendor = ebx; 292 max_level = eax; 293 294 if (max_level < 1) 295 { 296 __cpu_model.__cpu_vendor = VENDOR_OTHER; 297 return -1; 298 } 299 300 if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx)) 301 { 302 __cpu_model.__cpu_vendor = VENDOR_OTHER; 303 return -1; 304 } 305 306 model = (eax >> 4) & 0x0f; 307 family = (eax >> 8) & 0x0f; 308 brand_id = ebx & 0xff; 309 extended_model = (eax >> 12) & 0xf0; 310 extended_family = (eax >> 20) & 0xff; 311 312 if (vendor == SIG_INTEL) 313 { 314 /* Adjust model and family for Intel CPUS. */ 315 if (family == 0x0f) 316 { 317 family += extended_family; 318 model += extended_model; 319 } 320 else if (family == 0x06) 321 model += extended_model; 322 323 /* Get CPU type. */ 324 get_intel_cpu (family, model, brand_id); 325 /* Find available features. */ 326 get_available_features (ecx, edx, max_level); 327 __cpu_model.__cpu_vendor = VENDOR_INTEL; 328 } 329 else if (vendor == SIG_AMD) 330 { 331 /* Adjust model and family for AMD CPUS. */ 332 if (family == 0x0f) 333 { 334 family += extended_family; 335 model += (extended_model << 4); 336 } 337 338 /* Get CPU type. */ 339 get_amd_cpu (family, model); 340 /* Find available features. */ 341 get_available_features (ecx, edx, max_level); 342 __cpu_model.__cpu_vendor = VENDOR_AMD; 343 } 344 else 345 __cpu_model.__cpu_vendor = VENDOR_OTHER; 346 347 gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX); 348 gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX); 349 gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); 350 351 return 0; 352} 353