Patchwork Fix 59828 - Broken assembly on ppc* with two -mcpu= options

login
register
mail settings
Submitter Alan Modra
Date Jan. 18, 2014, 3:58 a.m.
Message ID <20140118035811.GI5390@bubble.grove.modra.org>
Download mbox | patch
Permalink /patch/312262/
State New
Headers show

Comments

Alan Modra - Jan. 18, 2014, 3:58 a.m.
This patch cures PR59828 by translating all the -mcpu options at once,
in order, to their equivalent assembler -m options by using a new spec
function.  In the process this removes some duplication.

All the rhs of -mcpu= options from the command line can be extracted
with %{mcpu=*:%*}, and then passed to a spec function.  The new
function was mostly already there in driver-rs6000.c to support
-mcpu=native.  However, the new spec function must be called for
non-native configurations, so it's necessary to split driver-rs6000.c
into two files, one for native support, the other always compiled in.

I deliberately omitted converting over aix42.h, aix51.h and aix52.h
because ASM_CPU_SPEC in those files translates -mcpu to different
assembly options than the aix -mcpu=native support.  Presumably the
assembler on older versions of aix doesn't understand the newer
options..

Bootstrapped and regression tested powerpc64-linux natively, and
x86_64-linux to powerpc64-linux cross.  OK to apply?

	PR target/59828
	* config/rs6000/driver-rs6000.c (asm_names): Add entries for "native".
	(translate_cpu_to_asm): New function.
	Move everything else to..
	* config/rs6000/driver-nat-rs6000.c: ..here.  New file.
	(host_detect_local_cpu): Make use of translate_cpu_to_asm.
	* config/rs6000/rs6000.h (ASM_CPU_SPEC): Likewise.
	(translate_cpu_to_asm): Declare.
	(EXTRA_SPEC_FUNCTIONS): Add translate_cpu_to_asm.
	* config/rs6000/x-rs6000: Adjust for renamed file.
	* config/rs6000/t-rs6000: Add driver-rs6000.o rule.
	* config/rs6000/aix53.h (ASM_CPU_SPEC): Use translate_cpu_to_asm.
	* config/rs6000/aix61.h (ASM_CPU_SPEC): Likewise.
	* config.gcc (extra_gcc_objs): Add driver-rs6000.o.
	* config.host (host_extra_gcc_objs): Remove driver-rs6000.o, add
	driver-nat-rs6000.o.

Patch

Index: gcc/config/rs6000/driver-rs6000.c
===================================================================
--- gcc/config/rs6000/driver-rs6000.c	(revision 206599)
+++ gcc/config/rs6000/driver-rs6000.c	(working copy)
@@ -21,325 +21,9 @@ 
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include <stdlib.h>
 
-#ifdef _AIX
-# include <sys/systemcfg.h>
-#endif
+/* Array to map -mcpu= names to the switches passed to the assembler.  */
 
-#ifdef __linux__
-# include <link.h>
-#endif
-
-#if defined (__APPLE__) || (__FreeBSD__)
-# include <sys/types.h>
-# include <sys/sysctl.h>
-#endif
-
-const char *host_detect_local_cpu (int argc, const char **argv);
-
-#if GCC_VERSION >= 0
-
-/* Returns parameters that describe L1_ASSOC associative cache of size
-   L1_SIZEKB with lines of size L1_LINE, and L2_SIZEKB.  */
-
-static char *
-describe_cache (unsigned l1_sizekb, unsigned l1_line,
-		unsigned l1_assoc ATTRIBUTE_UNUSED, unsigned l2_sizekb)
-{
-  char l1size[1000], line[1000], l2size[1000];
-
-  /* At the moment, gcc middle-end does not use the information about the
-     associativity of the cache.  */
-
-  sprintf (l1size, "--param l1-cache-size=%u", l1_sizekb);
-  sprintf (line, "--param l1-cache-line-size=%u", l1_line);
-  sprintf (l2size, "--param l2-cache-size=%u", l2_sizekb);
-
-  return concat (l1size, " ", line, " ", l2size, " ", NULL);
-}
-
-#ifdef __APPLE__
-
-/* Returns the description of caches on Darwin.  */
-
-static char *
-detect_caches_darwin (void)
-{
-  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
-  size_t len = 4;
-  static int l1_size_name[2] = { CTL_HW, HW_L1DCACHESIZE };
-  static int l1_line_name[2] = { CTL_HW, HW_CACHELINE };
-  static int l2_size_name[2] = { CTL_HW, HW_L2CACHESIZE };
-
-  sysctl (l1_size_name, 2, &l1_sizekb, &len, NULL, 0);
-  sysctl (l1_line_name, 2, &l1_line, &len, NULL, 0);
-  sysctl (l2_size_name, 2, &l2_sizekb, &len, NULL, 0);
-  l1_assoc = 0;
-
-  return describe_cache (l1_sizekb / 1024, l1_line, l1_assoc,
-			 l2_sizekb / 1024);
-}
-
-static const char *
-detect_processor_darwin (void)
-{
-  unsigned int proc;
-  size_t len = 4;
-
-  sysctlbyname ("hw.cpusubtype", &proc, &len, NULL, 0);
-
-  if (len > 0)
-    switch (proc)
-      {
-      case 1:
-	return "601";
-      case 2:
-	return "602";
-      case 3:
-	return "603";
-      case 4:
-      case 5:
-	return "603e";
-      case 6:
-	return "604";
-      case 7:
-	return "604e";
-      case 8:
-	return "620";
-      case 9:
-	return "750";
-      case 10:
-	return "7400";
-      case 11:
-	return "7450";
-      case 100:
-	return "970";
-      default:
-	return "powerpc";
-      }
-
-  return "powerpc";
-}
-
-#endif /* __APPLE__ */
-
-#ifdef __FreeBSD__
-
-/* Returns the description of caches on FreeBSD PPC.  */
-
-static char *
-detect_caches_freebsd (void)
-{
-  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
-  size_t len = 4;
-
-  /* Currently, as of FreeBSD-7.0, there is only the cacheline_size
-     available via sysctl.  */
-  sysctlbyname ("machdep.cacheline_size", &l1_line, &len, NULL, 0);
-
-  l1_sizekb = 32;
-  l1_assoc = 0;
-  l2_sizekb = 512;
-
-  return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
-}
-
-/* Currently returns default powerpc.  */
-static const char *
-detect_processor_freebsd (void)
-{
-  return "powerpc";
-}
-
-#endif /* __FreeBSD__  */
-
-#ifdef __linux__
-
-/* Returns AT_PLATFORM if present, otherwise generic PowerPC.  */
-
-static const char *
-elf_platform (void)
-{
-  int fd;
-
-  fd = open ("/proc/self/auxv", O_RDONLY);
-
-  if (fd != -1)
-    {
-      char buf[1024];
-      ElfW(auxv_t) *av;
-      ssize_t n;
-
-      n = read (fd, buf, sizeof (buf));
-      close (fd);
-
-      if (n > 0)
-	{
-	  for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av)
-	    switch (av->a_type)
-	      {
-	      case AT_PLATFORM:
-		return (const char *) av->a_un.a_val;
-
-	      default:
-		break;
-	      }
-	}
-    }
-  return NULL;
-}
-
-/* Returns AT_DCACHEBSIZE if present, otherwise generic 32.  */
-
-static int
-elf_dcachebsize (void)
-{
-  int fd;
-
-  fd = open ("/proc/self/auxv", O_RDONLY);
-
-  if (fd != -1)
-    {
-      char buf[1024];
-      ElfW(auxv_t) *av;
-      ssize_t n;
-
-      n = read (fd, buf, sizeof (buf));
-      close (fd);
-
-      if (n > 0)
-	{
-	  for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av)
-	    switch (av->a_type)
-	      {
-	      case AT_DCACHEBSIZE:
-		return av->a_un.a_val;
-
-	      default:
-		break;
-	      }
-	}
-    }
-  return 32;
-}
-
-/* Returns the description of caches on Linux.  */
-
-static char *
-detect_caches_linux (void)
-{
-  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
-  const char *platform;
-
-  platform = elf_platform ();
-
-  if (platform != NULL)
-    {
-      l1_line = 128;
-
-      if (platform[5] == '6')
-	/* POWER6 and POWER6x */
-	l1_sizekb = 64;
-      else
-	l1_sizekb = 32;
-    }
-  else
-    {
-      l1_line = elf_dcachebsize ();
-      l1_sizekb = 32;
-    }
-
-  l1_assoc = 0;
-  l2_sizekb = 512;
-
-  return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
-}
-
-static const char *
-detect_processor_linux (void)
-{
-  const char *platform;
-
-  platform = elf_platform ();
-
-  if (platform != NULL)
-    return platform;
-  else
-    return "powerpc";
-}
-
-#endif /* __linux__ */
-
-#ifdef _AIX
-/* Returns the description of caches on AIX.  */
-
-static char *
-detect_caches_aix (void)
-{
-  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
-
-  l1_sizekb = _system_configuration.dcache_size / 1024;
-  l1_line = _system_configuration.dcache_line;
-  l1_assoc = _system_configuration.dcache_asc;
-  l2_sizekb = _system_configuration.L2_cache_size / 1024;
-
-  return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
-}
-
-
-/* Returns the processor implementation on AIX.  */
-
-static const char *
-detect_processor_aix (void)
-{
-  switch (_system_configuration.implementation)
-    {
-    case 0x0008:
-      return "601";
-
-    case 0x0020:
-      return "603";
-
-    case 0x0010:
-      return "604";
-
-    case 0x0040:
-      return "620";
-
-    case 0x0080:
-      return "630";
-
-    case 0x0100:
-    case 0x0200:
-    case 0x0400:
-      return "rs64";
-
-    case 0x0800:
-      return "power4";
-
-    case 0x2000:
-      if (_system_configuration.version == 0x0F0000)
-	return "power5";
-      else
-	return "power5+";
-
-    case 0x4000:
-      return "power6";
-
-    default:
-      return "powerpc";
-    }
-}
-#endif /* _AIX */
-
-
-/*
- * Array to map -mcpu=native names to the switches passed to the assembler.
- * This list mirrors the specs in ASM_CPU_SPEC, and any changes made here
- * should be made there as well.
- */
-
 struct asm_name {
   const char *cpu;
   const char *asm_sw;
@@ -347,6 +31,7 @@ 
 
 static const struct asm_name asm_names[] = {
 #if defined (_AIX)
+  { "native",	"%(asm_cpu_native)" },
   { "power3",	"-m620" },
   { "power4",	"-mpwr4" },
   { "power5",	"-mpwr5" },
@@ -372,6 +57,7 @@ 
 %{!maltivec: %{!mpowerpc64: %(asm_default)}}}" },
 
 #else
+  { "native",	"%(asm_cpu_native)" },
   { "cell",	"-mcell" },
   { "power3",	"-mppc64" },
   { "power4",	"-mpower4" },
@@ -424,105 +110,24 @@ 
 #endif
 };
 
-/* This will be called by the spec parser in gcc.c when it sees
-   a %:local_cpu_detect(args) construct.  Currently it will be called
-   with either "arch" or "tune" as argument depending on if -march=native
-   or -mtune=native is to be substituted.
-
-   Additionally it will be called with "asm" to select the appropriate flags
-   for the assembler.
-
-   It returns a string containing new command line parameters to be
-   put at the place of the above two options, depending on what CPU
-   this is executed.
-
-   ARGC and ARGV are set depending on the actual arguments given
-   in the spec.  */
 const char *
-host_detect_local_cpu (int argc, const char **argv)
+translate_cpu_to_asm (int argc, const char **argv)
 {
-  const char *cpu = NULL;
-  const char *cache = "";
-  const char *options = "";
-  bool arch;
-  bool assembler;
-  size_t i;
+  const char *ret = NULL;
 
-  if (argc < 1)
-    return NULL;
-
-  arch = strcmp (argv[0], "cpu") == 0;
-  assembler = (!arch && strcmp (argv[0], "asm") == 0);
-  if (!arch && !assembler && strcmp (argv[0], "tune"))
-    return NULL;
-
-  if (! assembler)
+  while (argc-- > 0)
     {
-#if defined (_AIX)
-      cache = detect_caches_aix ();
-#elif defined (__APPLE__)
-      cache = detect_caches_darwin ();
-#elif defined (__FreeBSD__)
-      cache = detect_caches_freebsd ();
-      /* FreeBSD PPC does not provide any cache information yet.  */
-      cache = "";
-#elif defined (__linux__)
-      cache = detect_caches_linux ();
-      /* PPC Linux does not provide any cache information yet.  */
-      cache = "";
-#else
-      cache = "";
-#endif
-    }
+      unsigned int i;
+      const char *cpu = *argv++;
 
-#if defined (_AIX)
-  cpu = detect_processor_aix ();
-#elif defined (__APPLE__)
-  cpu = detect_processor_darwin ();
-#elif defined (__FreeBSD__)
-  cpu = detect_processor_freebsd ();
-#elif defined (__linux__)
-  cpu = detect_processor_linux ();
-#else
-  cpu = "powerpc";
-#endif
-
-  if (assembler)
-    {
-      for (i = 0; i < sizeof (asm_names) / sizeof (asm_names[0]); i++)
-	{
-	  if (!asm_names[i].cpu || !strcmp (asm_names[i].cpu, cpu))
-	    return asm_names[i].asm_sw;
-	}
-
-      return NULL;
+      for (i = 0; i < sizeof (asm_names) / sizeof (asm_names[0]) - 1; i++)
+	if (!strcmp (asm_names[i].cpu, cpu))
+	  break;
+      if (ret)
+	ret = concat (ret, " ", asm_names[i].asm_sw, (char *) 0);
+      else
+	ret = asm_names[i].asm_sw;
     }
 
-  return concat (cache, "-m", argv[0], "=", cpu, " ", options, NULL);
+  return ret;
 }
-
-#else /* GCC_VERSION */
-
-/* If we aren't compiling with GCC we just provide a minimal
-   default value.  */
-const char *
-host_detect_local_cpu (int argc, const char **argv)
-{
-  const char *cpu;
-  bool arch;
-
-  if (argc < 1)
-    return NULL;
-
-  arch = strcmp (argv[0], "cpu") == 0;
-  if (!arch && strcmp (argv[0], "tune"))
-    return NULL;
-  
-  if (arch)
-    cpu = "powerpc";
-
-  return concat ("-m", argv[0], "=", cpu, NULL);
-}
-
-#endif /* GCC_VERSION */
-
Index: gcc/config/rs6000/driver-nat-rs6000.c
===================================================================
--- gcc/config/rs6000/driver-nat-rs6000.c	(revision 0)
+++ gcc/config/rs6000/driver-nat-rs6000.c	(revision 0)
@@ -0,0 +1,425 @@ 
+/* Subroutines for the gcc driver, native targets only.
+   Copyright (C) 2007-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include <stdlib.h>
+
+#ifdef _AIX
+# include <sys/systemcfg.h>
+#endif
+
+#ifdef __linux__
+# include <link.h>
+#endif
+
+#if defined (__APPLE__) || (__FreeBSD__)
+# include <sys/types.h>
+# include <sys/sysctl.h>
+#endif
+
+const char *host_detect_local_cpu (int argc, const char **argv);
+
+#if GCC_VERSION >= 0
+
+/* Returns parameters that describe L1_ASSOC associative cache of size
+   L1_SIZEKB with lines of size L1_LINE, and L2_SIZEKB.  */
+
+static char *
+describe_cache (unsigned l1_sizekb, unsigned l1_line,
+		unsigned l1_assoc ATTRIBUTE_UNUSED, unsigned l2_sizekb)
+{
+  char l1size[1000], line[1000], l2size[1000];
+
+  /* At the moment, gcc middle-end does not use the information about the
+     associativity of the cache.  */
+
+  sprintf (l1size, "--param l1-cache-size=%u", l1_sizekb);
+  sprintf (line, "--param l1-cache-line-size=%u", l1_line);
+  sprintf (l2size, "--param l2-cache-size=%u", l2_sizekb);
+
+  return concat (l1size, " ", line, " ", l2size, " ", NULL);
+}
+
+#ifdef __APPLE__
+
+/* Returns the description of caches on Darwin.  */
+
+static char *
+detect_caches_darwin (void)
+{
+  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
+  size_t len = 4;
+  static int l1_size_name[2] = { CTL_HW, HW_L1DCACHESIZE };
+  static int l1_line_name[2] = { CTL_HW, HW_CACHELINE };
+  static int l2_size_name[2] = { CTL_HW, HW_L2CACHESIZE };
+
+  sysctl (l1_size_name, 2, &l1_sizekb, &len, NULL, 0);
+  sysctl (l1_line_name, 2, &l1_line, &len, NULL, 0);
+  sysctl (l2_size_name, 2, &l2_sizekb, &len, NULL, 0);
+  l1_assoc = 0;
+
+  return describe_cache (l1_sizekb / 1024, l1_line, l1_assoc,
+			 l2_sizekb / 1024);
+}
+
+static const char *
+detect_processor_darwin (void)
+{
+  unsigned int proc;
+  size_t len = 4;
+
+  sysctlbyname ("hw.cpusubtype", &proc, &len, NULL, 0);
+
+  if (len > 0)
+    switch (proc)
+      {
+      case 1:
+	return "601";
+      case 2:
+	return "602";
+      case 3:
+	return "603";
+      case 4:
+      case 5:
+	return "603e";
+      case 6:
+	return "604";
+      case 7:
+	return "604e";
+      case 8:
+	return "620";
+      case 9:
+	return "750";
+      case 10:
+	return "7400";
+      case 11:
+	return "7450";
+      case 100:
+	return "970";
+      default:
+	return "powerpc";
+      }
+
+  return "powerpc";
+}
+
+#endif /* __APPLE__ */
+
+#ifdef __FreeBSD__
+
+/* Returns the description of caches on FreeBSD PPC.  */
+
+static char *
+detect_caches_freebsd (void)
+{
+  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
+  size_t len = 4;
+
+  /* Currently, as of FreeBSD-7.0, there is only the cacheline_size
+     available via sysctl.  */
+  sysctlbyname ("machdep.cacheline_size", &l1_line, &len, NULL, 0);
+
+  l1_sizekb = 32;
+  l1_assoc = 0;
+  l2_sizekb = 512;
+
+  return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
+}
+
+/* Currently returns default powerpc.  */
+static const char *
+detect_processor_freebsd (void)
+{
+  return "powerpc";
+}
+
+#endif /* __FreeBSD__  */
+
+#ifdef __linux__
+
+/* Returns AT_PLATFORM if present, otherwise generic PowerPC.  */
+
+static const char *
+elf_platform (void)
+{
+  int fd;
+
+  fd = open ("/proc/self/auxv", O_RDONLY);
+
+  if (fd != -1)
+    {
+      char buf[1024];
+      ElfW(auxv_t) *av;
+      ssize_t n;
+
+      n = read (fd, buf, sizeof (buf));
+      close (fd);
+
+      if (n > 0)
+	{
+	  for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av)
+	    switch (av->a_type)
+	      {
+	      case AT_PLATFORM:
+		return (const char *) av->a_un.a_val;
+
+	      default:
+		break;
+	      }
+	}
+    }
+  return NULL;
+}
+
+/* Returns AT_DCACHEBSIZE if present, otherwise generic 32.  */
+
+static int
+elf_dcachebsize (void)
+{
+  int fd;
+
+  fd = open ("/proc/self/auxv", O_RDONLY);
+
+  if (fd != -1)
+    {
+      char buf[1024];
+      ElfW(auxv_t) *av;
+      ssize_t n;
+
+      n = read (fd, buf, sizeof (buf));
+      close (fd);
+
+      if (n > 0)
+	{
+	  for (av = (ElfW(auxv_t) *) buf; av->a_type != AT_NULL; ++av)
+	    switch (av->a_type)
+	      {
+	      case AT_DCACHEBSIZE:
+		return av->a_un.a_val;
+
+	      default:
+		break;
+	      }
+	}
+    }
+  return 32;
+}
+
+/* Returns the description of caches on Linux.  */
+
+static char *
+detect_caches_linux (void)
+{
+  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
+  const char *platform;
+
+  platform = elf_platform ();
+
+  if (platform != NULL)
+    {
+      l1_line = 128;
+
+      if (platform[5] == '6')
+	/* POWER6 and POWER6x */
+	l1_sizekb = 64;
+      else
+	l1_sizekb = 32;
+    }
+  else
+    {
+      l1_line = elf_dcachebsize ();
+      l1_sizekb = 32;
+    }
+
+  l1_assoc = 0;
+  l2_sizekb = 512;
+
+  return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
+}
+
+static const char *
+detect_processor_linux (void)
+{
+  const char *platform;
+
+  platform = elf_platform ();
+
+  if (platform != NULL)
+    return platform;
+  else
+    return "powerpc";
+}
+
+#endif /* __linux__ */
+
+#ifdef _AIX
+/* Returns the description of caches on AIX.  */
+
+static char *
+detect_caches_aix (void)
+{
+  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
+
+  l1_sizekb = _system_configuration.dcache_size / 1024;
+  l1_line = _system_configuration.dcache_line;
+  l1_assoc = _system_configuration.dcache_asc;
+  l2_sizekb = _system_configuration.L2_cache_size / 1024;
+
+  return describe_cache (l1_sizekb, l1_line, l1_assoc, l2_sizekb);
+}
+
+
+/* Returns the processor implementation on AIX.  */
+
+static const char *
+detect_processor_aix (void)
+{
+  switch (_system_configuration.implementation)
+    {
+    case 0x0008:
+      return "601";
+
+    case 0x0020:
+      return "603";
+
+    case 0x0010:
+      return "604";
+
+    case 0x0040:
+      return "620";
+
+    case 0x0080:
+      return "630";
+
+    case 0x0100:
+    case 0x0200:
+    case 0x0400:
+      return "rs64";
+
+    case 0x0800:
+      return "power4";
+
+    case 0x2000:
+      if (_system_configuration.version == 0x0F0000)
+	return "power5";
+      else
+	return "power5+";
+
+    case 0x4000:
+      return "power6";
+
+    default:
+      return "powerpc";
+    }
+}
+#endif /* _AIX */
+
+
+/* This will be called by the spec parser in gcc.c when it sees
+   a %:local_cpu_detect(args) construct.  Currently it will be called
+   with either "arch" or "tune" as argument depending on if -march=native
+   or -mtune=native is to be substituted.
+
+   Additionally it will be called with "asm" to select the appropriate flags
+   for the assembler.
+
+   It returns a string containing new command line parameters to be
+   put at the place of the above two options, depending on what CPU
+   this is executed.
+
+   ARGC and ARGV are set depending on the actual arguments given
+   in the spec.  */
+const char *
+host_detect_local_cpu (int argc, const char **argv)
+{
+  const char *cpu;
+  const char *cache ;
+  bool arch;
+  bool assembler;
+
+  if (argc < 1)
+    return NULL;
+
+  arch = strcmp (argv[0], "cpu") == 0;
+  assembler = (!arch && strcmp (argv[0], "asm") == 0);
+  if (!arch && !assembler && strcmp (argv[0], "tune"))
+    return NULL;
+
+#if defined (_AIX)
+  cpu = detect_processor_aix ();
+#elif defined (__APPLE__)
+  cpu = detect_processor_darwin ();
+#elif defined (__FreeBSD__)
+  cpu = detect_processor_freebsd ();
+#elif defined (__linux__)
+  cpu = detect_processor_linux ();
+#else
+  cpu = "powerpc";
+#endif
+
+  if (assembler)
+    return translate_cpu_to_asm (1, &cpu);
+
+#if defined (_AIX)
+  cache = detect_caches_aix ();
+#elif defined (__APPLE__)
+  cache = detect_caches_darwin ();
+#elif defined (__FreeBSD__)
+  cache = detect_caches_freebsd ();
+  /* FreeBSD PPC does not provide any cache information yet.  */
+  cache = "";
+#elif defined (__linux__)
+  cache = detect_caches_linux ();
+  /* PPC Linux does not provide any cache information yet.  */
+  cache = "";
+#else
+  cache = "";
+#endif
+
+  return concat (cache, "-m", argv[0], "=", cpu, NULL);
+}
+
+#else /* GCC_VERSION */
+
+/* If we aren't compiling with GCC we just provide a minimal
+   default value.  */
+const char *
+host_detect_local_cpu (int argc, const char **argv)
+{
+  const char *cpu;
+  bool arch;
+
+  if (argc < 1)
+    return NULL;
+
+  arch = strcmp (argv[0], "cpu") == 0;
+  if (!arch && strcmp (argv[0], "tune"))
+    return NULL;
+  
+  if (arch)
+    cpu = "powerpc";
+
+  return concat ("-m", argv[0], "=", cpu, NULL);
+}
+
+#endif /* GCC_VERSION */
+
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 206599)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -102,66 +102,12 @@ 
 #endif
 
 /* Common ASM definitions used by ASM_SPEC among the various targets for
-   handling -mcpu=xxx switches.  There is a parallel list in driver-rs6000.c to
-   provide the default assembler options if the user uses -mcpu=native, so if
-   you make changes here, make them also there.  */
+   handling -mcpu=xxx switches.  See the list in driver-rs6000.c.  */
 #define ASM_CPU_SPEC \
 "%{!mcpu*: \
   %{mpowerpc64*: -mppc64} \
   %{!mpowerpc64*: %(asm_default)}} \
-%{mcpu=native: %(asm_cpu_native)} \
-%{mcpu=cell: -mcell} \
-%{mcpu=power3: -mppc64} \
-%{mcpu=power4: -mpower4} \
-%{mcpu=power5: %(asm_cpu_power5)} \
-%{mcpu=power5+: %(asm_cpu_power5)} \
-%{mcpu=power6: %(asm_cpu_power6) -maltivec} \
-%{mcpu=power6x: %(asm_cpu_power6) -maltivec} \
-%{mcpu=power7: %(asm_cpu_power7)} \
-%{mcpu=power8: %(asm_cpu_power8)} \
-%{mcpu=a2: -ma2} \
-%{mcpu=powerpc: -mppc} \
-%{mcpu=rs64a: -mppc64} \
-%{mcpu=401: -mppc} \
-%{mcpu=403: -m403} \
-%{mcpu=405: -m405} \
-%{mcpu=405fp: -m405} \
-%{mcpu=440: -m440} \
-%{mcpu=440fp: -m440} \
-%{mcpu=464: -m440} \
-%{mcpu=464fp: -m440} \
-%{mcpu=476: %(asm_cpu_476)} \
-%{mcpu=476fp: %(asm_cpu_476)} \
-%{mcpu=505: -mppc} \
-%{mcpu=601: -m601} \
-%{mcpu=602: -mppc} \
-%{mcpu=603: -mppc} \
-%{mcpu=603e: -mppc} \
-%{mcpu=ec603e: -mppc} \
-%{mcpu=604: -mppc} \
-%{mcpu=604e: -mppc} \
-%{mcpu=620: -mppc64} \
-%{mcpu=630: -mppc64} \
-%{mcpu=740: -mppc} \
-%{mcpu=750: -mppc} \
-%{mcpu=G3: -mppc} \
-%{mcpu=7400: -mppc -maltivec} \
-%{mcpu=7450: -mppc -maltivec} \
-%{mcpu=G4: -mppc -maltivec} \
-%{mcpu=801: -mppc} \
-%{mcpu=821: -mppc} \
-%{mcpu=823: -mppc} \
-%{mcpu=860: -mppc} \
-%{mcpu=970: -mpower4 -maltivec} \
-%{mcpu=G5: -mpower4 -maltivec} \
-%{mcpu=8540: -me500} \
-%{mcpu=8548: -me500} \
-%{mcpu=e300c2: -me300} \
-%{mcpu=e300c3: -me300} \
-%{mcpu=e500mc: -me500mc} \
-%{mcpu=e500mc64: -me500mc64} \
-%{mcpu=e5500: -me5500} \
-%{mcpu=e6500: -me6500} \
+%{mcpu*:%:translate_cpu_to_asm(%{mcpu=*:%*})} \
 %{maltivec: -maltivec} \
 %{mvsx: -mvsx %{!maltivec: -maltivec} %{!mcpu*: %(asm_cpu_power7)}} \
 %{mpower8-vector|mcrypto|mdirect-move|mhtm: %{!mcpu*: %(asm_cpu_power8)}} \
@@ -196,6 +142,8 @@ 
   { "asm_cpu_476",		ASM_CPU_476_SPEC },			\
   SUBTARGET_EXTRA_SPECS
 
+extern const char *translate_cpu_to_asm (int argc, const char **argv);
+
 /* -mcpu=native handling only makes sense with compiler running on
    an PowerPC chip.  If changing this condition, also change
    the condition in driver-rs6000.c.  */
@@ -203,12 +151,15 @@ 
 /* In driver-rs6000.c.  */
 extern const char *host_detect_local_cpu (int argc, const char **argv);
 #define EXTRA_SPEC_FUNCTIONS \
-  { "local_cpu_detect", host_detect_local_cpu },
+  { "local_cpu_detect", host_detect_local_cpu },	\
+  { "translate_cpu_to_asm", translate_cpu_to_asm },
 #define HAVE_LOCAL_CPU_DETECT
 #define ASM_CPU_NATIVE_SPEC "%:local_cpu_detect(asm)"
 
 #else
 #define ASM_CPU_NATIVE_SPEC "%(asm_default)"
+#define EXTRA_SPEC_FUNCTIONS \
+  { "translate_cpu_to_asm", translate_cpu_to_asm },
 #endif
 
 #ifndef CC1_CPU_SPEC
Index: gcc/config/rs6000/x-rs6000
===================================================================
--- gcc/config/rs6000/x-rs6000	(revision 206599)
+++ gcc/config/rs6000/x-rs6000	(working copy)
@@ -1,3 +1,3 @@ 
-driver-rs6000.o : $(srcdir)/config/rs6000/driver-rs6000.c \
+driver-nat-rs6000.o : $(srcdir)/config/rs6000/driver-nat-rs6000.c \
   $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
Index: gcc/config/rs6000/t-rs6000
===================================================================
--- gcc/config/rs6000/t-rs6000	(revision 206599)
+++ gcc/config/rs6000/t-rs6000	(working copy)
@@ -24,6 +24,10 @@ 
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+driver-rs6000.o : $(srcdir)/config/rs6000/driver-rs6000.c \
+  $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
 $(srcdir)/config/rs6000/rs6000-tables.opt: $(srcdir)/config/rs6000/genopt.sh \
   $(srcdir)/config/rs6000/rs6000-cpus.def
 	$(SHELL) $(srcdir)/config/rs6000/genopt.sh $(srcdir)/config/rs6000 > \
Index: gcc/config/rs6000/aix53.h
===================================================================
--- gcc/config/rs6000/aix53.h	(revision 206599)
+++ gcc/config/rs6000/aix53.h	(working copy)
@@ -54,25 +54,7 @@ 
   %{mpowerpc64: -mppc64} \
   %{maltivec: -m970} \
   %{!maltivec: %{!mpowerpc64: %(asm_default)}}}} \
-%{mcpu=native: %(asm_cpu_native)} \
-%{mcpu=power3: -m620} \
-%{mcpu=power4: -mpwr4} \
-%{mcpu=power5: -mpwr5} \
-%{mcpu=power5+: -mpwr5x} \
-%{mcpu=power6: -mpwr6} \
-%{mcpu=power6x: -mpwr6} \
-%{mcpu=power7: -mpwr7} \
-%{mcpu=power8: -mpwr8} \
-%{mcpu=powerpc: -mppc} \
-%{mcpu=rs64a: -mppc} \
-%{mcpu=603: -m603} \
-%{mcpu=603e: -m603} \
-%{mcpu=604: -m604} \
-%{mcpu=604e: -m604} \
-%{mcpu=620: -m620} \
-%{mcpu=630: -m620} \
-%{mcpu=970: -m970} \
-%{mcpu=G5: -m970}"
+%{mcpu*:%:translate_cpu_to_asm(%{mcpu=*:%*})}"
 
 #undef	ASM_DEFAULT_SPEC
 #define ASM_DEFAULT_SPEC "-mppc"
Index: gcc/config/rs6000/aix61.h
===================================================================
--- gcc/config/rs6000/aix61.h	(revision 206599)
+++ gcc/config/rs6000/aix61.h	(working copy)
@@ -71,25 +71,7 @@ 
   %{mpowerpc64: -mppc64} \
   %{maltivec: -m970} \
   %{!maltivec: %{!mpowerpc64: %(asm_default)}}}} \
-%{mcpu=native: %(asm_cpu_native)} \
-%{mcpu=power3: -m620} \
-%{mcpu=power4: -mpwr4} \
-%{mcpu=power5: -mpwr5} \
-%{mcpu=power5+: -mpwr5x} \
-%{mcpu=power6: -mpwr6} \
-%{mcpu=power6x: -mpwr6} \
-%{mcpu=power7: -mpwr7} \
-%{mcpu=power8: -mpwr8} \
-%{mcpu=powerpc: -mppc} \
-%{mcpu=rs64a: -mppc} \
-%{mcpu=603: -m603} \
-%{mcpu=603e: -m603} \
-%{mcpu=604: -m604} \
-%{mcpu=604e: -m604} \
-%{mcpu=620: -m620} \
-%{mcpu=630: -m620} \
-%{mcpu=970: -m970} \
-%{mcpu=G5: -m970} \
+%{mcpu*:%:translate_cpu_to_asm(%{mcpu=*:%*})} \
 %{mvsx: %{!mcpu*: -mpwr6}} \
 -many"
 
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 206599)
+++ gcc/config.gcc	(working copy)
@@ -445,10 +445,12 @@ 
 		cpu_is_64bit=yes
 		;;
 	esac
+	extra_gcc_objs="driver-rs6000.o"
 	extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt"
 	;;
 rs6000*-*-*)
 	need_64bit_hwint=yes
+	extra_gcc_objs="driver-rs6000.o"
 	extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt"
 	;;
 score*-*-*)
@@ -618,7 +620,7 @@ 
   fortran_target_objs="darwin-f.o"
   target_has_targetcm=yes
   extra_objs="darwin.o"
-  extra_gcc_objs="darwin-driver.o"
+  extra_gcc_objs="$extra_gcc_objs darwin-driver.o"
   default_use_cxa_atexit=yes
   use_gcc_stdint=wrap
   case ${enable_threads} in
Index: gcc/config.host
===================================================================
--- gcc/config.host	(revision 206599)
+++ gcc/config.host	(working copy)
@@ -138,7 +138,7 @@ 
     case ${target} in
       rs6000-*-* \
       | powerpc*-*-* )
-        host_extra_gcc_objs="driver-rs6000.o"
+        host_extra_gcc_objs="driver-nat-rs6000.o"
         host_xmake_file="${host_xmake_file} rs6000/x-rs6000"
         ;;
     esac