Skip various cmp-mem-const tests on lp64 hppa*-*-*
[official-gcc.git] / gcc / config / nvptx / mkoffload.cc
bloba7fc28cbd3fe5f694a426587929ad24a564a93f5
1 /* Offload image generation tool for PTX.
3 Copyright (C) 2014-2024 Free Software Foundation, Inc.
5 Contributed by Nathan Sidwell <nathan@codesourcery.com> and
6 Bernd Schmidt <bernds@codesourcery.com>.
8 This file is part of GCC.
10 GCC is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published
12 by the Free Software Foundation; either version 3, or (at your
13 option) any later version.
15 GCC is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
18 License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING3. If not see
22 <http://www.gnu.org/licenses/>. */
24 /* Munges PTX assembly into a C source file defining the PTX code as a
25 string.
27 This is not a complete assembler. We presume the source is well
28 formed from the compiler and can die horribly if it is not. */
30 #define IN_TARGET_CODE 1
32 #include "config.h"
33 #include "system.h"
34 #include "coretypes.h"
35 #include "obstack.h"
36 #include "diagnostic.h"
37 #include "intl.h"
38 #include <libgen.h>
39 #include "collect-utils.h"
40 #include "gomp-constants.h"
42 const char tool_name[] = "nvptx mkoffload";
44 #define COMMENT_PREFIX "#"
46 struct id_map
48 id_map *next;
49 char *ptx_name;
50 char *dim;
53 static id_map *func_ids, **funcs_tail = &func_ids;
54 static id_map *ind_func_ids, **ind_funcs_tail = &ind_func_ids;
55 static id_map *var_ids, **vars_tail = &var_ids;
57 /* Files to unlink. */
58 static const char *ptx_name;
59 static const char *ptx_cfile_name;
60 static const char *omp_requires_file;
61 static const char *ptx_dumpbase;
63 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
65 /* Delete tempfiles. */
67 void
68 tool_cleanup (bool from_signal ATTRIBUTE_UNUSED)
70 if (ptx_cfile_name)
71 maybe_unlink (ptx_cfile_name);
72 if (ptx_name)
73 maybe_unlink (ptx_name);
74 if (omp_requires_file)
75 maybe_unlink (omp_requires_file);
78 static void
79 mkoffload_cleanup (void)
81 tool_cleanup (false);
84 /* Unlink FILE unless requested otherwise. */
86 void
87 maybe_unlink (const char *file)
89 if (!save_temps)
91 if (unlink_if_ordinary (file)
92 && errno != ENOENT)
93 fatal_error (input_location, "deleting file %s: %m", file);
95 else if (verbose)
96 fprintf (stderr, "[Leaving %s]\n", file);
99 /* Add or change the value of an environment variable, outputting the
100 change to standard error if in verbose mode. */
101 static void
102 xputenv (const char *string)
104 if (verbose)
105 fprintf (stderr, "%s\n", string);
106 putenv (CONST_CAST (char *, string));
110 static void
111 record_id (const char *p1, id_map ***where)
113 gcc_assert (p1[0] == '"');
114 p1++;
115 const char *end = strchr (p1, '"');
116 const char *end2 = strchr (p1, '\n');
117 if (!end || !end2 || end >= end2)
118 fatal_error (input_location, "malformed ptx file");
120 id_map *v = XNEW (id_map);
121 size_t len = end - p1;
122 v->ptx_name = XNEWVEC (char, len + 1);
123 memcpy (v->ptx_name, p1, len);
124 v->ptx_name[len] = '\0';
125 p1 = end + 1;
126 if (*end != '\n')
128 len = end2 - p1;
129 v->dim = XNEWVEC (char, len + 1);
130 memcpy (v->dim, p1, len);
131 v->dim[len] = '\0';
133 else
134 v->dim = NULL;
135 v->next = NULL;
136 id_map **tail = *where;
137 *tail = v;
138 *where = &v->next;
141 /* Read the whole input file. It will be NUL terminated (but
142 remember, there could be a NUL in the file itself. */
144 static const char *
145 read_file (FILE *stream, size_t *plen)
147 size_t alloc = 16384;
148 size_t base = 0;
149 char *buffer;
151 if (!fseek (stream, 0, SEEK_END))
153 /* Get the file size. */
154 long s = ftell (stream);
155 if (s >= 0)
156 alloc = s + 100;
157 fseek (stream, 0, SEEK_SET);
159 buffer = XNEWVEC (char, alloc);
161 for (;;)
163 size_t n = fread (buffer + base, 1, alloc - base - 1, stream);
165 if (!n)
166 break;
167 base += n;
168 if (base + 1 == alloc)
170 alloc *= 2;
171 buffer = XRESIZEVEC (char, buffer, alloc);
174 buffer[base] = 0;
175 *plen = base;
176 return buffer;
179 /* Parse STR, saving found tokens into PVALUES and return their number.
180 Tokens are assumed to be delimited by ':'. */
181 static unsigned
182 parse_env_var (const char *str, char ***pvalues)
184 const char *curval, *nextval;
185 char **values;
186 unsigned num = 1, i;
188 curval = strchr (str, ':');
189 while (curval)
191 num++;
192 curval = strchr (curval + 1, ':');
195 values = (char **) xmalloc (num * sizeof (char *));
196 curval = str;
197 nextval = strchr (curval, ':');
198 if (nextval == NULL)
199 nextval = strchr (curval, '\0');
201 for (i = 0; i < num; i++)
203 int l = nextval - curval;
204 values[i] = (char *) xmalloc (l + 1);
205 memcpy (values[i], curval, l);
206 values[i][l] = 0;
207 curval = nextval + 1;
208 nextval = strchr (curval, ':');
209 if (nextval == NULL)
210 nextval = strchr (curval, '\0');
212 *pvalues = values;
213 return num;
216 /* Auxiliary function that frees elements of PTR and PTR itself.
217 N is number of elements to be freed. If PTR is NULL, nothing is freed.
218 If an element is NULL, subsequent elements are not freed. */
219 static void
220 free_array_of_ptrs (void **ptr, unsigned n)
222 unsigned i;
223 if (!ptr)
224 return;
225 for (i = 0; i < n; i++)
227 if (!ptr[i])
228 break;
229 free (ptr[i]);
231 free (ptr);
232 return;
235 /* Check whether NAME can be accessed in MODE. This is like access,
236 except that it never considers directories to be executable. */
237 static int
238 access_check (const char *name, int mode)
240 if (mode == X_OK)
242 struct stat st;
244 if (stat (name, &st) < 0 || S_ISDIR (st.st_mode))
245 return -1;
248 return access (name, mode);
251 static void
252 process (FILE *in, FILE *out, uint32_t omp_requires)
254 size_t len = 0;
255 const char *input = read_file (in, &len);
256 const char *comma;
257 id_map const *id;
258 unsigned obj_count = 0;
259 unsigned ix;
260 const char *sm_ver = NULL, *version = NULL;
261 const char *sm_ver2 = NULL, *version2 = NULL;
262 size_t file_cnt = 0;
263 size_t *file_idx = XALLOCAVEC (size_t, len);
265 fprintf (out, "#include <stdint.h>\n\n");
267 /* Dump out char arrays for each PTX object file. These are
268 terminated by a NUL. */
269 for (size_t i = 0; i != len;)
271 char c;
272 bool output_fn_ptr = false;
273 file_idx[file_cnt++] = i;
275 fprintf (out, "static const char ptx_code_%u[] =\n\t\"", obj_count++);
276 while ((c = input[i++]))
278 switch (c)
280 case '\r':
281 continue;
282 case '\n':
283 fprintf (out, "\\n\"\n\t\"");
284 /* Look for mappings on subsequent lines. */
285 if (UNLIKELY (startswith (input + i, ".target sm_")))
287 sm_ver = input + i + strlen (".target sm_");
288 continue;
290 if (UNLIKELY (startswith (input + i, ".version ")))
292 version = input + i + strlen (".version ");
293 continue;
295 while (startswith (input + i, "//:"))
297 i += 3;
299 if (startswith (input + i, "VAR_MAP "))
300 record_id (input + i + 8, &vars_tail);
301 else if (startswith (input + i, "FUNC_MAP "))
303 output_fn_ptr = true;
304 record_id (input + i + 9, &funcs_tail);
306 else if (startswith (input + i, "IND_FUNC_MAP "))
308 output_fn_ptr = true;
309 record_id (input + i + 13, &ind_funcs_tail);
311 else
312 abort ();
313 /* Skip to next line. */
314 while (input[i++] != '\n')
315 continue;
317 continue;
318 case '"':
319 case '\\':
320 putc ('\\', out);
321 break;
322 default:
323 break;
325 putc (c, out);
327 fprintf (out, "\";\n\n");
328 if (output_fn_ptr
329 && (omp_requires & GOMP_REQUIRES_REVERSE_OFFLOAD) != 0)
331 if (sm_ver && sm_ver[0] == '3' && sm_ver[1] == '0'
332 && sm_ver[2] == '\n')
334 warning_at (input_location, 0,
335 "%<omp requires reverse_offload%> requires at "
336 "least %<sm_35%> for "
337 "%<-foffload-options=nvptx-none=-march=%> - disabling"
338 " offload-code generation for this device type");
339 /* As now an empty file is compiled and there is no call to
340 GOMP_offload_register_ver, this device type is effectively
341 disabled. */
342 fflush (out);
343 ftruncate (fileno (out), 0);
344 return;
346 sm_ver2 = sm_ver;
347 version2 = version;
351 /* Create function-pointer array, required for reverse
352 offload function-pointer lookup. */
354 if (func_ids && (omp_requires & GOMP_REQUIRES_REVERSE_OFFLOAD) != 0)
356 const char needle[] = "// BEGIN GLOBAL FUNCTION DECL: ";
357 fprintf (out, "static const char ptx_code_%u[] =\n", obj_count++);
358 fprintf (out, "\t\".version ");
359 for (size_t i = 0; version2[i] != '\0' && version2[i] != '\n'; i++)
360 fputc (version2[i], out);
361 fprintf (out, "\"\n\t\".target sm_");
362 for (size_t i = 0; version2[i] != '\0' && sm_ver2[i] != '\n'; i++)
363 fputc (sm_ver2[i], out);
364 fprintf (out, "\"\n\t\".file 1 \\\"<dummy>\\\"\"\n");
366 /* WORKAROUND - see PR 108098
367 It seems as if older CUDA JIT compiler optimizes the function pointers
368 in offload_func_table to NULL, which can be prevented by adding a
369 dummy procedure. With CUDA 11.1, it seems to work fine without
370 workaround while CUDA 10.2 as some ancient version have need the
371 workaround. Assuming CUDA 11.0 fixes it, emitting it could be
372 restricted to 'if (sm_ver2[0] < 8 && version2[0] < 7)' as sm_80 and
373 PTX ISA 7.0 are new in CUDA 11.0; for 11.1 it would be sm_86 and
374 PTX ISA 7.1. */
375 fprintf (out, "\n\t\".func __dummy$func ( );\"\n");
376 fprintf (out, "\t\".func __dummy$func ( )\"\n");
377 fprintf (out, "\t\"{\"\n");
378 fprintf (out, "\t\"}\"\n");
380 size_t fidx = 0;
381 for (id = func_ids; id; id = id->next)
383 /* Only 'nohost' functions are needed - use NULL for the rest.
384 Alternatively, besides searching for 'BEGIN FUNCTION DECL',
385 checking for '.visible .entry ' + id->ptx_name would be
386 required. */
387 if (!endswith (id->ptx_name, "$nohost")
388 && !strstr (id->ptx_name, "$nohost$"))
389 continue;
390 fprintf (out, "\t\".extern ");
391 const char *p = input + file_idx[fidx];
392 while (true)
394 p = strstr (p, needle);
395 if (!p)
397 fidx++;
398 if (fidx >= file_cnt)
399 break;
400 p = input + file_idx[fidx];
401 continue;
403 p += strlen (needle);
404 if (!startswith (p, id->ptx_name))
405 continue;
406 p += strlen (id->ptx_name);
407 if (*p != '\n')
408 continue;
409 p++;
410 gcc_assert (startswith (p, ".visible "));
411 p += strlen (".visible ");
412 for (; *p != '\0' && *p != '\n'; p++)
413 fputc (*p, out);
414 break;
416 fprintf (out, "\"\n");
417 if (fidx == file_cnt)
418 fatal_error (input_location,
419 "Cannot find function declaration for %qs",
420 id->ptx_name);
422 fprintf (out, "\t\".visible .global .align 8 .u64 "
423 "$offload_func_table[] = {");
424 for (comma = "", id = func_ids; id; comma = ",", id = id->next)
425 fprintf (out, "%s\"\n\t\t\"%s", comma,
426 (endswith (id->ptx_name, "$nohost")
427 || strstr (id->ptx_name, "$nohost$")) ? id->ptx_name : "0");
428 fprintf (out, "};\\n\";\n\n");
431 if (ind_func_ids)
433 const char needle[] = "// BEGIN GLOBAL FUNCTION DECL: ";
435 fprintf (out, "static const char ptx_code_%u[] =\n", obj_count++);
436 fprintf (out, "\t\".version ");
437 for (size_t i = 0; version[i] != '\0' && version[i] != '\n'; i++)
438 fputc (version[i], out);
439 fprintf (out, "\"\n\t\".target sm_");
440 for (size_t i = 0; sm_ver[i] != '\0' && sm_ver[i] != '\n'; i++)
441 fputc (sm_ver[i], out);
442 fprintf (out, "\"\n\t\".file 2 \\\"<dummy>\\\"\"\n");
444 /* WORKAROUND - see PR 108098
445 It seems as if older CUDA JIT compiler optimizes the function pointers
446 in offload_func_table to NULL, which can be prevented by adding a
447 dummy procedure. With CUDA 11.1, it seems to work fine without
448 workaround while CUDA 10.2 as some ancient version have need the
449 workaround. Assuming CUDA 11.0 fixes it, emitting it could be
450 restricted to 'if (sm_ver2[0] < 8 && version2[0] < 7)' as sm_80 and
451 PTX ISA 7.0 are new in CUDA 11.0; for 11.1 it would be sm_86 and
452 PTX ISA 7.1. */
453 fprintf (out, "\n\t\".func __dummy$func2 ( );\"\n");
454 fprintf (out, "\t\".func __dummy$func2 ( )\"\n");
455 fprintf (out, "\t\"{\"\n");
456 fprintf (out, "\t\"}\"\n");
458 size_t fidx = 0;
459 for (id = ind_func_ids; id; id = id->next)
461 fprintf (out, "\t\".extern ");
462 const char *p = input + file_idx[fidx];
463 while (true)
465 p = strstr (p, needle);
466 if (!p)
468 fidx++;
469 if (fidx >= file_cnt)
470 break;
471 p = input + file_idx[fidx];
472 continue;
474 p += strlen (needle);
475 if (!startswith (p, id->ptx_name))
476 continue;
477 p += strlen (id->ptx_name);
478 if (*p != '\n')
479 continue;
480 p++;
481 /* Skip over any directives. */
482 while (!startswith (p, ".func"))
483 while (*p++ != ' ');
484 for (; *p != '\0' && *p != '\n'; p++)
485 fputc (*p, out);
486 break;
488 fprintf (out, "\"\n");
489 if (fidx == file_cnt)
490 fatal_error (input_location,
491 "Cannot find function declaration for %qs",
492 id->ptx_name);
495 fprintf (out, "\t\".visible .global .align 8 .u64 "
496 "$offload_ind_func_table[] = {");
497 for (comma = "", id = ind_func_ids; id; comma = ",", id = id->next)
498 fprintf (out, "%s\"\n\t\t\"%s", comma, id->ptx_name);
499 fprintf (out, "};\\n\";\n\n");
502 /* Dump out array of pointers to ptx object strings. */
503 fprintf (out, "static const struct ptx_obj {\n"
504 " const char *code;\n"
505 " __SIZE_TYPE__ size;\n"
506 "} ptx_objs[] = {");
507 for (comma = "", ix = 0; ix != obj_count; comma = ",", ix++)
508 fprintf (out, "%s\n\t{ptx_code_%u, sizeof (ptx_code_%u)}", comma, ix, ix);
509 fprintf (out, "\n};\n\n");
511 /* Dump out variable idents. */
512 fprintf (out, "static const char *const var_mappings[] = {");
513 for (comma = "", id = var_ids; id; comma = ",", id = id->next)
514 fprintf (out, "%s\n\t\"%s\"", comma, id->ptx_name);
515 fprintf (out, "\n};\n\n");
517 /* Dump out function idents. */
518 fprintf (out, "static const struct nvptx_fn {\n"
519 " const char *name;\n"
520 " unsigned short dim[%d];\n"
521 "} func_mappings[] = {\n", GOMP_DIM_MAX);
522 for (comma = "", id = func_ids; id; comma = ",", id = id->next)
523 fprintf (out, "%s\n\t{\"%s\"%s}", comma, id->ptx_name,
524 id->dim ? id->dim : "");
525 fprintf (out, "\n};\n\n");
527 /* Dump out indirect function idents. */
528 fprintf (out, "static const char *const ind_func_mappings[] = {");
529 for (comma = "", id = ind_func_ids; id; comma = ",", id = id->next)
530 fprintf (out, "%s\n\t\"%s\"", comma, id->ptx_name);
531 fprintf (out, "\n};\n\n");
533 fprintf (out,
534 "static const struct nvptx_data {\n"
535 " uintptr_t omp_requires_mask;\n"
536 " const struct ptx_obj *ptx_objs;\n"
537 " unsigned ptx_num;\n"
538 " const char *const *var_names;\n"
539 " unsigned var_num;\n"
540 " const struct nvptx_fn *fn_names;\n"
541 " unsigned fn_num;\n"
542 " unsigned ind_fn_num;\n"
543 "} nvptx_data = {\n"
544 " %d, ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n"
545 " var_mappings,"
546 " sizeof (var_mappings) / sizeof (var_mappings[0]),\n"
547 " func_mappings,"
548 " sizeof (func_mappings) / sizeof (func_mappings[0]),\n"
549 " sizeof (ind_func_mappings) / sizeof (ind_func_mappings[0])\n"
550 "};\n\n", omp_requires);
552 fprintf (out, "#ifdef __cplusplus\n"
553 "extern \"C\" {\n"
554 "#endif\n");
556 fprintf (out, "extern void GOMP_offload_register_ver"
557 " (unsigned, const void *, int, const void *);\n");
558 fprintf (out, "extern void GOMP_offload_unregister_ver"
559 " (unsigned, const void *, int, const void *);\n");
561 fprintf (out, "#ifdef __cplusplus\n"
562 "}\n"
563 "#endif\n");
565 fprintf (out, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
567 fprintf (out, "static __attribute__((constructor)) void init (void)\n"
568 "{\n"
569 " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
570 " %d/*NVIDIA_PTX*/, &nvptx_data);\n"
571 "};\n",
572 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
573 GOMP_DEVICE_NVIDIA_PTX);
575 fprintf (out, "static __attribute__((destructor)) void fini (void)\n"
576 "{\n"
577 " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
578 " %d/*NVIDIA_PTX*/, &nvptx_data);\n"
579 "};\n",
580 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
581 GOMP_DEVICE_NVIDIA_PTX);
584 static void
585 compile_native (const char *infile, const char *outfile, const char *compiler,
586 bool fPIC, bool fpic)
588 const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
589 if (!collect_gcc_options)
590 fatal_error (input_location,
591 "environment variable COLLECT_GCC_OPTIONS must be set");
593 struct obstack argv_obstack;
594 obstack_init (&argv_obstack);
595 obstack_ptr_grow (&argv_obstack, compiler);
596 if (fPIC)
597 obstack_ptr_grow (&argv_obstack, "-fPIC");
598 if (fpic)
599 obstack_ptr_grow (&argv_obstack, "-fpic");
600 if (save_temps)
601 obstack_ptr_grow (&argv_obstack, "-save-temps");
602 if (verbose)
603 obstack_ptr_grow (&argv_obstack, "-v");
604 obstack_ptr_grow (&argv_obstack, "-dumpdir");
605 obstack_ptr_grow (&argv_obstack, "");
606 obstack_ptr_grow (&argv_obstack, "-dumpbase");
607 obstack_ptr_grow (&argv_obstack, ptx_dumpbase);
608 obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
609 obstack_ptr_grow (&argv_obstack, ".c");
610 switch (offload_abi)
612 case OFFLOAD_ABI_LP64:
613 obstack_ptr_grow (&argv_obstack, "-m64");
614 break;
615 case OFFLOAD_ABI_ILP32:
616 obstack_ptr_grow (&argv_obstack, "-m32");
617 break;
618 default:
619 gcc_unreachable ();
621 obstack_ptr_grow (&argv_obstack, infile);
622 obstack_ptr_grow (&argv_obstack, "-c");
623 obstack_ptr_grow (&argv_obstack, "-o");
624 obstack_ptr_grow (&argv_obstack, outfile);
625 obstack_ptr_grow (&argv_obstack, NULL);
627 const char **new_argv = XOBFINISH (&argv_obstack, const char **);
628 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true,
629 ".gccnative_args");
630 obstack_free (&argv_obstack, NULL);
634 main (int argc, char **argv)
636 FILE *in = stdin;
637 FILE *out = stdout;
638 const char *outname = 0;
640 progname = tool_name;
641 diagnostic_initialize (global_dc, 0);
643 if (atexit (mkoffload_cleanup) != 0)
644 fatal_error (input_location, "atexit failed");
646 char *collect_gcc = getenv ("COLLECT_GCC");
647 if (collect_gcc == NULL)
648 fatal_error (input_location, "COLLECT_GCC must be set.");
649 const char *gcc_path = dirname (ASTRDUP (collect_gcc));
650 const char *gcc_exec = basename (ASTRDUP (collect_gcc));
652 size_t len = (strlen (gcc_path) + 1
653 + strlen (GCC_INSTALL_NAME)
654 + 1);
655 char *driver = XALLOCAVEC (char, len);
657 if (strcmp (gcc_exec, collect_gcc) == 0)
658 /* collect_gcc has no path, so it was found in PATH. Make sure we also
659 find accel-gcc in PATH. */
660 gcc_path = NULL;
662 int driver_used = 0;
663 if (gcc_path != NULL)
664 driver_used = sprintf (driver, "%s/", gcc_path);
665 sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME);
667 bool found = false;
668 if (gcc_path == NULL)
669 found = true;
670 else if (access_check (driver, X_OK) == 0)
671 found = true;
672 else
674 /* Don't use alloca pointer with XRESIZEVEC. */
675 driver = NULL;
676 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */
677 char **paths = NULL;
678 unsigned n_paths;
679 n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
680 for (unsigned i = 0; i < n_paths; i++)
682 len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1;
683 driver = XRESIZEVEC (char, driver, len);
684 sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME);
685 if (access_check (driver, X_OK) == 0)
687 found = true;
688 break;
691 free_array_of_ptrs ((void **) paths, n_paths);
694 if (!found)
695 fatal_error (input_location,
696 "offload compiler %s not found (consider using %<-B%>)",
697 GCC_INSTALL_NAME);
699 /* We may be called with all the arguments stored in some file and
700 passed with @file. Expand them into argv before processing. */
701 expandargv (&argc, &argv);
703 /* Scan the argument vector. */
704 bool fopenmp = false;
705 bool fopenacc = false;
706 bool fPIC = false;
707 bool fpic = false;
708 for (int i = 1; i < argc; i++)
710 #define STR "-foffload-abi="
711 if (startswith (argv[i], STR))
713 if (strcmp (argv[i] + strlen (STR), "lp64") == 0)
714 offload_abi = OFFLOAD_ABI_LP64;
715 else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0)
716 offload_abi = OFFLOAD_ABI_ILP32;
717 else
718 fatal_error (input_location,
719 "unrecognizable argument of option " STR);
721 #undef STR
722 else if (strcmp (argv[i], "-fopenmp") == 0)
723 fopenmp = true;
724 else if (strcmp (argv[i], "-fopenacc") == 0)
725 fopenacc = true;
726 else if (strcmp (argv[i], "-fPIC") == 0)
727 fPIC = true;
728 else if (strcmp (argv[i], "-fpic") == 0)
729 fpic = true;
730 else if (strcmp (argv[i], "-save-temps") == 0)
731 save_temps = true;
732 else if (strcmp (argv[i], "-v") == 0)
733 verbose = true;
734 else if (strcmp (argv[i], "-dumpbase") == 0
735 && i + 1 < argc)
736 dumppfx = argv[++i];
737 /* Translate host into offloading libraries. */
738 else if (strcmp (argv[i], "-l_GCC_gfortran") == 0
739 || strcmp (argv[i], "-l_GCC_m") == 0)
741 /* Elide '_GCC_'. */
742 size_t i_dst = strlen ("-l");
743 size_t i_src = strlen ("-l_GCC_");
744 char c;
746 c = argv[i][i_dst++] = argv[i][i_src++];
747 while (c != '\0');
750 if (!(fopenacc ^ fopenmp))
751 fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
752 "must be set");
754 struct obstack argv_obstack;
755 obstack_init (&argv_obstack);
756 obstack_ptr_grow (&argv_obstack, driver);
757 if (save_temps)
758 obstack_ptr_grow (&argv_obstack, "-save-temps");
759 if (verbose)
760 obstack_ptr_grow (&argv_obstack, "-v");
761 obstack_ptr_grow (&argv_obstack, "-xlto");
762 switch (offload_abi)
764 case OFFLOAD_ABI_LP64:
765 obstack_ptr_grow (&argv_obstack, "-m64");
766 break;
767 case OFFLOAD_ABI_ILP32:
768 obstack_ptr_grow (&argv_obstack, "-m32");
769 break;
770 default:
771 gcc_unreachable ();
773 if (fopenmp)
774 obstack_ptr_grow (&argv_obstack, "-mgomp");
776 for (int ix = 1; ix != argc; ix++)
778 if (!strcmp (argv[ix], "-o") && ix + 1 != argc)
779 outname = argv[++ix];
780 else
781 obstack_ptr_grow (&argv_obstack, argv[ix]);
784 if (!dumppfx)
785 dumppfx = outname;
787 ptx_dumpbase = concat (dumppfx, ".c", NULL);
788 if (save_temps)
789 ptx_cfile_name = ptx_dumpbase;
790 else
791 ptx_cfile_name = make_temp_file (".c");
793 out = fopen (ptx_cfile_name, "w");
794 if (!out)
795 fatal_error (input_location, "cannot open '%s'", ptx_cfile_name);
797 /* PR libgomp/65099: Currently, we only support offloading in 64-bit
798 configurations. */
799 if (offload_abi == OFFLOAD_ABI_LP64)
801 char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
802 if (save_temps)
803 ptx_name = mko_dumpbase;
804 else
805 ptx_name = make_temp_file (".mkoffload");
806 obstack_ptr_grow (&argv_obstack, "-dumpdir");
807 obstack_ptr_grow (&argv_obstack, "");
808 obstack_ptr_grow (&argv_obstack, "-dumpbase");
809 obstack_ptr_grow (&argv_obstack, mko_dumpbase);
810 obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
811 obstack_ptr_grow (&argv_obstack, "");
812 obstack_ptr_grow (&argv_obstack, "-o");
813 obstack_ptr_grow (&argv_obstack, ptx_name);
814 obstack_ptr_grow (&argv_obstack, NULL);
815 const char **new_argv = XOBFINISH (&argv_obstack, const char **);
817 char *execpath = getenv ("GCC_EXEC_PREFIX");
818 char *cpath = getenv ("COMPILER_PATH");
819 char *lpath = getenv ("LIBRARY_PATH");
820 unsetenv ("GCC_EXEC_PREFIX");
821 unsetenv ("COMPILER_PATH");
822 unsetenv ("LIBRARY_PATH");
824 if (save_temps)
825 omp_requires_file = concat (dumppfx, ".mkoffload.omp_requires", NULL);
826 else
827 omp_requires_file = make_temp_file (".mkoffload.omp_requires");
829 xputenv (concat ("GCC_OFFLOAD_OMP_REQUIRES_FILE=", omp_requires_file, NULL));
830 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true,
831 ".gcc_args");
832 obstack_free (&argv_obstack, NULL);
833 unsetenv("GCC_OFFLOAD_OMP_REQUIRES_FILE");
835 xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL));
836 xputenv (concat ("COMPILER_PATH=", cpath, NULL));
837 xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
839 in = fopen (omp_requires_file, "rb");
840 if (!in)
841 fatal_error (input_location, "cannot open omp_requires file %qs",
842 omp_requires_file);
843 uint32_t omp_requires;
844 if (fread (&omp_requires, sizeof (omp_requires), 1, in) != 1)
845 fatal_error (input_location, "cannot read omp_requires file %qs",
846 omp_requires_file);
847 fclose (in);
849 in = fopen (ptx_name, "r");
850 if (!in)
851 fatal_error (input_location, "cannot open intermediate ptx file");
853 process (in, out, omp_requires);
854 fclose (in);
857 fclose (out);
859 compile_native (ptx_cfile_name, outname, collect_gcc, fPIC, fpic);
861 return 0;