1 /* Subroutines for the gcc driver. 2 Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. 3 4 This file is part of GCC. 5 6 GCC is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GCC is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GCC; see the file COPYING3. If not see 18 <http://www.gnu.org/licenses/>. */ 19 20 #include "config.h" 21 #include "system.h" 22 #include "coretypes.h" 23 #include "tm.h" 24 #include <stdlib.h> 25 26 #ifdef _AIX 27 # include <sys/systemcfg.h> 28 #endif 29 30 #ifdef __linux__ 31 # include <link.h> 32 #endif 33 34 #if defined (__APPLE__) || (__FreeBSD__) 35 # include <sys/types.h> 36 # include <sys/sysctl.h> 37 #endif 38 39 const char *host_detect_local_cpu (int argc, const char **argv); 40 41 #if GCC_VERSION >= 0 42 43 /* Returns parameters that describe L1_ASSOC associative cache of size 44 L1_SIZEKB with lines of size L1_LINE, and L2_SIZEKB. */ 45 46 static char * 47 describe_cache (unsigned l1_sizekb, unsigned l1_line, 48 unsigned l1_assoc ATTRIBUTE_UNUSED, unsigned l2_sizekb) 49 { 50 char l1size[1000], line[1000], l2size[1000]; 51 52 /* At the moment, gcc middle-end does not use the information about the 53 associativity of the cache. */ 54 55 sprintf (l1size, "--param l1-cache-size=%u", l1_sizekb); 56 sprintf (line, "--param l1-cache-line-size=%u", l1_line); 57 sprintf (l2size, "--param l2-cache-size=%u", l2_sizekb); 58 59 return concat (l1size, " ", line, " ", l2size, " ", NULL); 60 } 61 62 #ifdef __APPLE__ 63 64 /* Returns the description of caches on Darwin. */ 65 66 static char * 67 detect_caches_darwin (void) 68 { 69 unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb; 70 size_t len = 4; 71 static int l1_size_name[2] = { CTL_HW, HW_L1DCACHESIZE }; 72 static int l1_line_name[2] = { CTL_HW, HW_CACHELINE }; 73 static int l2_size_name[2] = { CTL_HW, HW_L2CACHESIZE }; 74 75 sysctl (l1_size_name, 2, &l1_sizekb, &len, NULL, 0); 76 sysctl (l1_line_name, 2, &l1_line, &len, NULL, 0); 77 sysctl (l2_size_name, 2, &l2_sizekb, &len, NULL, 0); 78 l1_assoc = 0; 79 80 return describe_cache (l1_sizekb / 1024, l1_line, l1_assoc, 81 l2_sizekb / 1024); 82 } 83 84 static const char * 85 detect_processor_darwin (void) 86 { 87 unsigned int proc; 88 size_t len = 4; 89 90 sysctlbyname ("hw.cpusubtype", &proc, &len, NULL, 0); 91 92 if (len > 0) 93 switch (proc) 94 { 95 case 1: 96 return "601"; 97 case 2: 98 return "602"; 99 case 3: 100 return "603"; 101 case 4: 102 case 5: 103 return "603e"; 104 case 6: 105 return "604"; 106 case 7: 107 return "604e"; 108 case 8: 109 return "620"; 110 case 9: 111 return "750"; 112 case 10: 113 return "7400"; 114 case 11: 115 return "7450"; 116 case 100: 117 return "970"; 118 default: 119 return "powerpc"; 120 } 121 122 return "powerpc"; 123 } 124 125 #endif /* __APPLE__ */ 126 127 #ifdef __FreeBSD__ 128 129 /* Returns the description of caches on FreeBSD PPC. */ 130 131 static char * 132 detect_caches_freebsd (void) 133 { 134 unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb; 135 size_t len = 4; 136 137 /* Currently, as of FreeBSD-7.0, there is only the cacheline_size 138 available via sysctl. */ 139 sysctlbyname ("machdep.cacheline_size", &l1_line, &len, NULL, 0); 140 141 l1_sizekb = 32; 142 l1_assoc = 0; 143 l2_sizekb = 512; 144 145 return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb); 146 } 147 148 /* Currently returns default powerpc. */ 149 static const char * 150 detect_processor_freebsd (void) 151 { 152 return "powerpc"; 153 } 154 155 #endif /* __FreeBSD__ */ 156 157 #ifdef __linux__ 158 159 /* Returns AT_PLATFORM if present, otherwise generic PowerPC. */ 160 161 static const char * 162 elf_platform (void) 163 { 164 int fd; 165 166 fd = open ("/proc/self/auxv", O_RDONLY); 167 168 if (fd != -1) 169 { 170 char buf[1024]; 171 ElfW(auxv_t) *av; 172 ssize_t n; 173 174 n = read (fd, buf, sizeof (buf)); 175 close (fd); 176 177 if (n > 0) 178 { 179 for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av) 180 switch (av->a_type) 181 { 182 case AT_PLATFORM: 183 return (const char *) av->a_un.a_val; 184 185 default: 186 break; 187 } 188 } 189 } 190 return NULL; 191 } 192 193 /* Returns AT_PLATFORM if present, otherwise generic 32. */ 194 195 static int 196 elf_dcachebsize (void) 197 { 198 int fd; 199 200 fd = open ("/proc/self/auxv", O_RDONLY); 201 202 if (fd != -1) 203 { 204 char buf[1024]; 205 ElfW(auxv_t) *av; 206 ssize_t n; 207 208 n = read (fd, buf, sizeof (buf)); 209 close (fd); 210 211 if (n > 0) 212 { 213 for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av) 214 switch (av->a_type) 215 { 216 case AT_DCACHEBSIZE: 217 return av->a_un.a_val; 218 219 default: 220 break; 221 } 222 } 223 } 224 return 32; 225 } 226 227 /* Returns the description of caches on Linux. */ 228 229 static char * 230 detect_caches_linux (void) 231 { 232 unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb; 233 const char *platform; 234 235 platform = elf_platform (); 236 237 if (platform != NULL) 238 { 239 l1_line = 128; 240 241 if (platform[5] == '6') 242 /* POWER6 and POWER6x */ 243 l1_sizekb = 64; 244 else 245 l1_sizekb = 32; 246 } 247 else 248 { 249 l1_line = elf_dcachebsize (); 250 l1_sizekb = 32; 251 } 252 253 l1_assoc = 0; 254 l2_sizekb = 512; 255 256 return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb); 257 } 258 259 static const char * 260 detect_processor_linux (void) 261 { 262 const char *platform; 263 264 platform = elf_platform (); 265 266 if (platform != NULL) 267 return platform; 268 else 269 return "powerpc"; 270 } 271 272 #endif /* __linux__ */ 273 274 #ifdef _AIX 275 /* Returns the description of caches on AIX. */ 276 277 static char * 278 detect_caches_aix (void) 279 { 280 unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb; 281 282 l1_sizekb = _system_configuration.dcache_size / 1024; 283 l1_line = _system_configuration.dcache_line; 284 l1_assoc = _system_configuration.dcache_asc; 285 l2_sizekb = _system_configuration.L2_cache_size / 1024; 286 287 return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb); 288 } 289 290 291 /* Returns the processor implementation on AIX. */ 292 293 static const char * 294 detect_processor_aix (void) 295 { 296 switch (_system_configuration.implementation) 297 { 298 case 0x0001: 299 return "rios1"; 300 301 case 0x0002: 302 return "rsc"; 303 304 case 0x0004: 305 return "rios2"; 306 307 case 0x0008: 308 return "601"; 309 310 case 0x0020: 311 return "603"; 312 313 case 0x0010: 314 return "604"; 315 316 case 0x0040: 317 return "620"; 318 319 case 0x0080: 320 return "630"; 321 322 case 0x0100: 323 case 0x0200: 324 case 0x0400: 325 return "rs64"; 326 327 case 0x0800: 328 return "power4"; 329 330 case 0x2000: 331 if (_system_configuration.version == 0x0F0000) 332 return "power5"; 333 else 334 return "power5+"; 335 336 case 0x4000: 337 return "power6"; 338 339 default: 340 return "powerpc"; 341 } 342 } 343 #endif /* _AIX */ 344 345 346 /* 347 * Array to map -mcpu=native names to the switches passed to the assembler. 348 * This list mirrors the specs in ASM_CPU_SPEC, and any changes made here 349 * should be made there as well. 350 */ 351 352 struct asm_name { 353 const char *cpu; 354 const char *asm_sw; 355 }; 356 357 static const struct asm_name asm_names[] = { 358 #if defined (_AIX) 359 { "power3", "-m620" }, 360 { "power4", "-mpwr4" }, 361 { "power5", "-mpwr5" }, 362 { "power5+", "-mpwr5x" }, 363 { "power6", "-mpwr6" }, 364 { "power6x", "-mpwr6" }, 365 { "power7", "-mpwr7" }, 366 { "powerpc", "-mppc" }, 367 { "rs64a", "-mppc" }, 368 { "603", "-m603" }, 369 { "603e", "-m603" }, 370 { "604", "-m604" }, 371 { "604e", "-m604" }, 372 { "620", "-m620" }, 373 { "630", "-m620" }, 374 { "970", "-m970" }, 375 { "G5", "-m970" }, 376 { NULL, "\ 377 %{!maix64: \ 378 %{mpowerpc64: -mppc64} \ 379 %{maltivec: -m970} \ 380 %{!maltivec: %{!mpower64: %(asm_default)}}}" }, 381 382 #else 383 { "common", "-mcom" }, 384 { "cell", "-mcell" }, 385 { "power", "-mpwr" }, 386 { "power2", "-mpwrx" }, 387 { "power3", "-mppc64" }, 388 { "power4", "-mpower4" }, 389 { "power5", "%(asm_cpu_power5)" }, 390 { "power5+", "%(asm_cpu_power5)" }, 391 { "power6", "%(asm_cpu_power6) -maltivec" }, 392 { "power6x", "%(asm_cpu_power6) -maltivec" }, 393 { "power7", "%(asm_cpu_power7)" }, 394 { "powerpc", "-mppc" }, 395 { "rios", "-mpwr" }, 396 { "rios1", "-mpwr" }, 397 { "rios2", "-mpwrx" }, 398 { "rsc", "-mpwr" }, 399 { "rsc1", "-mpwr" }, 400 { "rs64a", "-mppc64" }, 401 { "401", "-mppc" }, 402 { "403", "-m403" }, 403 { "405", "-m405" }, 404 { "405fp", "-m405" }, 405 { "440", "-m440" }, 406 { "440fp", "-m440" }, 407 { "464", "-m440" }, 408 { "464fp", "-m440" }, 409 { "505", "-mppc" }, 410 { "601", "-m601" }, 411 { "602", "-mppc" }, 412 { "603", "-mppc" }, 413 { "603e", "-mppc" }, 414 { "ec603e", "-mppc" }, 415 { "604", "-mppc" }, 416 { "604e", "-mppc" }, 417 { "620", "-mppc64" }, 418 { "630", "-mppc64" }, 419 { "740", "-mppc" }, 420 { "750", "-mppc" }, 421 { "G3", "-mppc" }, 422 { "7400", "-mppc -maltivec" }, 423 { "7450", "-mppc -maltivec" }, 424 { "G4", "-mppc -maltivec" }, 425 { "801", "-mppc" }, 426 { "821", "-mppc" }, 427 { "823", "-mppc" }, 428 { "860", "-mppc" }, 429 { "970", "-mpower4 -maltivec" }, 430 { "G5", "-mpower4 -maltivec" }, 431 { "8540", "-me500" }, 432 { "8548", "-me500" }, 433 { "e300c2", "-me300" }, 434 { "e300c3", "-me300" }, 435 { "e500mc", "-me500mc" }, 436 { NULL, "\ 437 %{mpower: %{!mpower2: -mpwr}} \ 438 %{mpower2: -mpwrx} \ 439 %{mpowerpc64*: -mppc64} \ 440 %{!mpowerpc64*: %{mpowerpc*: -mppc}} \ 441 %{mno-power: %{!mpowerpc*: -mcom}} \ 442 %{!mno-power: %{!mpower*: %(asm_default)}}" }, 443 #endif 444 }; 445 446 /* This will be called by the spec parser in gcc.c when it sees 447 a %:local_cpu_detect(args) construct. Currently it will be called 448 with either "arch" or "tune" as argument depending on if -march=native 449 or -mtune=native is to be substituted. 450 451 Additionally it will be called with "asm" to select the appropriate flags 452 for the assembler. 453 454 It returns a string containing new command line parameters to be 455 put at the place of the above two options, depending on what CPU 456 this is executed. 457 458 ARGC and ARGV are set depending on the actual arguments given 459 in the spec. */ 460 const char * 461 host_detect_local_cpu (int argc, const char **argv) 462 { 463 const char *cpu = NULL; 464 const char *cache = ""; 465 const char *options = ""; 466 bool arch; 467 bool assembler; 468 size_t i; 469 470 if (argc < 1) 471 return NULL; 472 473 arch = strcmp (argv[0], "cpu") == 0; 474 assembler = (!arch && strcmp (argv[0], "asm") == 0); 475 if (!arch && !assembler && strcmp (argv[0], "tune")) 476 return NULL; 477 478 if (! assembler) 479 { 480 #if defined (_AIX) 481 cache = detect_caches_aix (); 482 #elif defined (__APPLE__) 483 cache = detect_caches_darwin (); 484 #elif defined (__FreeBSD__) 485 cache = detect_caches_freebsd (); 486 /* FreeBSD PPC does not provide any cache information yet. */ 487 cache = ""; 488 #elif defined (__linux__) 489 cache = detect_caches_linux (); 490 /* PPC Linux does not provide any cache information yet. */ 491 cache = ""; 492 #else 493 cache = ""; 494 #endif 495 } 496 497 #if defined (_AIX) 498 cpu = detect_processor_aix (); 499 #elif defined (__APPLE__) 500 cpu = detect_processor_darwin (); 501 #elif defined (__FreeBSD__) 502 cpu = detect_processor_freebsd (); 503 #elif defined (__linux__) 504 cpu = detect_processor_linux (); 505 #else 506 cpu = "powerpc"; 507 #endif 508 509 if (assembler) 510 { 511 for (i = 0; i < sizeof (asm_names) / sizeof (asm_names[0]); i++) 512 { 513 if (!asm_names[i].cpu || !strcmp (asm_names[i].cpu, cpu)) 514 return asm_names[i].asm_sw; 515 } 516 517 return NULL; 518 } 519 520 return concat (cache, "-m", argv[0], "=", cpu, " ", options, NULL); 521 } 522 523 #else /* GCC_VERSION */ 524 525 /* If we aren't compiling with GCC we just provide a minimal 526 default value. */ 527 const char * 528 host_detect_local_cpu (int argc, const char **argv) 529 { 530 const char *cpu; 531 bool arch; 532 533 if (argc < 1) 534 return NULL; 535 536 arch = strcmp (argv[0], "cpu") == 0; 537 if (!arch && strcmp (argv[0], "tune")) 538 return NULL; 539 540 if (arch) 541 cpu = "powerpc"; 542 543 return concat ("-m", argv[0], "=", cpu, NULL); 544 } 545 546 #endif /* GCC_VERSION */ 547 548