From patchwork Thu Mar 20 17:08:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernd Schmidt X-Patchwork-Id: 332320 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 66DC12C007C for ; Fri, 21 Mar 2014 04:10:28 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=TV0nc7Gpau281h8KSjt+fpKfDD/dyWrN1wlIYz8izPu IG8fxvdncFzkCxJ94fY6GwyuiTH5DR+eNc1sTzYgx5XmDNxbmAId/qmRWuWwWfI+ tYsxwX/LzadKlKswTozhJfdi/a5jF+3BuACroIkSIorhu8FlFsG20RqUJwHs+OmA = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=S/oCUuIHmlWVRrivQCKvj4aZmok=; b=G/W8971Hw3Co028/b f9HIoDGhA6CKqMqQcUOSqjcjGImMrmm683tA+7S4+igd4KYYIELwrQCKNNz93Fsl X5CH50SIwdh378V1gowdu8s2y0nuojuDz8v+JENhEkMYt787R90pZP4AJHUQHR3/ nuH8q90K2N6t3xx9Dp618y5IsA= Received: (qmail 7012 invoked by alias); 20 Mar 2014 17:10:22 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 6994 invoked by uid 89); 20 Mar 2014 17:10:21 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.5 required=5.0 tests=AWL, BAYES_50 autolearn=ham version=3.3.2 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 20 Mar 2014 17:10:20 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1WQgTw-00079R-8Z from Bernd_Schmidt@mentor.com ; Thu, 20 Mar 2014 10:10:16 -0700 Received: from SVR-IES-FEM-01.mgc.mentorg.com ([137.202.0.104]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Thu, 20 Mar 2014 10:10:16 -0700 Received: from [127.0.0.1] (137.202.0.76) by SVR-IES-FEM-01.mgc.mentorg.com (137.202.0.104) with Microsoft SMTP Server id 14.2.247.3; Thu, 20 Mar 2014 17:10:13 +0000 Message-ID: <532B207C.9060502@codesourcery.com> Date: Thu, 20 Mar 2014 18:08:12 +0100 From: Bernd Schmidt User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.3.0 MIME-Version: 1.0 To: GCC Patches CC: Ilya Verbin , Michael Zolotukhin Subject: [gomp4] Add mkoffload invocations to lto-wrapper This is based on Michael Zolotukhin's patch 3/3 from a while ago. It enables lto-wrapper to build target images using the offload compilers (identifying them through an env variable passed in by the gcc driver). All the target-specific code is gone, however. We now expect an offload compiler to provide a mkoffload tool to generate the image, and we just call it from lto-wrapper. Committed on gomp-4_0-branch. Bernd Index: gcc/ChangeLog =================================================================== --- gcc/ChangeLog (revision 208725) +++ gcc/ChangeLog (working copy) @@ -1,5 +1,15 @@ 2014-03-20 Bernd Schmidt + Mostly by Michael Zolotukhin: + * lto-wrapper.c (OFFLOAD_FUNC_TABLE_SECTION_NAME, + OFFLOAD_TARGET_NAMES_ENV): New defines. + (offload_names): New static variable. + (free_array_of_ptrs, parse_env_var, access_check, + prepare_target_image, replace_special_characters, + compile_images_for_openmp_targets): New static functions. + (run_gcc): Determine whether offload sections are present. If so, + run compile_images_for_openmp_targets and print the image names. + * Makefile.in (COLLECT2_OBJS): Add collect-utils.o. (LTO_WRAPPER_OBJS): New variable. (lto-wrapper$(exeext)): Use it. Index: gcc/lto-wrapper.c =================================================================== --- gcc/lto-wrapper.c (revision 208725) +++ gcc/lto-wrapper.c (working copy) @@ -49,6 +49,9 @@ along with GCC; see the file COPYING3. #include "lto-section-names.h" #include "collect-utils.h" +#define OFFLOAD_FUNC_TABLE_SECTION_NAME ".offload_func_table_section" +#define OFFLOAD_TARGET_NAMES_ENV "OFFLOAD_TARGET_NAMES" + enum lto_mode_d { LTO_MODE_NONE, /* Not doing LTO. */ LTO_MODE_LTO, /* Normal LTO. */ @@ -63,6 +66,7 @@ static char *flto_out; static unsigned int nr; static char **input_names; static char **output_names; +static char **offload_names; static char *makefile; const char tool_name[] = "lto-wrapper"; @@ -279,6 +283,203 @@ merge_and_complain (struct cl_decoded_op } } +/* Auxiliary function that frees elements of PTR and PTR itself. + N is number of elements to be freed. + If PTR is NULL, nothing is freed. If an element is NULL, subsequent elements + are not freed. */ +static void** +free_array_of_ptrs (void **ptr, unsigned n) +{ + unsigned i; + if (!ptr) + return NULL; + for (i = 0; i < n; i++) + { + if (!ptr[i]) + break; + free (ptr[i]); + } + free (ptr); + return NULL; +} + +/* Parse STR, saving found tokens into PVALUES and return their number. + Tokens are assumed to be delimited by ':'. If APPEND is non-null, + append it to every token we find. */ + +static unsigned +parse_env_var (const char *str, char ***pvalues, const char *append) +{ + const char *curval, *nextval; + char **values; + unsigned num = 1, i; + + curval = strchr (str, ':'); + while (curval) + { + num++; + curval = strchr (curval + 1, ':'); + } + + values = (char**) xmalloc (num * sizeof (char*)); + curval = str; + nextval = strchrnul (curval, ':'); + + int append_len = append ? strlen (append) : 0; + for (i = 0; i < num; i++) + { + int l = nextval - curval; + values[i] = (char*) xmalloc (l + 1 + append_len); + memcpy (values[i], curval, l); + values[i][l] = 0; + if (append) + strcat (values[i], append); + curval = nextval + 1; + nextval = strchrnul (curval, ':'); + } + *pvalues = values; + return num; +} + +/* Check whether NAME can be accessed in MODE. This is like access, + except that it never considers directories to be executable. */ + +static int +access_check (const char *name, int mode) +{ + if (mode == X_OK) + { + struct stat st; + + if (stat (name, &st) < 0 + || S_ISDIR (st.st_mode)) + return -1; + } + + return access (name, mode); +} + +/* Prepare target image for target NAME. + Firstly, we execute COMPILER, passing all input files to it to produce DSO. + When target DSO is ready, we pass it to objcopy to place its image into a + special data section. After that we rename target image's symbols to values, + expected by the host side, and return the name of the resultant file. */ + +static char* +prepare_target_image (const char *target, const char *compiler_path, + unsigned in_argc, char *in_argv[]) +{ + const char **argv; + struct obstack argv_obstack; + unsigned i; + char *filename = NULL; + char *suffix = XALLOCAVEC (char, strlen ("/accel//mkoffload") + 1 + strlen (target)); + const char *compiler = NULL; + + strcpy (suffix, "/accel/"); + strcat (suffix, target); + strcat (suffix, "/mkoffload"); + + char **paths; + int n_paths = parse_env_var (compiler_path, &paths, suffix); + + for (int i = 0; i < n_paths; i++) + if (access_check (paths[i], X_OK) == 0) + { + compiler = paths[i]; + break; + } + + if (compiler == NULL) + goto out; + + /* 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"); + obstack_ptr_grow (&argv_obstack, filename); + + for (i = 1; i < in_argc; ++i) + if (strncmp (in_argv[i], "-fresolution=", sizeof ("-fresolution=") - 1)) + obstack_ptr_grow (&argv_obstack, in_argv[i]); + obstack_ptr_grow (&argv_obstack, NULL); + + argv = XOBFINISH (&argv_obstack, const char **); + fork_execute (argv[0], CONST_CAST (char **, argv), true); + obstack_free (&argv_obstack, NULL); + + out: + free_array_of_ptrs ((void**) paths, n_paths); + return filename; +} + + +/* Replace all special characters in array of strings with '_'. + This is needed, e.g., when we want to use a string for a symbol name. */ +static void +replace_special_characters (char **ptr, unsigned n) +{ + unsigned i, j; + const char *special_chars = "-+=/\\~`!@#$%^&*()[]{},;.:\"'"; + for (i = 0; i < n; i++) + { + char *str = ptr[i]; + for (j = 0; j < strlen (str); j++) + { + if (strchr (special_chars, str[j])) + str[j] = '_'; + } + } +} + +/* The main routine dealing with openmp offloading. + The routine builds a target image for each offloading target. + IN_ARGC and IN_ARGV specify input files. As all of them could contain + omp-sections, we pass them all to target compilers. + Env-variable OFFLOAD_TARGET_NAMES_ENV describes for which targets we should + build images. + This function stores the names of the object files in the OFFLOAD_NAMES + array. */ + +static void +compile_images_for_openmp_targets (unsigned in_argc, char *in_argv[]) +{ + char *target_names; + char **names; + unsigned num_targets; + + /* Obtain names of offload targets and corresponding compilers. */ + target_names = getenv (OFFLOAD_TARGET_NAMES_ENV); + if (!target_names) + return; + + num_targets = parse_env_var (target_names, &names, NULL); + replace_special_characters (names, num_targets); + + const char *compiler_path = getenv ("COMPILER_PATH"); + if (compiler_path == NULL) + goto out; + + /* Prepare an image for each target. The array is terminated by a NULL + entry. */ + 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); + if (!offload_names[i]) + fatal_perror ("Problem with building target image for %s.\n", names[i]); + } + + out: + free_array_of_ptrs ((void**) names, num_targets); +} + + /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */ static void @@ -299,6 +500,7 @@ run_gcc (unsigned argc, char *argv[]) unsigned int decoded_options_count; struct obstack argv_obstack; int new_head_argc; + bool have_offload = false; /* Get the driver and options. */ collect_gcc = getenv ("COLLECT_GCC"); @@ -354,6 +556,11 @@ run_gcc (unsigned argc, char *argv[]) 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); @@ -752,6 +959,19 @@ cont: for (i = 0; i < nr; ++i) maybe_unlink (input_names[i]); } + if (have_offload) + { + compile_images_for_openmp_targets (argc, argv); + if (offload_names) + { + for (i = 0; offload_names[i]; i++) + { + fputs (offload_names[i], stdout); + putc ('\n', stdout); + } + free_array_of_ptrs ((void **)offload_names, i); + } + } for (i = 0; i < nr; ++i) { fputs (output_names[i], stdout);