From patchwork Wed Oct 15 14:18:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Verbin X-Patchwork-Id: 400000 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id B66141400B6 for ; Thu, 16 Oct 2014 01:19:26 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; q=dns; s=default; b=CnLx/1CnR/djpSpfG L9I64bYY9QFp3qXESEx1ZJPX8A3SrcEtxCVoO1Tq8SGCJsnTzJ6BwXBWJEWaCunf wVnQZu4NtzTJ5+MqOaHXQcYwxNcAukjrRgXJCUjWR+Hc58sTn2Aa6O7RZZUBGd4c 8rtGvpHS9+SqkcYiPrboQAmv7Q= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:references:mime-version :content-type:in-reply-to; s=default; bh=IhBv6jn9NSYgd4Z4AwKwHnN l5tA=; b=eg+2DKS/zPNJVX8kg/SYrbCR0pwsFP3QfBKV5HUpBQ3IuRoA9wsK6IR F7OofXrglaGzrQ5+jiXwG5JQ9JQgOXRd98bgBPsWSDBon5Xd9cn8MSIUE8Xjv+Gt 5Qi79UVpe57p1e2N3HxqhQcq3VIjWwn0BLwtPGeuB3L0zrUldQu4= Received: (qmail 8880 invoked by alias); 15 Oct 2014 14:19:19 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 8869 invoked by uid 89); 15 Oct 2014 14:19:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pd0-f173.google.com Received: from mail-pd0-f173.google.com (HELO mail-pd0-f173.google.com) (209.85.192.173) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Wed, 15 Oct 2014 14:19:16 +0000 Received: by mail-pd0-f173.google.com with SMTP id g10so1328970pdj.18 for ; Wed, 15 Oct 2014 07:19:14 -0700 (PDT) X-Received: by 10.66.253.105 with SMTP id zz9mr12705367pac.49.1413382753899; Wed, 15 Oct 2014 07:19:13 -0700 (PDT) Received: from msticlxl57.ims.intel.com (fmdmzpr01-ext.fm.intel.com. [192.55.54.36]) by mx.google.com with ESMTPSA id y16sm17230454pbt.17.2014.10.15.07.19.06 for (version=TLSv1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 15 Oct 2014 07:19:12 -0700 (PDT) Date: Wed, 15 Oct 2014 18:18:56 +0400 From: Ilya Verbin To: Jakub Jelinek , Bernd Schmidt Cc: Cary Coutant , Richard Biener , Jan Hubicka , gcc-patches , Thomas Schwinge , Kirill Yukhin , Andrey Turetskiy Subject: Re: [PATCH 4/n] OpenMP 4.0 offloading infrastructure: lto-wrapper Message-ID: <20141015141856.GA46277@msticlxl57.ims.intel.com> References: <20141002151457.GA59899@msticlxl57.ims.intel.com> <20141008102650.GV1986@tucnak.redhat.com> <20141009120738.GA7420@msticlxl57.ims.intel.com> <20141009200703.GA56445@GumBook.local> <20141010065320.GA10376@tucnak.redhat.com> <20141010170043.GQ10376@tucnak.redhat.com> <20141013224247.GA61615@msticlxl57.ims.intel.com> <20141014094009.GX10376@tucnak.redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20141014094009.GX10376@tucnak.redhat.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes On 14 Oct 11:40, Jakub Jelinek wrote: > My preference would be to add the | SECTION_EXCLUDE unconditionally, and > instead guard the > if (flags & SECTION_EXCLUDE) > *f++ = 'e'; > in varasm.c (default_elf_asm_named_section). The only other user of > SECTION_EXCLUDE seems to be -gsplit-dwarf right now, Cary, is such a change > ok with you? Done. But it turned out that the gcc_GAS_CHECK_FEATURE from gcc/configure.ac: gcc_GAS_CHECK_FEATURE([.section with e], gcc_cv_as_section_has_e, [2,22,51],, [.section foo1,"e" .byte 0,0,0,0]) does not work properly. Maybe it works on "cygwin* | pe | mingw32* | interix*" targets, but on linux with GNU as version 2.20.51 (which doesn't support exclude sections) it successfully assembles conftest.s into conftest.o (with warnings) and HAVE_GAS_SECTION_EXCLUDE becomes defined. $ cat conftest.s .section foo1,"e" .byte 0,0,0,0 $ as conftest.s -o conftest.o conftest.s: Assembler messages: conftest.s:1: Warning: entity size for SHF_MERGE not specified conftest.s:1: Warning: group name for SHF_GROUP not specified as: a.out: warning: sh_link not set for section `foo1' $ readelf -t conftest.o [4] foo1 PROGBITS 0000000000000000 0000000000000040 0 0000000000000004 0000000000000000 0 1 [fffffffffffffdef]: WRITE, ALLOC, EXEC, STRINGS, INFO LINK, LINK ORDER, OS NONCONF, TLS, ORDERED, EXCLUDE, OS (000000000ff00000), PROC (0000000030000000), UNKNOWN (ffffffff000ff808) And therefore instead of assembling "e" flag, I had to check the version of gas. If it is >= 2.21.51 then HAVE_GAS_SECTION_EXCLUDE becomes defined. > If you have new gas and old linker, I'd expect it would just ignore > SHF_EXCLUDE. Yes, gas 2.21.51 + ld 2.20.51 build sections with SHF_EXCLUDE bit without warnings, ld just ignores it. I've updated the patch. It also fixes the issue with paths to accel specs. On 09 Oct 14:08, Bernd Schmidt wrote: > >>Why do you want to disable specs reading for the accel compiler? > >>Then users won't have the possibility to override defaults etc. easily... > I suspect the paths aren't right. If that can be fixed it should be > fine to remove the ifdef. Bootstrapped and regtested on i686-linux and x86_64-linux. Is it OK now? Thanks, -- Ilya gcc/ * configure: Regenerate. * configure.ac (HAVE_GAS_SECTION_EXCLUDE): Define if GNU assembler version >= 2.21.51 is used. * gcc.c (spec_host_machine, accel_dir_suffix): New variables. (process_command): Tweak path construction for the possibility of being configured as an offload compiler. (driver::maybe_putenv_OFFLOAD_TARGETS): New function. (driver::main): Call maybe_putenv_OFFLOAD_TARGETS. (driver::set_up_specs): Tweak path construction for the possibility of being configured as an offload compiler. * langhooks.c (lhd_begin_section): Set SECTION_EXCLUDE flag. * lto-wrapper.c (OFFLOAD_TARGET_NAMES_ENV): Define. (offload_names, offloadbegin, offloadend): New static variables. (free_array_of_ptrs, parse_env_var, access_check, compile_offload_image) (compile_images_for_offload_targets, copy_file, find_offloadbeginend): New static functions. (run_gcc): Determine whether offload sections are present. If so, run compile_images_for_offload_targets and return the names of new generated objects to linker. If there are offload sections, but no LTO sections, then return the copies of input objects without link-time recompilation. * varasm.c (default_elf_asm_named_section): Guard SECTION_EXCLUDE with ifdef HAVE_GAS_SECTION_EXCLUDE. lto-plugin/ * lto-plugin.c (OFFLOAD_SECTION, OFFLOAD_SECTION_LEN): Define. (struct plugin_objfile): Add new field "offload". (process_offload_section): New static function. (claim_file_handler): Claim file if it contains offload sections. diff --git a/gcc/configure b/gcc/configure index ff1e398..5e61ac8 100755 --- a/gcc/configure +++ b/gcc/configure @@ -24755,13 +24755,37 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_section_has_e" >&5 $as_echo "$gcc_cv_as_section_has_e" >&6; } + ;; + esac + + # GAS versions before 2.21.51 do not support the section flag 'e' for + # specifying an excluded section. + if test "$gcc_cv_as_section_has_e" != "yes"; then + as_ver=`$gcc_cv_as --version 2>/dev/null | sed 1q` + if echo "$as_ver" | grep GNU > /dev/null; then + as_vers=`echo $as_ver | sed -n \ + -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*.*\)$,\1,p'` + as_major=`expr "$as_vers" : '\([0-9]*\)'` + as_minor=`expr "$as_vers" : '[0-9]*\.\([0-9]*\)'` + as_patch=`expr "$as_vers" : '[0-9]*\.[0-9]*\.\([0-9]*\)'` + if test $as_major -ge 3; then + gcc_cv_as_section_has_e=yes + elif test $as_major -eq 2; then + if test $as_minor -ge 22; then + gcc_cv_as_section_has_e=yes + elif test $as_minor -eq 21; then + if test $as_patch -ge 51; then + gcc_cv_as_section_has_e=yes + fi + fi + fi + fi + fi cat >>confdefs.h <<_ACEOF #define HAVE_GAS_SECTION_EXCLUDE `if test $gcc_cv_as_section_has_e = yes; then echo 1; else echo 0; fi` _ACEOF - ;; - esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for filds and fists mnemonics" >&5 $as_echo_n "checking assembler for filds and fists mnemonics... " >&6; } diff --git a/gcc/configure.ac b/gcc/configure.ac index 05a55f4..5edbebe 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -3843,12 +3843,36 @@ foo: nop [2,22,51],, [.section foo1,"e" .byte 0,0,0,0]) - AC_DEFINE_UNQUOTED(HAVE_GAS_SECTION_EXCLUDE, - [`if test $gcc_cv_as_section_has_e = yes; then echo 1; else echo 0; fi`], - [Define if your assembler supports specifying the section flag e.]) ;; esac + # GAS versions before 2.21.51 do not support the section flag 'e' for + # specifying an excluded section. + [if test "$gcc_cv_as_section_has_e" != "yes"; then + as_ver=`$gcc_cv_as --version 2>/dev/null | sed 1q` + if echo "$as_ver" | grep GNU > /dev/null; then + as_vers=`echo $as_ver | sed -n \ + -e 's,^.*[ ]\([0-9][0-9]*\.[0-9][0-9]*.*\)$,\1,p'` + as_major=`expr "$as_vers" : '\([0-9]*\)'` + as_minor=`expr "$as_vers" : '[0-9]*\.\([0-9]*\)'` + as_patch=`expr "$as_vers" : '[0-9]*\.[0-9]*\.\([0-9]*\)'` + if test $as_major -ge 3; then + gcc_cv_as_section_has_e=yes + elif test $as_major -eq 2; then + if test $as_minor -ge 22; then + gcc_cv_as_section_has_e=yes + elif test $as_minor -eq 21; then + if test $as_patch -ge 51; then + gcc_cv_as_section_has_e=yes + fi + fi + fi + fi + fi] + AC_DEFINE_UNQUOTED(HAVE_GAS_SECTION_EXCLUDE, + [`if test $gcc_cv_as_section_has_e = yes; then echo 1; else echo 0; fi`], + [Define if your assembler supports specifying the section flag e.]) + gcc_GAS_CHECK_FEATURE([filds and fists mnemonics], gcc_cv_as_ix86_filds,,, [filds mem; fists mem],, diff --git a/gcc/gcc.c b/gcc/gcc.c index 71c76f8..4619fe7 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -157,6 +157,7 @@ static const char *const spec_version = DEFAULT_TARGET_VERSION; /* The target machine. */ static const char *spec_machine = DEFAULT_TARGET_MACHINE; +static const char *spec_host_machine = DEFAULT_REAL_TARGET_MACHINE; /* Nonzero if cross-compiling. When -b is used, the value comes from the `specs' file. */ @@ -1296,6 +1297,9 @@ static const char *const standard_startfile_prefix_2 relative to the driver. */ static const char *const tooldir_base_prefix = TOOLDIR_BASE_PREFIX; +/* A prefix to be used when this is an accelerator compiler. */ +static const char *const accel_dir_suffix = ACCEL_DIR_SUFFIX; + /* Subdirectory to use for locating libraries. Set by set_multilib_dir based on the compilation options. */ @@ -4122,15 +4126,15 @@ process_command (unsigned int decoded_options_count, } gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix)); - tooldir_prefix2 = concat (tooldir_base_prefix, spec_machine, + tooldir_prefix2 = concat (tooldir_base_prefix, spec_host_machine, dir_separator_str, NULL); /* Look for tools relative to the location from which the driver is running, or, if that is not available, the configured prefix. */ tooldir_prefix = concat (gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix, - spec_machine, dir_separator_str, - spec_version, dir_separator_str, tooldir_prefix2, NULL); + spec_host_machine, dir_separator_str, spec_version, + accel_dir_suffix, dir_separator_str, tooldir_prefix2, NULL); free (tooldir_prefix2); add_prefix (&exec_prefixes, @@ -6742,6 +6746,7 @@ class driver void set_up_specs () const; void putenv_COLLECT_GCC (const char *argv0) const; void maybe_putenv_COLLECT_LTO_WRAPPER () const; + void maybe_putenv_OFFLOAD_TARGETS () const; void handle_unrecognized_options () const; int maybe_print_and_exit () const; bool prepare_infiles (); @@ -6784,6 +6789,7 @@ driver::main (int argc, char **argv) set_up_specs (); putenv_COLLECT_GCC (argv[0]); maybe_putenv_COLLECT_LTO_WRAPPER (); + maybe_putenv_OFFLOAD_TARGETS (); handle_unrecognized_options (); if (!maybe_print_and_exit ()) @@ -6953,6 +6959,7 @@ driver::build_multilib_strings () const void driver::set_up_specs () const { + const char *spec_machine_suffix; char *specs_file; size_t i; @@ -6976,8 +6983,8 @@ driver::set_up_specs () const /* Read specs from a file if there is one. */ - machine_suffix = concat (spec_machine, dir_separator_str, - spec_version, dir_separator_str, NULL); + machine_suffix = concat (spec_host_machine, dir_separator_str, spec_version, + accel_dir_suffix, dir_separator_str, NULL); just_machine_suffix = concat (spec_machine, dir_separator_str, NULL); specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true); @@ -6987,13 +6994,18 @@ driver::set_up_specs () const else init_spec (); - /* We need to check standard_exec_prefix/just_machine_suffix/specs +#ifdef ACCEL_COMPILER + spec_machine_suffix = machine_suffix; +#else + spec_machine_suffix = just_machine_suffix; +#endif + + /* We need to check standard_exec_prefix/spec_machine_suffix/specs for any override of as, ld and libraries. */ specs_file = (char *) alloca (strlen (standard_exec_prefix) - + strlen (just_machine_suffix) + sizeof ("specs")); - + + strlen (spec_machine_suffix) + sizeof ("specs")); strcpy (specs_file, standard_exec_prefix); - strcat (specs_file, just_machine_suffix); + strcat (specs_file, spec_machine_suffix); strcat (specs_file, "specs"); if (access (specs_file, R_OK) == 0) read_specs (specs_file, true, false); @@ -7175,8 +7187,9 @@ driver::set_up_specs () const /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake. */ if (gcc_exec_prefix) - gcc_exec_prefix = concat (gcc_exec_prefix, spec_machine, dir_separator_str, - spec_version, dir_separator_str, NULL); + gcc_exec_prefix = concat (gcc_exec_prefix, spec_host_machine, + dir_separator_str, spec_version, + accel_dir_suffix, dir_separator_str, NULL); /* Now we have the specs. Set the `valid' bits for switches that match anything in any spec. */ @@ -7227,6 +7240,21 @@ driver::maybe_putenv_COLLECT_LTO_WRAPPER () const } +/* Set up to remember the names of offload targets. */ + +void +driver::maybe_putenv_OFFLOAD_TARGETS () const +{ + if (strlen (OFFLOAD_TARGETS) > 0) + { + obstack_grow (&collect_obstack, "OFFLOAD_TARGET_NAMES=", + sizeof ("OFFLOAD_TARGET_NAMES=") - 1); + obstack_grow (&collect_obstack, OFFLOAD_TARGETS, + strlen (OFFLOAD_TARGETS) + 1); + xputenv (XOBFINISH (&collect_obstack, char *)); + } +} + /* Reject switches that no pass was interested in. */ void diff --git a/gcc/langhooks.c b/gcc/langhooks.c index 7d4c294..4bdeaa0 100644 --- a/gcc/langhooks.c +++ b/gcc/langhooks.c @@ -660,7 +660,7 @@ lhd_begin_section (const char *name) saved_section = text_section; /* Create a new section and switch to it. */ - section = get_section (name, SECTION_DEBUG, NULL); + section = get_section (name, SECTION_DEBUG | SECTION_EXCLUDE, NULL); switch_to_section (section); } diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c index 8033b15..cbda36b 100644 --- a/gcc/lto-wrapper.c +++ b/gcc/lto-wrapper.c @@ -49,6 +49,10 @@ along with GCC; see the file COPYING3. If not see #include "lto-section-names.h" #include "collect-utils.h" +/* Environment variable, used for passing the names of offload targets from GCC + driver to lto-wrapper. */ +#define OFFLOAD_TARGET_NAMES_ENV "OFFLOAD_TARGET_NAMES" + enum lto_mode_d { LTO_MODE_NONE, /* Not doing LTO. */ LTO_MODE_LTO, /* Normal LTO. */ @@ -63,6 +67,8 @@ static char *flto_out; static unsigned int nr; static char **input_names; static char **output_names; +static char **offload_names; +static const char *offloadbegin, *offloadend; static char *makefile; const char tool_name[] = "lto-wrapper"; @@ -364,6 +370,223 @@ merge_and_complain (struct cl_decoded_option **decoded_options, } } +/* Auxiliary function that frees elements of PTR and PTR itself. + N is number of elements to be freed. If PTR is NULL, nothing is freed. + If an element is NULL, subsequent elements are not freed. */ + +static void ** +free_array_of_ptrs (void **ptr, unsigned n) +{ + if (!ptr) + return NULL; + for (unsigned i = 0; i < n; i++) + { + if (!ptr[i]) + break; + free (ptr[i]); + } + free (ptr); + return NULL; +} + +/* Parse STR, saving found tokens into PVALUES and return their number. + Tokens are assumed to be delimited by ':'. If APPEND is non-null, + append it to every token we find. */ + +static unsigned +parse_env_var (const char *str, char ***pvalues, const char *append) +{ + const char *curval, *nextval; + char **values; + unsigned num = 1, i; + + curval = strchr (str, ':'); + while (curval) + { + num++; + curval = strchr (curval + 1, ':'); + } + + values = (char**) xmalloc (num * sizeof (char*)); + curval = str; + nextval = strchrnul (curval, ':'); + + int append_len = append ? strlen (append) : 0; + for (i = 0; i < num; i++) + { + int l = nextval - curval; + values[i] = (char*) xmalloc (l + 1 + append_len); + memcpy (values[i], curval, l); + values[i][l] = 0; + if (append) + strcat (values[i], append); + curval = nextval + 1; + nextval = strchrnul (curval, ':'); + } + *pvalues = values; + return num; +} + +/* Check whether NAME can be accessed in MODE. This is like access, + except that it never considers directories to be executable. */ + +static int +access_check (const char *name, int mode) +{ + if (mode == X_OK) + { + struct stat st; + + if (stat (name, &st) < 0 + || S_ISDIR (st.st_mode)) + return -1; + } + + return access (name, mode); +} + +/* Prepare a target image for offload TARGET, using mkoffload tool from + COMPILER_PATH. Return the name of the resultant object file. */ + +static char * +compile_offload_image (const char *target, const char *compiler_path, + unsigned in_argc, char *in_argv[]) +{ + char *filename = NULL; + char **argv; + char *suffix + = XALLOCAVEC (char, sizeof ("/accel//mkoffload") + strlen (target)); + strcpy (suffix, "/accel/"); + strcat (suffix, target); + strcat (suffix, "/mkoffload"); + + char **paths = NULL; + unsigned n_paths = parse_env_var (compiler_path, &paths, suffix); + + const char *compiler = NULL; + for (unsigned i = 0; i < n_paths; i++) + if (access_check (paths[i], X_OK) == 0) + { + compiler = paths[i]; + break; + } + + if (compiler) + { + /* Generate temporary output file name. */ + filename = make_temp_file (".target.o"); + + struct obstack argv_obstack; + obstack_init (&argv_obstack); + obstack_ptr_grow (&argv_obstack, compiler); + obstack_ptr_grow (&argv_obstack, "-o"); + obstack_ptr_grow (&argv_obstack, filename); + + for (unsigned i = 1; i < in_argc; i++) + obstack_ptr_grow (&argv_obstack, in_argv[i]); + obstack_ptr_grow (&argv_obstack, NULL); + + argv = XOBFINISH (&argv_obstack, char **); + fork_execute (argv[0], argv, true); + obstack_free (&argv_obstack, NULL); + } + + free_array_of_ptrs ((void **) paths, n_paths); + return filename; +} + + +/* The main routine dealing with offloading. + The routine builds a target image for each offload target. IN_ARGC and + IN_ARGV specify options and input object files. As all of them could contain + target sections, we pass them all to target compilers. */ + +static void +compile_images_for_offload_targets (unsigned in_argc, char *in_argv[]) +{ + char **names = NULL; + const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV); + if (!target_names) + return; + unsigned num_targets = parse_env_var (target_names, &names, NULL); + + const char *compiler_path = getenv ("COMPILER_PATH"); + if (!compiler_path) + goto out; + + /* Prepare an image for each target and save the name of the resultant object + file to the OFFLOAD_NAMES array. It is terminated by a NULL entry. */ + offload_names = XCNEWVEC (char *, num_targets + 1); + for (unsigned i = 0; i < num_targets; i++) + { + offload_names[i] = compile_offload_image (names[i], compiler_path, + in_argc, in_argv); + if (!offload_names[i]) + fatal_error ("problem with building target image for %s\n", names[i]); + } + + out: + 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 ("reading input file"); + if (len > 0) + { + fwrite (buffer, 1, len, d); + if (ferror (d) != 0) + fatal_error ("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 ("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 ("installation error, can't find crtoffloadbegin.o"); + + free_array_of_ptrs ((void **) paths, n_paths); +} + /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */ static void @@ -384,6 +607,8 @@ run_gcc (unsigned argc, char *argv[]) unsigned int decoded_options_count; struct obstack argv_obstack; int new_head_argc; + bool have_lto = false; + bool have_offload = false; /* Get the driver and options. */ collect_gcc = getenv ("COLLECT_GCC"); @@ -432,6 +657,9 @@ run_gcc (unsigned argc, char *argv[]) close (fd); continue; } + if (simple_object_find_section (sobj, OFFLOAD_SECTION_NAME_PREFIX ".opts", + &offset, &length, &errmsg, &err)) + have_offload = true; if (!simple_object_find_section (sobj, LTO_SECTION_NAME_PREFIX "." "opts", &offset, &length, &errmsg, &err)) { @@ -439,6 +667,7 @@ run_gcc (unsigned argc, char *argv[]) close (fd); continue; } + have_lto = true; lseek (fd, file_offset + offset, SEEK_SET); data = (char *)xmalloc (length); read (fd, data, length); @@ -633,6 +862,43 @@ run_gcc (unsigned argc, char *argv[]) /* Remember at which point we can scrub args to re-use the commons. */ new_head_argc = obstack_object_size (&argv_obstack) / sizeof (void *); + if (have_offload) + { + compile_images_for_offload_targets (argc, argv); + 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)) + { + 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; + } + if (lto_mode == LTO_MODE_LTO) { flto_out = make_temp_file (".lto.o"); @@ -859,6 +1125,10 @@ cont: obstack_free (&env_obstack, NULL); } + finish: + if (offloadend) + printf ("%s\n", offloadend); + obstack_free (&argv_obstack, NULL); } diff --git a/gcc/varasm.c b/gcc/varasm.c index abb743b..4ae9d58 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -6141,8 +6141,10 @@ default_elf_asm_named_section (const char *name, unsigned int flags, if (!(flags & SECTION_DEBUG)) *f++ = 'a'; +#if defined (HAVE_GAS_SECTION_EXCLUDE) && HAVE_GAS_SECTION_EXCLUDE == 1 if (flags & SECTION_EXCLUDE) *f++ = 'e'; +#endif if (flags & SECTION_WRITE) *f++ = 'w'; if (flags & SECTION_CODE) diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c index 910e23c..fb6555d 100644 --- a/lto-plugin/lto-plugin.c +++ b/lto-plugin/lto-plugin.c @@ -86,6 +86,8 @@ along with this program; see the file COPYING3. If not see #define LTO_SECTION_PREFIX ".gnu.lto_.symtab" #define LTO_SECTION_PREFIX_LEN (sizeof (LTO_SECTION_PREFIX) - 1) +#define OFFLOAD_SECTION ".gnu.offload_lto_.opts" +#define OFFLOAD_SECTION_LEN (sizeof (OFFLOAD_SECTION) - 1) /* The part of the symbol table the plugin has to keep track of. Note that we must keep SYMS until all_symbols_read is called to give the linker time to @@ -111,6 +113,7 @@ struct plugin_symtab struct plugin_objfile { int found; + int offload; simple_object_read *objfile; struct plugin_symtab *out; const struct ld_plugin_input_file *file; @@ -862,6 +865,21 @@ err: return 0; } +/* Find an offload section of an object file. */ + +static int +process_offload_section (void *data, const char *name, off_t offset, off_t len) +{ + if (!strncmp (name, OFFLOAD_SECTION, OFFLOAD_SECTION_LEN)) + { + struct plugin_objfile *obj = (struct plugin_objfile *) data; + obj->offload = 1; + return 0; + } + + return 1; +} + /* Callback used by gold to check if the plugin will claim FILE. Writes the result in CLAIMED. */ @@ -899,6 +917,7 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed) *claimed = 0; obj.file = file; obj.found = 0; + obj.offload = 0; obj.out = <o_file.symtab; errmsg = NULL; obj.objfile = simple_object_start_read (file->fd, file->offset, LTO_SEGMENT_NAME, @@ -920,7 +939,11 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed) goto err; } - if (obj.found == 0) + if (obj.objfile) + simple_object_find_sections (obj.objfile, process_offload_section, + &obj, &err); + + if (obj.found == 0 && obj.offload == 0) goto err; if (obj.found > 1)