diff mbox

nvptx offloading patches [3/n], i386 bits RFD

Message ID 5458C7F8.8080702@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt Nov. 4, 2014, 12:35 p.m. UTC
On 11/03/2014 11:27 PM, Jeff Law wrote:
> On 11/01/14 05:57, Bernd Schmidt wrote:
>> This is not against current trunk; it applies to gomp-4_0-branch where
>> it is one of the necessary parts to make offloading x86->nvptx work. The
>> issue is that the LTO file format depends on the machine_modes enum, it
>> needs to match between host and offload target. The easiest way to do
>> this is to just use the host-modes.def when compiling an offload
>> compiler.
>>
>> Ports that want to be hosts for offloading may need to modify their
>> modes.def. The patch below contains changes to i386-modes.def which
>> modifies XFmode depending on a target switch. I'm not actually entirely
>> sure what to do about this. Do we want to make this flag an error when
>> offloading is enabled? Or maybe add float format support to the
>> -foffload-abi option?
>>
>> Thoughts? Ok for the first part of the patch once the other offloading
>> patches have gone in (bootstrapped and tested on x86_64-linux)?
> It feels like we've got another real distinction to make.  We've had
> host, build & target and they're all independent.  It feels like we need
> offload target and better separate between target and offload target.
> Then we need to figure out the places where we've got bleed-out.

Is this a question of terminology? I agree that saying "offload host" 
when we'd normally be calling it the "target" is confusing, but it's 
difficult to come up with better names.

Offload host and target are not quite independent - when it's 
implemented through LTO at least there has to be a fairly close 
agreement even down to machine modes, which is why a patch like this is 
necessary.

> Not sure how to deal with this any further out than the immediate term
> than using a hack like this. Though I'd prefer to avoid the #ifdef as it
> seems to me this shouldn't be baked in at build/configure time.

Yeah, I'm not expecting the i386 part to go in quite as-is. For 
reference I'm including the offload-abi patch - Ilya is submitting this 
along with other option changes. One possibility would be to print and 
recognize strings such as lp64D128 or lp64D96 which would include 
information about the size of long double. Somehow though I can't really 
bring myself to believe that -mlong-double128 is a real use case with 
offloading so we might just disallow the combination.

CCing Uros in case he has an opinion.


Bernd

Comments

Uros Bizjak Nov. 4, 2014, 6:58 p.m. UTC | #1
On Tue, Nov 4, 2014 at 1:35 PM, Bernd Schmidt <bernds@codesourcery.com> wrote:

>> Not sure how to deal with this any further out than the immediate term
>> than using a hack like this. Though I'd prefer to avoid the #ifdef as it
>> seems to me this shouldn't be baked in at build/configure time.
>
>
> Yeah, I'm not expecting the i386 part to go in quite as-is. For reference
> I'm including the offload-abi patch - Ilya is submitting this along with
> other option changes. One possibility would be to print and recognize
> strings such as lp64D128 or lp64D96 which would include information about
> the size of long double. Somehow though I can't really bring myself to
> believe that -mlong-double128 is a real use case with offloading so we might
> just disallow the combination.
>
> CCing Uros in case he has an opinion.

-mlong-double-128 was introduced for Android in:

2014-02-03  H.J. Lu  <hongjiu.lu@intel.com>

    * config/i386/i386.c (flag_opts): Add -mlong-double-128.
    (ix86_option_override_internal): Default long double to 64-bit for
    32-bit Bionic and to 128-bit for 64-bit Bionic.

    [...]

IMO, if it troubles offloading, anything else than the default
-mlong-double-80 should be disallowed.

Uros.
Jeff Law Nov. 4, 2014, 9:50 p.m. UTC | #2
On 11/04/14 05:35, Bernd Schmidt wrote:
>>> Ports that want to be hosts for offloading may need to modify their
>>> modes.def. The patch below contains changes to i386-modes.def which
>>> modifies XFmode depending on a target switch. I'm not actually entirely
>>> sure what to do about this. Do we want to make this flag an error when
>>> offloading is enabled? Or maybe add float format support to the
>>> -foffload-abi option?
>>>
>>> Thoughts? Ok for the first part of the patch once the other offloading
>>> patches have gone in (bootstrapped and tested on x86_64-linux)?
>> It feels like we've got another real distinction to make.  We've had
>> host, build & target and they're all independent.  It feels like we need
>> offload target and better separate between target and offload target.
>> Then we need to figure out the places where we've got bleed-out.
>
> Is this a question of terminology? I agree that saying "offload host"
> when we'd normally be calling it the "target" is confusing, but it's
> difficult to come up with better names.
No, I don't think it's terminology.  It's really that in effect we have 
two targets.  One is a normal CPU, the other is a GPU.

ie, there's nothing that says we won't have a GPU that's being driven by 
an ARM or PPC.  What I want to avoid is GPU-isms getting sprinkled into 
the x86 (or any other) backend.

The problem is we don't have any infrastructure in place for this kind 
of situation.  So we start off with a few hacks and hopefully we're able 
to see some commonality and start to see how to handle the 
multi-architecture target issues a bit better.

Jeff
Bernd Schmidt Nov. 5, 2014, 12:19 a.m. UTC | #3
On 11/04/2014 10:50 PM, Jeff Law wrote:
> No, I don't think it's terminology.  It's really that in effect we have
> two targets.  One is a normal CPU, the other is a GPU.
>
> ie, there's nothing that says we won't have a GPU that's being driven by
> an ARM or PPC.  What I want to avoid is GPU-isms getting sprinkled into
> the x86 (or any other) backend.
>
> The problem is we don't have any infrastructure in place for this kind
> of situation.  So we start off with a few hacks and hopefully we're able
> to see some commonality and start to see how to handle the
> multi-architecture target issues a bit better.

FWIW the three non-ptx patches I sent plus the -foffload-abi stuff are 
the only ones necessary to make offloading through the LTO path work 
(this was against the gomp-4_0-branch with earlier versions of the 
offload patches Ilya's been posting; I haven't had a chance to test 
everything together in trunk yet). That doesn't seem like a large amount 
of changes.

For other targets I don't expect the situation to be too different. ARM 
has a similar float mode issue for HFmode, and things like 
m{big,little}-endian may have to be handled. I expect these can be 
handled with -foffload-abi machinery.

So, looking ahead - I'm imagining extra switches along the lines of
  -foffload-abi-hflt={arm,ieee,...}
  -foffload-abi-ldbl={64,x86,128}
  -foffload-abi-endian={big,little}

On some targets it might make sense to disallow offloading if certain 
switches are used. Uros seems to agree that on x86 the -mlong-double-128 
switch isn't very interesting. I'm thinking about how to deal with such 
a situation - maybe an offload_abi_valid hook that gets called whenever 
we find that we want to stream out offloaded functions. That would then 
sorry out (or maybe just warn) if the hook returns false.

I can do either or both, whatever the consensus turns out to be.


Bernd
Bernd Schmidt Nov. 14, 2014, 6:21 p.m. UTC | #4
On 11/05/2014 01:19 AM, Bernd Schmidt wrote:
> On 11/04/2014 10:50 PM, Jeff Law wrote:
>> No, I don't think it's terminology.  It's really that in effect we have
>> two targets.  One is a normal CPU, the other is a GPU.
>>
>> ie, there's nothing that says we won't have a GPU that's being driven by
>> an ARM or PPC.  What I want to avoid is GPU-isms getting sprinkled into
>> the x86 (or any other) backend.
>>
>> The problem is we don't have any infrastructure in place for this kind
>> of situation.  So we start off with a few hacks and hopefully we're able
>> to see some commonality and start to see how to handle the
>> multi-architecture target issues a bit better.
>
> FWIW the three non-ptx patches I sent plus the -foffload-abi stuff are
> the only ones necessary to make offloading through the LTO path work
> (this was against the gomp-4_0-branch with earlier versions of the
> offload patches Ilya's been posting; I haven't had a chance to test
> everything together in trunk yet). That doesn't seem like a large amount
> of changes.
>
> For other targets I don't expect the situation to be too different. ARM
> has a similar float mode issue for HFmode, and things like
> m{big,little}-endian may have to be handled. I expect these can be
> handled with -foffload-abi machinery.
>
> So, looking ahead - I'm imagining extra switches along the lines of
>   -foffload-abi-hflt={arm,ieee,...}
>   -foffload-abi-ldbl={64,x86,128}
>   -foffload-abi-endian={big,little}
>
> On some targets it might make sense to disallow offloading if certain
> switches are used. Uros seems to agree that on x86 the -mlong-double-128
> switch isn't very interesting. I'm thinking about how to deal with such
> a situation - maybe an offload_abi_valid hook that gets called whenever
> we find that we want to stream out offloaded functions. That would then
> sorry out (or maybe just warn) if the hook returns false.
>
> I can do either or both, whatever the consensus turns out to be.

The discussion on these patches kind of stalled, so a gentle ping - it 
would be nice to integrate these now that Ilya's offload patches are in.


Bernd
diff mbox

Patch

Index: gcc/common.opt
===================================================================
--- gcc/common.opt.orig
+++ gcc/common.opt
@@ -1601,6 +1601,19 @@  fnon-call-exceptions
 Common Report Var(flag_non_call_exceptions) Optimization
 Support synchronous non-call exceptions
 
+foffload-abi=
+Common Joined RejectNegative Enum(offload_abi) Var(flag_offload_abi) Init(OFFLOAD_ABI_UNSET)
+-foffload-abi=[lp64|ilp32]	Set the ABI to use in an offload compiler
+
+Enum
+Name(offload_abi) Type(enum offload_abi) UnknownError(unknown offload ABI %qs)
+
+EnumValue
+Enum(offload_abi) String(ilp32) Value(OFFLOAD_ABI_ILP32)
+
+EnumValue
+Enum(offload_abi) String(lp64) Value(OFFLOAD_ABI_LP64)
+
 fomit-frame-pointer
 Common Report Var(flag_omit_frame_pointer) Optimization
 When possible do not generate stack frames
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c.orig
+++ gcc/config/i386/i386.c
@@ -4261,6 +4261,15 @@  ix86_option_override (void)
   register_pass (&insert_vzeroupper_info);
 }
 
+/* Implement the TARGET_OFFLOAD_OPTIONS hook.  */
+static char *
+ix86_offload_options (void)
+{
+  if (TARGET_LP64)
+    return xstrdup ("-foffload-abi=lp64");
+  return xstrdup ("-foffload-abi=ilp32");
+}
+
 /* Update register usage after having seen the compiler flags.  */
 
 static void
@@ -47142,6 +47151,10 @@  ix86_atomic_assign_expand_fenv (tree *ho
 #define TARGET_FLOAT_EXCEPTIONS_ROUNDING_SUPPORTED_P \
   ix86_float_exceptions_rounding_supported_p
 
+#undef TARGET_OFFLOAD_OPTIONS
+#define TARGET_OFFLOAD_OPTIONS \
+  ix86_offload_options
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-i386.h"
Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h.orig
+++ gcc/coretypes.h
@@ -111,6 +111,12 @@  enum tls_model {
   TLS_MODEL_LOCAL_EXEC
 };
 
+enum offload_abi {
+  OFFLOAD_ABI_UNSET,
+  OFFLOAD_ABI_LP64,
+  OFFLOAD_ABI_ILP32
+};
+
 /* Types of unwind/exception handling info that can be generated.  */
 
 enum unwind_info_type
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi.orig
+++ gcc/doc/tm.texi
@@ -11446,3 +11446,12 @@  Used when offloaded functions are seen i
 sections are available.  It is called once for each symbol that must be
 recorded in the offload function and variable table.
 @end deftypefn
+
+@deftypefn {Target Hook} {char *} TARGET_OFFLOAD_OPTIONS (void)
+Used when writing out the list of options into an LTO file.  It should
+translate any relevant target-specific options (such as the ABI in use)
+into one of the @option{-foffload} options that exist as a common interface
+to express such options. It should return a string containing these options,
+separated by spaces, which the caller will free.
+
+@end deftypefn
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in.orig
+++ gcc/doc/tm.texi.in
@@ -8427,3 +8427,5 @@  and the associated definitions of those
 @hook TARGET_ATOMIC_ASSIGN_EXPAND_FENV
 
 @hook TARGET_RECORD_OFFLOAD_SYMBOL
+
+@hook TARGET_OFFLOAD_OPTIONS
Index: gcc/hooks.c
===================================================================
--- gcc/hooks.c.orig
+++ gcc/hooks.c
@@ -373,12 +373,19 @@  hook_tree_tree_tree_tree_3rd_identity (t
   return c;
 }
 
-/* Generic hook that takes no arguments and returns a NULL string.  */
+/* Generic hook that takes no arguments and returns a NULL const string.  */
 const char *
 hook_constcharptr_void_null (void)
 {
   return NULL;
 }
+
+/* Generic hook that takes no arguments and returns a NULL string.  */
+char *
+hook_charptr_void_null (void)
+{
+  return NULL;
+}
 
 /* Generic hook that takes a tree and returns a NULL string.  */
 const char *
Index: gcc/hooks.h
===================================================================
--- gcc/hooks.h.orig
+++ gcc/hooks.h
@@ -101,6 +101,7 @@  extern rtx hook_rtx_rtx_identity (rtx);
 extern rtx hook_rtx_rtx_null (rtx);
 extern rtx hook_rtx_tree_int_null (tree, int);
 
+extern char *hook_charptr_void_null (void);
 extern const char *hook_constcharptr_void_null (void);
 extern const char *hook_constcharptr_const_tree_null (const_tree);
 extern const char *hook_constcharptr_const_rtx_null (const_rtx);
Index: gcc/lto-opts.c
===================================================================
--- gcc/lto-opts.c.orig
+++ gcc/lto-opts.c
@@ -37,6 +37,7 @@  along with GCC; see the file COPYING3.
 #include "common/common-target.h"
 #include "diagnostic.h"
 #include "lto-streamer.h"
+#include "lto-section-names.h"
 #include "toplev.h"
 
 /* Append the option piece OPT to the COLLECT_GCC_OPTIONS string
@@ -130,6 +131,22 @@  lto_write_options (void)
     append_to_collect_gcc_options (&temporary_obstack, &first_p,
 			       "-fno-strict-overflow");
 
+  if (strcmp (section_name_prefix, OMP_SECTION_NAME_PREFIX) == 0)
+    {
+      char *offload_opts = targetm.offload_options ();
+      char *offload_ptr = offload_opts;
+      while (offload_ptr)
+	{
+	  char *next = strchr (offload_ptr, ' ');
+	  if (next)
+	    *next++ = '\0';
+	  append_to_collect_gcc_options (&temporary_obstack, &first_p,
+					 offload_ptr);
+	  offload_ptr = next;
+	}
+      free (offload_opts);
+    }
+
   /* Output explicitly passed options.  */
   for (i = 1; i < save_decoded_options_count; ++i)
     {
@@ -153,6 +170,10 @@  lto_write_options (void)
       if (!(cl_options[option->opt_index].flags & (CL_COMMON|CL_TARGET|CL_LTO)))
 	continue;
 
+      if ((cl_options[option->opt_index].flags & CL_TARGET)
+	  && strcmp (section_name_prefix, OMP_SECTION_NAME_PREFIX) == 0)
+	continue;
+
       /* Drop options created from the gcc driver that will be rejected
 	 when passed on to the driver again.  */
       if (cl_options[option->opt_index].cl_reject_driver)
Index: gcc/lto-wrapper.c
===================================================================
--- gcc/lto-wrapper.c.orig
+++ gcc/lto-wrapper.c
@@ -282,6 +282,17 @@  merge_and_complain (struct cl_decoded_op
 		   foption->orig_option_with_args_text);
 	  break;
 
+	case OPT_foffload_abi_:
+	  for (j = 0; j < *decoded_options_count; ++j)
+	    if ((*decoded_options)[j].opt_index == foption->opt_index)
+	      break;
+	  if (j == *decoded_options_count)
+	    append_option (decoded_options, decoded_options_count, foption);
+	  else if (foption->value != (*decoded_options)[j].value)
+	    fatal ("Option %s not used consistently in all LTO input files",
+		   foption->orig_option_with_args_text);
+	  break;
+
 	case OPT_O:
 	case OPT_Ofast:
 	case OPT_Og:
@@ -414,6 +425,109 @@  parse_env_var (const char *str, char ***
   return num;
 }
 
+static void
+append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts,
+			 unsigned int count)
+{
+  /* Append compiler driver arguments as far as they were merged.  */
+  for (unsigned int j = 1; j < count; ++j)
+    {
+      struct cl_decoded_option *option = &opts[j];
+
+      /* File options have been properly filtered by lto-opts.c.  */
+      switch (option->opt_index)
+	{
+	  /* Drop arguments that we want to take from the link line.  */
+	case OPT_flto_:
+	case OPT_flto:
+	case OPT_flto_partition_:
+	  continue;
+
+	default:
+	  break;
+	}
+
+      /* For now do what the original LTO option code was doing - pass
+	 on any CL_TARGET flag and a few selected others.  */
+      switch (option->opt_index)
+	{
+	case OPT_fPIC:
+	case OPT_fpic:
+	case OPT_fPIE:
+	case OPT_fpie:
+	case OPT_fcommon:
+	case OPT_fexceptions:
+	case OPT_fnon_call_exceptions:
+	case OPT_fgnu_tm:
+	case OPT_freg_struct_return:
+	case OPT_fpcc_struct_return:
+	case OPT_fshort_double:
+	case OPT_ffp_contract_:
+	case OPT_fwrapv:
+	case OPT_ftrapv:
+	case OPT_fstrict_overflow:
+	case OPT_foffload_abi_:
+	case OPT_O:
+	case OPT_Ofast:
+	case OPT_Og:
+	case OPT_Os:
+	  break;
+
+	default:
+	  if (!(cl_options[option->opt_index].flags & CL_TARGET))
+	    continue;
+	}
+
+      /* Pass the option on.  */
+      for (unsigned int i = 0; i < option->canonical_option_num_elements; ++i)
+	obstack_ptr_grow (argv_obstack, option->canonical_option[i]);
+    }
+}
+
+static void
+append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
+		       unsigned int count, bool include_target_options)
+{
+  /* Append linker driver arguments.  Compiler options from the linker
+     driver arguments will override / merge with those from the compiler.  */
+  for (unsigned int j = 1; j < count; ++j)
+    {
+      struct cl_decoded_option *option = &opts[j];
+
+      /* Do not pass on frontend specific flags not suitable for lto.  */
+      if (!(cl_options[option->opt_index].flags
+	    & (CL_COMMON|CL_TARGET|CL_DRIVER|CL_LTO)))
+	continue;
+
+      if ((cl_options[option->opt_index].flags & CL_TARGET)
+	  && !include_target_options)
+	continue;
+
+      switch (option->opt_index)
+	{
+	case OPT_o:
+	case OPT_flto_:
+	case OPT_flto:
+	  /* We've handled these LTO options, do not pass them on.  */
+	  continue;
+
+	case OPT_freg_struct_return:
+	case OPT_fpcc_struct_return:
+	case OPT_fshort_double:
+	  /* Ignore these, they are determined by the input files.
+	     ???  We fail to diagnose a possible mismatch here.  */
+	  continue;
+
+	default:
+	  break;
+	}
+
+      /* Pass the option on.  */
+      for (unsigned int i = 0; i < option->canonical_option_num_elements; ++i)
+	obstack_ptr_grow (argv_obstack, option->canonical_option[i]);
+    }
+}
+
 /* Check whether NAME can be accessed in MODE.  This is like access,
    except that it never considers directories to be executable.  */
 
@@ -440,7 +554,11 @@  access_check (const char *name, int mode
 
 static char*
 prepare_target_image (const char *target, const char *compiler_path,
-		      unsigned in_argc, char *in_argv[])
+		      unsigned in_argc, char *in_argv[],
+		      struct cl_decoded_option *compiler_opts,
+		      unsigned int compiler_opt_count,
+		      struct cl_decoded_option * /*linker_opts */,
+		      unsigned int /*linker_opt_count*/)
 {
   const char **argv;
   struct obstack argv_obstack;
@@ -469,8 +587,6 @@  prepare_target_image (const char *target
   /* Generate temp file name.  */
   filename = make_temp_file (".target.o");
 
-  /* --------------------------------------  */
-  /* Run gcc for target.  */
   obstack_init (&argv_obstack);
   obstack_ptr_grow (&argv_obstack, compiler);
   obstack_ptr_grow (&argv_obstack, "-o");
@@ -479,6 +595,8 @@  prepare_target_image (const char *target
   for (i = 1; i < in_argc; ++i)
     if (strncmp (in_argv[i], "-fresolution=", sizeof ("-fresolution=") - 1))
       obstack_ptr_grow (&argv_obstack, in_argv[i]);
+
+  append_compiler_options (&argv_obstack, compiler_opts, compiler_opt_count);
   obstack_ptr_grow (&argv_obstack, NULL);
 
   argv = XOBFINISH (&argv_obstack, const char **);
@@ -501,7 +619,11 @@  prepare_target_image (const char *target
    array.  */
 
 static void
-compile_images_for_openmp_targets (unsigned in_argc, char *in_argv[])
+compile_images_for_openmp_targets (unsigned in_argc, char *in_argv[],
+				   struct cl_decoded_option *compiler_opts,
+				   unsigned int compiler_opt_count,
+				   struct cl_decoded_option *linker_opts,
+				   unsigned int linker_opt_count)
 {
   char *target_names;
   char **names;
@@ -523,8 +645,10 @@  compile_images_for_openmp_targets (unsig
   offload_names = XCNEWVEC (char *, num_targets + 1);
   for (unsigned i = 0; i < num_targets; i++)
     {
-      offload_names[i] = prepare_target_image (names[i], compiler_path,
-					       in_argc, in_argv);
+      offload_names[i]
+	= prepare_target_image (names[i], compiler_path, in_argc, in_argv,
+				compiler_opts, compiler_opt_count,
+				linker_opts, linker_opt_count);
       if (!offload_names[i])
 	fatal_perror ("Problem with building target image for %s.\n", names[i]);
     }
@@ -592,6 +716,74 @@  find_ompbeginend (void)
   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
+   otherwise.  COLLECT_GCC holds the value of the environment variable with
+   the same name.  */
+
+static bool
+find_and_merge_options (int fd, off_t file_offset, const char *prefix,
+			struct cl_decoded_option **opts,
+			unsigned int *opt_count, const char *collect_gcc)
+{
+  off_t offset, length;
+  char *data;
+  char *fopts;
+  const char *errmsg;
+  int err;
+  struct cl_decoded_option *fdecoded_options = *opts;
+  unsigned int fdecoded_options_count = *opt_count;
+
+  simple_object_read *sobj;
+  sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO",
+				   &errmsg, &err);
+  if (!sobj)
+    return false;
+
+  char *secname = XNEWVEC (char, strlen (prefix) + 6);
+  strcpy (secname, prefix);
+  strcat (secname, ".opts");
+  if (!simple_object_find_section (sobj, secname, &offset, &length,
+				   &errmsg, &err))
+    {
+      simple_object_release_read (sobj);
+      return false;
+    }
+
+  lseek (fd, file_offset + offset, SEEK_SET);
+  data = (char *)xmalloc (length);
+  read (fd, data, length);
+  fopts = data;
+  do
+    {
+      struct cl_decoded_option *f2decoded_options;
+      unsigned int f2decoded_options_count;
+      get_options_from_collect_gcc_options (collect_gcc,
+					    fopts, CL_LANG_ALL,
+					    &f2decoded_options,
+					    &f2decoded_options_count);
+      if (!fdecoded_options)
+	{
+	  fdecoded_options = f2decoded_options;
+	  fdecoded_options_count = f2decoded_options_count;
+	}
+      else
+	merge_and_complain (&fdecoded_options,
+			    &fdecoded_options_count,
+			    f2decoded_options, f2decoded_options_count);
+
+      fopts += strlen (fopts) + 1;
+    }
+  while (fopts - data < length);
+
+  free (data);
+  simple_object_release_read (sobj);
+  *opts = fdecoded_options;
+  *opt_count = fdecoded_options_count;
+  return true;
+}
+
 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
 
 static void
@@ -607,7 +799,9 @@  run_gcc (unsigned argc, char *argv[])
   int jobserver = 0;
   bool no_partition = false;
   struct cl_decoded_option *fdecoded_options = NULL;
+  struct cl_decoded_option *omp_fdecoded_options = NULL;
   unsigned int fdecoded_options_count = 0;
+  unsigned int omp_fdecoded_options_count = 0;
   struct cl_decoded_option *decoded_options;
   unsigned int decoded_options_count;
   struct obstack argv_obstack;
@@ -629,18 +823,13 @@  run_gcc (unsigned argc, char *argv[])
   /* Look at saved options in the IL files.  */
   for (i = 1; i < argc; ++i)
     {
-      char *data, *p;
-      char *fopts;
+      char *p;
       int fd;
-      const char *errmsg;
-      int err;
-      off_t file_offset = 0, offset, length;
+      off_t file_offset = 0;
       long loffset;
-      simple_object_read *sobj;
       int consumed;
-      struct cl_decoded_option *f2decoded_options;
-      unsigned int f2decoded_options_count;
       char *filename = argv[i];
+
       if ((p = strrchr (argv[i], '@'))
 	  && p != argv[i] 
 	  && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
@@ -654,51 +843,16 @@  run_gcc (unsigned argc, char *argv[])
       fd = open (argv[i], O_RDONLY);
       if (fd == -1)
 	continue;
-      sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO", 
-	  			       &errmsg, &err);
-      if (!sobj)
-	{
-	  close (fd);
-	  continue;
-	}
-      if (!simple_object_find_section (sobj, LTO_SECTION_NAME_PREFIX "." "opts",
-				       &offset, &length, &errmsg, &err))
-	{
-	  simple_object_release_read (sobj);
-	  close (fd);
-	  continue;
-	}
-      /* We may choose not to write out this .opts section in the future.  In
-	 that case we'll have to use something else to look for.  */
-      if (simple_object_find_section (sobj, OMP_SECTION_NAME_PREFIX "." "opts",
-				      &offset, &length, &errmsg, &err))
-	have_offload = true;
-      lseek (fd, file_offset + offset, SEEK_SET);
-      data = (char *)xmalloc (length);
-      read (fd, data, length);
-      fopts = data;
-      do
-	{
-	  get_options_from_collect_gcc_options (collect_gcc,
-						fopts, CL_LANG_ALL,
-						&f2decoded_options,
-						&f2decoded_options_count);
-	  if (!fdecoded_options)
-	    {
-	      fdecoded_options = f2decoded_options;
-	      fdecoded_options_count = f2decoded_options_count;
-	    }
-	  else
-	    merge_and_complain (&fdecoded_options,
-				&fdecoded_options_count,
-				f2decoded_options, f2decoded_options_count);
-
-	  fopts += strlen (fopts) + 1;
-	}
-      while (fopts - data < length);
-
-      free (data);
-      simple_object_release_read (sobj);
+      bool omp_found;
+      find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
+			      &fdecoded_options, &fdecoded_options_count,
+			      collect_gcc);
+      omp_found = find_and_merge_options (fd, file_offset,
+					  OMP_SECTION_NAME_PREFIX,
+					  &omp_fdecoded_options,
+					  &omp_fdecoded_options_count,
+					  collect_gcc);
+      have_offload |= omp_found;
       close (fd);
     }
 
@@ -708,76 +862,21 @@  run_gcc (unsigned argc, char *argv[])
   obstack_ptr_grow (&argv_obstack, "-xlto");
   obstack_ptr_grow (&argv_obstack, "-c");
 
-  /* Append compiler driver arguments as far as they were merged.  */
-  for (j = 1; j < fdecoded_options_count; ++j)
-    {
-      struct cl_decoded_option *option = &fdecoded_options[j];
-
-      /* File options have been properly filtered by lto-opts.c.  */
-      switch (option->opt_index)
-	{
-	  /* Drop arguments that we want to take from the link line.  */
-	  case OPT_flto_:
-	  case OPT_flto:
-	  case OPT_flto_partition_:
-	      continue;
-
-	  default:
-	      break;
-	}
-
-      /* For now do what the original LTO option code was doing - pass
-	 on any CL_TARGET flag and a few selected others.  */
-      switch (option->opt_index)
-	{
-	case OPT_fPIC:
-	case OPT_fpic:
-	case OPT_fPIE:
-	case OPT_fpie:
-	case OPT_fcommon:
-	case OPT_fexceptions:
-	case OPT_fnon_call_exceptions:
-	case OPT_fgnu_tm:
-	case OPT_freg_struct_return:
-	case OPT_fpcc_struct_return:
-	case OPT_fshort_double:
-	case OPT_ffp_contract_:
-	case OPT_fwrapv:
-	case OPT_ftrapv:
-	case OPT_fstrict_overflow:
-	case OPT_O:
-	case OPT_Ofast:
-	case OPT_Og:
-	case OPT_Os:
-	  break;
-
-	default:
-	  if (!(cl_options[option->opt_index].flags & CL_TARGET))
-	    continue;
-	}
+  append_compiler_options (&argv_obstack, fdecoded_options,
+			   fdecoded_options_count);
+  append_linker_options (&argv_obstack, decoded_options, decoded_options_count,
+		      true);
 
-      /* Pass the option on.  */
-      for (i = 0; i < option->canonical_option_num_elements; ++i)
-	obstack_ptr_grow (&argv_obstack, option->canonical_option[i]);
-    }
-
-  /* Append linker driver arguments.  Compiler options from the linker
-     driver arguments will override / merge with those from the compiler.  */
+  /* Scan linker driver arguments for things that are of relevance to us.  */
   for (j = 1; j < decoded_options_count; ++j)
     {
       struct cl_decoded_option *option = &decoded_options[j];
 
-      /* Do not pass on frontend specific flags not suitable for lto.  */
-      if (!(cl_options[option->opt_index].flags
-	    & (CL_COMMON|CL_TARGET|CL_DRIVER|CL_LTO)))
-	continue;
-
       switch (option->opt_index)
 	{
 	case OPT_o:
 	  linker_output = option->arg;
-	  /* We generate new intermediate output, drop this arg.  */
-	  continue;
+	  break;
 
 	case OPT_save_temps:
 	  debug = 1;
@@ -808,23 +907,11 @@  run_gcc (unsigned argc, char *argv[])
 
 	case OPT_flto:
 	  lto_mode = LTO_MODE_WHOPR;
-	  /* We've handled these LTO options, do not pass them on.  */
-	  continue;
-
-	case OPT_freg_struct_return:
-	case OPT_fpcc_struct_return:
-	case OPT_fshort_double:
-	  /* Ignore these, they are determined by the input files.
-	     ???  We fail to diagnose a possible mismatch here.  */
-	  continue;
+	  break;
 
 	default:
 	  break;
 	}
-
-      /* Pass the option on.  */
-      for (i = 0; i < option->canonical_option_num_elements; ++i)
-	obstack_ptr_grow (&argv_obstack, option->canonical_option[i]);
     }
 
   if (no_partition)
@@ -897,7 +984,7 @@  run_gcc (unsigned argc, char *argv[])
       else
 	ltrans_output_file = make_temp_file (".ltrans.out");
       list_option_full = (char *) xmalloc (sizeof (char) *
-		         (strlen (ltrans_output_file) + list_option_len + 1));
+					   (strlen (ltrans_output_file) + list_option_len + 1));
       tmp = list_option_full;
 
       obstack_ptr_grow (&argv_obstack, tmp);
@@ -952,7 +1039,7 @@  run_gcc (unsigned argc, char *argv[])
 	  size_t len;
 
 	  buf = input_name;
-cont:
+	cont:
 	  if (!fgets (buf, piece, stream))
 	    break;
 	  len = strlen (input_name);
@@ -1003,8 +1090,8 @@  cont:
 	  if (linker_output)
 	    {
 	      char *dumpbase
-		  = (char *) xmalloc (strlen (linker_output)
-				      + sizeof (DUMPBASE_SUFFIX) + 1);
+		= (char *) xmalloc (strlen (linker_output)
+				    + sizeof (DUMPBASE_SUFFIX) + 1);
 	      snprintf (dumpbase,
 			strlen (linker_output) + sizeof (DUMPBASE_SUFFIX),
 			"%s.ltrans%u", linker_output, i);
@@ -1079,7 +1166,10 @@  cont:
 	}
       if (have_offload)
 	{
-	  compile_images_for_openmp_targets (argc, argv);
+	  compile_images_for_openmp_targets (argc, argv, omp_fdecoded_options,
+					     omp_fdecoded_options_count,
+					     decoded_options,
+					     decoded_options_count);
 	  if (offload_names)
 	    {
 	      find_ompbeginend ();
Index: gcc/target.def
===================================================================
--- gcc/target.def.orig
+++ gcc/target.def
@@ -1795,6 +1795,15 @@  actions then, you should have @code{TARG
  void, (void),
  hook_void_void)
 
+DEFHOOK
+(offload_options,
+ "Used when writing out the list of options into an LTO file.  It should\n\
+translate any relevant target-specific options (such as the ABI in use)\n\
+into one of the @option{-foffload} options that exist as a common interface\n\
+to express such options. It should return a string containing these options,\n\
+separated by spaces, which the caller will free.\n",
+char *, (void), hook_charptr_void_null)
+
 DEFHOOK_UNDOC
 (eh_return_filter_mode,
  "Return machine mode for filter value.",