diff mbox

Support -mcpu=native on Solaris/SPARC

Message ID yddsjprddlx.fsf@manam.CeBiTec.Uni-Bielefeld.DE
State New
Headers show

Commit Message

Rainer Orth July 27, 2011, 2:04 p.m. UTC
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 mbox

Patch

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)