Rainer Orth <[email protected]> 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 <[email protected]>
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