]>
Commit | Line | Data |
---|---|---|
0eab6840 | 1 | /* Subroutines for the gcc driver. |
cacf1ca8 | 2 | Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. |
0eab6840 DE |
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__ | |
656ca3ad | 31 | # include <link.h> |
0eab6840 DE |
32 | #endif |
33 | ||
3b7abfda | 34 | #if defined (__APPLE__) || (__FreeBSD__) |
0eab6840 DE |
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 | ||
3b7abfda AT |
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 | ||
0eab6840 DE |
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]; | |
656ca3ad | 171 | ElfW(auxv_t) *av; |
0eab6840 DE |
172 | ssize_t n; |
173 | ||
174 | n = read (fd, buf, sizeof (buf)); | |
175 | close (fd); | |
176 | ||
177 | if (n > 0) | |
178 | { | |
656ca3ad | 179 | for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av) |
0eab6840 DE |
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]; | |
656ca3ad | 205 | ElfW(auxv_t) *av; |
0eab6840 DE |
206 | ssize_t n; |
207 | ||
208 | n = read (fd, buf, sizeof (buf)); | |
209 | close (fd); | |
210 | ||
211 | if (n > 0) | |
212 | { | |
656ca3ad | 213 | for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av) |
0eab6840 DE |
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 | ||
cacf1ca8 MM |
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 | ||
0eab6840 DE |
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 | ||
cacf1ca8 MM |
451 | Additionally it will be called with "asm" to select the appropriate flags |
452 | for the assembler. | |
453 | ||
0eab6840 DE |
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. */ | |
cacf1ca8 MM |
460 | const char * |
461 | host_detect_local_cpu (int argc, const char **argv) | |
0eab6840 DE |
462 | { |
463 | const char *cpu = NULL; | |
464 | const char *cache = ""; | |
465 | const char *options = ""; | |
466 | bool arch; | |
cacf1ca8 MM |
467 | bool assembler; |
468 | size_t i; | |
0eab6840 DE |
469 | |
470 | if (argc < 1) | |
471 | return NULL; | |
472 | ||
473 | arch = strcmp (argv[0], "cpu") == 0; | |
cacf1ca8 MM |
474 | assembler = (!arch && strcmp (argv[0], "asm") == 0); |
475 | if (!arch && !assembler && strcmp (argv[0], "tune")) | |
0eab6840 DE |
476 | return NULL; |
477 | ||
cacf1ca8 MM |
478 | if (! assembler) |
479 | { | |
0eab6840 | 480 | #if defined (_AIX) |
cacf1ca8 | 481 | cache = detect_caches_aix (); |
0eab6840 | 482 | #elif defined (__APPLE__) |
cacf1ca8 | 483 | cache = detect_caches_darwin (); |
3b7abfda | 484 | #elif defined (__FreeBSD__) |
cacf1ca8 MM |
485 | cache = detect_caches_freebsd (); |
486 | /* FreeBSD PPC does not provide any cache information yet. */ | |
487 | cache = ""; | |
0eab6840 | 488 | #elif defined (__linux__) |
cacf1ca8 MM |
489 | cache = detect_caches_linux (); |
490 | /* PPC Linux does not provide any cache information yet. */ | |
491 | cache = ""; | |
0eab6840 | 492 | #else |
cacf1ca8 | 493 | cache = ""; |
0eab6840 | 494 | #endif |
cacf1ca8 | 495 | } |
0eab6840 DE |
496 | |
497 | #if defined (_AIX) | |
498 | cpu = detect_processor_aix (); | |
499 | #elif defined (__APPLE__) | |
500 | cpu = detect_processor_darwin (); | |
3b7abfda AT |
501 | #elif defined (__FreeBSD__) |
502 | cpu = detect_processor_freebsd (); | |
0eab6840 DE |
503 | #elif defined (__linux__) |
504 | cpu = detect_processor_linux (); | |
505 | #else | |
506 | cpu = "powerpc"; | |
507 | #endif | |
508 | ||
cacf1ca8 MM |
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 | ||
0eab6840 DE |
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. */ | |
cacf1ca8 MM |
527 | const char * |
528 | host_detect_local_cpu (int argc, const char **argv) | |
0eab6840 DE |
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 |