diff mbox

[gomp4] Add mkoffload invocations to lto-wrapper

Message ID 532B207C.9060502@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt March 20, 2014, 5:08 p.m. UTC
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
diff mbox

Patch

Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 208725)
+++ gcc/ChangeLog	(working copy)
@@ -1,5 +1,15 @@ 
 2014-03-20  Bernd Schmidt  <bernds@codesourcery.com>
 
+	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);