From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10877 invoked by alias); 6 Aug 2007 20:45:00 -0000 Received: (qmail 10644 invoked by uid 22791); 6 Aug 2007 20:44:58 -0000 X-Spam-Check-By: sourceware.org Received: from igw2.watson.ibm.com (HELO igw2.watson.ibm.com) (129.34.20.6) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 06 Aug 2007 20:44:49 +0000 Received: from mailhub4.watson.ibm.com (mailhub4.watson.ibm.com [129.34.20.46]) by igw2.watson.ibm.com (8.13.1/8.13.1/8.13.1-2005-04-25 igw) with ESMTP id l76KkN3j029657 for ; Mon, 6 Aug 2007 16:46:23 -0400 Received: from mailhub4.watson.ibm.com (localhost.localdomain [127.0.0.1]) by mailhub4.watson.ibm.com (8.13.1/8.13.1/8.13.1-01-23-2007-Delivery) with ESMTP id l76KikqE025459 for ; Mon, 6 Aug 2007 16:44:46 -0400 Received: from mgsmtp00.watson.ibm.com (mgsmtp00.watson.ibm.com [9.2.40.58]) by mailhub4.watson.ibm.com (8.13.1/8.13.1/8.13.1-01-23-2007-IMSS) with ESMTP id l76Kikpw025456 for ; Mon, 6 Aug 2007 16:44:46 -0400 Received: from makai.watson.ibm.com (makai.watson.ibm.com [9.2.216.144]) by mgsmtp00.watson.ibm.com (8.12.11/8.12.11/2005/09/01) with ESMTP id l76JX70a026357 for ; Mon, 6 Aug 2007 15:33:07 -0400 Received: from watson.ibm.com (localhost [127.0.0.1]) by makai.watson.ibm.com (AIX5.3/8.13.4/8.13.4/03-06-2002) with ESMTP id l76KjhhY029738 for ; Mon, 6 Aug 2007 16:45:43 -0400 Message-Id: <200708062045.l76KjhhY029738@makai.watson.ibm.com> To: gcc-patches@gcc.gnu.org Subject: [RFC] PowerPC processor and cache detection Date: Mon, 06 Aug 2007 20:45:00 -0000 From: David Edelsohn Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2007-08/txt/msg00388.txt.bz2 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:%. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include + +#ifdef _AIX +# include +#endif + +#ifdef __ELF__ +# include +#endif + +#ifdef __APPLE__ +# include +# include +#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*)