Mercurial > hg > CbC > CbC_gcc
diff gcc/lto-wrapper.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
line wrap: on
line diff
--- a/gcc/lto-wrapper.c Thu Oct 25 07:37:49 2018 +0900 +++ b/gcc/lto-wrapper.c Thu Feb 13 11:34:05 2020 +0900 @@ -1,5 +1,5 @@ /* Wrapper to call lto. Used by collect2 and the linker plugin. - Copyright (C) 2009-2018 Free Software Foundation, Inc. + Copyright (C) 2009-2020 Free Software Foundation, Inc. Factored out of collect2 by Rafael Espindola <espindola@google.com> @@ -71,7 +71,8 @@ static char **offload_names; static char *offload_objects_file_name; static char *makefile; -static char *debug_obj; +static unsigned int num_deb_objs; +static const char **early_debug_object_names; const char tool_name[] = "lto-wrapper"; @@ -90,8 +91,10 @@ maybe_unlink (offload_objects_file_name); if (makefile) maybe_unlink (makefile); - if (debug_obj) - maybe_unlink (debug_obj); + if (early_debug_object_names) + for (i = 0; i < num_deb_objs; ++i) + if (early_debug_object_names[i]) + maybe_unlink (early_debug_object_names[i]); for (i = 0; i < nr; ++i) { maybe_unlink (input_names[i]); @@ -125,12 +128,11 @@ #define DUMPBASE_SUFFIX ".ltrans18446744073709551615" /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS - environment according to LANG_MASK. */ + environment. */ static void get_options_from_collect_gcc_options (const char *collect_gcc, const char *collect_gcc_options, - unsigned int lang_mask, struct cl_decoded_option **decoded_options, unsigned int *decoded_options_count) { @@ -152,7 +154,8 @@ do { if (argv_storage[j] == '\0') - fatal_error (input_location, "malformed COLLECT_GCC_OPTIONS"); + fatal_error (input_location, + "malformed %<COLLECT_GCC_OPTIONS%>"); else if (strncmp (&argv_storage[j], "'\\''", 4) == 0) { argv_storage[k++] = '\''; @@ -172,8 +175,7 @@ argc = obstack_object_size (&argv_obstack) / sizeof (void *) - 1; argv = XOBFINISH (&argv_obstack, const char **); - decode_cmdline_options_to_array (argc, (const char **)argv, - lang_mask, + decode_cmdline_options_to_array (argc, (const char **)argv, CL_DRIVER, decoded_options, decoded_options_count); obstack_free (&argv_obstack, NULL); } @@ -245,7 +247,7 @@ { case OPT_SPECIAL_unknown: case OPT_SPECIAL_ignore: - case OPT_SPECIAL_deprecated: + case OPT_SPECIAL_warn_removed: case OPT_SPECIAL_program_name: case OPT_SPECIAL_input_file: break; @@ -263,6 +265,7 @@ case OPT_fshow_column: case OPT_fcommon: case OPT_fgnu_tm: + case OPT_g: /* Do what the old LTO code did - collect exactly one option setting per OPT code, we pick the first we encounter. ??? This doesn't make too much sense, but when it doesn't @@ -307,7 +310,7 @@ append_option (decoded_options, decoded_options_count, foption); else if (strcmp ((*decoded_options)[j].arg, foption->arg)) fatal_error (input_location, - "Option %s with different values", + "option %s with different values", foption->orig_option_with_args_text); break; @@ -391,7 +394,7 @@ append_option (decoded_options, decoded_options_count, foption); else if (foption->value != (*decoded_options)[j].value) fatal_error (input_location, - "Option %s not used consistently in all LTO input" + "option %s not used consistently in all LTO input" " files", foption->orig_option_with_args_text); break; @@ -405,7 +408,7 @@ /* Merge PIC options: -fPIC + -fpic = -fpic -fPIC + -fno-pic = -fno-pic - -fpic/-fPIC + nothin = nothing. + -fpic/-fPIC + nothing = nothing. It is a common mistake to mix few -fPIC compiled objects into otherwise non-PIC code. We do not want to build everything with PIC then. @@ -435,9 +438,10 @@ && pie_option->opt_index == OPT_fPIE; (*decoded_options)[j].opt_index = big ? OPT_fPIE : OPT_fpie; if (pie_option->value) - (*decoded_options)[j].canonical_option[0] = big ? "-fPIE" : "-fpie"; + (*decoded_options)[j].canonical_option[0] + = big ? "-fPIE" : "-fpie"; else - (*decoded_options)[j].canonical_option[0] = big ? "-fno-pie" : "-fno-pie"; + (*decoded_options)[j].canonical_option[0] = "-fno-pie"; (*decoded_options)[j].value = pie_option->value; j++; } @@ -479,7 +483,7 @@ { (*decoded_options)[j].opt_index = OPT_fpie; (*decoded_options)[j].canonical_option[0] - = pic_option->value ? "-fpie" : "-fno-pie"; + = pic_option->value ? "-fpie" : "-fno-pie"; } else if (!pic_option->value) (*decoded_options)[j].canonical_option[0] = "-fno-pie"; @@ -615,6 +619,7 @@ case OPT_fopenacc: case OPT_fopenacc_dim_: case OPT_foffload_abi_: + case OPT_g: case OPT_O: case OPT_Ofast: case OPT_Og: @@ -646,6 +651,7 @@ switch (option->opt_index) { case OPT_fdiagnostics_color_: + case OPT_fdiagnostics_format_: case OPT_fdiagnostics_show_caret: case OPT_fdiagnostics_show_labels: case OPT_fdiagnostics_show_line_numbers: @@ -818,8 +824,8 @@ if (!compiler) fatal_error (input_location, - "could not find %s in %s (consider using '-B')\n", suffix + 1, - compiler_path); + "could not find %s in %s (consider using %<-B%>)", + suffix + 1, compiler_path); /* Generate temporary output file name. */ filename = make_temp_file (".target.o"); @@ -899,7 +905,7 @@ linker_opts, linker_opt_count); if (!offload_names[next_name_entry]) fatal_error (input_location, - "problem with building target image for %s\n", names[i]); + "problem with building target image for %s", names[i]); next_name_entry++; } @@ -956,7 +962,7 @@ } if (i == n_paths) fatal_error (input_location, - "installation error, can't find crtoffloadtable.o"); + "installation error, cannot find %<crtoffloadtable.o%>"); free_array_of_ptrs ((void **) paths, n_paths); } @@ -1004,8 +1010,7 @@ { struct cl_decoded_option *f2decoded_options; unsigned int f2decoded_options_count; - get_options_from_collect_gcc_options (collect_gcc, - fopts, CL_LANG_ALL, + get_options_from_collect_gcc_options (collect_gcc, fopts, &f2decoded_options, &f2decoded_options_count); if (!fdecoded_options) @@ -1035,11 +1040,12 @@ const char * debug_objcopy (const char *infile, bool rename) { - const char *outfile; + char *outfile; const char *errmsg; int err; const char *p; + const char *orig_infile = infile; off_t inoff = 0; long loffset; int consumed; @@ -1067,19 +1073,27 @@ &off, &len, &errmsg, &err) != 1) { if (errmsg) - fatal_error (0, "%s: %s\n", errmsg, xstrerror (err)); + fatal_error (0, "%s: %s", errmsg, xstrerror (err)); simple_object_release_read (inobj); close (infd); return NULL; } - outfile = make_temp_file ("debugobjtem"); + if (save_temps) + { + outfile = (char *) xmalloc (strlen (orig_infile) + + sizeof (".debug.temp.o") + 1); + strcpy (outfile, orig_infile); + strcat (outfile, ".debug.temp.o"); + } + else + outfile = make_temp_file (".debug.temp.o"); errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err, rename); if (errmsg) { unlink_if_ordinary (outfile); - fatal_error (0, "%s: %s\n", errmsg, xstrerror (err)); + fatal_error (0, "%s: %s", errmsg, xstrerror (err)); } simple_object_release_read (inobj); @@ -1096,6 +1110,136 @@ 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. */ @@ -1110,6 +1254,7 @@ 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; @@ -1131,13 +1276,12 @@ collect_gcc = getenv ("COLLECT_GCC"); if (!collect_gcc) fatal_error (input_location, - "environment variable COLLECT_GCC must be set"); + "environment variable %<COLLECT_GCC%> must be set"); collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS"); if (!collect_gcc_options) fatal_error (input_location, - "environment variable COLLECT_GCC_OPTIONS must be set"); + "environment variable %<COLLECT_GCC_OPTIONS%> must be set"); get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options, - CL_LANG_ALL, &decoded_options, &decoded_options_count); @@ -1234,8 +1378,13 @@ 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 { @@ -1253,6 +1402,10 @@ linker_output_rel = !strcmp (option->arg, "rel"); break; + case OPT_g: + /* Recognize -g0. */ + skip_debug = option->arg && !strcmp (option->arg, "0"); + break; default: break; @@ -1277,8 +1430,14 @@ { 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) { @@ -1411,9 +1570,16 @@ if (lto_mode == LTO_MODE_LTO) { - flto_out = make_temp_file (".lto.o"); if (linker_output) - obstack_ptr_grow (&argv_obstack, linker_output); + { + obstack_ptr_grow (&argv_obstack, linker_output); + flto_out = (char *) xmalloc (strlen (linker_output) + + sizeof (".lto.o") + 1); + strcpy (flto_out, linker_output); + strcat (flto_out, ".lto.o"); + } + else + flto_out = make_temp_file (".lto.o"); obstack_ptr_grow (&argv_obstack, "-o"); obstack_ptr_grow (&argv_obstack, flto_out); } @@ -1463,7 +1629,21 @@ 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]; @@ -1486,95 +1666,39 @@ argv_ptr = &new_argv[new_head_argc]; fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); - /* Handle early generated debug information. At compile-time - we output early DWARF debug info into .gnu.debuglto_ prefixed - sections. LTRANS object DWARF debug info refers to that. - So we need to transfer the .gnu.debuglto_ sections to the final - link. Ideally the linker plugin interface would allow us to - not claim those sections and instruct the linker to keep - them, renaming them in the process. For now we extract and - rename those sections via a simple-object interface to produce - regular objects containing only the early debug info. We - then partially link those to a single early debug info object - and pass that as additional output back to the linker plugin. */ - - /* Prepare the partial link to gather the compile-time generated - debug-info into a single input for the final link. */ - debug_obj = make_temp_file ("debugobj"); - obstack_ptr_grow (&argv_obstack, collect_gcc); - for (i = 1; i < decoded_options_count; ++i) - { - /* Retain linker choice and -B. */ - if (decoded_options[i].opt_index == OPT_B - || decoded_options[i].opt_index == OPT_fuse_ld_bfd - || decoded_options[i].opt_index == OPT_fuse_ld_gold) - append_linker_options (&argv_obstack, &decoded_options[i-1], 2); - /* Retain all target options, this preserves -m32 for example. */ - if (cl_options[decoded_options[i].opt_index].flags & CL_TARGET) - append_linker_options (&argv_obstack, &decoded_options[i-1], 2); - /* Recognize -g0. */ - if (decoded_options[i].opt_index == OPT_g - && strcmp (decoded_options[i].arg, "0") == 0) - skip_debug = true; - } - obstack_ptr_grow (&argv_obstack, "-r"); - obstack_ptr_grow (&argv_obstack, "-nostdlib"); - obstack_ptr_grow (&argv_obstack, "-o"); - obstack_ptr_grow (&argv_obstack, debug_obj); - /* Copy the early generated debug info from the objects to temporary files and append those to the partial link commandline. */ n_debugobj = 0; + early_debug_object_names = NULL; if (! skip_debug) - for (i = 0; i < ltoobj_argc; ++i) - { - const char *tem; - if ((tem = debug_objcopy (ltoobj_argv[i], !linker_output_rel))) - { - obstack_ptr_grow (&argv_obstack, tem); - n_debugobj++; - } - } - - /* Link them all into a single object. Ideally this would reduce - disk space usage mainly due to .debug_str merging but unfortunately - GNU ld doesn't perform this with -r. */ - if (n_debugobj) { - obstack_ptr_grow (&argv_obstack, NULL); - const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **); - fork_execute (debug_link_argv[0], - CONST_CAST (char **, debug_link_argv), false); - - /* And dispose the temporaries. */ - for (i = 0; debug_link_argv[i]; ++i) - ; - for (--i; i > 0; --i) + early_debug_object_names = XCNEWVEC (const char *, ltoobj_argc+ 1); + num_deb_objs = ltoobj_argc; + for (i = 0; i < ltoobj_argc; ++i) { - if (strcmp (debug_link_argv[i], debug_obj) == 0) - break; - maybe_unlink (debug_link_argv[i]); + const char *tem; + if ((tem = debug_objcopy (ltoobj_argv[i], !linker_output_rel))) + { + early_debug_object_names[i] = tem; + n_debugobj++; + } } } - else - { - unlink_if_ordinary (debug_obj); - free (debug_obj); - debug_obj = NULL; - skip_debug = true; - } if (lto_mode == LTO_MODE_LTO) { printf ("%s\n", flto_out); if (!skip_debug) { - printf ("%s\n", debug_obj); - free (debug_obj); - debug_obj = NULL; + for (i = 0; i < ltoobj_argc; ++i) + if (early_debug_object_names[i] != NULL) + printf ("%s\n", early_debug_object_names[i]); } + /* These now belong to collect2. */ free (flto_out); flto_out = NULL; + free (early_debug_object_names); + early_debug_object_names = NULL; } else { @@ -1584,7 +1708,7 @@ int priority; if (!stream) - fatal_error (input_location, "fopen: %s: %m", ltrans_output_file); + fatal_error (input_location, "%<fopen%>: %s: %m", ltrans_output_file); /* Parse the list of LTRANS inputs from the WPA stage. */ obstack_init (&env_obstack); @@ -1601,7 +1725,7 @@ { if (!feof (stream)) fatal_error (input_location, - "Corrupted ltrans output file %s", + "corrupted ltrans output file %s", ltrans_output_file); break; } @@ -1702,7 +1826,9 @@ struct pex_obj *pex; char jobs[32]; - fprintf (mstream, "all:"); + fprintf (mstream, + ".PHONY: all\n" + "all:"); for (i = 0; i < nr; ++i) { int j = ltrans_priorities[i*2 + 1]; @@ -1725,7 +1851,8 @@ 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"; @@ -1738,21 +1865,24 @@ for (i = 0; i < nr; ++i) maybe_unlink (input_names[i]); } - if (!skip_debug) - { - printf ("%s\n", debug_obj); - free (debug_obj); - debug_obj = NULL; - } for (i = 0; i < nr; ++i) { fputs (output_names[i], stdout); putc ('\n', stdout); free (input_names[i]); } + if (!skip_debug) + { + for (i = 0; i < ltoobj_argc; ++i) + if (early_debug_object_names[i] != NULL) + printf ("%s\n", early_debug_object_names[i]); + } nr = 0; free (ltrans_priorities); free (output_names); + output_names = NULL; + free (early_debug_object_names); + early_debug_object_names = NULL; free (input_names); free (list_option_full); obstack_free (&env_obstack, NULL); @@ -1785,7 +1915,7 @@ diagnostic_initialize (global_dc, 0); if (atexit (lto_wrapper_cleanup) != 0) - fatal_error (input_location, "atexit failed"); + fatal_error (input_location, "%<atexit%> failed"); if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, fatal_signal);