cpuinfo.c revision 1.1.1.2
1/* Get CPU type and Features for x86 processors. 2 Copyright (C) 2012-2015 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 39/* Processor Vendor and Models. */ 40 41enum processor_vendor 42{ 43 VENDOR_INTEL = 1, 44 VENDOR_AMD, 45 VENDOR_OTHER, 46 VENDOR_MAX 47}; 48 49/* Any new types or subtypes have to be inserted at the end. */ 50 51enum processor_types 52{ 53 INTEL_BONNELL = 1, 54 INTEL_CORE2, 55 INTEL_COREI7, 56 AMDFAM10H, 57 AMDFAM15H, 58 INTEL_SILVERMONT, 59 AMD_BTVER1, 60 AMD_BTVER2, 61 CPU_TYPE_MAX 62}; 63 64enum processor_subtypes 65{ 66 INTEL_COREI7_NEHALEM = 1, 67 INTEL_COREI7_WESTMERE, 68 INTEL_COREI7_SANDYBRIDGE, 69 AMDFAM10H_BARCELONA, 70 AMDFAM10H_SHANGHAI, 71 AMDFAM10H_ISTANBUL, 72 AMDFAM15H_BDVER1, 73 AMDFAM15H_BDVER2, 74 AMDFAM15H_BDVER3, 75 AMDFAM15H_BDVER4, 76 INTEL_COREI7_IVYBRIDGE, 77 INTEL_COREI7_HASWELL, 78 INTEL_COREI7_BROADWELL, 79 CPU_SUBTYPE_MAX 80}; 81 82/* ISA Features supported. */ 83 84enum processor_features 85{ 86 FEATURE_CMOV = 0, 87 FEATURE_MMX, 88 FEATURE_POPCNT, 89 FEATURE_SSE, 90 FEATURE_SSE2, 91 FEATURE_SSE3, 92 FEATURE_SSSE3, 93 FEATURE_SSE4_1, 94 FEATURE_SSE4_2, 95 FEATURE_AVX, 96 FEATURE_AVX2, 97 FEATURE_SSE4_A, 98 FEATURE_FMA4, 99 FEATURE_XOP, 100 FEATURE_FMA, 101 FEATURE_AVX512F, 102 FEATURE_BMI, 103 FEATURE_BMI2 104}; 105 106struct __processor_model 107{ 108 unsigned int __cpu_vendor; 109 unsigned int __cpu_type; 110 unsigned int __cpu_subtype; 111 unsigned int __cpu_features[1]; 112} __cpu_model; 113 114 115/* Get the specific type of AMD CPU. */ 116 117static void 118get_amd_cpu (unsigned int family, unsigned int model) 119{ 120 switch (family) 121 { 122 /* AMD Family 10h. */ 123 case 0x10: 124 __cpu_model.__cpu_type = AMDFAM10H; 125 switch (model) 126 { 127 case 0x2: 128 /* Barcelona. */ 129 __cpu_model.__cpu_subtype = AMDFAM10H_BARCELONA; 130 break; 131 case 0x4: 132 /* Shanghai. */ 133 __cpu_model.__cpu_subtype = AMDFAM10H_SHANGHAI; 134 break; 135 case 0x8: 136 /* Istanbul. */ 137 __cpu_model.__cpu_subtype = AMDFAM10H_ISTANBUL; 138 break; 139 default: 140 break; 141 } 142 break; 143 /* AMD Family 14h "btver1". */ 144 case 0x14: 145 __cpu_model.__cpu_type = AMD_BTVER1; 146 break; 147 /* AMD Family 15h "Bulldozer". */ 148 case 0x15: 149 __cpu_model.__cpu_type = AMDFAM15H; 150 /* Bulldozer version 1. */ 151 if ( model <= 0xf) 152 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER1; 153 /* Bulldozer version 2 "Piledriver" */ 154 if (model >= 0x10 && model <= 0x2f) 155 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER2; 156 /* Bulldozer version 3 "Steamroller" */ 157 if (model >= 0x30 && model <= 0x4f) 158 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER3; 159 /* Bulldozer version 4 "Excavator" */ 160 if (model >= 0x60 && model <= 0x7f) 161 __cpu_model.__cpu_subtype = AMDFAM15H_BDVER4; 162 break; 163 /* AMD Family 16h "btver2" */ 164 case 0x16: 165 __cpu_model.__cpu_type = AMD_BTVER2; 166 break; 167 default: 168 break; 169 } 170} 171 172/* Get the specific type of Intel CPU. */ 173 174static void 175get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id) 176{ 177 /* Parse family and model only if brand ID is 0. */ 178 if (brand_id == 0) 179 { 180 switch (family) 181 { 182 case 0x5: 183 /* Pentium. */ 184 break; 185 case 0x6: 186 switch (model) 187 { 188 case 0x1c: 189 case 0x26: 190 /* Bonnell. */ 191 __cpu_model.__cpu_type = INTEL_BONNELL; 192 break; 193 case 0x37: 194 case 0x4a: 195 case 0x4d: 196 case 0x5a: 197 case 0x5d: 198 /* Silvermont. */ 199 __cpu_model.__cpu_type = INTEL_SILVERMONT; 200 break; 201 case 0x1a: 202 case 0x1e: 203 case 0x1f: 204 case 0x2e: 205 /* Nehalem. */ 206 __cpu_model.__cpu_type = INTEL_COREI7; 207 __cpu_model.__cpu_subtype = INTEL_COREI7_NEHALEM; 208 break; 209 case 0x25: 210 case 0x2c: 211 case 0x2f: 212 /* Westmere. */ 213 __cpu_model.__cpu_type = INTEL_COREI7; 214 __cpu_model.__cpu_subtype = INTEL_COREI7_WESTMERE; 215 break; 216 case 0x2a: 217 case 0x2d: 218 /* Sandy Bridge. */ 219 __cpu_model.__cpu_type = INTEL_COREI7; 220 __cpu_model.__cpu_subtype = INTEL_COREI7_SANDYBRIDGE; 221 break; 222 case 0x3a: 223 case 0x3e: 224 /* Ivy Bridge. */ 225 __cpu_model.__cpu_type = INTEL_COREI7; 226 __cpu_model.__cpu_subtype = INTEL_COREI7_IVYBRIDGE; 227 break; 228 case 0x3c: 229 case 0x3f: 230 case 0x45: 231 case 0x46: 232 /* Haswell. */ 233 __cpu_model.__cpu_type = INTEL_COREI7; 234 __cpu_model.__cpu_subtype = INTEL_COREI7_HASWELL; 235 break; 236 case 0x3d: 237 case 0x4f: 238 case 0x56: 239 /* Broadwell. */ 240 __cpu_model.__cpu_type = INTEL_COREI7; 241 __cpu_model.__cpu_subtype = INTEL_COREI7_BROADWELL; 242 break; 243 case 0x17: 244 case 0x1d: 245 /* Penryn. */ 246 case 0x0f: 247 /* Merom. */ 248 __cpu_model.__cpu_type = INTEL_CORE2; 249 break; 250 default: 251 break; 252 } 253 break; 254 default: 255 /* We have no idea. */ 256 break; 257 } 258 } 259} 260 261/* ECX and EDX are output of CPUID at level one. MAX_CPUID_LEVEL is 262 the max possible level of CPUID insn. */ 263static void 264get_available_features (unsigned int ecx, unsigned int edx, 265 int max_cpuid_level) 266{ 267 unsigned int features = 0; 268 269 if (edx & bit_CMOV) 270 features |= (1 << FEATURE_CMOV); 271 if (edx & bit_MMX) 272 features |= (1 << FEATURE_MMX); 273 if (edx & bit_SSE) 274 features |= (1 << FEATURE_SSE); 275 if (edx & bit_SSE2) 276 features |= (1 << FEATURE_SSE2); 277 if (ecx & bit_POPCNT) 278 features |= (1 << FEATURE_POPCNT); 279 if (ecx & bit_SSE3) 280 features |= (1 << FEATURE_SSE3); 281 if (ecx & bit_SSSE3) 282 features |= (1 << FEATURE_SSSE3); 283 if (ecx & bit_SSE4_1) 284 features |= (1 << FEATURE_SSE4_1); 285 if (ecx & bit_SSE4_2) 286 features |= (1 << FEATURE_SSE4_2); 287 if (ecx & bit_AVX) 288 features |= (1 << FEATURE_AVX); 289 if (ecx & bit_FMA) 290 features |= (1 << FEATURE_FMA); 291 292 /* Get Advanced Features at level 7 (eax = 7, ecx = 0). */ 293 if (max_cpuid_level >= 7) 294 { 295 unsigned int eax, ebx, ecx, edx; 296 __cpuid_count (7, 0, eax, ebx, ecx, edx); 297 if (ebx & bit_BMI) 298 features |= (1 << FEATURE_BMI); 299 if (ebx & bit_AVX2) 300 features |= (1 << FEATURE_AVX2); 301 if (ebx & bit_BMI2) 302 features |= (1 << FEATURE_BMI2); 303 if (ebx & bit_AVX512F) 304 features |= (1 << FEATURE_AVX512F); 305 } 306 307 unsigned int ext_level; 308 unsigned int eax, ebx; 309 /* Check cpuid level of extended features. */ 310 __cpuid (0x80000000, ext_level, ebx, ecx, edx); 311 312 if (ext_level > 0x80000000) 313 { 314 __cpuid (0x80000001, eax, ebx, ecx, edx); 315 316 if (ecx & bit_SSE4a) 317 features |= (1 << FEATURE_SSE4_A); 318 if (ecx & bit_FMA4) 319 features |= (1 << FEATURE_FMA4); 320 if (ecx & bit_XOP) 321 features |= (1 << FEATURE_XOP); 322 } 323 324 __cpu_model.__cpu_features[0] = features; 325} 326 327/* A noinline function calling __get_cpuid. Having many calls to 328 cpuid in one function in 32-bit mode causes GCC to complain: 329 "can't find a register in class CLOBBERED_REGS". This is 330 related to PR rtl-optimization 44174. */ 331 332static int __attribute__ ((noinline)) 333__get_cpuid_output (unsigned int __level, 334 unsigned int *__eax, unsigned int *__ebx, 335 unsigned int *__ecx, unsigned int *__edx) 336{ 337 return __get_cpuid (__level, __eax, __ebx, __ecx, __edx); 338} 339 340 341/* A constructor function that is sets __cpu_model and __cpu_features with 342 the right values. This needs to run only once. This constructor is 343 given the highest priority and it should run before constructors without 344 the priority set. However, it still runs after ifunc initializers and 345 needs to be called explicitly there. */ 346 347int __attribute__ ((constructor CONSTRUCTOR_PRIORITY)) 348__cpu_indicator_init (void) 349{ 350 unsigned int eax, ebx, ecx, edx; 351 352 int max_level = 5; 353 unsigned int vendor; 354 unsigned int model, family, brand_id; 355 unsigned int extended_model, extended_family; 356 357 /* This function needs to run just once. */ 358 if (__cpu_model.__cpu_vendor) 359 return 0; 360 361 /* Assume cpuid insn present. Run in level 0 to get vendor id. */ 362 if (!__get_cpuid_output (0, &eax, &ebx, &ecx, &edx)) 363 { 364 __cpu_model.__cpu_vendor = VENDOR_OTHER; 365 return -1; 366 } 367 368 vendor = ebx; 369 max_level = eax; 370 371 if (max_level < 1) 372 { 373 __cpu_model.__cpu_vendor = VENDOR_OTHER; 374 return -1; 375 } 376 377 if (!__get_cpuid_output (1, &eax, &ebx, &ecx, &edx)) 378 { 379 __cpu_model.__cpu_vendor = VENDOR_OTHER; 380 return -1; 381 } 382 383 model = (eax >> 4) & 0x0f; 384 family = (eax >> 8) & 0x0f; 385 brand_id = ebx & 0xff; 386 extended_model = (eax >> 12) & 0xf0; 387 extended_family = (eax >> 20) & 0xff; 388 389 if (vendor == signature_INTEL_ebx) 390 { 391 /* Adjust model and family for Intel CPUS. */ 392 if (family == 0x0f) 393 { 394 family += extended_family; 395 model += extended_model; 396 } 397 else if (family == 0x06) 398 model += extended_model; 399 400 /* Get CPU type. */ 401 get_intel_cpu (family, model, brand_id); 402 /* Find available features. */ 403 get_available_features (ecx, edx, max_level); 404 __cpu_model.__cpu_vendor = VENDOR_INTEL; 405 } 406 else if (vendor == signature_AMD_ebx) 407 { 408 /* Adjust model and family for AMD CPUS. */ 409 if (family == 0x0f) 410 { 411 family += extended_family; 412 model += extended_model; 413 } 414 415 /* Get CPU type. */ 416 get_amd_cpu (family, model); 417 /* Find available features. */ 418 get_available_features (ecx, edx, max_level); 419 __cpu_model.__cpu_vendor = VENDOR_AMD; 420 } 421 else 422 __cpu_model.__cpu_vendor = VENDOR_OTHER; 423 424 gcc_assert (__cpu_model.__cpu_vendor < VENDOR_MAX); 425 gcc_assert (__cpu_model.__cpu_type < CPU_TYPE_MAX); 426 gcc_assert (__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX); 427 428 return 0; 429} 430