Home | History | Annotate | Line # | Download | only in nvptx
      1  1.1  mrg /* Offload image generation tool for PTX.
      2  1.1  mrg 
      3  1.1  mrg    Copyright (C) 2014-2022 Free Software Foundation, Inc.
      4  1.1  mrg 
      5  1.1  mrg    Contributed by Nathan Sidwell <nathan (at) codesourcery.com> and
      6  1.1  mrg    Bernd Schmidt <bernds (at) codesourcery.com>.
      7  1.1  mrg 
      8  1.1  mrg    This file is part of GCC.
      9  1.1  mrg 
     10  1.1  mrg    GCC is free software; you can redistribute it and/or modify it
     11  1.1  mrg    under the terms of the GNU General Public License as published
     12  1.1  mrg    by the Free Software Foundation; either version 3, or (at your
     13  1.1  mrg    option) any later version.
     14  1.1  mrg 
     15  1.1  mrg    GCC is distributed in the hope that it will be useful, but WITHOUT
     16  1.1  mrg    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     17  1.1  mrg    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     18  1.1  mrg    License for more details.
     19  1.1  mrg 
     20  1.1  mrg    You should have received a copy of the GNU General Public License
     21  1.1  mrg    along with GCC; see the file COPYING3.  If not see
     22  1.1  mrg    <http://www.gnu.org/licenses/>.  */
     23  1.1  mrg 
     24  1.1  mrg /* Munges PTX assembly into a C source file defining the PTX code as a
     25  1.1  mrg    string.
     26  1.1  mrg 
     27  1.1  mrg    This is not a complete assembler.  We presume the source is well
     28  1.1  mrg    formed from the compiler and can die horribly if it is not.  */
     29  1.1  mrg 
     30  1.1  mrg #define IN_TARGET_CODE 1
     31  1.1  mrg 
     32  1.1  mrg #include "config.h"
     33  1.1  mrg #include "system.h"
     34  1.1  mrg #include "coretypes.h"
     35  1.1  mrg #include "obstack.h"
     36  1.1  mrg #include "diagnostic.h"
     37  1.1  mrg #include "intl.h"
     38  1.1  mrg #include <libgen.h>
     39  1.1  mrg #include "collect-utils.h"
     40  1.1  mrg #include "gomp-constants.h"
     41  1.1  mrg 
     42  1.1  mrg const char tool_name[] = "nvptx mkoffload";
     43  1.1  mrg 
     44  1.1  mrg #define COMMENT_PREFIX "#"
     45  1.1  mrg 
     46  1.1  mrg struct id_map
     47  1.1  mrg {
     48  1.1  mrg   id_map *next;
     49  1.1  mrg   char *ptx_name;
     50  1.1  mrg };
     51  1.1  mrg 
     52  1.1  mrg static id_map *func_ids, **funcs_tail = &func_ids;
     53  1.1  mrg static id_map *var_ids, **vars_tail = &var_ids;
     54  1.1  mrg 
     55  1.1  mrg /* Files to unlink.  */
     56  1.1  mrg static const char *ptx_name;
     57  1.1  mrg static const char *ptx_cfile_name;
     58  1.1  mrg static const char *ptx_dumpbase;
     59  1.1  mrg 
     60  1.1  mrg enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
     61  1.1  mrg 
     62  1.1  mrg /* Delete tempfiles.  */
     63  1.1  mrg 
     64  1.1  mrg void
     65  1.1  mrg tool_cleanup (bool from_signal ATTRIBUTE_UNUSED)
     66  1.1  mrg {
     67  1.1  mrg   if (ptx_cfile_name)
     68  1.1  mrg     maybe_unlink (ptx_cfile_name);
     69  1.1  mrg   if (ptx_name)
     70  1.1  mrg     maybe_unlink (ptx_name);
     71  1.1  mrg }
     72  1.1  mrg 
     73  1.1  mrg static void
     74  1.1  mrg mkoffload_cleanup (void)
     75  1.1  mrg {
     76  1.1  mrg   tool_cleanup (false);
     77  1.1  mrg }
     78  1.1  mrg 
     79  1.1  mrg /* Unlink FILE unless requested otherwise.  */
     80  1.1  mrg 
     81  1.1  mrg void
     82  1.1  mrg maybe_unlink (const char *file)
     83  1.1  mrg {
     84  1.1  mrg   if (!save_temps)
     85  1.1  mrg     {
     86  1.1  mrg       if (unlink_if_ordinary (file)
     87  1.1  mrg 	  && errno != ENOENT)
     88  1.1  mrg 	fatal_error (input_location, "deleting file %s: %m", file);
     89  1.1  mrg     }
     90  1.1  mrg   else if (verbose)
     91  1.1  mrg     fprintf (stderr, "[Leaving %s]\n", file);
     92  1.1  mrg }
     93  1.1  mrg 
     94  1.1  mrg /* Add or change the value of an environment variable, outputting the
     95  1.1  mrg    change to standard error if in verbose mode.  */
     96  1.1  mrg static void
     97  1.1  mrg xputenv (const char *string)
     98  1.1  mrg {
     99  1.1  mrg   if (verbose)
    100  1.1  mrg     fprintf (stderr, "%s\n", string);
    101  1.1  mrg   putenv (CONST_CAST (char *, string));
    102  1.1  mrg }
    103  1.1  mrg 
    104  1.1  mrg 
    105  1.1  mrg static void
    106  1.1  mrg record_id (const char *p1, id_map ***where)
    107  1.1  mrg {
    108  1.1  mrg   const char *end = strchr (p1, '\n');
    109  1.1  mrg   if (!end)
    110  1.1  mrg     fatal_error (input_location, "malformed ptx file");
    111  1.1  mrg 
    112  1.1  mrg   id_map *v = XNEW (id_map);
    113  1.1  mrg   size_t len = end - p1;
    114  1.1  mrg   v->ptx_name = XNEWVEC (char, len + 1);
    115  1.1  mrg   memcpy (v->ptx_name, p1, len);
    116  1.1  mrg   v->ptx_name[len] = '\0';
    117  1.1  mrg   v->next = NULL;
    118  1.1  mrg   id_map **tail = *where;
    119  1.1  mrg   *tail = v;
    120  1.1  mrg   *where = &v->next;
    121  1.1  mrg }
    122  1.1  mrg 
    123  1.1  mrg /* Read the whole input file.  It will be NUL terminated (but
    124  1.1  mrg    remember, there could be a NUL in the file itself.  */
    125  1.1  mrg 
    126  1.1  mrg static const char *
    127  1.1  mrg read_file (FILE *stream, size_t *plen)
    128  1.1  mrg {
    129  1.1  mrg   size_t alloc = 16384;
    130  1.1  mrg   size_t base = 0;
    131  1.1  mrg   char *buffer;
    132  1.1  mrg 
    133  1.1  mrg   if (!fseek (stream, 0, SEEK_END))
    134  1.1  mrg     {
    135  1.1  mrg       /* Get the file size.  */
    136  1.1  mrg       long s = ftell (stream);
    137  1.1  mrg       if (s >= 0)
    138  1.1  mrg 	alloc = s + 100;
    139  1.1  mrg       fseek (stream, 0, SEEK_SET);
    140  1.1  mrg     }
    141  1.1  mrg   buffer = XNEWVEC (char, alloc);
    142  1.1  mrg 
    143  1.1  mrg   for (;;)
    144  1.1  mrg     {
    145  1.1  mrg       size_t n = fread (buffer + base, 1, alloc - base - 1, stream);
    146  1.1  mrg 
    147  1.1  mrg       if (!n)
    148  1.1  mrg 	break;
    149  1.1  mrg       base += n;
    150  1.1  mrg       if (base + 1 == alloc)
    151  1.1  mrg 	{
    152  1.1  mrg 	  alloc *= 2;
    153  1.1  mrg 	  buffer = XRESIZEVEC (char, buffer, alloc);
    154  1.1  mrg 	}
    155  1.1  mrg     }
    156  1.1  mrg   buffer[base] = 0;
    157  1.1  mrg   *plen = base;
    158  1.1  mrg   return buffer;
    159  1.1  mrg }
    160  1.1  mrg 
    161  1.1  mrg /* Parse STR, saving found tokens into PVALUES and return their number.
    162  1.1  mrg    Tokens are assumed to be delimited by ':'.  */
    163  1.1  mrg static unsigned
    164  1.1  mrg parse_env_var (const char *str, char ***pvalues)
    165  1.1  mrg {
    166  1.1  mrg   const char *curval, *nextval;
    167  1.1  mrg   char **values;
    168  1.1  mrg   unsigned num = 1, i;
    169  1.1  mrg 
    170  1.1  mrg   curval = strchr (str, ':');
    171  1.1  mrg   while (curval)
    172  1.1  mrg     {
    173  1.1  mrg       num++;
    174  1.1  mrg       curval = strchr (curval + 1, ':');
    175  1.1  mrg     }
    176  1.1  mrg 
    177  1.1  mrg   values = (char **) xmalloc (num * sizeof (char *));
    178  1.1  mrg   curval = str;
    179  1.1  mrg   nextval = strchr (curval, ':');
    180  1.1  mrg   if (nextval == NULL)
    181  1.1  mrg     nextval = strchr (curval, '\0');
    182  1.1  mrg 
    183  1.1  mrg   for (i = 0; i < num; i++)
    184  1.1  mrg     {
    185  1.1  mrg       int l = nextval - curval;
    186  1.1  mrg       values[i] = (char *) xmalloc (l + 1);
    187  1.1  mrg       memcpy (values[i], curval, l);
    188  1.1  mrg       values[i][l] = 0;
    189  1.1  mrg       curval = nextval + 1;
    190  1.1  mrg       nextval = strchr (curval, ':');
    191  1.1  mrg       if (nextval == NULL)
    192  1.1  mrg 	nextval = strchr (curval, '\0');
    193  1.1  mrg     }
    194  1.1  mrg   *pvalues = values;
    195  1.1  mrg   return num;
    196  1.1  mrg }
    197  1.1  mrg 
    198  1.1  mrg /* Auxiliary function that frees elements of PTR and PTR itself.
    199  1.1  mrg    N is number of elements to be freed.  If PTR is NULL, nothing is freed.
    200  1.1  mrg    If an element is NULL, subsequent elements are not freed.  */
    201  1.1  mrg static void
    202  1.1  mrg free_array_of_ptrs (void **ptr, unsigned n)
    203  1.1  mrg {
    204  1.1  mrg   unsigned i;
    205  1.1  mrg   if (!ptr)
    206  1.1  mrg     return;
    207  1.1  mrg   for (i = 0; i < n; i++)
    208  1.1  mrg     {
    209  1.1  mrg       if (!ptr[i])
    210  1.1  mrg 	break;
    211  1.1  mrg       free (ptr[i]);
    212  1.1  mrg     }
    213  1.1  mrg   free (ptr);
    214  1.1  mrg   return;
    215  1.1  mrg }
    216  1.1  mrg 
    217  1.1  mrg /* Check whether NAME can be accessed in MODE.  This is like access,
    218  1.1  mrg    except that it never considers directories to be executable.  */
    219  1.1  mrg static int
    220  1.1  mrg access_check (const char *name, int mode)
    221  1.1  mrg {
    222  1.1  mrg   if (mode == X_OK)
    223  1.1  mrg     {
    224  1.1  mrg       struct stat st;
    225  1.1  mrg 
    226  1.1  mrg       if (stat (name, &st) < 0 || S_ISDIR (st.st_mode))
    227  1.1  mrg 	return -1;
    228  1.1  mrg     }
    229  1.1  mrg 
    230  1.1  mrg   return access (name, mode);
    231  1.1  mrg }
    232  1.1  mrg 
    233  1.1  mrg static void
    234  1.1  mrg process (FILE *in, FILE *out)
    235  1.1  mrg {
    236  1.1  mrg   size_t len = 0;
    237  1.1  mrg   const char *input = read_file (in, &len);
    238  1.1  mrg   const char *comma;
    239  1.1  mrg   id_map const *id;
    240  1.1  mrg   unsigned obj_count = 0;
    241  1.1  mrg   unsigned ix;
    242  1.1  mrg 
    243  1.1  mrg   /* Dump out char arrays for each PTX object file.  These are
    244  1.1  mrg      terminated by a NUL.  */
    245  1.1  mrg   for (size_t i = 0; i != len;)
    246  1.1  mrg     {
    247  1.1  mrg       char c;
    248  1.1  mrg 
    249  1.1  mrg       fprintf (out, "static const char ptx_code_%u[] =\n\t\"", obj_count++);
    250  1.1  mrg       while ((c = input[i++]))
    251  1.1  mrg 	{
    252  1.1  mrg 	  switch (c)
    253  1.1  mrg 	    {
    254  1.1  mrg 	    case '\r':
    255  1.1  mrg 	      continue;
    256  1.1  mrg 	    case '\n':
    257  1.1  mrg 	      fprintf (out, "\\n\"\n\t\"");
    258  1.1  mrg 	      /* Look for mappings on subsequent lines.  */
    259  1.1  mrg 	      while (startswith (input + i, "//:"))
    260  1.1  mrg 		{
    261  1.1  mrg 		  i += 3;
    262  1.1  mrg 
    263  1.1  mrg 		  if (startswith (input + i, "VAR_MAP "))
    264  1.1  mrg 		    record_id (input + i + 8, &vars_tail);
    265  1.1  mrg 		  else if (startswith (input + i, "FUNC_MAP "))
    266  1.1  mrg 		    record_id (input + i + 9, &funcs_tail);
    267  1.1  mrg 		  else
    268  1.1  mrg 		    abort ();
    269  1.1  mrg 		  /* Skip to next line. */
    270  1.1  mrg 		  while (input[i++] != '\n')
    271  1.1  mrg 		    continue;
    272  1.1  mrg 		}
    273  1.1  mrg 	      continue;
    274  1.1  mrg 	    case '"':
    275  1.1  mrg 	    case '\\':
    276  1.1  mrg 	      putc ('\\', out);
    277  1.1  mrg 	      break;
    278  1.1  mrg 	    default:
    279  1.1  mrg 	      break;
    280  1.1  mrg 	    }
    281  1.1  mrg 	  putc (c, out);
    282  1.1  mrg 	}
    283  1.1  mrg       fprintf (out, "\";\n\n");
    284  1.1  mrg     }
    285  1.1  mrg 
    286  1.1  mrg   /* Dump out array of pointers to ptx object strings.  */
    287  1.1  mrg   fprintf (out, "static const struct ptx_obj {\n"
    288  1.1  mrg 	   "  const char *code;\n"
    289  1.1  mrg 	   "  __SIZE_TYPE__ size;\n"
    290  1.1  mrg 	   "} ptx_objs[] = {");
    291  1.1  mrg   for (comma = "", ix = 0; ix != obj_count; comma = ",", ix++)
    292  1.1  mrg     fprintf (out, "%s\n\t{ptx_code_%u, sizeof (ptx_code_%u)}", comma, ix, ix);
    293  1.1  mrg   fprintf (out, "\n};\n\n");
    294  1.1  mrg 
    295  1.1  mrg   /* Dump out variable idents.  */
    296  1.1  mrg   fprintf (out, "static const char *const var_mappings[] = {");
    297  1.1  mrg   for (comma = "", id = var_ids; id; comma = ",", id = id->next)
    298  1.1  mrg     fprintf (out, "%s\n\t%s", comma, id->ptx_name);
    299  1.1  mrg   fprintf (out, "\n};\n\n");
    300  1.1  mrg 
    301  1.1  mrg   /* Dump out function idents.  */
    302  1.1  mrg   fprintf (out, "static const struct nvptx_fn {\n"
    303  1.1  mrg 	   "  const char *name;\n"
    304  1.1  mrg 	   "  unsigned short dim[%d];\n"
    305  1.1  mrg 	   "} func_mappings[] = {\n", GOMP_DIM_MAX);
    306  1.1  mrg   for (comma = "", id = func_ids; id; comma = ",", id = id->next)
    307  1.1  mrg     fprintf (out, "%s\n\t{%s}", comma, id->ptx_name);
    308  1.1  mrg   fprintf (out, "\n};\n\n");
    309  1.1  mrg 
    310  1.1  mrg   fprintf (out,
    311  1.1  mrg 	   "static const struct nvptx_tdata {\n"
    312  1.1  mrg 	   "  const struct ptx_obj *ptx_objs;\n"
    313  1.1  mrg 	   "  unsigned ptx_num;\n"
    314  1.1  mrg 	   "  const char *const *var_names;\n"
    315  1.1  mrg 	   "  unsigned var_num;\n"
    316  1.1  mrg 	   "  const struct nvptx_fn *fn_names;\n"
    317  1.1  mrg 	   "  unsigned fn_num;\n"
    318  1.1  mrg 	   "} target_data = {\n"
    319  1.1  mrg 	   "  ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n"
    320  1.1  mrg 	   "  var_mappings,"
    321  1.1  mrg 	   "  sizeof (var_mappings) / sizeof (var_mappings[0]),\n"
    322  1.1  mrg 	   "  func_mappings,"
    323  1.1  mrg 	   "  sizeof (func_mappings) / sizeof (func_mappings[0])\n"
    324  1.1  mrg 	   "};\n\n");
    325  1.1  mrg 
    326  1.1  mrg   fprintf (out, "#ifdef __cplusplus\n"
    327  1.1  mrg 	   "extern \"C\" {\n"
    328  1.1  mrg 	   "#endif\n");
    329  1.1  mrg 
    330  1.1  mrg   fprintf (out, "extern void GOMP_offload_register_ver"
    331  1.1  mrg 	   " (unsigned, const void *, int, const void *);\n");
    332  1.1  mrg   fprintf (out, "extern void GOMP_offload_unregister_ver"
    333  1.1  mrg 	   " (unsigned, const void *, int, const void *);\n");
    334  1.1  mrg 
    335  1.1  mrg   fprintf (out, "#ifdef __cplusplus\n"
    336  1.1  mrg 	   "}\n"
    337  1.1  mrg 	   "#endif\n");
    338  1.1  mrg 
    339  1.1  mrg   fprintf (out, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
    340  1.1  mrg 
    341  1.1  mrg   fprintf (out, "static __attribute__((constructor)) void init (void)\n"
    342  1.1  mrg 	   "{\n"
    343  1.1  mrg 	   "  GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
    344  1.1  mrg 	   " %d/*NVIDIA_PTX*/, &target_data);\n"
    345  1.1  mrg 	   "};\n",
    346  1.1  mrg 	   GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
    347  1.1  mrg 	   GOMP_DEVICE_NVIDIA_PTX);
    348  1.1  mrg 
    349  1.1  mrg   fprintf (out, "static __attribute__((destructor)) void fini (void)\n"
    350  1.1  mrg 	   "{\n"
    351  1.1  mrg 	   "  GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
    352  1.1  mrg 	   " %d/*NVIDIA_PTX*/, &target_data);\n"
    353  1.1  mrg 	   "};\n",
    354  1.1  mrg 	   GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
    355  1.1  mrg 	   GOMP_DEVICE_NVIDIA_PTX);
    356  1.1  mrg }
    357  1.1  mrg 
    358  1.1  mrg static void
    359  1.1  mrg compile_native (const char *infile, const char *outfile, const char *compiler,
    360  1.1  mrg 		bool fPIC, bool fpic)
    361  1.1  mrg {
    362  1.1  mrg   const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
    363  1.1  mrg   if (!collect_gcc_options)
    364  1.1  mrg     fatal_error (input_location,
    365  1.1  mrg 		 "environment variable COLLECT_GCC_OPTIONS must be set");
    366  1.1  mrg 
    367  1.1  mrg   struct obstack argv_obstack;
    368  1.1  mrg   obstack_init (&argv_obstack);
    369  1.1  mrg   obstack_ptr_grow (&argv_obstack, compiler);
    370  1.1  mrg   if (fPIC)
    371  1.1  mrg     obstack_ptr_grow (&argv_obstack, "-fPIC");
    372  1.1  mrg   if (fpic)
    373  1.1  mrg     obstack_ptr_grow (&argv_obstack, "-fpic");
    374  1.1  mrg   if (save_temps)
    375  1.1  mrg     obstack_ptr_grow (&argv_obstack, "-save-temps");
    376  1.1  mrg   if (verbose)
    377  1.1  mrg     obstack_ptr_grow (&argv_obstack, "-v");
    378  1.1  mrg   obstack_ptr_grow (&argv_obstack, "-dumpdir");
    379  1.1  mrg   obstack_ptr_grow (&argv_obstack, "");
    380  1.1  mrg   obstack_ptr_grow (&argv_obstack, "-dumpbase");
    381  1.1  mrg   obstack_ptr_grow (&argv_obstack, ptx_dumpbase);
    382  1.1  mrg   obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
    383  1.1  mrg   obstack_ptr_grow (&argv_obstack, ".c");
    384  1.1  mrg   switch (offload_abi)
    385  1.1  mrg     {
    386  1.1  mrg     case OFFLOAD_ABI_LP64:
    387  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-m64");
    388  1.1  mrg       break;
    389  1.1  mrg     case OFFLOAD_ABI_ILP32:
    390  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-m32");
    391  1.1  mrg       break;
    392  1.1  mrg     default:
    393  1.1  mrg       gcc_unreachable ();
    394  1.1  mrg     }
    395  1.1  mrg   obstack_ptr_grow (&argv_obstack, infile);
    396  1.1  mrg   obstack_ptr_grow (&argv_obstack, "-c");
    397  1.1  mrg   obstack_ptr_grow (&argv_obstack, "-o");
    398  1.1  mrg   obstack_ptr_grow (&argv_obstack, outfile);
    399  1.1  mrg   obstack_ptr_grow (&argv_obstack, NULL);
    400  1.1  mrg 
    401  1.1  mrg   const char **new_argv = XOBFINISH (&argv_obstack, const char **);
    402  1.1  mrg   fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true,
    403  1.1  mrg 		".gccnative_args");
    404  1.1  mrg   obstack_free (&argv_obstack, NULL);
    405  1.1  mrg }
    406  1.1  mrg 
    407  1.1  mrg int
    408  1.1  mrg main (int argc, char **argv)
    409  1.1  mrg {
    410  1.1  mrg   FILE *in = stdin;
    411  1.1  mrg   FILE *out = stdout;
    412  1.1  mrg   const char *outname = 0;
    413  1.1  mrg 
    414  1.1  mrg   progname = "mkoffload";
    415  1.1  mrg   diagnostic_initialize (global_dc, 0);
    416  1.1  mrg 
    417  1.1  mrg   if (atexit (mkoffload_cleanup) != 0)
    418  1.1  mrg     fatal_error (input_location, "atexit failed");
    419  1.1  mrg 
    420  1.1  mrg   char *collect_gcc = getenv ("COLLECT_GCC");
    421  1.1  mrg   if (collect_gcc == NULL)
    422  1.1  mrg     fatal_error (input_location, "COLLECT_GCC must be set.");
    423  1.1  mrg   const char *gcc_path = dirname (ASTRDUP (collect_gcc));
    424  1.1  mrg   const char *gcc_exec = basename (ASTRDUP (collect_gcc));
    425  1.1  mrg 
    426  1.1  mrg   size_t len = (strlen (gcc_path) + 1
    427  1.1  mrg 		+ strlen (GCC_INSTALL_NAME)
    428  1.1  mrg 		+ 1);
    429  1.1  mrg   char *driver = XALLOCAVEC (char, len);
    430  1.1  mrg 
    431  1.1  mrg   if (strcmp (gcc_exec, collect_gcc) == 0)
    432  1.1  mrg     /* collect_gcc has no path, so it was found in PATH.  Make sure we also
    433  1.1  mrg        find accel-gcc in PATH.  */
    434  1.1  mrg     gcc_path = NULL;
    435  1.1  mrg 
    436  1.1  mrg   int driver_used = 0;
    437  1.1  mrg   if (gcc_path != NULL)
    438  1.1  mrg     driver_used = sprintf (driver, "%s/", gcc_path);
    439  1.1  mrg   sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME);
    440  1.1  mrg 
    441  1.1  mrg   bool found = false;
    442  1.1  mrg   if (gcc_path == NULL)
    443  1.1  mrg     found = true;
    444  1.1  mrg   else if (access_check (driver, X_OK) == 0)
    445  1.1  mrg     found = true;
    446  1.1  mrg   else
    447  1.1  mrg     {
    448  1.1  mrg       /* Don't use alloca pointer with XRESIZEVEC.  */
    449  1.1  mrg       driver = NULL;
    450  1.1  mrg       /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME.  */
    451  1.1  mrg       char **paths = NULL;
    452  1.1  mrg       unsigned n_paths;
    453  1.1  mrg       n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
    454  1.1  mrg       for (unsigned i = 0; i < n_paths; i++)
    455  1.1  mrg 	{
    456  1.1  mrg 	  len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1;
    457  1.1  mrg 	  driver = XRESIZEVEC (char, driver, len);
    458  1.1  mrg 	  sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME);
    459  1.1  mrg 	  if (access_check (driver, X_OK) == 0)
    460  1.1  mrg 	    {
    461  1.1  mrg 	      found = true;
    462  1.1  mrg 	      break;
    463  1.1  mrg 	    }
    464  1.1  mrg 	}
    465  1.1  mrg       free_array_of_ptrs ((void **) paths, n_paths);
    466  1.1  mrg     }
    467  1.1  mrg 
    468  1.1  mrg   if (!found)
    469  1.1  mrg     fatal_error (input_location,
    470  1.1  mrg 		 "offload compiler %s not found (consider using %<-B%>)",
    471  1.1  mrg 		 GCC_INSTALL_NAME);
    472  1.1  mrg 
    473  1.1  mrg   /* We may be called with all the arguments stored in some file and
    474  1.1  mrg      passed with @file.  Expand them into argv before processing.  */
    475  1.1  mrg   expandargv (&argc, &argv);
    476  1.1  mrg 
    477  1.1  mrg   /* Scan the argument vector.  */
    478  1.1  mrg   bool fopenmp = false;
    479  1.1  mrg   bool fopenacc = false;
    480  1.1  mrg   bool fPIC = false;
    481  1.1  mrg   bool fpic = false;
    482  1.1  mrg   for (int i = 1; i < argc; i++)
    483  1.1  mrg     {
    484  1.1  mrg #define STR "-foffload-abi="
    485  1.1  mrg       if (startswith (argv[i], STR))
    486  1.1  mrg 	{
    487  1.1  mrg 	  if (strcmp (argv[i] + strlen (STR), "lp64") == 0)
    488  1.1  mrg 	    offload_abi = OFFLOAD_ABI_LP64;
    489  1.1  mrg 	  else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0)
    490  1.1  mrg 	    offload_abi = OFFLOAD_ABI_ILP32;
    491  1.1  mrg 	  else
    492  1.1  mrg 	    fatal_error (input_location,
    493  1.1  mrg 			 "unrecognizable argument of option " STR);
    494  1.1  mrg 	}
    495  1.1  mrg #undef STR
    496  1.1  mrg       else if (strcmp (argv[i], "-fopenmp") == 0)
    497  1.1  mrg 	fopenmp = true;
    498  1.1  mrg       else if (strcmp (argv[i], "-fopenacc") == 0)
    499  1.1  mrg 	fopenacc = true;
    500  1.1  mrg       else if (strcmp (argv[i], "-fPIC") == 0)
    501  1.1  mrg 	fPIC = true;
    502  1.1  mrg       else if (strcmp (argv[i], "-fpic") == 0)
    503  1.1  mrg 	fpic = true;
    504  1.1  mrg       else if (strcmp (argv[i], "-save-temps") == 0)
    505  1.1  mrg 	save_temps = true;
    506  1.1  mrg       else if (strcmp (argv[i], "-v") == 0)
    507  1.1  mrg 	verbose = true;
    508  1.1  mrg       else if (strcmp (argv[i], "-dumpbase") == 0
    509  1.1  mrg 	       && i + 1 < argc)
    510  1.1  mrg 	dumppfx = argv[++i];
    511  1.1  mrg     }
    512  1.1  mrg   if (!(fopenacc ^ fopenmp))
    513  1.1  mrg     fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
    514  1.1  mrg 		 "must be set");
    515  1.1  mrg 
    516  1.1  mrg   struct obstack argv_obstack;
    517  1.1  mrg   obstack_init (&argv_obstack);
    518  1.1  mrg   obstack_ptr_grow (&argv_obstack, driver);
    519  1.1  mrg   if (save_temps)
    520  1.1  mrg     obstack_ptr_grow (&argv_obstack, "-save-temps");
    521  1.1  mrg   if (verbose)
    522  1.1  mrg     obstack_ptr_grow (&argv_obstack, "-v");
    523  1.1  mrg   obstack_ptr_grow (&argv_obstack, "-xlto");
    524  1.1  mrg   switch (offload_abi)
    525  1.1  mrg     {
    526  1.1  mrg     case OFFLOAD_ABI_LP64:
    527  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-m64");
    528  1.1  mrg       break;
    529  1.1  mrg     case OFFLOAD_ABI_ILP32:
    530  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-m32");
    531  1.1  mrg       break;
    532  1.1  mrg     default:
    533  1.1  mrg       gcc_unreachable ();
    534  1.1  mrg     }
    535  1.1  mrg   if (fopenmp)
    536  1.1  mrg     obstack_ptr_grow (&argv_obstack, "-mgomp");
    537  1.1  mrg 
    538  1.1  mrg   for (int ix = 1; ix != argc; ix++)
    539  1.1  mrg     {
    540  1.1  mrg       if (!strcmp (argv[ix], "-o") && ix + 1 != argc)
    541  1.1  mrg 	outname = argv[++ix];
    542  1.1  mrg       else
    543  1.1  mrg 	obstack_ptr_grow (&argv_obstack, argv[ix]);
    544  1.1  mrg     }
    545  1.1  mrg 
    546  1.1  mrg   if (!dumppfx)
    547  1.1  mrg     dumppfx = outname;
    548  1.1  mrg 
    549  1.1  mrg   ptx_dumpbase = concat (dumppfx, ".c", NULL);
    550  1.1  mrg   if (save_temps)
    551  1.1  mrg     ptx_cfile_name = ptx_dumpbase;
    552  1.1  mrg   else
    553  1.1  mrg     ptx_cfile_name = make_temp_file (".c");
    554  1.1  mrg 
    555  1.1  mrg   out = fopen (ptx_cfile_name, "w");
    556  1.1  mrg   if (!out)
    557  1.1  mrg     fatal_error (input_location, "cannot open '%s'", ptx_cfile_name);
    558  1.1  mrg 
    559  1.1  mrg   /* PR libgomp/65099: Currently, we only support offloading in 64-bit
    560  1.1  mrg      configurations.  */
    561  1.1  mrg   if (offload_abi == OFFLOAD_ABI_LP64)
    562  1.1  mrg     {
    563  1.1  mrg       char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
    564  1.1  mrg       if (save_temps)
    565  1.1  mrg 	ptx_name = mko_dumpbase;
    566  1.1  mrg       else
    567  1.1  mrg 	ptx_name = make_temp_file (".mkoffload");
    568  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-dumpdir");
    569  1.1  mrg       obstack_ptr_grow (&argv_obstack, "");
    570  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-dumpbase");
    571  1.1  mrg       obstack_ptr_grow (&argv_obstack, mko_dumpbase);
    572  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
    573  1.1  mrg       obstack_ptr_grow (&argv_obstack, "");
    574  1.1  mrg       obstack_ptr_grow (&argv_obstack, "-o");
    575  1.1  mrg       obstack_ptr_grow (&argv_obstack, ptx_name);
    576  1.1  mrg       obstack_ptr_grow (&argv_obstack, NULL);
    577  1.1  mrg       const char **new_argv = XOBFINISH (&argv_obstack, const char **);
    578  1.1  mrg 
    579  1.1  mrg       char *execpath = getenv ("GCC_EXEC_PREFIX");
    580  1.1  mrg       char *cpath = getenv ("COMPILER_PATH");
    581  1.1  mrg       char *lpath = getenv ("LIBRARY_PATH");
    582  1.1  mrg       unsetenv ("GCC_EXEC_PREFIX");
    583  1.1  mrg       unsetenv ("COMPILER_PATH");
    584  1.1  mrg       unsetenv ("LIBRARY_PATH");
    585  1.1  mrg 
    586  1.1  mrg       fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true,
    587  1.1  mrg 		    ".gcc_args");
    588  1.1  mrg       obstack_free (&argv_obstack, NULL);
    589  1.1  mrg 
    590  1.1  mrg       xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL));
    591  1.1  mrg       xputenv (concat ("COMPILER_PATH=", cpath, NULL));
    592  1.1  mrg       xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
    593  1.1  mrg 
    594  1.1  mrg       in = fopen (ptx_name, "r");
    595  1.1  mrg       if (!in)
    596  1.1  mrg 	fatal_error (input_location, "cannot open intermediate ptx file");
    597  1.1  mrg 
    598  1.1  mrg       process (in, out);
    599  1.1  mrg       fclose (in);
    600  1.1  mrg     }
    601  1.1  mrg 
    602  1.1  mrg   fclose (out);
    603  1.1  mrg 
    604  1.1  mrg   compile_native (ptx_cfile_name, outname, collect_gcc, fPIC, fpic);
    605  1.1  mrg 
    606  1.1  mrg   return 0;
    607  1.1  mrg }
    608