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