1 /* Subroutines for the gcc driver.
2    Copyright (C) 2007-2017 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 "diagnostic.h"
25 #include "opts.h"
26 #include <stdlib.h>
27 
28 #ifdef _AIX
29 # include <sys/systemcfg.h>
30 #endif
31 
32 #ifdef __linux__
33 # include <link.h>
34 #endif
35 
36 #if defined (__APPLE__) || (__FreeBSD__)
37 # include <sys/types.h>
38 # include <sys/sysctl.h>
39 #endif
40 
41 #ifdef __linux__
42 /* Canonical GCC cpu name table.  */
43 static const char *rs6000_supported_cpu_names[] =
44 {
45 #define RS6000_CPU(NAME, CPU, FLAGS) NAME,
46 #include "rs6000-cpus.def"
47 #undef RS6000_CPU
48 };
49 
50 /* This table holds a list of cpus where their Linux AT_PLATFORM name differs
51    from their GCC canonical name.  The first column in a row contains the GCC
52    canonical cpu name and the other columns in that row contain AT_PLATFORM
53    names that should be mapped to the canonical name.  */
54 
55 static const char *linux_cpu_translation_table[][4] = {
56   { "403", "ppc403", NULL },
57   { "405", "ppc405", NULL },
58   { "440", "ppc440", "ppc440gp", NULL },
59   { "476", "ppc470", NULL },
60   { "601", "ppc601", NULL },
61   { "603", "ppc603", NULL },
62   { "604", "ppc604", NULL },
63   { "7400", "ppc7400", NULL },
64   { "7450", "ppc7450", NULL },
65   { "750", "ppc750", NULL },
66   { "823", "ppc823", NULL },
67   { "8540", "ppc8540", NULL },
68   { "8548", "ppc8548", NULL },
69   { "970", "ppc970", NULL },
70   { "cell", "ppc-cell-be", NULL },
71   { "e500mc", "ppce500mc", NULL },
72   { "e5500", "ppce5500", NULL },
73   { "e6500", "ppce6500", NULL },
74   { "power7", "power7+", NULL },
75   { NULL } /* End of table sentinel.  */
76 };
77 #endif
78 
79 const char *host_detect_local_cpu (int argc, const char **argv);
80 
81 #if GCC_VERSION >= 0
82 
83 /* Returns parameters that describe L1_ASSOC associative cache of size
84    L1_SIZEKB with lines of size L1_LINE, and L2_SIZEKB.  */
85 
86 static char *
87 describe_cache (unsigned l1_sizekb, unsigned l1_line,
88 		unsigned l1_assoc ATTRIBUTE_UNUSED, unsigned l2_sizekb)
89 {
90   char l1size[1000], line[1000], l2size[1000];
91 
92   /* At the moment, gcc middle-end does not use the information about the
93      associativity of the cache.  */
94 
95   sprintf (l1size, "--param l1-cache-size=%u", l1_sizekb);
96   sprintf (line, "--param l1-cache-line-size=%u", l1_line);
97   sprintf (l2size, "--param l2-cache-size=%u", l2_sizekb);
98 
99   return concat (l1size, " ", line, " ", l2size, " ", NULL);
100 }
101 
102 #ifdef __APPLE__
103 
104 /* Returns the description of caches on Darwin.  */
105 
106 static char *
107 detect_caches_darwin (void)
108 {
109   unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
110   size_t len = 4;
111   static int l1_size_name[2] = { CTL_HW, HW_L1DCACHESIZE };
112   static int l1_line_name[2] = { CTL_HW, HW_CACHELINE };
113   static int l2_size_name[2] = { CTL_HW, HW_L2CACHESIZE };
114 
115   sysctl (l1_size_name, 2, &l1_sizekb, &len, NULL, 0);
116   sysctl (l1_line_name, 2, &l1_line, &len, NULL, 0);
117   sysctl (l2_size_name, 2, &l2_sizekb, &len, NULL, 0);
118   l1_assoc = 0;
119 
120   return describe_cache (l1_sizekb / 1024, l1_line, l1_assoc,
121 			 l2_sizekb / 1024);
122 }
123 
124 static const char *
125 detect_processor_darwin (void)
126 {
127   unsigned int proc;
128   size_t len = 4;
129 
130   sysctlbyname ("hw.cpusubtype", &proc, &len, NULL, 0);
131 
132   if (len > 0)
133     switch (proc)
134       {
135       case 1:
136 	return "601";
137       case 2:
138 	return "602";
139       case 3:
140 	return "603";
141       case 4:
142       case 5:
143 	return "603e";
144       case 6:
145 	return "604";
146       case 7:
147 	return "604e";
148       case 8:
149 	return "620";
150       case 9:
151 	return "750";
152       case 10:
153 	return "7400";
154       case 11:
155 	return "7450";
156       case 100:
157 	return "970";
158       default:
159 	return "powerpc";
160       }
161 
162   return "powerpc";
163 }
164 
165 #endif /* __APPLE__ */
166 
167 #ifdef __FreeBSD__
168 
169 /* Returns the description of caches on FreeBSD PPC.  */
170 
171 static char *
172 detect_caches_freebsd (void)
173 {
174   unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
175   size_t len = 4;
176 
177   /* Currently, as of FreeBSD-7.0, there is only the cacheline_size
178      available via sysctl.  */
179   sysctlbyname ("machdep.cacheline_size", &l1_line, &len, NULL, 0);
180 
181   l1_sizekb = 32;
182   l1_assoc = 0;
183   l2_sizekb = 512;
184 
185   return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
186 }
187 
188 /* Currently returns default powerpc.  */
189 static const char *
190 detect_processor_freebsd (void)
191 {
192   return "powerpc";
193 }
194 
195 #endif /* __FreeBSD__  */
196 
197 #ifdef __linux__
198 
199 /* Returns the canonical AT_PLATFORM if present, otherwise NULL.  */
200 
201 static const char *
202 elf_platform (void)
203 {
204   /* Used to cache the result we determine below.  */
205   static const char *cpu = NULL;
206 
207   /* Use the cached AT_PLATFORM cpu name if we've already determined it.  */
208   if (cpu != NULL)
209     return cpu;
210 
211   int fd = open ("/proc/self/auxv", O_RDONLY);
212 
213   if (fd != -1)
214     {
215       char buf[1024];
216       ElfW(auxv_t) *av;
217       ssize_t n;
218 
219       n = read (fd, buf, sizeof (buf));
220       close (fd);
221 
222       if (n > 0)
223 	{
224 	  for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av)
225 	    if (av->a_type == AT_PLATFORM)
226 	      {
227 		/* Cache the result.  */
228 		cpu = (const char *) av->a_un.a_val;
229 		break;
230 	      }
231 	}
232 
233       /* Verify that CPU is either a valid -mcpu=<cpu> option name, or is a
234 	 valid alternative name.  If it is a valid alternative name, then use
235 	 the canonical name.  */
236       if (cpu != NULL)
237 	{
238 	  size_t i, j;
239 	  char *s;
240 
241 	  /* Check if AT_PLATFORM is a GCC canonical cpu name.  */
242 	  for (i = 0; i < ARRAY_SIZE (rs6000_supported_cpu_names); i++)
243 	    if (!strcmp (cpu, rs6000_supported_cpu_names[i]))
244 	      return cpu;
245 
246 	  /* Check if AT_PLATFORM can be translated to a canonical cpu name.  */
247 	  for (i = 0; linux_cpu_translation_table[i][0] != NULL; i++)
248 	    {
249 	      const char *canonical = linux_cpu_translation_table[i][0];
250 	      for (j = 1; linux_cpu_translation_table[i][j] != NULL; j++)
251 		if (!strcmp (cpu, linux_cpu_translation_table[i][j]))
252 		  {
253 		    /* Cache the result.  */
254 		    cpu = canonical;
255 		    return cpu;
256 		  }
257 	    }
258 
259 	  /* The kernel returned an AT_PLATFORM name we do not support.  */
260 	  auto_vec <const char *> candidates;
261 	  for (i = 0; i < ARRAY_SIZE (rs6000_supported_cpu_names); i++)
262 	    candidates.safe_push (rs6000_supported_cpu_names[i]);
263 	  candidates_list_and_hint (cpu, s, candidates);
264 	  fatal_error (
265 	    input_location,
266 	    "Unsupported cpu name returned from kernel for -mcpu=native: %s\n"
267 	    "Please use an explicit cpu name.  Valid cpu names are: %s",
268 	    cpu, s);
269 	}
270     }
271   return NULL;
272 }
273 
274 /* Returns AT_DCACHEBSIZE if present, otherwise generic 32.  */
275 
276 static int
277 elf_dcachebsize (void)
278 {
279   int fd;
280 
281   fd = open ("/proc/self/auxv", O_RDONLY);
282 
283   if (fd != -1)
284     {
285       char buf[1024];
286       ElfW(auxv_t) *av;
287       ssize_t n;
288 
289       n = read (fd, buf, sizeof (buf));
290       close (fd);
291 
292       if (n > 0)
293 	{
294 	  for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av)
295 	    switch (av->a_type)
296 	      {
297 	      case AT_DCACHEBSIZE:
298 		return av->a_un.a_val;
299 
300 	      default:
301 		break;
302 	      }
303 	}
304     }
305   return 32;
306 }
307 
308 /* Returns the description of caches on Linux.  */
309 
310 static char *
311 detect_caches_linux (void)
312 {
313   unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
314   const char *platform;
315 
316   platform = elf_platform ();
317 
318   if (platform != NULL)
319     {
320       l1_line = 128;
321 
322       if (platform[5] == '6')
323 	/* POWER6 and POWER6x */
324 	l1_sizekb = 64;
325       else
326 	l1_sizekb = 32;
327     }
328   else
329     {
330       l1_line = elf_dcachebsize ();
331       l1_sizekb = 32;
332     }
333 
334   l1_assoc = 0;
335   l2_sizekb = 512;
336 
337   return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
338 }
339 
340 static const char *
341 detect_processor_linux (void)
342 {
343   const char *platform;
344 
345   platform = elf_platform ();
346 
347   if (platform != NULL)
348     return platform;
349   else
350     return "powerpc";
351 }
352 
353 #endif /* __linux__ */
354 
355 #ifdef _AIX
356 /* Returns the description of caches on AIX.  */
357 
358 static char *
359 detect_caches_aix (void)
360 {
361   unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
362 
363   l1_sizekb = _system_configuration.dcache_size / 1024;
364   l1_line = _system_configuration.dcache_line;
365   l1_assoc = _system_configuration.dcache_asc;
366   l2_sizekb = _system_configuration.L2_cache_size / 1024;
367 
368   return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
369 }
370 
371 
372 /* Returns the processor implementation on AIX.  */
373 
374 static const char *
375 detect_processor_aix (void)
376 {
377   switch (_system_configuration.implementation)
378     {
379     case 0x0008:
380       return "601";
381 
382     case 0x0020:
383       return "603";
384 
385     case 0x0010:
386       return "604";
387 
388     case 0x0040:
389       return "620";
390 
391     case 0x0080:
392       return "630";
393 
394     case 0x0100:
395     case 0x0200:
396     case 0x0400:
397       return "rs64";
398 
399     case 0x0800:
400       return "power4";
401 
402     case 0x2000:
403       if (_system_configuration.version == 0x0F0000)
404 	return "power5";
405       else
406 	return "power5+";
407 
408     case 0x4000:
409       return "power6";
410 
411     case 0x8000:
412       return "power7";
413 
414     case 0x10000:
415       return "power8";
416 
417     case 0x20000:
418       return "power9";
419 
420     default:
421       return "powerpc";
422     }
423 }
424 #endif /* _AIX */
425 
426 
427 /*
428  * Array to map -mcpu=native names to the switches passed to the assembler.
429  * This list mirrors the specs in ASM_CPU_SPEC, and any changes made here
430  * should be made there as well.
431  */
432 
433 struct asm_name {
434   const char *cpu;
435   const char *asm_sw;
436 };
437 
438 static const struct asm_name asm_names[] = {
439 #if defined (_AIX)
440   { "power3",	"-m620" },
441   { "power4",	"-mpwr4" },
442   { "power5",	"-mpwr5" },
443   { "power5+",	"-mpwr5x" },
444   { "power6",	"-mpwr6" },
445   { "power6x",	"-mpwr6" },
446   { "power7",	"-mpwr7" },
447   { "power8",	"-mpwr8" },
448   { "power9",	"-mpwr9" },
449   { "powerpc",	"-mppc" },
450   { "rs64a",	"-mppc" },
451   { "603",	"-m603" },
452   { "603e",	"-m603" },
453   { "604",	"-m604" },
454   { "604e",	"-m604" },
455   { "620",	"-m620" },
456   { "630",	"-m620" },
457   { "970",	"-m970" },
458   { "G5",	"-m970" },
459   { NULL,	"\
460 %{!maix64: \
461 %{mpowerpc64: -mppc64} \
462 %{maltivec: -m970} \
463 %{!maltivec: %{!mpowerpc64: %(asm_default)}}}" },
464 
465 #else
466   { "cell",	"-mcell" },
467   { "power3",	"-mppc64" },
468   { "power4",	"-mpower4" },
469   { "power5",	"%(asm_cpu_power5)" },
470   { "power5+",	"%(asm_cpu_power5)" },
471   { "power6",	"%(asm_cpu_power6) -maltivec" },
472   { "power6x",	"%(asm_cpu_power6) -maltivec" },
473   { "power7",	"%(asm_cpu_power7)" },
474   { "power8",	"%(asm_cpu_power8)" },
475   { "power9",	"%(asm_cpu_power9)" },
476   { "powerpc",	"-mppc" },
477   { "rs64a",	"-mppc64" },
478   { "401",	"-mppc" },
479   { "403",	"-m403" },
480   { "405",	"-m405" },
481   { "405fp",	"-m405" },
482   { "440",	"-m440" },
483   { "440fp",	"-m440" },
484   { "464",	"-m440" },
485   { "464fp",	"-m440" },
486   { "505",	"-mppc" },
487   { "601",	"-m601" },
488   { "602",	"-mppc" },
489   { "603",	"-mppc" },
490   { "603e",	"-mppc" },
491   { "ec603e",	"-mppc" },
492   { "604",	"-mppc" },
493   { "604e",	"-mppc" },
494   { "620",	"-mppc64" },
495   { "630",	"-mppc64" },
496   { "740",	"-mppc" },
497   { "750",	"-mppc" },
498   { "G3",	"-mppc" },
499   { "7400",	"-mppc -maltivec" },
500   { "7450",	"-mppc -maltivec" },
501   { "G4",	"-mppc -maltivec" },
502   { "801",	"-mppc" },
503   { "821",	"-mppc" },
504   { "823",	"-mppc" },
505   { "860",	"-mppc" },
506   { "970",	"-mpower4 -maltivec" },
507   { "G5",	"-mpower4 -maltivec" },
508   { "8540",	"-me500" },
509   { "8548",	"-me500" },
510   { "e300c2",	"-me300" },
511   { "e300c3",	"-me300" },
512   { "e500mc",	"-me500mc" },
513   { NULL,	"\
514 %{mpowerpc64*: -mppc64} \
515 %{!mpowerpc64*: %(asm_default)}" },
516 #endif
517 };
518 
519 /* This will be called by the spec parser in gcc.c when it sees
520    a %:local_cpu_detect(args) construct.  Currently it will be called
521    with either "arch" or "tune" as argument depending on if -march=native
522    or -mtune=native is to be substituted.
523 
524    Additionally it will be called with "asm" to select the appropriate flags
525    for the assembler.
526 
527    It returns a string containing new command line parameters to be
528    put at the place of the above two options, depending on what CPU
529    this is executed.
530 
531    ARGC and ARGV are set depending on the actual arguments given
532    in the spec.  */
533 const char *
534 host_detect_local_cpu (int argc, const char **argv)
535 {
536   const char *cpu = NULL;
537   const char *cache = "";
538   const char *options = "";
539   bool arch;
540   bool assembler;
541   size_t i;
542 
543   if (argc < 1)
544     return NULL;
545 
546   arch = strcmp (argv[0], "cpu") == 0;
547   assembler = (!arch && strcmp (argv[0], "asm") == 0);
548   if (!arch && !assembler && strcmp (argv[0], "tune"))
549     return NULL;
550 
551   if (! assembler)
552     {
553 #if defined (_AIX)
554       cache = detect_caches_aix ();
555 #elif defined (__APPLE__)
556       cache = detect_caches_darwin ();
557 #elif defined (__FreeBSD__)
558       cache = detect_caches_freebsd ();
559       /* FreeBSD PPC does not provide any cache information yet.  */
560       cache = "";
561 #elif defined (__linux__)
562       cache = detect_caches_linux ();
563       /* PPC Linux does not provide any cache information yet.  */
564       cache = "";
565 #else
566       cache = "";
567 #endif
568     }
569 
570 #if defined (_AIX)
571   cpu = detect_processor_aix ();
572 #elif defined (__APPLE__)
573   cpu = detect_processor_darwin ();
574 #elif defined (__FreeBSD__)
575   cpu = detect_processor_freebsd ();
576 #elif defined (__linux__)
577   cpu = detect_processor_linux ();
578 #else
579   cpu = "powerpc";
580 #endif
581 
582   if (assembler)
583     {
584       for (i = 0; i < sizeof (asm_names) / sizeof (asm_names[0]); i++)
585 	{
586 	  if (!asm_names[i].cpu || !strcmp (asm_names[i].cpu, cpu))
587 	    return asm_names[i].asm_sw;
588 	}
589 
590       return NULL;
591     }
592 
593   return concat (cache, "-m", argv[0], "=", cpu, " ", options, NULL);
594 }
595 
596 #else /* GCC_VERSION */
597 
598 /* If we aren't compiling with GCC we just provide a minimal
599    default value.  */
600 const char *
601 host_detect_local_cpu (int argc, const char **argv)
602 {
603   const char *cpu;
604   bool arch;
605 
606   if (argc < 1)
607     return NULL;
608 
609   arch = strcmp (argv[0], "cpu") == 0;
610   if (!arch && strcmp (argv[0], "tune"))
611     return NULL;
612 
613   if (arch)
614     cpu = "powerpc";
615 
616   return concat ("-m", argv[0], "=", cpu, NULL);
617 }
618 
619 #endif /* GCC_VERSION */
620 
621