diff mbox

[gomp4] Offload option handling

Message ID 5391D946.1070709@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt June 6, 2014, 3:07 p.m. UTC
There's a problem when offloading from a compiler for one target machine 
to another: the machine specific options don't necessarily match. This 
patch tries to address this.

The idea is that since we have two options sections anyway, with 
different section name prefixes, we can arrange to pass only 
target-independent options in the omp_ version of the options section.
However, some target-specific options (specifically the ones specifying 
the ABI) need to be preserved somehow, so there's a new target hook for 
translating them to common a -foffload-* syntax.

How does this look? Comments on the approach, and ok for the 
gomp-4_0-branch?


Bernd

Comments

Bernd Schmidt July 23, 2014, 12:51 p.m. UTC | #1
Ping.
   https://gcc.gnu.org/ml/gcc-patches/2014-06/msg00616.html

On 06/06/2014 05:07 PM, Bernd Schmidt wrote:
> There's a problem when offloading from a compiler for one target machine
> to another: the machine specific options don't necessarily match. This
> patch tries to address this.
>
> The idea is that since we have two options sections anyway, with
> different section name prefixes, we can arrange to pass only
> target-independent options in the omp_ version of the options section.
> However, some target-specific options (specifically the ones specifying
> the ABI) need to be preserved somehow, so there's a new target hook for
> translating them to common a -foffload-* syntax.
>
> How does this look? Comments on the approach, and ok for the
> gomp-4_0-branch?
Ilya Verbin July 23, 2014, 3:09 p.m. UTC | #2
On 23 Jul 14:51, Bernd Schmidt wrote:
> Ping.
>   https://gcc.gnu.org/ml/gcc-patches/2014-06/msg00616.html
> 
> On 06/06/2014 05:07 PM, Bernd Schmidt wrote:
> >There's a problem when offloading from a compiler for one target machine
> >to another: the machine specific options don't necessarily match. This
> >patch tries to address this.
> >
> >The idea is that since we have two options sections anyway, with
> >different section name prefixes, we can arrange to pass only
> >target-independent options in the omp_ version of the options section.
> >However, some target-specific options (specifically the ones specifying
> >the ABI) need to be preserved somehow, so there's a new target hook for
> >translating them to common a -foffload-* syntax.
> >
> >How does this look? Comments on the approach, and ok for the
> >gomp-4_0-branch?

How about passing target-specific options from the command-line?  Will it be
possible with this approach?

We had a patch, that parses options from -foffload-target=<target>=<options> and
stores them to the environment variable.  Now it is obsolete, but I like the
idea of having such a user-adjustable options for the accel compilers.

https://gcc.gnu.org/ml/gcc-patches/2013-12/msg01242.html

  -- Ilya
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.",