diff options
Diffstat (limited to 'debian/patches/gcc-lto-jobserver.diff')
-rw-r--r-- | debian/patches/gcc-lto-jobserver.diff | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/debian/patches/gcc-lto-jobserver.diff b/debian/patches/gcc-lto-jobserver.diff new file mode 100644 index 0000000..82dd009 --- /dev/null +++ b/debian/patches/gcc-lto-jobserver.diff @@ -0,0 +1,499 @@ +# DP: Backport LTO jobserver support. + +f12fbeb535f192f742025cc4f9b69a48136730f1 +e63ca5570db076ec7b7bdfa55d51ef6f654d9412 +d25b1154d110c5403525b66fa54c5aefddd50de7 +907e3499443d0e441fcb3b7575d6432598413bff +567ef43c98f6783dde4290467476f8de389c3c10 +267389902a985871dd172ab5c5b651f0cd082290 +5aa3a1348175aff8d670cb9d0fb5f28444e84aa5 + +gcc/ + +2019-07-30 Martin Liska <mliska@suse.cz> + + * doc/invoke.texi: Document new behavior. + * lto-wrapper.c (cpuset_popcount): New function + is a copy of libgomp/config/linux/proc.c. + (init_num_threads): Likewise. + (run_gcc): Automatically detect core count for -flto. + (jobserver_active_p): New function. + +2019-08-02 Martin Liska <mliska@suse.cz> + + PR lto/91313 + * gcc.c (driver::maybe_run_linker): Call detect_jobserver + to detect working job server. + (driver::detect_jobserver): Test whether jobserver + is active from GCC driver. That will prevent situation where + GCC is invoked from a LD plugin and the linker already uses + file descriptors suggested by make. That leads to a wrong + detection. + * gcc.h (driver): Add detect_jobserver. + * lto-wrapper.c (jobserver_active_p): Simplify sscanf by + not scanning for --jobserver-auth prefix. + +2019-08-08 Martin Liska <mliska@suse.cz> + + PR bootstrap/91352 + * gcc.c (driver::detect_jobserver): Use is_valid_fd. + * lto-wrapper.c (jobserver_active_p): Likewise. + +2019-08-09 Martin Liska <mliska@suse.cz> + + * opts.c (common_handle_option): Error for an invalid argument + to -flto=. + +2019-08-09 Martin Liska <mliska@suse.cz> + + * doc/invoke.texi: Document the option value. + * lto-wrapper.c (run_gcc): Set auto_parallel + only with -flto=auto. + +2019-08-23 Martin Liska <mliska@suse.cz> + + * lto-wrapper.c (run_gcc): When setting jobserver + set also parallel to 1. This was done so before r273908. + +gcc/testsuite/ + +2019-08-09 Martin Liska <mliska@suse.cz> + + * gcc.dg/spellcheck-options-21.c: New test. + +2019-08-09 Martin Liska <mliska@suse.cz> + + * g++.dg/lto/devirt-19_0.C: Add -flto=auto. + +include/ + +2019-08-08 Martin Liska <mliska@suse.cz> + + PR bootstrap/91352 + * libiberty.h (is_valid_fd): New function. + +libiberty/ + +2019-08-08 Martin Liska <mliska@suse.cz> + + PR bootstrap/91352 + * lrealpath.c (is_valid_fd): New function. + +2019-08-12 Martin Liska <mliska@suse.cz> + + * Makefile.in: Add filedescriptor.c. + * filedescriptor.c: New file. + * lrealpath.c (is_valid_fd): Remove. + + + +--- a/src/gcc/gcc.c ++++ b/src/gcc/gcc.c +@@ -8261,6 +8261,8 @@ driver::maybe_run_linker (const char *ar + { + int tmp = execution_count; + ++ detect_jobserver (); ++ + if (! have_c) + { + #if HAVE_LTO_PLUGIN > 0 +@@ -8350,6 +8352,46 @@ driver::final_actions () const + } + } + ++/* Detect whether jobserver is active and working. If not drop ++ --jobserver-auth from MAKEFLAGS. */ ++ ++void ++driver::detect_jobserver () const ++{ ++ /* Detect jobserver and drop it if it's not working. */ ++ const char *makeflags = env.get ("MAKEFLAGS"); ++ if (makeflags != NULL) ++ { ++ const char *needle = "--jobserver-auth="; ++ const char *n = strstr (makeflags, needle); ++ if (n != NULL) ++ { ++ int rfd = -1; ++ int wfd = -1; ++ ++ bool jobserver ++ = (sscanf (n + strlen (needle), "%d,%d", &rfd, &wfd) == 2 ++ && rfd > 0 ++ && wfd > 0 ++ && is_valid_fd (rfd) ++ && is_valid_fd (wfd)); ++ ++ /* Drop the jobserver if it's not working now. */ ++ if (!jobserver) ++ { ++ unsigned offset = n - makeflags; ++ char *dup = xstrdup (makeflags); ++ dup[offset] = '\0'; ++ ++ const char *space = strchr (makeflags + offset, ' '); ++ if (space != NULL) ++ strcpy (dup + offset, space); ++ xputenv (concat ("MAKEFLAGS=", dup, NULL)); ++ } ++ } ++ } ++} ++ + /* Determine what the exit code of the driver should be. */ + + int +--- a/src/gcc/gcc.h ++++ b/src/gcc/gcc.h +@@ -51,6 +51,7 @@ class driver + void do_spec_on_infiles () const; + void maybe_run_linker (const char *argv0) const; + void final_actions () const; ++ void detect_jobserver () const; + int get_exit_code () const; + + private: +--- a/src/gcc/lto-wrapper.c ++++ b/src/gcc/lto-wrapper.c +@@ -1106,6 +1106,136 @@ cmp_priority (const void *a, const void + return *((const int *)b)-*((const int *)a); + } + ++/* Number of CPUs that can be used for parallel LTRANS phase. */ ++ ++static unsigned long nthreads_var = 0; ++ ++#ifdef HAVE_PTHREAD_AFFINITY_NP ++unsigned long cpuset_size; ++static unsigned long get_cpuset_size; ++cpu_set_t *cpusetp; ++ ++unsigned long ++static cpuset_popcount (unsigned long cpusetsize, cpu_set_t *cpusetp) ++{ ++#ifdef CPU_COUNT_S ++ /* glibc 2.7 and above provide a macro for this. */ ++ return CPU_COUNT_S (cpusetsize, cpusetp); ++#else ++#ifdef CPU_COUNT ++ if (cpusetsize == sizeof (cpu_set_t)) ++ /* glibc 2.6 and above provide a macro for this. */ ++ return CPU_COUNT (cpusetp); ++#endif ++ size_t i; ++ unsigned long ret = 0; ++ STATIC_ASSERT (sizeof (cpusetp->__bits[0]) == sizeof (unsigned long int)); ++ for (i = 0; i < cpusetsize / sizeof (cpusetp->__bits[0]); i++) ++ { ++ unsigned long int mask = cpusetp->__bits[i]; ++ if (mask == 0) ++ continue; ++ ret += __builtin_popcountl (mask); ++ } ++ return ret; ++#endif ++} ++#endif ++ ++/* At startup, determine the default number of threads. It would seem ++ this should be related to the number of cpus online. */ ++ ++static void ++init_num_threads (void) ++{ ++#ifdef HAVE_PTHREAD_AFFINITY_NP ++#if defined (_SC_NPROCESSORS_CONF) && defined (CPU_ALLOC_SIZE) ++ cpuset_size = sysconf (_SC_NPROCESSORS_CONF); ++ cpuset_size = CPU_ALLOC_SIZE (cpuset_size); ++#else ++ cpuset_size = sizeof (cpu_set_t); ++#endif ++ ++ cpusetp = (cpu_set_t *) xmalloc (gomp_cpuset_size); ++ do ++ { ++ int ret = pthread_getaffinity_np (pthread_self (), gomp_cpuset_size, ++ cpusetp); ++ if (ret == 0) ++ { ++ /* Count only the CPUs this process can use. */ ++ nthreads_var = cpuset_popcount (cpuset_size, cpusetp); ++ if (nthreads_var == 0) ++ break; ++ get_cpuset_size = cpuset_size; ++#ifdef CPU_ALLOC_SIZE ++ unsigned long i; ++ for (i = cpuset_size * 8; i; i--) ++ if (CPU_ISSET_S (i - 1, cpuset_size, cpusetp)) ++ break; ++ cpuset_size = CPU_ALLOC_SIZE (i); ++#endif ++ return; ++ } ++ if (ret != EINVAL) ++ break; ++#ifdef CPU_ALLOC_SIZE ++ if (cpuset_size < sizeof (cpu_set_t)) ++ cpuset_size = sizeof (cpu_set_t); ++ else ++ cpuset_size = cpuset_size * 2; ++ if (cpuset_size < 8 * sizeof (cpu_set_t)) ++ cpusetp ++ = (cpu_set_t *) realloc (cpusetp, cpuset_size); ++ else ++ { ++ /* Avoid fatal if too large memory allocation would be ++ requested, e.g. kernel returning EINVAL all the time. */ ++ void *p = realloc (cpusetp, cpuset_size); ++ if (p == NULL) ++ break; ++ cpusetp = (cpu_set_t *) p; ++ } ++#else ++ break; ++#endif ++ } ++ while (1); ++ cpuset_size = 0; ++ nthreads_var = 1; ++ free (cpusetp); ++ cpusetp = NULL; ++#endif ++#ifdef _SC_NPROCESSORS_ONLN ++ nthreads_var = sysconf (_SC_NPROCESSORS_ONLN); ++#endif ++} ++ ++/* FIXME: once using -std=c11, we can use std::thread::hardware_concurrency. */ ++ ++/* Return true when a jobserver is running and can accept a job. */ ++ ++static bool ++jobserver_active_p (void) ++{ ++ const char *makeflags = getenv ("MAKEFLAGS"); ++ if (makeflags == NULL) ++ return false; ++ ++ const char *needle = "--jobserver-auth="; ++ const char *n = strstr (makeflags, needle); ++ if (n == NULL) ++ return false; ++ ++ int rfd = -1; ++ int wfd = -1; ++ ++ return (sscanf (n + strlen (needle), "%d,%d", &rfd, &wfd) == 2 ++ && rfd > 0 ++ && wfd > 0 ++ && is_valid_fd (rfd) ++ && is_valid_fd (wfd)); ++} + + /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */ + +@@ -1120,6 +1250,7 @@ run_gcc (unsigned argc, char *argv[]) + const char *collect_gcc, *collect_gcc_options; + int parallel = 0; + int jobserver = 0; ++ int auto_parallel = 0; + bool no_partition = false; + struct cl_decoded_option *fdecoded_options = NULL; + struct cl_decoded_option *offload_fdecoded_options = NULL; +@@ -1243,8 +1374,13 @@ run_gcc (unsigned argc, char *argv[]) + case OPT_flto_: + if (strcmp (option->arg, "jobserver") == 0) + { ++ parallel = 1; + jobserver = 1; ++ } ++ else if (strcmp (option->arg, "auto") == 0) ++ { + parallel = 1; ++ auto_parallel = 1; + } + else + { +@@ -1286,8 +1422,14 @@ run_gcc (unsigned argc, char *argv[]) + { + lto_mode = LTO_MODE_LTO; + jobserver = 0; ++ auto_parallel = 0; + parallel = 0; + } ++ else if (!jobserver && jobserver_active_p ()) ++ { ++ parallel = 1; ++ jobserver = 1; ++ } + + if (linker_output) + { +@@ -1479,7 +1621,21 @@ cont1: + strcpy (tmp, ltrans_output_file); + + if (jobserver) +- obstack_ptr_grow (&argv_obstack, xstrdup ("-fwpa=jobserver")); ++ { ++ if (verbose) ++ fprintf (stderr, "Using make jobserver\n"); ++ obstack_ptr_grow (&argv_obstack, xstrdup ("-fwpa=jobserver")); ++ } ++ else if (auto_parallel) ++ { ++ char buf[256]; ++ init_num_threads (); ++ if (verbose) ++ fprintf (stderr, "LTO parallelism level set to %ld\n", ++ nthreads_var); ++ sprintf (buf, "-fwpa=%ld", nthreads_var); ++ obstack_ptr_grow (&argv_obstack, xstrdup (buf)); ++ } + else if (parallel > 1) + { + char buf[256]; +@@ -1687,7 +1843,8 @@ cont: + i = 3; + if (!jobserver) + { +- snprintf (jobs, 31, "-j%d", parallel); ++ snprintf (jobs, 31, "-j%ld", ++ auto_parallel ? nthreads_var : parallel); + new_argv[i++] = jobs; + } + new_argv[i++] = "all"; +--- a/src/gcc/opts.c ++++ b/src/gcc/opts.c +@@ -2738,6 +2738,15 @@ common_handle_option (struct gcc_options + opts->x_flag_lto = value ? "" : NULL; + break; + ++ case OPT_flto_: ++ if (strcmp (arg, "none") != 0 ++ && strcmp (arg, "jobserver") != 0 ++ && strcmp (arg, "auto") != 0 ++ && atoi (arg) == 0) ++ error_at (loc, ++ "unrecognized argument to %<-flto=%> option: %qs", arg); ++ break; ++ + case OPT_w: + dc->dc_inhibit_warnings = true; + break; +--- a/src/gcc/testsuite/g++.dg/lto/devirt-19_0.C ++++ b/src/gcc/testsuite/g++.dg/lto/devirt-19_0.C +@@ -1,5 +1,5 @@ + /* { dg-lto-do link } */ + /* { dg-lto-options { "-O2 -fdump-ipa-cp -Wno-return-type -flto -r -nostdlib" } } */ +-/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */ ++/* { dg-extra-ld-options "-flinker-output=nolto-rel -flto=auto" } */ + #include "../ipa/devirt-19.C" + /* { dg-final { scan-wpa-ipa-dump-times "Discovered a virtual call to a known target" 1 "cp" } } */ +--- /dev/null ++++ b/src/gcc/testsuite/gcc.dg/spellcheck-options-21.c +@@ -0,0 +1,3 @@ ++/* { dg-do compile } */ ++/* { dg-options "-flto=sparta" } */ ++/* { dg-error "unrecognized argument to '-flto=' option: 'sparta'" "" { target *-*-* } 0 } */ +--- a/src/include/libiberty.h ++++ b/src/include/libiberty.h +@@ -137,6 +137,10 @@ extern const char *unix_lbasename (const + + extern char *lrealpath (const char *); + ++/* Return true when FD file descriptor exists. */ ++ ++extern int is_valid_fd (int fd); ++ + /* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using xmalloc. */ +--- a/src/libiberty/Makefile.in ++++ b/src/libiberty/Makefile.in +@@ -127,7 +127,7 @@ CFILES = alloca.c argv.c asprintf.c atex + calloc.c choose-temp.c clock.c concat.c cp-demangle.c \ + cp-demint.c cplus-dem.c crc32.c \ + d-demangle.c dwarfnames.c dyn-string.c \ +- fdmatch.c ffs.c fibheap.c filename_cmp.c floatformat.c \ ++ fdmatch.c ffs.c fibheap.c filedescriptor.c filename_cmp.c floatformat.c \ + fnmatch.c fopen_unlocked.c \ + getcwd.c getopt.c getopt1.c getpagesize.c getpwd.c getruntime.c \ + gettimeofday.c \ +@@ -171,6 +171,7 @@ REQUIRED_OFILES = \ + ./cp-demint.$(objext) ./crc32.$(objext) ./d-demangle.$(objext) \ + ./dwarfnames.$(objext) ./dyn-string.$(objext) \ + ./fdmatch.$(objext) ./fibheap.$(objext) \ ++ ./filedescriptor.$(objext) \ + ./filename_cmp.$(objext) ./floatformat.$(objext) \ + ./fnmatch.$(objext) ./fopen_unlocked.$(objext) \ + ./getopt.$(objext) ./getopt1.$(objext) ./getpwd.$(objext) \ +@@ -756,6 +757,17 @@ $(CONFIGURED_OFILES): stamp-picdir stamp + else true; fi + $(COMPILE.c) $(srcdir)/fibheap.c $(OUTPUT_OPTION) + ++./filedescriptor.$(objext): $(srcdir)/filedescriptor.c config.h $(INCDIR)/ansidecl.h \ ++ $(INCDIR)/libiberty.h ++ if [ x"$(PICFLAG)" != x ]; then \ ++ $(COMPILE.c) $(PICFLAG) $(srcdir)/filedescriptor.c -o pic/$@; \ ++ else true; fi ++ if [ x"$(NOASANFLAG)" != x ]; then \ ++ $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/filedescriptor.c -o noasan/$@; \ ++ else true; fi ++ $(COMPILE.c) $(srcdir)/filedescriptor.c $(OUTPUT_OPTION) ++ ++ + ./filename_cmp.$(objext): $(srcdir)/filename_cmp.c config.h $(INCDIR)/ansidecl.h \ + $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ + $(INCDIR)/safe-ctype.h +--- /dev/null ++++ b/src/libiberty/filedescriptor.c +@@ -0,0 +1,47 @@ ++/* File descriptor related functions. ++ ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ ++ This file is part of the libiberty library. ++ ++ This program 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 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, ++ Boston, MA 02110-1301, USA. */ ++ ++#include "config.h" ++#include "ansidecl.h" ++#include "libiberty.h" ++ ++#ifdef HAVE_FCNTL_H ++#include <fcntl.h> ++#endif ++ ++#if defined (_WIN32) ++#define WIN32_LEAN_AND_MEAN ++#include <windows.h> /* for GetFullPathName */ ++#endif ++/* Return true when FD file descriptor exists. */ ++ ++int ++is_valid_fd (int fd) ++{ ++#if defined(_WIN32) ++ HANDLE h = (HANDLE) _get_osfhandle (fd); ++ return h != (HANDLE) -1; ++#elif defined(F_GETFD) ++ return fcntl (fd, F_GETFD) >= 0; ++#else ++ return dup2 (fd, fd) < 0; ++#endif ++} |