diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c40487d2d87..22c2e0443f9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,38 @@ +2014-11-13 Bernd Schmidt + Andrey Turetskiy + Ilya Verbin + + * 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_. + Forbid OPT_foffload_abi_ for non-offload compiler. + * target.def (offload_options): New target hook. + 2014-11-13 Ilya Verbin Bernd Schmidt Andrey Turetskiy diff --git a/gcc/common.opt b/gcc/common.opt index 1a58cfb0385..e57c45770ba 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1665,6 +1665,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== 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 b70c56c600b..3400ca3d577 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -4335,6 +4335,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 @@ -51673,6 +51682,10 @@ ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts) #undef TARGET_SETUP_INCOMING_VARARG_BOUNDS #define TARGET_SETUP_INCOMING_VARARG_BOUNDS ix86_setup_incoming_vararg_bounds +#undef TARGET_OFFLOAD_OPTIONS +#define TARGET_OFFLOAD_OPTIONS \ + ix86_offload_options + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-i386.h" diff --git a/gcc/coretypes.h b/gcc/coretypes.h index f66e0941c76..a21359d7ddd 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 778e90d989d..6e2825f2e01 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -11402,6 +11402,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 6c82448c5a8..929ee85de36 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -8171,6 +8171,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 abadfbf2e93..4422fa038e8 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. */ @@ -3358,6 +3362,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. */ @@ -3735,6 +3825,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 @@ -7252,14 +7346,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 356c64c9d92..f698d1d2e9e 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -386,13 +386,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 5e4f95b0f0a..b1b312d176a 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -106,6 +106,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 d1d153d0408..72b09571e26 100644 --- a/gcc/lto-opts.c +++ b/gcc/lto-opts.c @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-ref.h" #include "cgraph.h" #include "lto-streamer.h" +#include "lto-section-names.h" #include "toplev.h" /* Append the option piece OPT to the COLLECT_GCC_OPTIONS string @@ -158,6 +159,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) { @@ -181,15 +199,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 cbda36bface..de73ebcdb8b 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]; + append_compiler_options (&argv_obstack, fdecoded_options, + fdecoded_options_count); + append_linker_options (&argv_obstack, decoded_options, decoded_options_count); - /* 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 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 4df7389fc78..d22882bf3a2 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1807,6 +1807,17 @@ common_handle_option (struct gcc_options *opts, /* Deferred. */ break; + case OPT_foffload_: + /* Deferred. */ + break; + +#ifndef ACCEL_COMPILER + case OPT_foffload_abi_: + error_at (loc, "-foffload-abi option can be specified only for " + "offload compiler"); + break; +#endif + 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 682d22ead00..01549679440 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -1802,6 +1802,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.",