public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 6/n] OpenMP 4.0 offloading infrastructure: option handling
@ 2014-10-11 14:59 Ilya Verbin
  2014-10-13 10:27 ` Jakub Jelinek
                   ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Ilya Verbin @ 2014-10-11 14:59 UTC (permalink / raw)
  To: Jakub Jelinek, Bernd Schmidt, gcc-patches
  Cc: Richard Biener, Thomas Schwinge, Kirill Yukhin, Andrey Turetskiy

Hello,

This is the last common infrastructure patch in the series.
(Next patches will contain tests for libgomp testsuite and MIC specific things)

It introduces 2 new options:
1. -foffload=<targets>=<options>
   By default, GCC will build offload images for all offload targets specified
in configure, with non-target-specific options passed to host compiler.
This option is used to control offload targets and options for them.

It can be used in a few ways:
* -foffload=disable
  Tells GCC to disable offload support.
  OpenMP target regions will be run in host fallback mode.
* -foffload=<targets>
  Tells GCC to build offload images for <targets>.
  They will be built with non-target-specific options passed to host compiler.
* -foffload=<options>
  Tells GCC to build offload images for all targets specified in configure. 
  They will be built with non-target-specific options passed to host compiler
  plus <options>.
* -foffload=<targets>=<options>
  Tells GCC to build offload images for <targets>.
  They will be built with non-target-specific options passed to host compiler
  plus <options>.

Options specified by -foffload are appended to the end of option set, so in case
of option conflicts they have more priority.

2. -foffload-abi=[lp64|ilp32]
   This option is supposed to tell mkoffload (and offload compiler) which ABI is
used in streamed GIMPLE.  This option is desirable, because host and offload
compilers must have the same ABI.  The option is generated by the host compiler
automatically, it should not be specified by user.

Examples:
$ gcc -fopenmp -c -O2 test1.c
$ gcc -fopenmp -c -O1 -msse -foffload=-mavx test2.c
$ gcc -fopenmp -foffload="-O3 -v" test1.o test2.o

In this example the offload images will be built with the following options:
"-O2 -mavx -O3 -v" for targets specified in configure.

$ gcc -fopenmp -foffload=x86_64-intelmicemul-linux-gnu="-mavx2" \
  -foffload=nvptx-none -foffload="-O3" -O2 test.c

In this example 2 offload images will be built:
for MIC with "-O2 -mavx2 -O3" and for PTX with "-O2 -O3".

Bootstrapped and regtested on top of patch 5.  Is it OK for trunk?
kyukhin/gomp4-offload branch is updated correspondingly.

Thanks,
  -- Ilya


2014-10-11  Bernd Schmidt  <bernds@codesourcery.com>
	    Andrey Turetskiy  <andrey.turetskiy@intel.com>
	    Ilya Verbin  <ilya.verbin@intel.com>

gcc/
	* common.opt (foffload, foffload-abi): New options.
	* config/i386/i386.c (ix86_offload_options): New static function.
	(TARGET_OFFLOAD_OPTIONS): Define.
	* coretypes.h (enum offload_abi): New enum.
	* doc/tm.texi: Regenerate.
	* doc/tm.texi.in (TARGET_OFFLOAD_OPTIONS): Document.
	* gcc.c (offload_targets): New static variable.
	(handle_foffload_option): New static function.
	(driver_handle_option): Handle OPT_foffload_.
	(driver::maybe_putenv_OFFLOAD_TARGETS): Set OFFLOAD_TARGET_NAMES
	according to offload_targets.
	* hooks.c (hook_charptr_void_null): New hook.
	* hooks.h (hook_charptr_void_null): Declare.
	* lto-opts.c: Include lto-section-names.h.
	(lto_write_options): Append options from target offload_options hook and
	store them to offload_lto section.  Do not store target-specific,
	driver and diagnostic options in offload_lto section.
	* lto-wrapper.c (merge_and_complain): Handle OPT_foffload_ and
	OPT_foffload_abi_.
	(append_compiler_options, append_linker_options)
	(append_offload_options): New static functions.
	(compile_offload_image): Add new arguments with options.
	Call append_compiler_options and append_offload_options.
	(compile_images_for_offload_targets): Add new arguments with options.
	(find_and_merge_options): New static function.
	(run_gcc): Outline options handling into the new functions:
	find_and_merge_options, append_compiler_options, append_linker_options.
	* opts.c (common_handle_option): Don't handle OPT_foffload_.
	* target.def (offload_options): New target hook.

---

diff --git a/gcc/common.opt b/gcc/common.opt
index b4f0ed4..37a5fd4 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1640,6 +1640,23 @@ fnon-call-exceptions
 Common Report Var(flag_non_call_exceptions) Optimization
 Support synchronous non-call exceptions
 
+foffload=
+Common Driver Joined MissingArgError(options or targets missing after %qs)
+-foffload=<targets>=<options>  Specify offloading targets and options for them
+
+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
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index ed8fe2d..ec0c5d6 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4301,6 +4301,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
@@ -47621,6 +47630,10 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
 #undef TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS
 #define TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS true
 
+#undef TARGET_OFFLOAD_OPTIONS
+#define TARGET_OFFLOAD_OPTIONS \
+  ix86_offload_options
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index c850ff4..7de374b 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -132,6 +132,13 @@ enum tls_model {
   TLS_MODEL_LOCAL_EXEC
 };
 
+/* Types of ABI for an offload compiler.  */
+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
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 80da884..61fb994 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11201,6 +11201,15 @@ 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
+
 @defmac TARGET_SUPPORTS_WIDE_INT
 
 On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 2b5d4f0..eefe5e3 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8165,6 +8165,8 @@ and the associated definitions of those functions.
 
 @hook TARGET_RECORD_OFFLOAD_SYMBOL
 
+@hook TARGET_OFFLOAD_OPTIONS
+
 @defmac TARGET_SUPPORTS_WIDE_INT
 
 On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 63c86e1..728b216 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -159,6 +159,10 @@ static const char *const spec_version = DEFAULT_TARGET_VERSION;
 static const char *spec_machine = DEFAULT_TARGET_MACHINE;
 static const char *spec_host_machine = DEFAULT_REAL_TARGET_MACHINE;
 
+/* List of offload targets.  */
+
+static char *offload_targets = NULL;
+
 /* Nonzero if cross-compiling.
    When -b is used, the value comes from the `specs' file.  */
 
@@ -3362,6 +3366,92 @@ driver_wrong_lang_callback (const struct cl_decoded_option *decoded,
 static const char *spec_lang = 0;
 static int last_language_n_infiles;
 
+/* Parse -foffload option argument.  */
+
+static void
+handle_foffload_option (const char *arg)
+{
+  const char *c, *cur, *n, *next, *end;
+  char *target;
+
+  /* If option argument starts with '-' then no target is specified and we
+     do not need to parse it.  */
+  if (arg[0] == '-')
+    return;
+
+  end = strchrnul (arg, '=');
+  cur = arg;
+
+  while (cur < end)
+    {
+      next = strchrnul (cur, ',');
+      next = (next > end) ? end : next;
+
+      target = XNEWVEC (char, next - cur + 1);
+      strncpy (target, cur, next - cur);
+      target[next - cur] = '\0';
+
+      /* If 'disable' is passed to the option, stop parsing the option and clean
+         the list of offload targets.  */
+      if (strcmp (target, "disable") == 0)
+	{
+	  free (offload_targets);
+	  offload_targets = xstrdup ("");
+	  break;
+	}
+
+      /* Check that GCC is configured to support the offload target.  */
+      c = OFFLOAD_TARGETS;
+      while (c)
+	{
+	  n = strchrnul (c, ',');
+
+	  if (strlen (target) == (size_t) (n - c)
+	      && strncmp (target, c, n - c) == 0)
+	    break;
+
+	  c = *n ? n + 1 : NULL;
+	}
+
+      if (!c)
+	fatal_error ("GCC is not configured to support %s as offload target",
+		     target);
+
+      if (!offload_targets)
+	offload_targets = xstrdup (target);
+      else
+	{
+	  /* Check that the target hasn't already presented in the list.  */
+	  c = offload_targets;
+	  do
+	    {
+	      n = strchrnul (c, ':');
+
+	      if (strlen (target) == (size_t) (n - c)
+		  && strncmp (c, target, n - c) == 0)
+		break;
+
+	      c = n + 1;
+	    }
+	  while (*n);
+
+	  /* If duplicate is not found, append the target to the list.  */
+	  if (c > n)
+	    {
+	      offload_targets
+		= XRESIZEVEC (char, offload_targets,
+			      strlen (offload_targets) + strlen (target) + 2);
+	      if (strlen (offload_targets) != 0)
+		strcat (offload_targets, ":");
+	      strcat (offload_targets, target);
+	    }
+	}
+
+      cur = next + 1;
+      XDELETEVEC (target);
+    }
+}
+
 /* Handle a driver option; arguments and return value as for
    handle_option.  */
 
@@ -3738,6 +3828,10 @@ driver_handle_option (struct gcc_options *opts,
       flag_wpa = "";
       break;
 
+    case OPT_foffload_:
+      handle_foffload_option (arg);
+      break;
+
     default:
       /* Various driver options need no special processing at this
 	 point, having been handled in a prescan above or being
@@ -7240,14 +7334,22 @@ driver::maybe_putenv_COLLECT_LTO_WRAPPER () const
 void
 driver::maybe_putenv_OFFLOAD_TARGETS () const
 {
-  if (strlen (OFFLOAD_TARGETS) > 0)
+  const char *targets = offload_targets;
+
+  /* If no targets specified by -foffload, use all available targets.  */
+  if (!targets)
+    targets = OFFLOAD_TARGETS;
+
+  if (strlen (targets) > 0)
     {
       obstack_grow (&collect_obstack, "OFFLOAD_TARGET_NAMES=",
 		    sizeof ("OFFLOAD_TARGET_NAMES=") - 1);
-      obstack_grow (&collect_obstack, OFFLOAD_TARGETS,
-		    strlen (OFFLOAD_TARGETS) + 1);
+      obstack_grow (&collect_obstack, targets,
+		    strlen (targets) + 1);
       xputenv (XOBFINISH (&collect_obstack, char *));
     }
+
+  free (offload_targets);
 }
 
 /* Reject switches that no pass was interested in.  */
diff --git a/gcc/hooks.c b/gcc/hooks.c
index ce62dfd..d4c172a 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -374,13 +374,20 @@ hook_tree_tree_tree_tree_3rd_identity (tree a ATTRIBUTE_UNUSED,
   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 *
 hook_constcharptr_const_tree_null (const_tree t ATTRIBUTE_UNUSED)
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 76a6551..1142aa4 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -103,6 +103,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_insn_null (const rtx_insn *);
diff --git a/gcc/lto-opts.c b/gcc/lto-opts.c
index ceccb6f..f008e60 100644
--- a/gcc/lto-opts.c
+++ b/gcc/lto-opts.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #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
@@ -146,6 +147,23 @@ lto_write_options (void)
     append_to_collect_gcc_options (&temporary_obstack, &first_p,
 			       "-fno-strict-overflow");
 
+  /* Append options from target hook and store them to offload_lto section.  */
+  if (strcmp (section_name_prefix, OFFLOAD_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)
     {
@@ -169,15 +187,23 @@ lto_write_options (void)
       if (!(cl_options[option->opt_index].flags & (CL_COMMON|CL_TARGET|CL_LTO)))
 	continue;
 
+      /* Do not store target-specific options in offload_lto section.  */
+      if ((cl_options[option->opt_index].flags & CL_TARGET)
+	 && strcmp (section_name_prefix, OFFLOAD_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)
 	continue;
 
       /* Also drop all options that are handled by the driver as well,
-         which includes things like -o and -v or -fhelp for example.
-	 We do not need those.  Also drop all diagnostic options.  */
-      if (cl_options[option->opt_index].flags & (CL_DRIVER|CL_WARNING))
+	 which includes things like -o and -v or -fhelp for example.
+	 We do not need those.  The only exception is -foffload option, if we
+	 write it in offload_lto section.  Also drop all diagnostic options.  */
+      if ((cl_options[option->opt_index].flags & (CL_DRIVER|CL_WARNING))
+	  && (strcmp (section_name_prefix, OFFLOAD_SECTION_NAME_PREFIX) != 0
+	      || option->opt_index != OPT_foffload_))
 	continue;
 
       for (j = 0; j < option->canonical_option_num_elements; ++j)
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index f5a508d..9e6250a 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -296,6 +296,17 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
 			 " files", 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_error ("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:
@@ -366,6 +377,10 @@ merge_and_complain (struct cl_decoded_option **decoded_options,
 	      (*decoded_options)[j].value = 1;
 	    }
 	  break;
+
+	case OPT_foffload_:
+	  append_option (decoded_options, decoded_options_count, foption);
+	  break;
 	}
     }
 }
@@ -427,6 +442,167 @@ parse_env_var (const char *str, char ***pvalues, const char *append)
   return num;
 }
 
+/* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK.  */
+
+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_fmath_errno:
+	case OPT_fsigned_zeros:
+	case OPT_ftrapping_math:
+	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]);
+    }
+}
+
+/* Append linker options OPTS to ARGV_OBSTACK.  */
+
+static void
+append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts,
+		       unsigned int count)
+{
+  /* 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;
+
+      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]);
+    }
+}
+
+/* Extract options for TARGET offload compiler from OPTIONS and append
+   them to ARGV_OBSTACK.  */
+
+static void
+append_offload_options (obstack *argv_obstack, const char *target,
+			struct cl_decoded_option *options,
+			unsigned int options_count)
+{
+  for (unsigned i = 0; i < options_count; i++)
+    {
+      const char *cur, *next, *opts;
+      char **argv;
+      unsigned argc;
+      struct cl_decoded_option *option = &options[i];
+
+      if (option->opt_index != OPT_foffload_)
+	continue;
+
+      /* If option argument starts with '-' then no target is specified.  That
+	 means offload options are specified for all targets, so we need to
+	 append them.  */
+      if (option->arg[0] == '-')
+	opts = option->arg;
+      else
+	{
+	  opts = strchr (option->arg, '=');
+	  if (!opts)
+	    continue;
+
+	  cur = option->arg;
+
+	  while (cur < opts)
+	    {
+	      next = strchrnul (cur, ',');
+	      next = (next > opts) ? opts : next;
+
+	      if (strlen (target) == (size_t) (next - cur)
+		  && strncmp (target, cur, next - cur) == 0)
+		break;
+
+	      cur = next + 1;
+	    }
+
+	  if (cur >= opts)
+	    continue;
+
+	  opts++;
+	}
+
+      argv = buildargv (opts);
+      for (argc = 0; argv[argc]; argc++)
+	obstack_ptr_grow (argv_obstack, argv[argc]);
+    }
+}
+
 /* Check whether NAME can be accessed in MODE.  This is like access,
    except that it never considers directories to be executable.  */
 
@@ -450,7 +626,11 @@ access_check (const char *name, int mode)
 
 static char *
 compile_offload_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)
 {
   char *filename = NULL;
   char **argv;
@@ -482,10 +662,22 @@ compile_offload_image (const char *target, const char *compiler_path,
       obstack_ptr_grow (&argv_obstack, "-o");
       obstack_ptr_grow (&argv_obstack, filename);
 
+      /* Append names of input object files.  */
       for (unsigned i = 1; i < in_argc; i++)
 	obstack_ptr_grow (&argv_obstack, in_argv[i]);
-      obstack_ptr_grow (&argv_obstack, NULL);
 
+      /* Append options from offload_lto sections.  */
+      append_compiler_options (&argv_obstack, compiler_opts,
+			       compiler_opt_count);
+
+      /* Append options specified by -foffload last.  In case of conflicting
+	 options we expect offload compiler to choose the latest.  */
+      append_offload_options (&argv_obstack, target, compiler_opts,
+			      compiler_opt_count);
+      append_offload_options (&argv_obstack, target, linker_opts,
+			      linker_opt_count);
+
+      obstack_ptr_grow (&argv_obstack, NULL);
       argv = XOBFINISH (&argv_obstack, char **);
       fork_execute (argv[0], argv, true);
       obstack_free (&argv_obstack, NULL);
@@ -502,7 +694,11 @@ compile_offload_image (const char *target, const char *compiler_path,
    target sections, we pass them all to target compilers.  */
 
 static void
-compile_images_for_offload_targets (unsigned in_argc, char *in_argv[])
+compile_images_for_offload_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 **names = NULL;
   const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV);
@@ -519,8 +715,10 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[])
   offload_names = XCNEWVEC (char *, num_targets + 1);
   for (unsigned i = 0; i < num_targets; i++)
     {
-      offload_names[i] = compile_offload_image (names[i], compiler_path,
-						in_argc, in_argv);
+      offload_names[i]
+	= compile_offload_image (names[i], compiler_path, in_argc, in_argv,
+				 compiler_opts, compiler_opt_count,
+				 linker_opts, linker_opt_count);
       if (!offload_names[i])
 	fatal_error ("problem with building target image for %s\n", names[i]);
     }
@@ -587,6 +785,74 @@ find_offloadbeginend (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 = XALLOCAVEC (char, strlen (prefix) + sizeof (".opts"));
+  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
@@ -602,7 +868,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 *offload_fdecoded_options = NULL;
   unsigned int fdecoded_options_count = 0;
+  unsigned int offload_fdecoded_options_count = 0;
   struct cl_decoded_option *decoded_options;
   unsigned int decoded_options_count;
   struct obstack argv_obstack;
@@ -625,18 +893,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
@@ -650,50 +913,15 @@ 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, OFFLOAD_SECTION_NAME_PREFIX ".opts",
-				      &offset, &length, &errmsg, &err))
-	have_offload = true;
-      if (!simple_object_find_section (sobj, LTO_SECTION_NAME_PREFIX "." "opts",
-				       &offset, &length, &errmsg, &err))
-	{
-	  simple_object_release_read (sobj);
-	  close (fd);
-	  continue;
-	}
-      have_lto = 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);
+      have_lto
+	= find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX,
+				  &fdecoded_options, &fdecoded_options_count,
+				  collect_gcc);
+      have_offload
+	= find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
+				  &offload_fdecoded_options,
+				  &offload_fdecoded_options_count, collect_gcc);
       close (fd);
     }
 
@@ -703,79 +931,19 @@ 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_fmath_errno:
-	case OPT_fsigned_zeros:
-	case OPT_ftrapping_math:
-	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;
-	}
-
-      /* Pass the option on.  */
-      for (i = 0; i < option->canonical_option_num_elements; ++i)
-	obstack_ptr_grow (&argv_obstack, option->canonical_option[i]);
-    }
+  append_compiler_options (&argv_obstack, fdecoded_options,
+			   fdecoded_options_count);
+  append_linker_options (&argv_obstack, decoded_options, decoded_options_count);
 
-  /* 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:
 	  save_temps = 1;
@@ -806,23 +974,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)
@@ -864,7 +1020,10 @@ run_gcc (unsigned argc, char *argv[])
 
   if (have_offload)
     {
-      compile_images_for_offload_targets (argc, argv);
+      compile_images_for_offload_targets (argc, argv, offload_fdecoded_options,
+					  offload_fdecoded_options_count,
+					  decoded_options,
+					  decoded_options_count);
       if (offload_names)
 	{
 	  find_offloadbeginend ();
diff --git a/gcc/opts.c b/gcc/opts.c
index 5cb5a39..8c53356 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1726,6 +1726,10 @@ common_handle_option (struct gcc_options *opts,
       /* Deferred.  */
       break;
 
+    case OPT_foffload_:
+      /* Deferred.  */
+      break;
+
     case OPT_fpack_struct_:
       if (value <= 0 || (value & (value - 1)) || value > 16)
 	error_at (loc,
diff --git a/gcc/target.def b/gcc/target.def
index aa5a680..c4b28a2 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -1783,6 +1783,15 @@ actions then, you should have @code{TARGET_OPTION_OVERRIDE} call\n\
  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.",
-- 
1.7.1

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2015-11-23 11:08 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-11 14:59 [PATCH 6/n] OpenMP 4.0 offloading infrastructure: option handling Ilya Verbin
2014-10-13 10:27 ` Jakub Jelinek
2014-10-13 10:36   ` Ilya Verbin
2014-10-13 15:08     ` Bernd Schmidt
2014-10-14  7:31       ` Richard Biener
2014-10-14 12:58         ` Bernd Schmidt
2014-10-15 14:12           ` Richard Biener
2014-10-27 10:59             ` Bernd Schmidt
2015-02-18 17:04     ` Thomas Schwinge
2015-02-19  9:28       ` Thomas Schwinge
2015-03-10 12:37         ` Thomas Schwinge
2015-04-27 16:08           ` Thomas Schwinge
2015-04-28 13:39             ` Bernd Schmidt
2015-04-29 16:41               ` Thomas Schwinge
2015-07-14 20:10                 ` Thomas Schwinge
2015-07-14 20:15                   ` Richard Biener
2014-10-24 18:33   ` Ilya Verbin
2014-10-24 18:41     ` Jakub Jelinek
2014-10-27 12:06       ` Ilya Verbin
2014-11-28  1:45 ` Ilya Verbin
2014-11-28  9:32   ` Richard Biener
2014-12-07 23:55     ` Ilya Verbin
2014-12-09 14:06       ` Richard Biener
2014-12-09 22:48         ` Ilya Verbin
2015-11-20 19:34           ` Ilya Verbin
2015-11-23 11:09             ` Richard Biener
2015-09-21 15:51 ` Thomas Schwinge
2015-09-21 16:59   ` Ilya Verbin
2015-09-22 12:20     ` Thomas Schwinge
2015-09-22 23:03       ` Bernd Schmidt
2015-09-23 15:19         ` Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).