On Mon, Feb 02, 2015 at 13:10:19 +0100, Jakub Jelinek wrote: > [...] Generally, the solution if something goes > wrong during the offloading compilation should be just to give up on the > offloading to the particular offloading target (i.e. fill in the sections > libgomp reads in a way that will result in host fallback).
Do you mean something like this? Bootstrapped/regtested on x86_64-linux and i686-linux. Is this patch OK for stage4 or stage1? gcc/ * collect-utils.c (do_wait, fork_execute): New argument. * collect-utils.h: Likewise. * collect2.c: Pass new argument to do_wait and fork_execute. * config/i386/intelmic-mkoffload.c: Likewise. (compile_for_target): Don't call fatal_error if compilation failed. (generate_target_descr_file, generate_target_offloadend_file) (prepare_target_image): Pass out_filename to compile_for_target. * config/nvptx/mkoffload.c: Pass new argument fork_execute. * lto-wrapper.c (num_offload_targets): New static global variable. (compile_offload_image): Return NULL if an image was not created. (compile_images_for_offload_targets): Call warning instead of fatal_error if an image was not created. (run_gcc): Do not return empty images to linker. Pass new argument to do_wait and fork_execute. libgomp/ * target.c (gomp_target_fallback): New static function. (GOMP_target): Move host fallback to the new gomp_target_fallback. Run gomp_target_fallback if tgt_fn is not present in the splay tree. diff --git a/gcc/collect-utils.c b/gcc/collect-utils.c index 6bbe9eb..2dce3c9 100644 --- a/gcc/collect-utils.c +++ b/gcc/collect-utils.c @@ -85,10 +85,10 @@ collect_wait (const char *prog, struct pex_obj *pex) } void -do_wait (const char *prog, struct pex_obj *pex) +do_wait (const char *prog, struct pex_obj *pex, bool non_fatal) { int ret = collect_wait (prog, pex); - if (ret != 0) + if (!non_fatal && ret != 0) fatal_error (input_location, "%s returned %d exit status", prog, ret); if (response_file && !save_temps) @@ -201,13 +201,13 @@ collect_execute (const char *prog, char **argv, const char *outname, } void -fork_execute (const char *prog, char **argv, bool use_atfile) +fork_execute (const char *prog, char **argv, bool use_atfile, bool non_fatal) { struct pex_obj *pex; pex = collect_execute (prog, argv, NULL, NULL, PEX_LAST | PEX_SEARCH, use_atfile); - do_wait (prog, pex); + do_wait (prog, pex, non_fatal); } /* Delete tempfiles. */ diff --git a/gcc/collect-utils.h b/gcc/collect-utils.h index 2b3ed44..7b3b3da 100644 --- a/gcc/collect-utils.h +++ b/gcc/collect-utils.h @@ -29,8 +29,8 @@ extern struct pex_obj *collect_execute (const char *, char **, const char *, const char *, int, bool); extern int collect_wait (const char *, struct pex_obj *); -extern void do_wait (const char *, struct pex_obj *); -extern void fork_execute (const char *, char **, bool); +extern void do_wait (const char *, struct pex_obj *, bool); +extern void fork_execute (const char *, char **, bool, bool); extern void utils_cleanup (bool); diff --git a/gcc/collect2.c b/gcc/collect2.c index b53e151..f8be7da 100644 --- a/gcc/collect2.c +++ b/gcc/collect2.c @@ -758,7 +758,7 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, obstack_free (&temporary_obstack, temporary_firstobj); } - do_wait (prog, pex); + do_wait (prog, pex, false); pex = NULL; /* Compute memory needed for new LD arguments. At most number of original arguemtns @@ -803,7 +803,8 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, /* Run the linker again, this time replacing the object files optimized by the LTO with the temporary file generated by the LTO. */ - fork_execute ("ld", out_lto_ld_argv, HAVE_GNU_LD && at_file_supplied); + fork_execute ("ld", out_lto_ld_argv, HAVE_GNU_LD && at_file_supplied, + false); post_ld_pass (true); free (lto_ld_argv); @@ -813,7 +814,7 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, { /* Our caller is relying on us to do the link even though there is no LTO back end work to be done. */ - fork_execute ("ld", lto_ld_argv, HAVE_GNU_LD && at_file_supplied); + fork_execute ("ld", lto_ld_argv, HAVE_GNU_LD && at_file_supplied, false); post_ld_pass (false); } else @@ -1706,7 +1707,7 @@ main (int argc, char **argv) strip_argv[0] = strip_file_name; strip_argv[1] = output_file; strip_argv[2] = (char *) 0; - fork_execute ("strip", real_strip_argv, false); + fork_execute ("strip", real_strip_argv, false, false); } #ifdef COLLECT_EXPORT_LIST @@ -1792,7 +1793,7 @@ main (int argc, char **argv) /* Assemble the constructor and destructor tables. Link the tables in with the rest of the program. */ - fork_execute ("gcc", c_argv, at_file_supplied); + fork_execute ("gcc", c_argv, at_file_supplied, false); #ifdef COLLECT_EXPORT_LIST /* On AIX we must call tlink because of possible templates resolution. */ do_tlink (ld2_argv, object_lst); @@ -1805,7 +1806,7 @@ main (int argc, char **argv) maybe_run_lto_and_relink (ld2_argv, object_lst, object, true); else { - fork_execute ("ld", ld2_argv, HAVE_GNU_LD && at_file_supplied); + fork_execute ("ld", ld2_argv, HAVE_GNU_LD && at_file_supplied, false); post_ld_pass (false); } @@ -2486,7 +2487,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass, if (debug) fprintf (stderr, "\n"); - do_wait (nm_file_name, pex); + do_wait (nm_file_name, pex, false); signal (SIGINT, int_handler); #ifdef SIGQUIT @@ -2606,7 +2607,7 @@ scan_libraries (const char *prog_name) if (debug) fprintf (stderr, "\n"); - do_wait (ldd_file_name, pex); + do_wait (ldd_file_name, pex, false); signal (SIGINT, int_handler); #ifdef SIGQUIT @@ -3023,7 +3024,7 @@ do_dsymutil (const char *output_file) { pex = collect_execute (dsymutil, real_argv, NULL, NULL, PEX_LAST | PEX_SEARCH, false); - do_wait (dsymutil, pex); + do_wait (dsymutil, pex, false); } static void diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c index e6394e9..45d8677 100644 --- a/gcc/config/i386/intelmic-mkoffload.c +++ b/gcc/config/i386/intelmic-mkoffload.c @@ -187,12 +187,15 @@ out: } static void -compile_for_target (struct obstack *argv_obstack) +compile_for_target (struct obstack *argv_obstack, const char *out_filename) { if (target_ilp32) obstack_ptr_grow (argv_obstack, "-m32"); else obstack_ptr_grow (argv_obstack, "-m64"); + + obstack_ptr_grow (argv_obstack, "-o"); + obstack_ptr_grow (argv_obstack, out_filename); obstack_ptr_grow (argv_obstack, NULL); char **argv = XOBFINISH (argv_obstack, char **); @@ -206,7 +209,7 @@ compile_for_target (struct obstack *argv_obstack) unsetenv ("LIBRARY_PATH"); unsetenv ("LD_RUN_PATH"); - fork_execute (argv[0], argv, false); + fork_execute (argv[0], argv, false, true); obstack_free (argv_obstack, NULL); /* Restore environment variables. */ @@ -214,6 +217,12 @@ compile_for_target (struct obstack *argv_obstack) xputenv (concat ("COMPILER_PATH=", cpath, NULL)); xputenv (concat ("LIBRARY_PATH=", lpath, NULL)); xputenv (concat ("LD_RUN_PATH=", rpath, NULL)); + + /* If something went wrong during the compilation, exit mkoffload without + producing an object file. */ + struct stat st; + if (stat (out_filename, &st) != 0 || st.st_size == 0) + exit (EXIT_SUCCESS); } /* Generates object file with the descriptor for the target library. */ @@ -268,9 +277,7 @@ generate_target_descr_file (const char *target_compiler) obstack_ptr_grow (&argv_obstack, "-shared"); obstack_ptr_grow (&argv_obstack, "-fPIC"); obstack_ptr_grow (&argv_obstack, src_filename); - obstack_ptr_grow (&argv_obstack, "-o"); - obstack_ptr_grow (&argv_obstack, obj_filename); - compile_for_target (&argv_obstack); + compile_for_target (&argv_obstack, obj_filename); return obj_filename; } @@ -306,9 +313,7 @@ generate_target_offloadend_file (const char *target_compiler) obstack_ptr_grow (&argv_obstack, "-shared"); obstack_ptr_grow (&argv_obstack, "-fPIC"); obstack_ptr_grow (&argv_obstack, src_filename); - obstack_ptr_grow (&argv_obstack, "-o"); - obstack_ptr_grow (&argv_obstack, obj_filename); - compile_for_target (&argv_obstack); + compile_for_target (&argv_obstack, obj_filename); return obj_filename; } @@ -364,7 +369,7 @@ generate_host_descr_file (const char *host_compiler) new_argv[new_argc++] = obj_filename; new_argv[new_argc++] = NULL; - fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false); + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false, false); return obj_filename; } @@ -403,9 +408,7 @@ prepare_target_image (const char *target_compiler, int argc, char **argv) if (!out_obj_filename) fatal_error (input_location, "output file not specified"); obstack_ptr_grow (&argv_obstack, opt2); - obstack_ptr_grow (&argv_obstack, "-o"); - obstack_ptr_grow (&argv_obstack, target_so_filename); - compile_for_target (&argv_obstack); + compile_for_target (&argv_obstack, target_so_filename); /* Run objcopy. */ char *rename_section_opt @@ -426,7 +429,8 @@ prepare_target_image (const char *target_compiler, int argc, char **argv) objcopy_argv[8] = "--rename-section"; objcopy_argv[9] = rename_section_opt; objcopy_argv[10] = NULL; - fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false); + fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false, + false); /* Objcopy has created symbols, containing the input file name with special characters replaced with '_'. We are going to rename these @@ -464,7 +468,7 @@ prepare_target_image (const char *target_compiler, int argc, char **argv) objcopy_argv[6] = "--redefine-sym"; objcopy_argv[7] = opt_for_objcopy[2]; objcopy_argv[8] = NULL; - fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false); + fork_execute (objcopy_argv[0], CONST_CAST (char **, objcopy_argv), false, false); return target_so_filename; } @@ -527,7 +531,7 @@ main (int argc, char **argv) new_argv[new_argc++] = "-o"; new_argv[new_argc++] = out_obj_filename; new_argv[new_argc++] = NULL; - fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false); + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false, false); /* Run objcopy on the resultant object file to localize generated symbols to avoid conflicting between different DSO and an executable. */ @@ -540,7 +544,7 @@ main (int argc, char **argv) new_argv[6] = symbols[2]; new_argv[7] = out_obj_filename; new_argv[8] = NULL; - fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false); + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), false, false); return 0; } diff --git a/gcc/config/nvptx/mkoffload.c b/gcc/config/nvptx/mkoffload.c index 739aee8..67c87b9 100644 --- a/gcc/config/nvptx/mkoffload.c +++ b/gcc/config/nvptx/mkoffload.c @@ -817,7 +817,7 @@ compile_native (const char *infile, const char *outfile, const char *compiler) obstack_ptr_grow (&argv_obstack, NULL); const char **new_argv = XOBFINISH (&argv_obstack, const char **); - fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true, false); obstack_free (&argv_obstack, NULL); } @@ -884,7 +884,7 @@ main (int argc, char **argv) unsetenv ("COMPILER_PATH"); unsetenv ("LIBRARY_PATH"); - fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true, false); obstack_free (&argv_obstack, NULL); xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL)); diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c index 404cb68..aef077f 100644 --- a/gcc/lto-wrapper.c +++ b/gcc/lto-wrapper.c @@ -68,6 +68,7 @@ static unsigned int nr; static char **input_names; static char **output_names; static char **offload_names; +static unsigned num_offload_targets; static const char *offloadbegin, *offloadend; static char *makefile; @@ -644,6 +645,7 @@ compile_offload_image (const char *target, const char *compiler_path, struct cl_decoded_option *linker_opts, unsigned int linker_opt_count) { + struct stat st; char *filename = NULL; char **argv; char *suffix @@ -691,11 +693,18 @@ compile_offload_image (const char *target, const char *compiler_path, obstack_ptr_grow (&argv_obstack, NULL); argv = XOBFINISH (&argv_obstack, char **); - fork_execute (argv[0], argv, true); + fork_execute (argv[0], argv, true, false); obstack_free (&argv_obstack, NULL); } free_array_of_ptrs ((void **) paths, n_paths); + + if (filename && (stat (filename, &st) != 0 || st.st_size == 0)) + { + XDELETEVEC (filename); + filename = NULL; + } + return filename; } @@ -716,28 +725,27 @@ compile_images_for_offload_targets (unsigned in_argc, char *in_argv[], const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV); if (!target_names) return; - unsigned num_targets = parse_env_var (target_names, &names, NULL); + num_offload_targets = parse_env_var (target_names, &names, NULL); const char *compiler_path = getenv ("COMPILER_PATH"); if (!compiler_path) goto out; /* Prepare an image for each target and save the name of the resultant object - file to the OFFLOAD_NAMES array. It is terminated by a NULL entry. */ - offload_names = XCNEWVEC (char *, num_targets + 1); - for (unsigned i = 0; i < num_targets; i++) + file to the OFFLOAD_NAMES array. */ + offload_names = XCNEWVEC (char *, num_offload_targets + 1); + for (unsigned i = 0; i < num_offload_targets; i++) { 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 (input_location, - "problem with building target image for %s\n", names[i]); + warning (0, "problem with building target image for %s", names[i]); } out: - free_array_of_ptrs ((void **) names, num_targets); + free_array_of_ptrs ((void **) names, num_offload_targets); } /* Copy a file from SRC to DEST. */ @@ -1063,9 +1071,10 @@ run_gcc (unsigned argc, char *argv[]) if (offload_names) { find_offloadbeginend (); - for (i = 0; offload_names[i]; i++) - printf ("%s\n", offload_names[i]); - free_array_of_ptrs ((void **) offload_names, i); + for (i = 0; i < num_offload_targets; i++) + if (offload_names[i]) + printf ("%s\n", offload_names[i]); + free_array_of_ptrs ((void **) offload_names, num_offload_targets); } } @@ -1154,7 +1163,7 @@ run_gcc (unsigned argc, char *argv[]) new_argv = XOBFINISH (&argv_obstack, const char **); argv_ptr = &new_argv[new_head_argc]; - fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); + fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true, false); if (lto_mode == LTO_MODE_LTO) { @@ -1263,7 +1272,7 @@ cont: else { fork_execute (new_argv[0], CONST_CAST (char **, new_argv), - true); + true, false); maybe_unlink (input_name); } @@ -1301,7 +1310,7 @@ cont: new_argv[i++] = NULL; pex = collect_execute (new_argv[0], CONST_CAST (char **, new_argv), NULL, NULL, PEX_SEARCH, false); - do_wait (new_argv[0], pex); + do_wait (new_argv[0], pex, false); maybe_unlink (makefile); makefile = NULL; for (i = 0; i < nr; ++i) diff --git a/libgomp/target.c b/libgomp/target.c index 73e757a..4d770c4 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -735,6 +735,24 @@ gomp_fini_device (struct gomp_device_descr *devicep) devicep->is_initialized = false; } +/* Host fallback for GOMP_target routine. */ + +static void +gomp_target_fallback (void (*fn) (void *), void **hostaddrs) +{ + struct gomp_thread old_thr, *thr = gomp_thread (); + old_thr = *thr; + memset (thr, '\0', sizeof (*thr)); + if (gomp_places_list) + { + thr->place = old_thr.place; + thr->ts.place_partition_len = gomp_places_list_len; + } + fn (hostaddrs); + gomp_free_thread (thr); + *thr = old_thr; +} + /* Called when encountering a target directive. If DEVICE is GOMP_DEVICE_ICV, it means use device-var ICV. If it is GOMP_DEVICE_HOST_FALLBACK (or any value @@ -754,21 +772,7 @@ GOMP_target (int device, void (*fn) (void *), const void *unused, if (devicep == NULL || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) - { - /* Host fallback. */ - struct gomp_thread old_thr, *thr = gomp_thread (); - old_thr = *thr; - memset (thr, '\0', sizeof (*thr)); - if (gomp_places_list) - { - thr->place = old_thr.place; - thr->ts.place_partition_len = gomp_places_list_len; - } - fn (hostaddrs); - gomp_free_thread (thr); - *thr = old_thr; - return; - } + return gomp_target_fallback (fn, hostaddrs); gomp_mutex_lock (&devicep->lock); if (!devicep->is_initialized) @@ -792,8 +796,11 @@ GOMP_target (int device, void (*fn) (void *), const void *unused, k.host_end = k.host_start + 1; splay_tree_key tgt_fn = splay_tree_lookup (&mm->splay_tree, &k); if (tgt_fn == NULL) - gomp_fatal ("Target function wasn't mapped"); - + { + gomp_target_fallback (fn, hostaddrs); + gomp_mutex_unlock (&mm->lock); + return; + } gomp_mutex_unlock (&mm->lock); fn_addr = (void *) tgt_fn->tgt->tgt_start; Thanks, -- Ilya