@@ -49,14 +49,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
%{" NO_PIE_SPEC ":crtbegin.o%s}} \
%{fvtable-verify=none:%s; \
fvtable-verify=preinit:vtv_start_preinit.o%s; \
- fvtable-verify=std:vtv_start.o%s}"
+ fvtable-verify=std:vtv_start.o%s} \
+ %{fopenacc|fopenmp:%:if-exists(crtoffloadbegin%O%s)}"
#else
#define GNU_USER_TARGET_STARTFILE_SPEC \
"%{!shared: %{pg|p|profile:gcrt1.o%s;:crt1.o%s}} \
crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} \
%{fvtable-verify=none:%s; \
fvtable-verify=preinit:vtv_start_preinit.o%s; \
- fvtable-verify=std:vtv_start.o%s}"
+ fvtable-verify=std:vtv_start.o%s} \
+ %{fopenacc|fopenmp:%:if-exists(crtoffloadbegin%O%s)}"
#endif
#undef STARTFILE_SPEC
#define STARTFILE_SPEC GNU_USER_TARGET_STARTFILE_SPEC
@@ -73,13 +75,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
fvtable-verify=preinit:vtv_end_preinit.o%s; \
fvtable-verify=std:vtv_end.o%s} \
%{shared:crtendS.o%s;: %{" PIE_SPEC ":crtendS.o%s} \
- %{" NO_PIE_SPEC ":crtend.o%s}} crtn.o%s"
+ %{" NO_PIE_SPEC ":crtend.o%s}} crtn.o%s \
+ %{fopenacc|fopenmp:%:if-exists(crtoffloadend%O%s)}"
#else
#define GNU_USER_TARGET_ENDFILE_SPEC \
"%{fvtable-verify=none:%s; \
fvtable-verify=preinit:vtv_end_preinit.o%s; \
fvtable-verify=std:vtv_end.o%s} \
- %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+ %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s \
+ %{fopenacc|fopenmp:%:if-exists(crtoffloadend%O%s)}"
#endif
#undef ENDFILE_SPEC
#define ENDFILE_SPEC GNU_USER_TARGET_ENDFILE_SPEC
@@ -68,7 +68,7 @@ static unsigned int nr;
static char **input_names;
static char **output_names;
static char **offload_names;
-static const char *offloadbegin, *offloadend;
+static char *offload_objects_file_name;
static char *makefile;
const char tool_name[] = "lto-wrapper";
@@ -84,6 +84,8 @@ tool_cleanup (bool)
maybe_unlink (ltrans_output_file);
if (flto_out)
maybe_unlink (flto_out);
+ if (offload_objects_file_name)
+ maybe_unlink (offload_objects_file_name);
if (makefile)
maybe_unlink (makefile);
for (i = 0; i < nr; ++i)
@@ -818,66 +820,6 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[],
free_array_of_ptrs ((void **) names, num_targets);
}
-/* Copy a file from SRC to DEST. */
-
-static void
-copy_file (const char *dest, const char *src)
-{
- FILE *d = fopen (dest, "wb");
- FILE *s = fopen (src, "rb");
- char buffer[512];
- while (!feof (s))
- {
- size_t len = fread (buffer, 1, 512, s);
- if (ferror (s) != 0)
- fatal_error (input_location, "reading input file");
- if (len > 0)
- {
- fwrite (buffer, 1, len, d);
- if (ferror (d) != 0)
- fatal_error (input_location, "writing output file");
- }
- }
-}
-
-/* Find the crtoffloadbegin.o and crtoffloadend.o files in LIBRARY_PATH, make
- copies and store the names of the copies in offloadbegin and offloadend. */
-
-static void
-find_offloadbeginend (void)
-{
- char **paths = NULL;
- const char *library_path = getenv ("LIBRARY_PATH");
- if (!library_path)
- return;
- unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffloadbegin.o");
-
- unsigned i;
- for (i = 0; i < n_paths; i++)
- if (access_check (paths[i], R_OK) == 0)
- {
- size_t len = strlen (paths[i]);
- char *tmp = xstrdup (paths[i]);
- strcpy (paths[i] + len - strlen ("begin.o"), "end.o");
- if (access_check (paths[i], R_OK) != 0)
- fatal_error (input_location,
- "installation error, can't find crtoffloadend.o");
- /* The linker will delete the filenames we give it, so make
- copies. */
- offloadbegin = make_temp_file (".o");
- offloadend = make_temp_file (".o");
- copy_file (offloadbegin, tmp);
- copy_file (offloadend, paths[i]);
- free (tmp);
- break;
- }
- if (i == n_paths)
- fatal_error (input_location,
- "installation error, can't find crtoffloadbegin.o");
-
- free_array_of_ptrs ((void **) paths, n_paths);
-}
-
/* A subroutine of run_gcc. Examine the open file FD for lto sections with
name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS
and OPT_COUNT. Return true if we found a matchingn section, false
@@ -970,8 +912,8 @@ run_gcc (unsigned argc, char *argv[])
int new_head_argc;
bool have_lto = false;
bool have_offload = false;
- unsigned lto_argc = 0, offload_argc = 0;
- char **lto_argv, **offload_argv;
+ unsigned lto_argc = 0;
+ char **lto_argv;
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
@@ -987,10 +929,9 @@ run_gcc (unsigned argc, char *argv[])
&decoded_options,
&decoded_options_count);
- /* Allocate arrays for input object files with LTO or offload IL,
+ /* Allocate array for input object files with LTO IL,
and for possible preceding arguments. */
lto_argv = XNEWVEC (char *, argc);
- offload_argv = XNEWVEC (char *, argc);
/* Look at saved options in the IL files. */
for (i = 1; i < argc; ++i)
@@ -1002,6 +943,15 @@ run_gcc (unsigned argc, char *argv[])
int consumed;
char *filename = argv[i];
+ if (strncmp (argv[i], "-foffload-objects=",
+ sizeof ("-foffload-objects=") - 1) == 0)
+ {
+ have_offload = true;
+ offload_objects_file_name
+ = argv[i] + sizeof ("-foffload-objects=") - 1;
+ continue;
+ }
+
if ((p = strrchr (argv[i], '@'))
&& p != argv[i]
&& sscanf (p, "@%li%n", &loffset, &consumed) >= 1
@@ -1026,15 +976,6 @@ run_gcc (unsigned argc, char *argv[])
have_lto = true;
lto_argv[lto_argc++] = argv[i];
}
-
- if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
- &offload_fdecoded_options,
- &offload_fdecoded_options_count, collect_gcc))
- {
- have_offload = true;
- offload_argv[offload_argc++] = argv[i];
- }
-
close (fd);
}
@@ -1133,47 +1074,101 @@ run_gcc (unsigned argc, char *argv[])
if (have_offload)
{
- compile_images_for_offload_targets (offload_argc, offload_argv,
+ unsigned i, num_offload_files;
+ char **offload_argv;
+ FILE *f;
+
+ f = fopen (offload_objects_file_name, "r");
+ if (f == NULL)
+ fatal_error (input_location, "cannot open %s: %m",
+ offload_objects_file_name);
+ if (fscanf (f, "%u ", &num_offload_files) != 1)
+ fatal_error (input_location, "cannot read %s: %m",
+ offload_objects_file_name);
+ offload_argv = XCNEWVEC (char *, num_offload_files);
+
+ /* Read names of object files with offload. */
+ for (i = 0; i < num_offload_files; i++)
+ {
+ const unsigned piece = 32;
+ char *buf, *filename = XNEWVEC (char, piece);
+ size_t len;
+
+ buf = filename;
+cont1:
+ if (!fgets (buf, piece, f))
+ break;
+ len = strlen (filename);
+ if (filename[len - 1] != '\n')
+ {
+ filename = XRESIZEVEC (char, filename, len + piece);
+ buf = filename + len;
+ goto cont1;
+ }
+ filename[len - 1] = '\0';
+ offload_argv[i] = filename;
+ }
+ fclose (f);
+ if (offload_argv[num_offload_files - 1] == NULL)
+ fatal_error (input_location, "invalid format of %s",
+ offload_objects_file_name);
+ maybe_unlink (offload_objects_file_name);
+ offload_objects_file_name = NULL;
+
+ /* Look at saved offload options in files. */
+ for (i = 0; i < num_offload_files; i++)
+ {
+ char *p;
+ long loffset;
+ int fd, consumed;
+ off_t file_offset = 0;
+ char *filename = offload_argv[i];
+
+ if ((p = strrchr (offload_argv[i], '@'))
+ && p != offload_argv[i]
+ && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (p) == (unsigned int) consumed)
+ {
+ filename = XNEWVEC (char, p - offload_argv[i] + 1);
+ memcpy (filename, offload_argv[i], p - offload_argv[i]);
+ filename[p - offload_argv[i]] = '\0';
+ file_offset = (off_t) loffset;
+ }
+ fd = open (filename, O_RDONLY | O_BINARY);
+ if (fd == -1)
+ fatal_error (input_location, "cannot open %s: %m", filename);
+ if (!find_and_merge_options (fd, file_offset,
+ OFFLOAD_SECTION_NAME_PREFIX,
+ &offload_fdecoded_options,
+ &offload_fdecoded_options_count,
+ collect_gcc))
+ fatal_error (input_location, "cannot read %s: %m", filename);
+ close (fd);
+ if (filename != offload_argv[i])
+ XDELETEVEC (filename);
+ }
+
+ compile_images_for_offload_targets (num_offload_files, offload_argv,
offload_fdecoded_options,
offload_fdecoded_options_count,
decoded_options,
decoded_options_count);
+
+ free_array_of_ptrs ((void **) offload_argv, num_offload_files);
+
if (offload_names)
{
- find_offloadbeginend ();
for (i = 0; offload_names[i]; i++)
printf ("%s\n", offload_names[i]);
free_array_of_ptrs ((void **) offload_names, i);
}
}
- if (offloadbegin)
- printf ("%s\n", offloadbegin);
-
/* If object files contain offload sections, but do not contain LTO sections,
then there is no need to perform a link-time recompilation, i.e.
lto-wrapper is used only for a compilation of offload images. */
if (have_offload && !have_lto)
- {
- for (i = 1; i < argc; ++i)
- if (strncmp (argv[i], "-fresolution=",
- sizeof ("-fresolution=") - 1) != 0
- && strncmp (argv[i], "-flinker-output=",
- sizeof ("-flinker-output=") - 1) != 0)
- {
- char *out_file;
- /* Can be ".o" or ".so". */
- char *ext = strrchr (argv[i], '.');
- if (ext == NULL)
- out_file = make_temp_file ("");
- else
- out_file = make_temp_file (ext);
- /* The linker will delete the files we give it, so make copies. */
- copy_file (out_file, argv[i]);
- printf ("%s\n", out_file);
- }
- goto finish;
- }
+ goto finish;
if (lto_mode == LTO_MODE_LTO)
{
@@ -1402,11 +1397,7 @@ cont:
}
finish:
- if (offloadend)
- printf ("%s\n", offloadend);
-
XDELETE (lto_argv);
- XDELETE (offload_argv);
obstack_free (&argv_obstack, NULL);
}
@@ -129,6 +129,14 @@ struct plugin_file_info
struct plugin_symtab conflicts;
};
+/* List item with name of the file with offloading. */
+
+struct plugin_offload_file
+{
+ char *name;
+ struct plugin_offload_file *next;
+};
+
/* Until ASM_OUTPUT_LABELREF can be hookized and decoupled from
stdio file streams, we do simple label translation here. */
@@ -152,8 +160,16 @@ static ld_plugin_add_symbols add_symbols;
static struct plugin_file_info *claimed_files = NULL;
static unsigned int num_claimed_files = 0;
-static struct plugin_file_info *offload_files = NULL;
-static unsigned int num_offload_files = 0;
+/* List of files with offloading. */
+static struct plugin_offload_file *offload_files;
+/* Last file in the list. */
+static struct plugin_offload_file *offload_files_last;
+/* Last non-archive file in the list. */
+static struct plugin_offload_file *offload_files_last_obj;
+/* Last LTO file in the list. */
+static struct plugin_offload_file *offload_files_last_lto;
+/* Total number of files with offloading. */
+static unsigned num_offload_files;
static char **output_files = NULL;
static unsigned int num_output_files = 0;
@@ -351,14 +367,6 @@ free_2 (void)
free (info->name);
}
- for (i = 0; i < num_offload_files; i++)
- {
- struct plugin_file_info *info = &offload_files[i];
- struct plugin_symtab *symtab = &info->symtab;
- free (symtab->aux);
- free (info->name);
- }
-
for (i = 0; i < num_output_files; i++)
free (output_files[i]);
free (output_files);
@@ -367,8 +375,12 @@ free_2 (void)
claimed_files = NULL;
num_claimed_files = 0;
- free (offload_files);
- offload_files = NULL;
+ while (offload_files)
+ {
+ struct plugin_offload_file *ofld = offload_files;
+ offload_files = offload_files->next;
+ free (ofld);
+ }
num_offload_files = 0;
free (arguments_file_name);
@@ -625,8 +637,7 @@ static enum ld_plugin_status
all_symbols_read_handler (void)
{
unsigned i;
- unsigned num_lto_args
- = num_claimed_files + num_offload_files + lto_wrapper_num_args + 2;
+ unsigned num_lto_args = num_claimed_files + lto_wrapper_num_args + 3;
char **lto_argv;
const char *linker_output_str = NULL;
const char **lto_arg_ptr;
@@ -646,7 +657,6 @@ all_symbols_read_handler (void)
write_resolution ();
free_1 (claimed_files, num_claimed_files);
- free_1 (offload_files, num_offload_files);
for (i = 0; i < lto_wrapper_num_args; i++)
*lto_arg_ptr++ = lto_wrapper_argv[i];
@@ -671,16 +681,37 @@ all_symbols_read_handler (void)
break;
}
*lto_arg_ptr++ = xstrdup (linker_output_str);
- for (i = 0; i < num_claimed_files; i++)
+
+ if (num_offload_files > 0)
{
- struct plugin_file_info *info = &claimed_files[i];
+ FILE *f;
+ char *arg;
+ char *offload_objects_file_name;
+ struct plugin_offload_file *ofld;
+
+ offload_objects_file_name = make_temp_file (".ofldlist");
+ check (offload_objects_file_name, LDPL_FATAL,
+ "Failed to generate a temporary file name");
+ f = fopen (offload_objects_file_name, "w");
+ check (f, LDPL_FATAL, "could not open file with offload objects");
+ fprintf (f, "%u\n", num_offload_files);
+
+ ofld = offload_files;
+ while (ofld)
+ {
+ fprintf (f, "%s\n", ofld->name);
+ ofld = ofld->next;
+ }
+ fclose (f);
- *lto_arg_ptr++ = info->name;
+ arg = concat ("-foffload-objects=", offload_objects_file_name, NULL);
+ check (arg, LDPL_FATAL, "could not allocate");
+ *lto_arg_ptr++ = arg;
}
- for (i = 0; i < num_offload_files; i++)
+ for (i = 0; i < num_claimed_files; i++)
{
- struct plugin_file_info *info = &offload_files[i];
+ struct plugin_file_info *info = &claimed_files[i];
*lto_arg_ptr++ = info->name;
}
@@ -1007,19 +1038,63 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
xrealloc (claimed_files,
num_claimed_files * sizeof (struct plugin_file_info));
claimed_files[num_claimed_files - 1] = lto_file;
+
+ *claimed = 1;
}
- if (obj.found == 0 && obj.offload == 1)
+ if (obj.offload == 1)
{
+ struct plugin_offload_file *ofld
+ = xmalloc (sizeof (struct plugin_offload_file));
+ ofld->name = lto_file.name;
+ ofld->next = NULL;
+
+ if (offload_files == NULL)
+ offload_files = ofld;
+
+ /* Add file to the list. The order must be exactly the same as the final
+ order after recompilation and linking, otherwise host and target tables
+ with addresses wouldn't match. If a static library contains both LTO
+ and non-LTO objects, ld and gold link them in a different order. */
+ if (*claimed && offload_files_last_lto == NULL && file->offset != 0
+ && gold_version == -1)
+ {
+ /* ld only: insert first LTO file from the archive after the last real
+ object file immediately preceding the archive, or at the begin of
+ the list if there was no real objects before archives. */
+ if (offload_files_last_obj != NULL)
+ {
+ ofld->next = offload_files_last_obj->next;
+ offload_files_last_obj->next = ofld;
+ }
+ else if (offload_files != ofld)
+ {
+ ofld->next = offload_files;
+ offload_files = ofld;
+ }
+ }
+ else if (*claimed && offload_files_last_lto != NULL)
+ {
+ /* Insert LTO file after the last LTO file in the list. */
+ ofld->next = offload_files_last_lto->next;
+ offload_files_last_lto->next = ofld;
+ }
+ else if (offload_files_last != NULL)
+ {
+ /* Add non-LTO file or first non-archive LTO file to the end of the
+ list. */
+ offload_files_last->next = ofld;
+ }
+
+ if (ofld->next == NULL)
+ offload_files_last = ofld;
+ if (file->offset == 0)
+ offload_files_last_obj = ofld;
+ if (*claimed)
+ offload_files_last_lto = ofld;
num_offload_files++;
- offload_files =
- xrealloc (offload_files,
- num_offload_files * sizeof (struct plugin_file_info));
- offload_files[num_offload_files - 1] = lto_file;
}
- *claimed = 1;
-
goto cleanup;
err: