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