Rainer Orth <r...@cebitec.uni-bielefeld.de> writes: > This is a first cut at supporting -mcpu=native/-mtune=native on > Solaris/SPARC. Unlike it's Tru64 UNIX/Alpha and IRIX/MIPS (to be > submitted soon) counterparts, it's a bit more involved: > > * There's no support for -mcpu=native in the SPARC port yet. > > * Access to the %ver register is privileged, so we need OS interfaces to > access the information. I couldn't find anything in libc. While the > AT_SUN_CPU file from <sys/auxv.h> might fill the bill, it isn't > actually set according to pargs -x. > > There seem to be two options: libkstat and libpicl. The former has > the advantage that it's a tad better documented and talks directly to > the kernel, while the latter needs picld, which seems overkill. Both > are present in Solaris 8, though. > > I prefer the cpu_info:::brand kstat over cpu_info:::implementation: > > The former looks like (from kstat -p cpu_info:::brand): > > cpu_info:0:cpu_info0:brand UltraSPARC-T2 > > compared to > > cpu_info:0:cpu_info0:implementation UltraSPARC-T2 (chipid 0, clock 1165 > MHz) > > but brand was only introduced in Solaris 10. Before that, only > implementation existed with this contents: > > cpu_info:0:cpu_info0:implementation UltraSPARC-IIIi > > * Unlike IRIX and Tru64 UNIX, where the respective interfaces return a > numeric identifier for the cpu type from a finite range, on SPARC we > get string names, and I'm having some trouble determining the complete > set. The patch below is based on what I've found so far, but > certainly needs to be augmented for sun4m cpus which I don't have any > longer. > > * The requirement to link the drivers with an additional library > (-lkstat) prompted me to introduce GCC_EXTRA_LIBS. I didn't want to > link the backends with -lkstat since they don't need it. The build > maintainers may not like the way this was done, though. > > * Right now, this is Solaris-only since I have no idea what > /proc/cpuinfo on Linux/SPARC contains. > > With all those caveats, the patch has been run through a C-only > non-bootstrap build on sparc-sun-solaris2.11 so far. > -mcpu=native/-mtune=native seem to work as expected, though I'll have to > broaden the range of OS versions tested. I'm seeing tons of testsuite
Here's an updated version of the patch, containing two changes: * Solaris 8 doesn't support KSTAT_DATA_STRING. * I've updated the list of known cpu types, based on the /platform/sun4?/kernel/cpu{, /sparcv9} entries found in Solaris 8, 9, 10 and 11. It seems that the vendor field sometimes present there (SUNW, TI, Ross, ...) is consistently absent in the kstat output. While I could confirm this on all sun4u/sun4v system we have, I don't have access to sun4m machines any longer, so it's just a guess. Bootstrapped without regressions no sparc-sun-solaris2.{8, 9, 10, 11} without regressions (Solaris 8 bootstrap still running), -mcpu is correctly detected everywhere. Ok for mainline? Thanks. Rainer 2011-07-27 Rainer Orth <r...@cebitec.uni-bielefeld.de> gcc: * config/sparc/driver-sparc.c: New file. * config/sparc/x-sparc: New file. * config.host: Use driver-sparc.o, sparc/x-sparc on sparc*-*-solaris2*. * config/sparc/sparc.opt (native): New value for enum processor_type. * config/sparc/sparc-opts.h (PROCESSOR_NATIVE): Declare. * config/sparc/sparc.c (sparc_option_override): Abort if PROCESSOR_NATIVE gets here. * config/sparc/sol2.h [__sparc__] (host_detect_local_cpu): Declare. (EXTRA_SPEC_FUNCTIONS, MCPU_MTUNE_NATIVE_SPECS, DRIVER_SELF_SPECS): Define. * configure.ac (EXTRA_GCC_LIBS): Check for libkstat. Substitute result. * configure: Regenerate. * Makefile.in (EXTRA_GCC_LIBS): Set. (xgcc$(exeext)): Add $(EXTRA_GCC_LIBS). (cpp$(exeext)): Likewise. gcc/cp: * Make-lang.in (g++$(exeext)): Add $(EXTRA_GCC_LIBS). gcc/fortran: * Make-lang.in (gfortran$(exeext)): Add $(EXTRA_GCC_LIBS). gcc/go: * Make-lang.in (gccgo$(exeext)): Add $(EXTRA_GCC_LIBS). gcc/java: * Make-lang.in ($(XGCJ)$(exeext)): Add $(EXTRA_GCC_LIBS). diff --git a/gcc/Makefile.in b/gcc/Makefile.in --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -723,6 +723,9 @@ EXTRA_OBJS = @extra_objs@ # the gcc driver. EXTRA_GCC_OBJS =@extra_gcc_objs@ +# List of extra libraries that should be linked with the gcc driver. +EXTRA_GCC_LIBS = @EXTRA_GCC_LIBS@ + # List of additional header files to install. EXTRA_HEADERS =@extra_headers_list@ @@ -1828,7 +1831,8 @@ libcommon.a: $(OBJS-libcommon) xgcc$(exeext): $(GCC_OBJS) gccspec.o libcommon-target.a $(LIBDEPS) \ $(EXTRA_GCC_OBJS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ $(GCC_OBJS) \ - gccspec.o $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBS) + gccspec.o $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) # cpp is to cpp0 as gcc is to cc1. # The only difference from xgcc is that it's linked with cppspec.o @@ -1836,7 +1840,8 @@ xgcc$(exeext): $(GCC_OBJS) gccspec.o lib cpp$(exeext): $(GCC_OBJS) cppspec.o libcommon-target.a $(LIBDEPS) \ $(EXTRA_GCC_OBJS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ $(GCC_OBJS) \ - cppspec.o $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBS) + cppspec.o $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) # Dump a specs file to make -B./ read these specs over installed ones. $(SPECS): xgcc$(exeext) diff --git a/gcc/config.host b/gcc/config.host --- a/gcc/config.host +++ b/gcc/config.host @@ -157,6 +157,14 @@ case ${host} in ;; esac ;; + sparc*-*-solaris2*) + case ${target} in + sparc*-*-solaris2*) + host_extra_gcc_objs="driver-sparc.o" + host_xmake_file="${host_xmake_file} sparc/x-sparc" + ;; + esac + ;; esac # Machine-specific settings. diff --git a/gcc/config/sparc/driver-sparc.c b/gcc/config/sparc/driver-sparc.c new file mode 100644 --- /dev/null +++ b/gcc/config/sparc/driver-sparc.c @@ -0,0 +1,158 @@ +/* Subroutines for the gcc driver. + Copyright (C) 2011 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" + +static const struct cpu_names { + const char *const name; + const char *const cpu; +} cpu_names[] = { +#if defined __sun__ && defined __svr4__ + { "TMS390S10", "supersparc" }, /* Texas Instruments microSPARC I */ + { "TMS390Z50", "supersparc" }, /* Texas Instruments SuperSPARC I */ + { "TMS390Z55", "supersparc" }, /* Texas Instruments + SuperSPARC I with SuperCache */ + { "MB86904", "supersparc" }, /* Fujitsu microSPARC II */ + { "MB86907", "supersparc" }, /* Fujitsu TurboSPARC */ + { "RT623", "hypersparc" }, /* Ross hyperSPARC */ + { "RT625", "hypersparc" }, + { "RT626", "hypersparc" }, + { "UltraSPARC-I", "ultrasparc" }, + { "UltraSPARC-II", "ultrasparc" }, + { "UltraSPARC-IIe", "ultrasparc" }, + { "UltraSPARC-IIi", "ultrasparc" }, + { "SPARC64-III", "ultrasparc" }, + { "SPARC64-IV", "ultrasparc" }, + { "UltraSPARC-III", "ultrasparc3" }, + { "UltraSPARC-III+", "ultrasparc3" }, + { "UltraSPARC-IIIi", "ultrasparc3" }, + { "UltraSPARC-IIIi+", "ultrasparc3" }, + { "UltraSPARC-IV", "ultrasparc3" }, + { "UltraSPARC-IV+", "ultrasparc3" }, + { "SPARC64-V", "ultrasparc3" }, + { "SPARC64-VI", "ultrasparc3" }, + { "SPARC64-VII", "ultrasparc3" }, + { "UltraSPARC-T1", "niagara" }, + { "UltraSPARC-T2", "niagara2" }, + { "UltraSPARC-T2", "niagara2" }, + { "UltraSPARC-T2+", "niagara2" }, + { "SPARC-T3", "niagara2" }, + { "SPARC-T4", "niagara2" }, +#else + /* FIXME: Provide Linux/SPARC values. */ +#endif + { NULL, NULL } + }; + +#if defined __sun__ && defined __svr4__ +#include <kstat.h> +#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 "cpu" or "tune" as argument depending on if -mcpu=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. E.g. "-mcpu=ultrasparc3" on an UltraSPARC III for + -mcpu=native. If the routine can't detect a known processor, + the -mcpu or -mtune option is discarded. + + 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; +#if defined __sun__ && defined __svr4__ + char *buf = NULL; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *brand = NULL; +#else + char buf[128]; + FILE *f; +#endif + int i; + + if (argc < 1) + return NULL; + + if (strcmp (argv[0], "cpu") && strcmp (argv[0], "tune")) + return NULL; + +#if defined __sun__ && defined __svr4__ + kc = kstat_open (); + if (kc != NULL) + { + ksp = kstat_lookup (kc, CONST_CAST2 (char *, const char *, "cpu_info"), + -1, NULL); + if (ksp != NULL + && kstat_read (kc, ksp, NULL) != -1 + && ksp->ks_type == KSTAT_TYPE_NAMED) + brand = (kstat_named_t *) + kstat_data_lookup (ksp, CONST_CAST2 (char *, const char *, "brand")); + /* "brand" was only introduced in Solaris 10. */ + if (brand == NULL) + brand = (kstat_named_t *) + kstat_data_lookup (ksp, CONST_CAST2 (char *, const char *, + "implementation")); + /* KSTAT_DATA_STRING was introduced in Solaris 9. */ +#ifdef KSTAT_DATA_STRING + if (brand != NULL && brand->data_type == KSTAT_DATA_STRING) + buf = KSTAT_NAMED_STR_PTR (brand); +#else + if (brand != NULL && brand->data_type == KSTAT_DATA_CHAR) + buf = brand->value.c; +#endif + } + kstat_close (kc); + + for (i = 0; cpu_names[i].name != NULL; i++) + if (strcmp (buf, cpu_names[i].name) == 0) + cpu = cpu_names[i].cpu; +#else + f = fopen ("/proc/cpuinfo", "r"); + if (f == NULL) + return NULL; + + while (fgets (buf, sizeof (buf), f) != NULL) + if (strncmp (buf, "cpu model", sizeof ("cpu model") - 1) == 0) + { + for (i = 0; cpu_names [i].name; i++) + if (strstr (buf, cpu_names [i].name) != NULL) + { + cpu = cpu_names [i].cpu; + break; + } + break; + } + + fclose (f); +#endif + + if (cpu == NULL) + return NULL; + + return concat ("-m", argv[0], "=", cpu, NULL); +} diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h --- a/gcc/config/sparc/sol2.h +++ b/gcc/config/sparc/sol2.h @@ -157,6 +157,22 @@ along with GCC; see the file COPYING3. %{!m32:%{!m64:%(cpp_arch_default)}} \ " +/* -mcpu=native handling only makes sense with compiler running on + a SPARC chip. */ +#if defined(__sparc__) +extern const char *host_detect_local_cpu (int argc, const char **argv); +# define EXTRA_SPEC_FUNCTIONS \ + { "local_cpu_detect", host_detect_local_cpu }, + +# define MCPU_MTUNE_NATIVE_SPECS \ + " %{mcpu=native:%<mcpu=native %:local_cpu_detect(cpu)}" \ + " %{mtune=native:%<mtune=native %:local_cpu_detect(tune)}" +#else +# define MCPU_MTUNE_NATIVE_SPECS "" +#endif + +#define DRIVER_SELF_SPECS MCPU_MTUNE_NATIVE_SPECS + #undef CC1_SPEC #if DEFAULT_ARCH32_P #define CC1_SPEC "\ diff --git a/gcc/config/sparc/sparc-opts.h b/gcc/config/sparc/sparc-opts.h --- a/gcc/config/sparc/sparc-opts.h +++ b/gcc/config/sparc/sparc-opts.h @@ -41,7 +41,8 @@ enum processor_type { PROCESSOR_ULTRASPARC, PROCESSOR_ULTRASPARC3, PROCESSOR_NIAGARA, - PROCESSOR_NIAGARA2 + PROCESSOR_NIAGARA2, + PROCESSOR_NATIVE }; #endif diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -911,6 +911,8 @@ sparc_option_override (void) case PROCESSOR_NIAGARA2: sparc_costs = &niagara2_costs; break; + case PROCESSOR_NATIVE: + gcc_unreachable (); }; #ifdef TARGET_DEFAULT_LONG_DOUBLE_128 diff --git a/gcc/config/sparc/sparc.opt b/gcc/config/sparc/sparc.opt --- a/gcc/config/sparc/sparc.opt +++ b/gcc/config/sparc/sparc.opt @@ -101,6 +101,9 @@ Enum Name(sparc_processor_type) Type(enum processor_type) EnumValue +Enum(sparc_processor_type) String(native) Value(PROCESSOR_NATIVE) DriverOnly + +EnumValue Enum(sparc_processor_type) String(v7) Value(PROCESSOR_V7) EnumValue diff --git a/gcc/config/sparc/x-sparc b/gcc/config/sparc/x-sparc new file mode 100644 --- /dev/null +++ b/gcc/config/sparc/x-sparc @@ -0,0 +1,3 @@ +driver-sparc.o: $(srcdir)/config/sparc/driver-sparc.c \ + $(CONFIG_H) $(SYSTEM_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< diff --git a/gcc/configure.ac b/gcc/configure.ac --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -970,6 +970,14 @@ GNAT_LIBEXC="$LIBS" LIBS="$save_LIBS" AC_SUBST(GNAT_LIBEXC) +# To support -mcpu=native on Solaris/SPARC, we need libkstat. +save_LIBS="$LIBS" +LIBS= +AC_SEARCH_LIBS(kstat_open, kstat) +EXTRA_GCC_LIBS="$LIBS" +LIBS="$save_LIBS" +AC_SUBST(EXTRA_GCC_LIBS) + # Some systems put ldexp and frexp in libm instead of libc; assume # they're both in the same place. jcf-dump needs them. save_LIBS="$LIBS" diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -63,7 +63,8 @@ g++spec.o: $(srcdir)/cp/g++spec.c $(SYST GXX_OBJS = $(GCC_OBJS) g++spec.o g++$(exeext): $(GXX_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ - $(GXX_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBS) + $(GXX_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) # Create a version of the g++ driver which calls the cross-compiler. g++-cross$(exeext): g++$(exeext) diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in --- a/gcc/fortran/Make-lang.in +++ b/gcc/fortran/Make-lang.in @@ -88,7 +88,8 @@ GFORTRAN_D_OBJS = $(GCC_OBJS) gfortransp gfortran$(exeext): $(GFORTRAN_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ $(LIBDEPS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ - $(GFORTRAN_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBS) + $(GFORTRAN_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) # Create a version of the gfortran driver which calls the cross-compiler. gfortran-cross$(exeext): gfortran$(exeext) diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -39,7 +39,8 @@ gospec.o: $(srcdir)/go/gospec.c $(SYSTEM GCCGO_OBJS = $(GCC_OBJS) gospec.o gccgo$(exeext): $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) $(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ - $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBS) + $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) # Use strict warnings. go-warn = $(STRICT_WARN) diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in --- a/gcc/java/Make-lang.in +++ b/gcc/java/Make-lang.in @@ -66,7 +66,8 @@ jvspec.o: $(srcdir)/java/jvspec.c $(SYST $(XGCJ)$(exeext): $(GCC_OBJS) jvspec.o java/jcf-path.o \ libcommon-target.a $(LIBDEPS) $(EXTRA_GCC_OBJS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ $(GCC_OBJS) \ - jvspec.o java/jcf-path.o $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBS) + jvspec.o java/jcf-path.o $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) # Create a version of the $(XGCJ) driver which calls the cross-compiler. $(XGCJ)-cross$(exeext): $(XGCJ)$(exeext) -- ----------------------------------------------------------------------------- Rainer Orth, Center for Biotechnology, Bielefeld University