diff mbox

[RFC,Offloading] Fix PR68463

Message ID 20160220105420.GB13147@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Verbin Feb. 20, 2016, 10:54 a.m. UTC
On Fri, Feb 19, 2016 at 15:53:08 +0100, Jakub Jelinek wrote:
> On Wed, Feb 10, 2016 at 08:19:34PM +0300, Ilya Verbin wrote:
> > This patch adds crtoffload{begin,end}.o to all -fopenmp programs, if they exist.
> > I couldn't think of a better solution...
> > Tested using the testcase from the previous mail, e.g.:
> > 
> > $ gcc -DNUM=1 -c -fopenmp test.c -o obj1.o
> > $ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
> > $ gcc -DNUM=3 -c -fopenmp test.c -o obj3.o
> > $ gcc -DNUM=4 -c -fopenmp test.c -o obj4.o -flto
> > $ gcc -DNUM=5 -c -fopenmp test.c -o obj5.o
> > $ gcc -DNUM=6 -c -fopenmp test.c -o obj6.o -flto
> > $ gcc -DNUM=7 -c -fopenmp test.c -o obj7.o
> > $ gcc-ar -cvq libtest.a obj3.o obj4.o obj5.o
> > $ gcc -fopenmp main.c obj1.o obj2.o libtest.a obj6.o obj7.o
> > 
> > And other combinations.
> 
> Looking at this, I think I have no problem with crtoffloadbegin.o being
> included in all -fopenmp/-fopenacc linked programs/shared libraries,
> that just defines the symbols and nothing else.
> I have no problem with the
> __offload_funcs_end/__offload_vars_end part of crtoffloadend.o being
> included too.
> But, I really don't like __OFFLOAD_TABLE__ being added to all programs, that
> wastes real space in data (rodata or relro?) section, and dynamic
> relocations.
> So, perhaps, can we split offloadstuff.c into 3 objects instead of 2,
> crtoffload{begin,end,table}.o*, where the last one would be what
> defines __OFFLOAD_TABLE__, and add the last one only by the linker
> plugin/lto-wrapper/whatever, if any input objects had any offloading stuff
> in it?

Done.  Bootstrapped and regtested, lto-bootstrap in progress.

Thomas, could you please test it using nvptx, including the testcase with static
libraries?

Could this patch be considered for stage4?  On the one hand, this is not a
regression.  On the other hand, it fixes quite serious issues, and it shouldn't
affect non-offloading configurations.


gcc/
	PR driver/68463
	* config/gnu-user.h (GNU_USER_TARGET_STARTFILE_SPEC): Add
	crtoffloadbegin.o for -fopenacc/-fopenmp if it exists.
	(GNU_USER_TARGET_ENDFILE_SPEC): Add crtoffloadend.o for
	-fopenacc/-fopenmp if it exists.
	* lto-wrapper.c (offloadbegin, offloadend): Remove static vars.
	(offload_objects_file_name): New static var.
	(tool_cleanup): Remove offload_objects_file_name file.
	(find_offloadbeginend): Replace with ...
	(find_crtoffloadtable): ... this.
	(run_gcc): Remove offload_argc and offload_argv.
	Get offload_objects_file_name from -foffload-objects=... option.
	Read names of object files with offload from this file, pass them to
	compile_images_for_offload_targets.  Don't call find_offloadbeginend and
	don't pass offloadbegin and offloadend to the linker.  Don't pass
	offload non-LTO files to the linker, because now they're not claimed.
libgcc/
	PR driver/68463
	* Makefile.in (crtoffloadtable$(objext)): New rule.
	* configure.ac (extra_parts): Add crtoffloadtable$(objext) if
	enable_offload_targets is not empty.
	* configure: Regenerate.
	* offloadstuff.c: Move __OFFLOAD_TABLE__ from crtoffloadend to
	crtoffloadtable.
lto-plugin/
	PR driver/68463
	* lto-plugin.c (struct plugin_offload_file): New.
	(offload_files): Change type.
	(offload_files_last, offload_files_last_obj): New.
	(offload_files_last_lto): New.
	(free_2): Adjust accordingly.
	(all_symbols_read_handler): Don't add offload files to lto_arg_ptr.
	Don't call free_1 for offload_files.  Write names of object files with
	offloading to the temporary file.  Add new option to lto_arg_ptr.
	(claim_file_handler): Don't claim file if it contains offload sections
	without LTO sections.  If it contains offload sections, add to the list.



Thanks,
  -- Ilya

Comments

Jakub Jelinek Feb. 22, 2016, 10:59 a.m. UTC | #1
On Sat, Feb 20, 2016 at 01:54:20PM +0300, Ilya Verbin wrote:
> gcc/
> 	PR driver/68463
> 	* config/gnu-user.h (GNU_USER_TARGET_STARTFILE_SPEC): Add
> 	crtoffloadbegin.o for -fopenacc/-fopenmp if it exists.
> 	(GNU_USER_TARGET_ENDFILE_SPEC): Add crtoffloadend.o for
> 	-fopenacc/-fopenmp if it exists.
> 	* lto-wrapper.c (offloadbegin, offloadend): Remove static vars.
> 	(offload_objects_file_name): New static var.
> 	(tool_cleanup): Remove offload_objects_file_name file.
> 	(find_offloadbeginend): Replace with ...
> 	(find_crtoffloadtable): ... this.
> 	(run_gcc): Remove offload_argc and offload_argv.
> 	Get offload_objects_file_name from -foffload-objects=... option.
> 	Read names of object files with offload from this file, pass them to
> 	compile_images_for_offload_targets.  Don't call find_offloadbeginend and
> 	don't pass offloadbegin and offloadend to the linker.  Don't pass
> 	offload non-LTO files to the linker, because now they're not claimed.
> libgcc/
> 	PR driver/68463
> 	* Makefile.in (crtoffloadtable$(objext)): New rule.
> 	* configure.ac (extra_parts): Add crtoffloadtable$(objext) if
> 	enable_offload_targets is not empty.
> 	* configure: Regenerate.
> 	* offloadstuff.c: Move __OFFLOAD_TABLE__ from crtoffloadend to
> 	crtoffloadtable.
> lto-plugin/
> 	PR driver/68463
> 	* lto-plugin.c (struct plugin_offload_file): New.
> 	(offload_files): Change type.
> 	(offload_files_last, offload_files_last_obj): New.
> 	(offload_files_last_lto): New.
> 	(free_2): Adjust accordingly.
> 	(all_symbols_read_handler): Don't add offload files to lto_arg_ptr.
> 	Don't call free_1 for offload_files.  Write names of object files with
> 	offloading to the temporary file.  Add new option to lto_arg_ptr.
> 	(claim_file_handler): Don't claim file if it contains offload sections
> 	without LTO sections.  If it contains offload sections, add to the list.

LGTM.

	Jakub
Thomas Schwinge Feb. 22, 2016, 3:13 p.m. UTC | #2
Hi!

On Sat, 20 Feb 2016 13:54:20 +0300, Ilya Verbin <iverbin@gmail.com> wrote:
> On Fri, Feb 19, 2016 at 15:53:08 +0100, Jakub Jelinek wrote:
> > On Wed, Feb 10, 2016 at 08:19:34PM +0300, Ilya Verbin wrote:
> > > This patch adds crtoffload{begin,end}.o to all -fopenmp programs, if they exist.
> > > I couldn't think of a better solution...
> > > Tested using the testcase from the previous mail, e.g.:
> > > 
> > > $ gcc -DNUM=1 -c -fopenmp test.c -o obj1.o
> > > $ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
> > > $ gcc -DNUM=3 -c -fopenmp test.c -o obj3.o
> > > $ gcc -DNUM=4 -c -fopenmp test.c -o obj4.o -flto
> > > $ gcc -DNUM=5 -c -fopenmp test.c -o obj5.o
> > > $ gcc -DNUM=6 -c -fopenmp test.c -o obj6.o -flto
> > > $ gcc -DNUM=7 -c -fopenmp test.c -o obj7.o
> > > $ gcc-ar -cvq libtest.a obj3.o obj4.o obj5.o
> > > $ gcc -fopenmp main.c obj1.o obj2.o libtest.a obj6.o obj7.o
> > > 
> > > And other combinations.

> Thomas, could you please test it using nvptx

It mostly ;-) works.  With nvptx offloading enabled (which you don't
have, do you?), I'm seeing one test case regress:

    [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 9)
    [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 13)
    PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 execution test

(Same for C++.)  That testcase, just recently added by Tom in r233237
"Handle -fdiagnostics-color in lto", specifies 'dg-additional-options
"-flto -fno-use-linker-plugin"'.  Is that now an unsupported
combination/configuration?  (I have not yet looked in detail, but it
appears as if the offloading compilers are no longer being run for
-fno-use-linker-plugin.)

> including the testcase with static
> libraries?

Works in my manual testing if I work around the following issue:

> --- a/gcc/config/gnu-user.h
> +++ b/gcc/config/gnu-user.h
> @@ -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)}"

(..., and similar for others.)  The if-exists spec function only works
for absolute paths (I have not researched, why?), so it won't locate the
files for relative -Bbuild-gcc/[...] prefixes, and linking will fail:

    /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x0): undefined reference to `__offload_func_table'
    /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x8): undefined reference to `__offload_funcs_end'
    /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x10): undefined reference to `__offload_var_table'
    /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x18): undefined reference to `__offload_vars_end'

If I use the absolute -B$PWD/build-gcc/[...], it works.  (But there is no
requirement for -B prefixes to be absolute, as far as I know.)  Why not
make it a hard error, though, if these files are missing?  Can we use
something like (untested pseudo-patch):

    +#ifdef ENABLE_OFFLOADING
    +# define CRTOFFLOADBEGIN "%{fopenacc|fopenmp:%:crtoffloadbegin%O%s}"
    +#else
    +# define CRTOFFLOADBEGIN ""
    +#endif

    @@ -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} \
    +   " CRTOFFLOADBEGIN ")}"


I have not verified your patch's logic in detail (arcane...) ;-) so just
two drive-by comments:

>  #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

I guess we currently don't have to care about offloading configurations
not using the gnu-user.h file in which you modified the
STARTFILE_SPEC/ENDFILE_SPEC?

> --- a/lto-plugin/lto-plugin.c
> +++ b/lto-plugin/lto-plugin.c

> @@ -671,16 +681,37 @@ all_symbols_read_handler (void)

> +  if (num_offload_files > 0)
>      {
> +      [...]
> +      struct plugin_offload_file *ofld;
> +      [...]
> +      ofld = offload_files->next;
> +      while (ofld)
> +	{
> +	  fprintf (f, "%s\n", ofld->name);
> +	  ofld = ofld->next;
> +	}

To the casual reader, skipping the first offload_files looks like a
off-by-one error, so I suggest you add a comment "Skip the dummy item at
the start of the list.", or similar.


Grüße
 Thomas
Ilya Verbin Feb. 22, 2016, 6:07 p.m. UTC | #3
2016-02-22 18:13 GMT+03:00 Thomas Schwinge <thomas@codesourcery.com>:
> On Sat, 20 Feb 2016 13:54:20 +0300, Ilya Verbin <iverbin@gmail.com> wrote:
>> On Fri, Feb 19, 2016 at 15:53:08 +0100, Jakub Jelinek wrote:
>> > On Wed, Feb 10, 2016 at 08:19:34PM +0300, Ilya Verbin wrote:
>> > > This patch adds crtoffload{begin,end}.o to all -fopenmp programs, if they exist.
>> > > I couldn't think of a better solution...
>> > > Tested using the testcase from the previous mail, e.g.:
>> > >
>> > > $ gcc -DNUM=1 -c -fopenmp test.c -o obj1.o
>> > > $ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
>> > > $ gcc -DNUM=3 -c -fopenmp test.c -o obj3.o
>> > > $ gcc -DNUM=4 -c -fopenmp test.c -o obj4.o -flto
>> > > $ gcc -DNUM=5 -c -fopenmp test.c -o obj5.o
>> > > $ gcc -DNUM=6 -c -fopenmp test.c -o obj6.o -flto
>> > > $ gcc -DNUM=7 -c -fopenmp test.c -o obj7.o
>> > > $ gcc-ar -cvq libtest.a obj3.o obj4.o obj5.o
>> > > $ gcc -fopenmp main.c obj1.o obj2.o libtest.a obj6.o obj7.o
>> > >
>> > > And other combinations.
>
>> Thomas, could you please test it using nvptx
>
> It mostly ;-) works.  With nvptx offloading enabled (which you don't
> have, do you?), I'm seeing one test case regress:
>
>     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 9)
>     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 13)
>     PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 (test for excess errors)
>     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 execution test
>
> (Same for C++.)  That testcase, just recently added by Tom in r233237
> "Handle -fdiagnostics-color in lto", specifies 'dg-additional-options
> "-flto -fno-use-linker-plugin"'.  Is that now an unsupported
> combination/configuration?  (I have not yet looked in detail, but it
> appears as if the offloading compilers are no longer being run for
> -fno-use-linker-plugin.)

Yes, it's really hard to fix the "lto + non-lto objects" issue for
no-use-linker-plugin LTO path. In this patch lto-plugin prepares a
list of objects files with offloading and passes it to lto-wrapper, so
I believe we should consider offloading without lto-plugin as
unsupported. I'll update wiki when the patch will be committed.

>> including the testcase with static
>> libraries?
>
> Works in my manual testing if I work around the following issue:
>
>> --- a/gcc/config/gnu-user.h
>> +++ b/gcc/config/gnu-user.h
>> @@ -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)}"
>
> (..., and similar for others.)  The if-exists spec function only works
> for absolute paths (I have not researched, why?), so it won't locate the
> files for relative -Bbuild-gcc/[...] prefixes, and linking will fail:
>
>     /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x0): undefined reference to `__offload_func_table'
>     /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x8): undefined reference to `__offload_funcs_end'
>     /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x10): undefined reference to `__offload_var_table'
>     /tmp/ccGajPD4.crtoffloadtable.o:(.rodata+0x18): undefined reference to `__offload_vars_end'
>
> If I use the absolute -B$PWD/build-gcc/[...], it works.  (But there is no
> requirement for -B prefixes to be absolute, as far as I know.)  Why not
> make it a hard error, though, if these files are missing?  Can we use
> something like (untested pseudo-patch):
>
>     +#ifdef ENABLE_OFFLOADING
>     +# define CRTOFFLOADBEGIN "%{fopenacc|fopenmp:%:crtoffloadbegin%O%s}"
>     +#else
>     +# define CRTOFFLOADBEGIN ""
>     +#endif
>
>     @@ -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} \
>     +   " CRTOFFLOADBEGIN ")}"

OK, I'll replace if-exists with ifdef ENABLE_OFFLOADING.

> I have not verified your patch's logic in detail (arcane...) ;-) so just
> two drive-by comments:
>
>>  #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
>
> I guess we currently don't have to care about offloading configurations
> not using the gnu-user.h file in which you modified the
> STARTFILE_SPEC/ENDFILE_SPEC?

I think so.

>> --- a/lto-plugin/lto-plugin.c
>> +++ b/lto-plugin/lto-plugin.c
>
>> @@ -671,16 +681,37 @@ all_symbols_read_handler (void)
>
>> +  if (num_offload_files > 0)
>>      {
>> +      [...]
>> +      struct plugin_offload_file *ofld;
>> +      [...]
>> +      ofld = offload_files->next;
>> +      while (ofld)
>> +     {
>> +       fprintf (f, "%s\n", ofld->name);
>> +       ofld = ofld->next;
>> +     }
>
> To the casual reader, skipping the first offload_files looks like a
> off-by-one error, so I suggest you add a comment "Skip the dummy item at
> the start of the list.", or similar.

OK.

  -- Ilya
Tom de Vries Feb. 23, 2016, 7:37 a.m. UTC | #4
On 22/02/16 19:07, Ilya Verbin wrote:
> 2016-02-22 18:13 GMT+03:00 Thomas Schwinge<thomas@codesourcery.com>:
>> >On Sat, 20 Feb 2016 13:54:20 +0300, Ilya Verbin<iverbin@gmail.com>  wrote:
>>> >>On Fri, Feb 19, 2016 at 15:53:08 +0100, Jakub Jelinek wrote:
>>>> >> >On Wed, Feb 10, 2016 at 08:19:34PM +0300, Ilya Verbin wrote:
>>>>> >> > >This patch adds crtoffload{begin,end}.o to all -fopenmp programs, if they exist.
>>>>> >> > >I couldn't think of a better solution...
>>>>> >> > >Tested using the testcase from the previous mail, e.g.:
>>>>> >> > >
>>>>> >> > >$ gcc -DNUM=1 -c -fopenmp test.c -o obj1.o
>>>>> >> > >$ gcc -DNUM=2 -c -fopenmp test.c -o obj2.o
>>>>> >> > >$ gcc -DNUM=3 -c -fopenmp test.c -o obj3.o
>>>>> >> > >$ gcc -DNUM=4 -c -fopenmp test.c -o obj4.o -flto
>>>>> >> > >$ gcc -DNUM=5 -c -fopenmp test.c -o obj5.o
>>>>> >> > >$ gcc -DNUM=6 -c -fopenmp test.c -o obj6.o -flto
>>>>> >> > >$ gcc -DNUM=7 -c -fopenmp test.c -o obj7.o
>>>>> >> > >$ gcc-ar -cvq libtest.a obj3.o obj4.o obj5.o
>>>>> >> > >$ gcc -fopenmp main.c obj1.o obj2.o libtest.a obj6.o obj7.o
>>>>> >> > >
>>>>> >> > >And other combinations.
>> >
>>> >>Thomas, could you please test it using nvptx
>> >
>> >It mostly;-)  works.  With nvptx offloading enabled (which you don't
>> >have, do you?), I'm seeing one test case regress:
>> >
>> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 9)
>> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 13)
>> >     PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 (test for excess errors)
>> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 execution test
>> >
>> >(Same for C++.)  That testcase, just recently added by Tom in r233237
>> >"Handle -fdiagnostics-color in lto", specifies 'dg-additional-options
>> >"-flto -fno-use-linker-plugin"'.  Is that now an unsupported
>> >combination/configuration?  (I have not yet looked in detail, but it
>> >appears as if the offloading compilers are no longer being run for
>> >-fno-use-linker-plugin.)
> Yes, it's really hard to fix the "lto + non-lto objects" issue for
> no-use-linker-plugin LTO path. In this patch lto-plugin prepares a
> list of objects files with offloading and passes it to lto-wrapper, so
> I believe we should consider offloading without lto-plugin as
> unsupported. I'll update wiki when the patch will be committed.
>

Shouldn't we error (or at least warn) then if we compile a file 
containing an offload construct with fopenacc/fopenmp and 
-fno-use-linker-plugin?

Thanks,
- Tom
Thomas Schwinge Feb. 24, 2016, 4:13 p.m. UTC | #5
Hi!

On Tue, 23 Feb 2016 08:37:07 +0100, Tom de Vries <Tom_deVries@mentor.com> wrote:
> On 22/02/16 19:07, Ilya Verbin wrote:
> > 2016-02-22 18:13 GMT+03:00 Thomas Schwinge<thomas@codesourcery.com>:
> >> >On Sat, 20 Feb 2016 13:54:20 +0300, Ilya Verbin<iverbin@gmail.com>  wrote:
> >>> >>On Fri, Feb 19, 2016 at 15:53:08 +0100, Jakub Jelinek wrote:
> >>>> >> >On Wed, Feb 10, 2016 at 08:19:34PM +0300, Ilya Verbin wrote:
> >>>>> >> > >This patch adds crtoffload{begin,end}.o to all -fopenmp programs, if they exist.

> >>> >>Thomas, could you please test it using nvptx
> >> >
> >> >It mostly;-)  works.  With nvptx offloading enabled (which you don't
> >> >have, do you?), I'm seeing one test case regress:
> >> >
> >> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 9)
> >> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 13)
> >> >     PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 (test for excess errors)
> >> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 execution test
> >> >
> >> >(Same for C++.)  That testcase, just recently added by Tom in r233237
> >> >"Handle -fdiagnostics-color in lto", specifies 'dg-additional-options
> >> >"-flto -fno-use-linker-plugin"'.  Is that now an unsupported
> >> >combination/configuration?  (I have not yet looked in detail, but it
> >> >appears as if the offloading compilers are no longer being run for
> >> >-fno-use-linker-plugin.)
> > Yes, it's really hard to fix the "lto + non-lto objects" issue for
> > no-use-linker-plugin LTO path. In this patch lto-plugin prepares a
> > list of objects files with offloading and passes it to lto-wrapper, so
> > I believe we should consider offloading without lto-plugin as
> > unsupported. I'll update wiki when the patch will be committed.

Aha, I see.  I guess there's no point in keeping offloading supported for
the -fno-lto (default) with -fno-use-linker-plugin configuration?

Ilya, then please remove
libgomp/testsuite/libgomp.oacc-c-c++-common/parallel-dims-2.c as part of
your patch, unless Tom thinks it should be changed to a -flto test, but
without -fno-use-linker-plugin?

> Shouldn't we error (or at least warn) then if we compile a file 
> containing an offload construct with fopenacc/fopenmp and 
> -fno-use-linker-plugin?

Yes, that makes sense to me, too.  (Note that, as I understand it,
-fno-use-linker-plugin may also be the default for certain GCC
configurations...)  Aside from spec stuff in gcc/gcc.c relating to
LINK_PLUGIN_SPEC, I see there's some code in
gcc/gcc.c:driver::maybe_run_linker evaluating the three possible values
of HAVE_LTO_PLUGIN, but I have not yet thought about how and where to
conditionalize the diagnostic if attempting to do offloading in an
unsupported (-fno-use-linker-plugin) configuration.


Grüße
 Thomas
Ilya Verbin Feb. 24, 2016, 4:29 p.m. UTC | #6
On Wed, Feb 24, 2016 at 17:13:35 +0100, Thomas Schwinge wrote:
> On Tue, 23 Feb 2016 08:37:07 +0100, Tom de Vries <Tom_deVries@mentor.com> wrote:
> > On 22/02/16 19:07, Ilya Verbin wrote:
> > > 2016-02-22 18:13 GMT+03:00 Thomas Schwinge<thomas@codesourcery.com>:
> > >> >On Sat, 20 Feb 2016 13:54:20 +0300, Ilya Verbin<iverbin@gmail.com>  wrote:
> > >>> >>On Fri, Feb 19, 2016 at 15:53:08 +0100, Jakub Jelinek wrote:
> > >>>> >> >On Wed, Feb 10, 2016 at 08:19:34PM +0300, Ilya Verbin wrote:
> > >>>>> >> > >This patch adds crtoffload{begin,end}.o to all -fopenmp programs, if they exist.
> 
> > >>> >>Thomas, could you please test it using nvptx
> > >> >
> > >> >It mostly;-)  works.  With nvptx offloading enabled (which you don't
> > >> >have, do you?), I'm seeing one test case regress:
> > >> >
> > >> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 9)
> > >> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0  (test for errors, line 13)
> > >> >     PASS: libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 (test for excess errors)
> > >> >     [-PASS:-]{+FAIL:+} libgomp.oacc-c/../libgomp.oacc-c-c++-common/parallel-dims-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 execution test
> > >> >
> > >> >(Same for C++.)  That testcase, just recently added by Tom in r233237
> > >> >"Handle -fdiagnostics-color in lto", specifies 'dg-additional-options
> > >> >"-flto -fno-use-linker-plugin"'.  Is that now an unsupported
> > >> >combination/configuration?  (I have not yet looked in detail, but it
> > >> >appears as if the offloading compilers are no longer being run for
> > >> >-fno-use-linker-plugin.)
> > > Yes, it's really hard to fix the "lto + non-lto objects" issue for
> > > no-use-linker-plugin LTO path. In this patch lto-plugin prepares a
> > > list of objects files with offloading and passes it to lto-wrapper, so
> > > I believe we should consider offloading without lto-plugin as
> > > unsupported. I'll update wiki when the patch will be committed.
> 
> Aha, I see.  I guess there's no point in keeping offloading supported for
> the -fno-lto (default) with -fno-use-linker-plugin configuration?
> 
> Ilya, then please remove
> libgomp/testsuite/libgomp.oacc-c-c++-common/parallel-dims-2.c as part of
> your patch, unless Tom thinks it should be changed to a -flto test, but
> without -fno-use-linker-plugin?

OK.

> > Shouldn't we error (or at least warn) then if we compile a file 
> > containing an offload construct with fopenacc/fopenmp and 
> > -fno-use-linker-plugin?
> 
> Yes, that makes sense to me, too.  (Note that, as I understand it,
> -fno-use-linker-plugin may also be the default for certain GCC
> configurations...)  Aside from spec stuff in gcc/gcc.c relating to
> LINK_PLUGIN_SPEC, I see there's some code in
> gcc/gcc.c:driver::maybe_run_linker evaluating the three possible values
> of HAVE_LTO_PLUGIN, but I have not yet thought about how and where to
> conditionalize the diagnostic if attempting to do offloading in an
> unsupported (-fno-use-linker-plugin) configuration.

To print this error someone has to detect that at least one object contains
offload sections, only linker plugin and lto-wrapper can do it.  But if linker
plugin is absent, the lto-wrapper have to open all objects, scan for all
sections, etc.  Looks like too much overhead for a single diagnostic.

  -- Ilya
diff mbox

Patch

diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h
index 2f1bbcc..2fdb63c 100644
--- a/gcc/config/gnu-user.h
+++ b/gcc/config/gnu-user.h
@@ -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
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index ed20b4e..f240812 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -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)
@@ -840,40 +842,32 @@  copy_file (const char *dest, const char *src)
     }
 }
 
-/* Find the crtoffloadbegin.o and crtoffloadend.o files in LIBRARY_PATH, make
-   copies and store the names of the copies in offloadbegin and offloadend.  */
+/* Find the crtoffloadtable.o file in LIBRARY_PATH, make copy and pass name of
+   the copy to the linker.  */
 
 static void
-find_offloadbeginend (void)
+find_crtoffloadtable (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 n_paths = parse_env_var (library_path, &paths, "/crtoffloadtable.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);
+	/* The linker will delete the filename we give it, so make a copy.  */
+	char *crtoffloadtable = make_temp_file (".crtoffloadtable.o");
+	copy_file (crtoffloadtable, paths[i]);
+	printf ("%s\n", crtoffloadtable);
+	XDELETEVEC (crtoffloadtable);
 	break;
       }
   if (i == n_paths)
     fatal_error (input_location,
-		 "installation error, can't find crtoffloadbegin.o");
+		 "installation error, can't find crtoffloadtable.o");
 
   free_array_of_ptrs ((void **) paths, n_paths);
 }
@@ -970,8 +964,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 +981,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 +995,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 +1028,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 +1126,102 @@  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 ();
+	  find_crtoffloadtable ();
 	  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 +1450,7 @@  cont:
     }
 
  finish:
-  if (offloadend)
-    printf ("%s\n", offloadend);
-
   XDELETE (lto_argv);
-  XDELETE (offload_argv);
   obstack_free (&argv_obstack, NULL);
 }
 
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 570b1a7..f09b39b 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -995,12 +995,16 @@  crtbeginT$(objext): $(srcdir)/crtstuff.c
 	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
 
 # crtoffloadbegin and crtoffloadend contain symbols, that mark the begin and
-# the end of tables with addresses, required for offloading.
+# the end of tables with addresses, required for offloading.  crtoffloadtable
+# contains the array with addresses of those symbols.
 crtoffloadbegin$(objext): $(srcdir)/offloadstuff.c
 	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN
 
 crtoffloadend$(objext): $(srcdir)/offloadstuff.c
 	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_END
+
+crtoffloadtable$(objext): $(srcdir)/offloadstuff.c
+	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_TABLE
 endif
 
 ifeq ($(enable_vtable_verify),yes)
diff --git a/libgcc/configure b/libgcc/configure
index de8c13c..f3f3605 100644
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -4835,7 +4835,7 @@  fi
 
 
 if test x"$enable_offload_targets" != x; then
-  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o"
+  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o crtoffloadtable.o"
 fi
 
 # Check if Solaris/x86 linker supports ZERO terminator unwind entries.
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 860a5f5..897259e 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -418,7 +418,7 @@  AC_SUBST(accel_dir_suffix)
 AC_SUBST(real_host_noncanonical)
 
 if test x"$enable_offload_targets" != x; then
-  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o"
+  extra_parts="${extra_parts} crtoffloadbegin.o crtoffloadend.o crtoffloadtable.o"
 fi
 
 # Check if Solaris/x86 linker supports ZERO terminator unwind entries.
diff --git a/libgcc/offloadstuff.c b/libgcc/offloadstuff.c
index 45e89cf..a4ea3ac 100644
--- a/libgcc/offloadstuff.c
+++ b/libgcc/offloadstuff.c
@@ -40,23 +40,22 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include "tm.h"
 #include "libgcc_tm.h"
 
+#if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
+
 #define OFFLOAD_FUNC_TABLE_SECTION_NAME ".gnu.offload_funcs"
 #define OFFLOAD_VAR_TABLE_SECTION_NAME ".gnu.offload_vars"
 
 #ifdef CRT_BEGIN
 
-#if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
 const void *const __offload_func_table[0]
   __attribute__ ((__used__, visibility ("hidden"),
 		  section (OFFLOAD_FUNC_TABLE_SECTION_NAME))) = { };
 const void *const __offload_var_table[0]
   __attribute__ ((__used__, visibility ("hidden"),
 		  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
-#endif
 
 #elif defined CRT_END
 
-#if defined(HAVE_GAS_HIDDEN) && defined(ENABLE_OFFLOADING)
 const void *const __offload_funcs_end[0]
   __attribute__ ((__used__, visibility ("hidden"),
 		  section (OFFLOAD_FUNC_TABLE_SECTION_NAME))) = { };
@@ -64,8 +63,12 @@  const void *const __offload_vars_end[0]
   __attribute__ ((__used__, visibility ("hidden"),
 		  section (OFFLOAD_VAR_TABLE_SECTION_NAME))) = { };
 
+#elif defined CRT_TABLE
+
 extern const void *const __offload_func_table[];
 extern const void *const __offload_var_table[];
+extern const void *const __offload_funcs_end[];
+extern const void *const __offload_vars_end[];
 
 const void *const __OFFLOAD_TABLE__[]
   __attribute__ ((__visibility__ ("hidden"))) =
@@ -73,8 +76,9 @@  const void *const __OFFLOAD_TABLE__[]
   &__offload_func_table, &__offload_funcs_end,
   &__offload_var_table, &__offload_vars_end
 };
+
+#else /* ! CRT_BEGIN && ! CRT_END && ! CRT_TABLE  */
+#error "One of CRT_BEGIN, CRT_END or CRT_TABLE must be defined."
 #endif
 
-#else /* ! CRT_BEGIN && ! CRT_END */
-#error "One of CRT_BEGIN or CRT_END must be defined."
 #endif
diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c
index 1ed0f08..35cb63a 100644
--- a/lto-plugin/lto-plugin.c
+++ b/lto-plugin/lto-plugin.c
@@ -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->next;
+      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,18 +1038,72 @@  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 (offload_files == NULL)
     {
-      num_offload_files++;
-      offload_files =
-	xrealloc (offload_files,
-		  num_offload_files * sizeof (struct plugin_file_info));
-      offload_files[num_offload_files - 1] = lto_file;
+      /* Add dummy item to the start of the list.  */
+      offload_files = xmalloc (sizeof (struct plugin_offload_file));
+      offload_files->name = NULL;
+      offload_files->next = NULL;
+      offload_files_last = offload_files;
     }
 
-  *claimed = 1;
+  /* If this is an LTO file without offload, and it is the first LTO file, save
+     the pointer to the last offload file in the list.  Further offload LTO
+     files will be inserted after it, if any.  */
+  if (*claimed && obj.offload == 0 && offload_files_last_lto == NULL)
+    offload_files_last_lto = offload_files_last;
+
+  if (obj.offload == 1)
+    {
+      /* 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.  */
+      struct plugin_offload_file *ofld
+	= xmalloc (sizeof (struct plugin_offload_file));
+      ofld->name = lto_file.name;
+      ofld->next = NULL;
+
+      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
+	    {
+	      ofld->next = offload_files->next;
+	      offload_files->next = 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
+	/* 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++;
+    }
 
   goto cleanup;