This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] PowerPC processor and cache detection


	The appended patch implements -mcpu=native detecting the processor
and cache on AIX, Darwin and Linux.  Unfortunately, PPC Linux does not
communicate any cache information, so it only selects the processor.

	I am not sure whether to protect the Linux code with __ELF__ or
with __linux.

David

	* config/rs6000/x-rs6000: New file.
	* config/rs6000/darwin.h (CC1_SPEC): Add cc1_cpu.
	* config/rs6000/rs6000.h (EXTRA_SPECS): Add cc1_cpu.
	(EXTRA_SPEC_FUNCTIONS): Define.
	(HAVE_LOCAL_CPU_DETECT): Define.
	(CC1_CPU_SPEC): Define.
	* config/rs6000/driver-rs6000.c: New file.
	* config/rs6000/aix.h (CC1_SPEC): Define.
	* config/rs6000/sysv4.h (CC1_SPEC): Add cc1_cpu.
	* config.host: Add x-rs6000 to host_xmake_file if host and target
	are rs6000 or powerpc.

Index: x-rs6000
===================================================================
--- x-rs6000	(revision 0)
+++ x-rs6000	(revision 0)
@@ -0,0 +1,3 @@
+driver-rs6000.o : $(srcdir)/config/rs6000/driver-rs6000.c \
+  $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
Index: darwin.h
===================================================================
--- darwin.h	(revision 127241)
+++ darwin.h	(working copy)
@@ -90,6 +90,7 @@
    the kernel or some such.  */
 
 #define CC1_SPEC "\
+  %(cc1_cpu) \
   %{g: %{!fno-eliminate-unused-debug-symbols: -feliminate-unused-debug-symbols }} \
   %{static: %{Zdynamic: %e conflicting code gen style switches are used}}\
   %{!mmacosx-version-min=*:-mmacosx-version-min=%(darwin_minversion)} \
Index: rs6000.h
===================================================================
--- rs6000.h	(revision 127241)
+++ rs6000.h	(working copy)
@@ -135,8 +135,26 @@
   { "cpp_default",		CPP_DEFAULT_SPEC },			\
   { "asm_cpu",			ASM_CPU_SPEC },				\
   { "asm_default",		ASM_DEFAULT_SPEC },			\
+  { "cc1_cpu",			CC1_CPU_SPEC },				\
   SUBTARGET_EXTRA_SPECS
 
+/* -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.  */
+#if defined(__powerpc__) || defined(__POWERPC__) || defined(_AIX)
+/* 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 },
+#define HAVE_LOCAL_CPU_DETECT
+#endif
+
+#if !defined (CC1_CPU_SPEC) && defined (HAVE_LOCAL_CPU_DETECT)
+#define CC1_CPU_SPEC \
+"%{mcpu=native:%<mcpu=native %:local_cpu_detect(cpu)} \
+ %{mtune=native:%<mtune=native %:local_cpu_detect(tune)}"
+#endif
+
 /* Architecture type.  */
 
 /* Define TARGET_MFCRF if the target assembler does not support the
Index: driver-rs6000.c
===================================================================
--- driver-rs6000.c	(revision 0)
+++ driver-rs6000.c	(revision 0)
@@ -0,0 +1,388 @@
+/* Subroutines for the gcc driver.
+   Copyright (C) 2007 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 __ELF__
+# include <elf.h>
+#endif
+
+#ifdef __APPLE__
+# include <sys/types.h>
+# include <sys/sysctl.h>
+#endif
+
+const char *host_detect_local_cpu (int argc, const char **argv);
+
+#ifdef GCC_VERSION
+
+/* Returns parameters that describe L1_ASSOC associative cache of size
+   L1_SIZEKB with lines of size L1_LINE.  */
+
+static char *
+describe_cache (unsigned l1_sizekb, unsigned l1_line,
+		unsigned l1_assoc ATTRIBUTE_UNUSED, unsigned l2_sizekb)
+{
+  char l1size[1000], line[1000], l2size;
+
+  /* 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 Linux.  */
+
+static char *
+detect_caches_darwin (void)
+{
+  unsigned l1_sizekb, l1_line, l1_assoc, l2_sizekb;
+  size_t len = 4;
+  static int l1_line_name[2] = { CTL_HW, HW_CACHELINE };
+  static int l1_size_name[2] = { CTL_HW, HW_L1DCACHESIZE };
+  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 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:
+	gcc_unreachable ();
+      }
+
+  return "powerpc";
+}
+
+#endif
+
+#ifdef __ELF__
+
+/* Returns AT_PLATFORM if present, otherwise generic PowerPC.  */
+
+static char *
+elf_platform (void)
+{
+  int fd;
+
+  fd = open ("/proc/self/auxv", O_RDONLY);
+
+  if (fd != -1)
+    {
+      char buf[1024];
+      Elf32_auxv_t *av;
+      ssize_t n;
+
+      n = read (fd, buf, sizeof (buf));
+      close (fd);
+
+      if (n > 0)
+	{
+	  for (av = (Elf32_auxv_t *) buf; av->a_type != AT_NULL; ++av)
+	    switch (av->a_type)
+	      {
+	      case AT_PLATFORM:
+		return (char *) av->a_un.a_val;
+
+	      default:
+		break;
+	      }
+	}
+    }
+  return NULL;
+}
+
+/* Returns AT_PLATFORM 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];
+      Elf32_auxv_t *av;
+      ssize_t n;
+
+      n = read (fd, buf, sizeof (buf));
+      close (fd);
+
+      if (n > 0)
+	{
+	  for (av = (Elf32_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;
+  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 char *
+detect_processor_linux (void)
+{
+  char *platform;
+
+  platform = elf_platform ();
+
+  if (platform != NULL)
+    return platform;
+  else
+    return "powerpc";
+}
+
+#endif /* __ELF__ */
+
+#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_line = _system_configuration.dcache_line;
+  l1_sizekb = _system_configuration.dcache_size / 1024;
+  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 char *
+detect_processor_aix (void)
+{
+  switch (_system_configuration.implementation)
+    {
+    case POWER_RS1:
+      return "rios1";
+
+    case POWER_RSC:
+      return "rsc";
+
+    case POWER_RS2:
+      return "rios2";
+
+    case POWER_601:
+      return "601";
+
+    case POWER_603:
+      return "603";
+
+    case POWER_604:
+      return "604";
+
+    case POWER_620:
+      return "620";
+
+    case POWER_630:
+      return "630";
+
+    case POWER_A35:
+    case POWER_RS64II:
+    case POWER_RS64III:
+      return "rs64";
+
+    case POWER_4:
+      return "power4";
+
+    case POWER_5:
+      if (_system_configuration.version == PV_5)
+	return "power5";
+      else
+	return "power5+";
+
+    case POWER_6:
+      return "power6";
+
+    default:
+      gcc_unreachable ();
+    }
+}
+#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.
+
+   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 = NULL;
+  const char *cache = "";
+  const char *options = "";
+  bool arch;
+
+  if (argc < 1)
+    return NULL;
+
+  arch = strcmp (argv[0], "cpu") == 0;
+  if (!arch && strcmp (argv[0], "tune"))
+    return NULL;
+
+#if defined (_AIX)
+  cache = detect_caches_aix ();
+#elif defined (__APPLE__)
+  cache = detect_caches_darwin ();
+#elif defined (__ELF__)
+  /* cache = detect_caches_linux (); */
+#else
+#error unsupported OS
+#endif
+
+#if defined (_AIX)
+  cpu = detect_processor_aix ();
+#elif defined (__APPLE__)
+  cpu = detect_processor_darwin ();
+#elif defined (__ELF__)
+  cpu = detect_processor_linux ();
+#else
+#error unsupported OS
+#endif
+
+  return concat (cache, "-m", argv[0], "=", cpu, " ", options, 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: aix.h
===================================================================
--- aix.h	(revision 127241)
+++ aix.h	(working copy)
@@ -109,6 +109,8 @@
 #define CPP_SPEC "%{posix: -D_POSIX_SOURCE}\
    %{ansi: -D_ANSI_C_SOURCE}"
 
+#define CC1_SPEC "%(cc1_cpu)"
+
 #undef ASM_DEFAULT_SPEC
 #define ASM_DEFAULT_SPEC ""
 
Index: sysv4.h
===================================================================
--- sysv4.h	(revision 127241)
+++ sysv4.h	(working copy)
@@ -607,7 +607,7 @@
 #endif
 
 /* Pass -G xxx to the compiler and set correct endian mode.  */
-#define	CC1_SPEC "%{G*} \
+#define	CC1_SPEC "%{G*} %(cc1_cpu) \
 %{mlittle|mlittle-endian: %(cc1_endian_little);           \
   mbig   |mbig-endian   : %(cc1_endian_big);              \
   mcall-aixdesc |					  \
Index: config.host
===================================================================
--- config.host	(revision 127165)
+++ config.host	(working copy)
@@ -106,6 +106,19 @@
     ;;
 esac
 
+case ${host} in
+  rs6000-*-* \
+  | powerpc*-*-* )
+    case ${target} in
+      rs6000-*-* \
+      | powerpc*-*-* )
+        host_extra_gcc_objs="driver-rs6000.o"
+        host_xmake_file="${host_xmake_file} rs6000/x-rs6000"
+        ;;
+    esac
+    ;;
+esac
+
 # Machine-specific settings.
 case ${host} in
   alpha*-dec-*vms*)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]