#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "diagnostic.h"
+#include "opts.h"
#include <stdlib.h>
#ifdef _AIX
# include <sys/sysctl.h>
#endif
+#ifdef __linux__
+/* Canonical GCC cpu name table. */
+static const char *rs6000_supported_cpu_names[] =
+{
+#define RS6000_CPU(NAME, CPU, FLAGS) NAME,
+#include "rs6000-cpus.def"
+#undef RS6000_CPU
+};
+
+/* This table holds a list of cpus where their Linux AT_PLATFORM name differs
+ from their GCC canonical name. The first column in a row contains the GCC
+ canonical cpu name and the other columns in that row contain AT_PLATFORM
+ names that should be mapped to the canonical name. */
+
+static const char *linux_cpu_translation_table[][4] = {
+ { "403", "ppc403", NULL },
+ { "405", "ppc405", NULL },
+ { "440", "ppc440", "ppc440gp", NULL },
+ { "476", "ppc470", NULL },
+ { "601", "ppc601", NULL },
+ { "603", "ppc603", NULL },
+ { "604", "ppc604", NULL },
+ { "7400", "ppc7400", NULL },
+ { "7450", "ppc7450", NULL },
+ { "750", "ppc750", NULL },
+ { "823", "ppc823", NULL },
+ { "8540", "ppc8540", NULL },
+ { "8548", "ppc8548", NULL },
+ { "970", "ppc970", NULL },
+ { "cell", "ppc-cell-be", NULL },
+ { "e500mc", "ppce500mc", NULL },
+ { "e5500", "ppce5500", NULL },
+ { "e6500", "ppce6500", NULL },
+ { "power7", "power7+", NULL },
+ { NULL } /* End of table sentinel. */
+};
+#endif
+
const char *host_detect_local_cpu (int argc, const char **argv);
#if GCC_VERSION >= 0
#ifdef __linux__
-/* Returns AT_PLATFORM if present, otherwise generic PowerPC. */
+/* Returns the canonical AT_PLATFORM if present, otherwise NULL. */
static const char *
elf_platform (void)
{
- int fd;
+ /* Used to cache the result we determine below. */
+ static const char *cpu = NULL;
- fd = open ("/proc/self/auxv", O_RDONLY);
+ /* Use the cached AT_PLATFORM cpu name if we've already determined it. */
+ if (cpu != NULL)
+ return cpu;
+
+ int fd = open ("/proc/self/auxv", O_RDONLY);
if (fd != -1)
{
if (n > 0)
{
for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av)
- switch (av->a_type)
+ if (av->a_type == AT_PLATFORM)
{
- case AT_PLATFORM:
- return (const char *) av->a_un.a_val;
-
- default:
+ /* Cache the result. */
+ cpu = (const char *) av->a_un.a_val;
break;
}
}
+
+ /* Verify that CPU is either a valid -mcpu=<cpu> option name, or is a
+ valid alternative name. If it is a valid alternative name, then use
+ the canonical name. */
+ if (cpu != NULL)
+ {
+ size_t i, j;
+ char *s;
+
+ /* Check if AT_PLATFORM is a GCC canonical cpu name. */
+ for (i = 0; i < ARRAY_SIZE (rs6000_supported_cpu_names); i++)
+ if (!strcmp (cpu, rs6000_supported_cpu_names[i]))
+ return cpu;
+
+ /* Check if AT_PLATFORM can be translated to a canonical cpu name. */
+ for (i = 0; linux_cpu_translation_table[i][0] != NULL; i++)
+ {
+ const char *canonical = linux_cpu_translation_table[i][0];
+ for (j = 1; linux_cpu_translation_table[i][j] != NULL; j++)
+ if (!strcmp (cpu, linux_cpu_translation_table[i][j]))
+ {
+ /* Cache the result. */
+ cpu = canonical;
+ return cpu;
+ }
+ }
+
+ /* The kernel returned an AT_PLATFORM name we do not support. */
+ auto_vec <const char *> candidates;
+ for (i = 0; i < ARRAY_SIZE (rs6000_supported_cpu_names); i++)
+ candidates.safe_push (rs6000_supported_cpu_names[i]);
+ candidates_list_and_hint (cpu, s, candidates);
+ fatal_error (
+ input_location,
+ "Unsupported cpu name returned from kernel for -mcpu=native: %s\n"
+ "Please use an explicit cpu name. Valid cpu names are: %s",
+ cpu, s);
+ }
}
return NULL;
}