This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Support -mcpu=native on Solaris/SPARC
- From: Rainer Orth <ro at CeBiTec dot Uni-Bielefeld dot DE>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Eric Botcazou <ebotcazou at adacore dot com>, Paolo Bonzini <bonzini at gnu dot org>
- Date: Wed, 27 Jul 2011 16:04:10 +0200
- Subject: Support -mcpu=native on Solaris/SPARC
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
failures for -gdwarf-2 -g3 tests, but suppose they are related to recent
debug patches.
Comments, suggestions?
Thanks.
Rainer
2011-07-27 Rainer Orth <ro@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/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,171 @@
+/* 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__
+/* FIXME: Possible values for pre-UltraSPARC CPUs?
+
+ SuperSPARC
+ SuperSPARC II
+ microSPARC
+ microSPARC II
+ hyperSPARC
+ hyperSPARC II
+
+ FMI,MB86904
+ FMI,MB86907=FMI,MB86904
+ Ross,RT623=Ross,RT625
+ Ross,RT625
+ Ross,RT626=Ross,RT625
+ TI,TMS390S10
+ TI,TMS390Z50=TI,TMS390Z55
+ TI,TMS390Z55 */
+
+ { "", "v7" }, /* Generic cpu values probably unnecessary. */
+ { "", "cypress" }, /* Irrelevant for Solaris 8+. */
+ { "", "v8" },
+ { "SuperSPARC", "supersparc" },
+ { "hyperSPARC", "hypersparc" },
+ { "", "leon" }, /* Probably irrelevant for Solaris. */
+ { "", "sparclite" },
+ { "", "f930" },
+ { "", "f934" },
+ { "", "sparclite86x" },
+ { "", "tsc701" },
+ { "", "v9" },
+ { "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)
+ 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"));
+ if (brand != NULL && brand->data_type == KSTAT_DATA_STRING)
+ buf = KSTAT_NAMED_STR_PTR (brand);
+ }
+ 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.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