go: update builtin function attributes
[official-gcc.git] / gcc / config / nvptx / mkoffload.cc
blob958e16f3918e78107784fc7df5ee125d379f834c
1 /* Offload image generation tool for PTX.
3 Copyright (C) 2014-2025 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;
64 const char *offload_abi_host_opts = NULL;
66 /* Delete tempfiles. */
68 void
69 tool_cleanup (bool from_signal ATTRIBUTE_UNUSED)
71 if (ptx_cfile_name)
72 maybe_unlink (ptx_cfile_name);
73 if (ptx_name)
74 maybe_unlink (ptx_name);
75 if (omp_requires_file)
76 maybe_unlink (omp_requires_file);
79 static void
80 mkoffload_cleanup (void)
82 tool_cleanup (false);
85 /* Unlink FILE unless requested otherwise. */
87 void
88 maybe_unlink (const char *file)
90 if (!save_temps)
92 if (unlink_if_ordinary (file)
93 && errno != ENOENT)
94 fatal_error (input_location, "deleting file %s: %m", file);
96 else if (verbose)
97 fprintf (stderr, "[Leaving %s]\n", file);
100 /* Add or change the value of an environment variable, outputting the
101 change to standard error if in verbose mode. */
102 static void
103 xputenv (const char *string)
105 if (verbose)
106 fprintf (stderr, "%s\n", string);
107 putenv (CONST_CAST (char *, string));
111 static void
112 record_id (const char *p1, id_map ***where)
114 gcc_assert (p1[0] == '"');
115 p1++;
116 const char *end = strchr (p1, '"');
117 const char *end2 = strchr (p1, '\n');
118 if (!end || !end2 || end >= end2)
119 fatal_error (input_location, "malformed ptx file");
121 id_map *v = XNEW (id_map);
122 size_t len = end - p1;
123 v->ptx_name = XNEWVEC (char, len + 1);
124 memcpy (v->ptx_name, p1, len);
125 v->ptx_name[len] = '\0';
126 p1 = end + 1;
127 if (*end != '\n')
129 len = end2 - p1;
130 v->dim = XNEWVEC (char, len + 1);
131 memcpy (v->dim, p1, len);
132 v->dim[len] = '\0';
134 else
135 v->dim = NULL;
136 v->next = NULL;
137 id_map **tail = *where;
138 *tail = v;
139 *where = &v->next;
142 /* Read the whole input file. It will be NUL terminated (but
143 remember, there could be a NUL in the file itself. */
145 static const char *
146 read_file (FILE *stream, size_t *plen)
148 size_t alloc = 16384;
149 size_t base = 0;
150 char *buffer;
152 if (!fseek (stream, 0, SEEK_END))
154 /* Get the file size. */
155 long s = ftell (stream);
156 if (s >= 0)
157 alloc = s + 100;
158 fseek (stream, 0, SEEK_SET);
160 buffer = XNEWVEC (char, alloc);
162 for (;;)
164 size_t n = fread (buffer + base, 1, alloc - base - 1, stream);
166 if (!n)
167 break;
168 base += n;
169 if (base + 1 == alloc)
171 alloc *= 2;
172 buffer = XRESIZEVEC (char, buffer, alloc);
175 buffer[base] = 0;
176 *plen = base;
177 return buffer;
180 /* Parse STR, saving found tokens into PVALUES and return their number.
181 Tokens are assumed to be delimited by ':'. */
182 static unsigned
183 parse_env_var (const char *str, char ***pvalues)
185 const char *curval, *nextval;
186 char **values;
187 unsigned num = 1, i;
189 curval = strchr (str, ':');
190 while (curval)
192 num++;
193 curval = strchr (curval + 1, ':');
196 values = (char **) xmalloc (num * sizeof (char *));
197 curval = str;
198 nextval = strchr (curval, ':');
199 if (nextval == NULL)
200 nextval = strchr (curval, '\0');
202 for (i = 0; i < num; i++)
204 int l = nextval - curval;
205 values[i] = (char *) xmalloc (l + 1);
206 memcpy (values[i], curval, l);
207 values[i][l] = 0;
208 curval = nextval + 1;
209 nextval = strchr (curval, ':');
210 if (nextval == NULL)
211 nextval = strchr (curval, '\0');
213 *pvalues = values;
214 return num;
217 /* Auxiliary function that frees elements of PTR and PTR itself.
218 N is number of elements to be freed. If PTR is NULL, nothing is freed.
219 If an element is NULL, subsequent elements are not freed. */
220 static void
221 free_array_of_ptrs (void **ptr, unsigned n)
223 unsigned i;
224 if (!ptr)
225 return;
226 for (i = 0; i < n; i++)
228 if (!ptr[i])
229 break;
230 free (ptr[i]);
232 free (ptr);
233 return;
236 /* Check whether NAME can be accessed in MODE. This is like access,
237 except that it never considers directories to be executable. */
238 static int
239 access_check (const char *name, int mode)
241 if (mode == X_OK)
243 struct stat st;
245 if (stat (name, &st) < 0 || S_ISDIR (st.st_mode))
246 return -1;
249 return access (name, mode);
252 static void
253 process (FILE *in, FILE *out, uint32_t omp_requires)
255 size_t len = 0;
256 const char *input = read_file (in, &len);
257 const char *comma;
258 id_map const *id;
259 unsigned obj_count = 0;
260 unsigned ix;
261 const char *sm_ver = NULL, *version = NULL;
262 const char *sm_ver2 = NULL, *version2 = NULL;
263 size_t file_cnt = 0;
264 size_t *file_idx = XALLOCAVEC (size_t, len);
266 fprintf (out, "#include <stdint.h>\n\n");
268 /* Dump out char arrays for each PTX object file. These are
269 terminated by a NUL. */
270 for (size_t i = 0; i != len;)
272 char c;
273 bool output_fn_ptr = false;
274 file_idx[file_cnt++] = i;
276 fprintf (out, "static const char ptx_code_%u[] =\n\t\"", obj_count++);
277 while ((c = input[i++]))
279 switch (c)
281 case '\r':
282 continue;
283 case '\n':
284 fprintf (out, "\\n\"\n\t\"");
285 /* Look for mappings on subsequent lines. */
286 if (UNLIKELY (startswith (input + i, ".target sm_")))
288 sm_ver = input + i + strlen (".target sm_");
289 continue;
291 if (UNLIKELY (startswith (input + i, ".version ")))
293 version = input + i + strlen (".version ");
294 continue;
296 while (startswith (input + i, "//:"))
298 i += 3;
300 if (startswith (input + i, "VAR_MAP "))
301 record_id (input + i + 8, &vars_tail);
302 else if (startswith (input + i, "FUNC_MAP "))
304 output_fn_ptr = true;
305 record_id (input + i + 9, &funcs_tail);
307 else if (startswith (input + i, "IND_FUNC_MAP "))
309 output_fn_ptr = true;
310 record_id (input + i + 13, &ind_funcs_tail);
312 else
313 abort ();
314 /* Skip to next line. */
315 while (input[i++] != '\n')
316 continue;
318 continue;
319 case '"':
320 case '\\':
321 putc ('\\', out);
322 break;
323 default:
324 break;
326 putc (c, out);
328 fprintf (out, "\";\n\n");
329 if (output_fn_ptr
330 && (omp_requires & GOMP_REQUIRES_REVERSE_OFFLOAD) != 0)
332 if (sm_ver && sm_ver[0] == '3' && sm_ver[1] == '0'
333 && sm_ver[2] == '\n')
335 warning_at (input_location, 0,
336 "%<omp requires reverse_offload%> requires at "
337 "least %<sm_35%> for "
338 "%<-foffload-options=nvptx-none=-march=%> - disabling"
339 " offload-code generation for this device type");
340 /* As now an empty file is compiled and there is no call to
341 GOMP_offload_register_ver, this device type is effectively
342 disabled. */
343 fflush (out);
344 ftruncate (fileno (out), 0);
345 return;
347 sm_ver2 = sm_ver;
348 version2 = version;
352 /* Create function-pointer array, required for reverse
353 offload function-pointer lookup. */
355 if (func_ids && (omp_requires & GOMP_REQUIRES_REVERSE_OFFLOAD) != 0)
357 const char needle[] = "// BEGIN GLOBAL FUNCTION DECL: ";
358 fprintf (out, "static const char ptx_code_%u[] =\n", obj_count++);
359 fprintf (out, "\t\".version ");
360 for (size_t i = 0; version2[i] != '\0' && version2[i] != '\n'; i++)
361 fputc (version2[i], out);
362 fprintf (out, "\"\n\t\".target sm_");
363 for (size_t i = 0; version2[i] != '\0' && sm_ver2[i] != '\n'; i++)
364 fputc (sm_ver2[i], out);
365 fprintf (out, "\"\n\t\".file 1 \\\"<dummy>\\\"\"\n");
367 /* WORKAROUND - see PR 108098
368 It seems as if older CUDA JIT compiler optimizes the function pointers
369 in offload_func_table to NULL, which can be prevented by adding a
370 dummy procedure. With CUDA 11.1, it seems to work fine without
371 workaround while CUDA 10.2 as some ancient version have need the
372 workaround. Assuming CUDA 11.0 fixes it, emitting it could be
373 restricted to 'if (sm_ver2[0] < 8 && version2[0] < 7)' as sm_80 and
374 PTX ISA 7.0 are new in CUDA 11.0; for 11.1 it would be sm_86 and
375 PTX ISA 7.1. */
376 fprintf (out, "\n\t\".func __dummy$func ( );\"\n");
377 fprintf (out, "\t\".func __dummy$func ( )\"\n");
378 fprintf (out, "\t\"{\"\n");
379 fprintf (out, "\t\"}\"\n");
381 size_t fidx = 0;
382 for (id = func_ids; id; id = id->next)
384 /* Only 'nohost' functions are needed - use NULL for the rest.
385 Alternatively, besides searching for 'BEGIN FUNCTION DECL',
386 checking for '.visible .entry ' + id->ptx_name would be
387 required. */
388 if (!endswith (id->ptx_name, "$nohost")
389 && !strstr (id->ptx_name, "$nohost$"))
390 continue;
391 fprintf (out, "\t\".extern ");
392 const char *p = input + file_idx[fidx];
393 while (true)
395 p = strstr (p, needle);
396 if (!p)
398 fidx++;
399 if (fidx >= file_cnt)
400 break;
401 p = input + file_idx[fidx];
402 continue;
404 p += strlen (needle);
405 if (!startswith (p, id->ptx_name))
406 continue;
407 p += strlen (id->ptx_name);
408 if (*p != '\n')
409 continue;
410 p++;
411 gcc_assert (startswith (p, ".visible "));
412 p += strlen (".visible ");
413 for (; *p != '\0' && *p != '\n'; p++)
414 fputc (*p, out);
415 break;
417 fprintf (out, "\"\n");
418 if (fidx == file_cnt)
419 fatal_error (input_location,
420 "Cannot find function declaration for %qs",
421 id->ptx_name);
423 fprintf (out, "\t\".visible .global .align 8 .u64 "
424 "$offload_func_table[] = {");
425 for (comma = "", id = func_ids; id; comma = ",", id = id->next)
426 fprintf (out, "%s\"\n\t\t\"%s", comma,
427 (endswith (id->ptx_name, "$nohost")
428 || strstr (id->ptx_name, "$nohost$")) ? id->ptx_name : "0");
429 fprintf (out, "};\\n\";\n\n");
432 if (ind_func_ids)
434 const char needle[] = "// BEGIN GLOBAL FUNCTION DECL: ";
436 fprintf (out, "static const char ptx_code_%u[] =\n", obj_count++);
437 fprintf (out, "\t\".version ");
438 for (size_t i = 0; version[i] != '\0' && version[i] != '\n'; i++)
439 fputc (version[i], out);
440 fprintf (out, "\"\n\t\".target sm_");
441 for (size_t i = 0; sm_ver[i] != '\0' && sm_ver[i] != '\n'; i++)
442 fputc (sm_ver[i], out);
443 fprintf (out, "\"\n\t\".file 2 \\\"<dummy>\\\"\"\n");
445 /* WORKAROUND - see PR 108098
446 It seems as if older CUDA JIT compiler optimizes the function pointers
447 in offload_func_table to NULL, which can be prevented by adding a
448 dummy procedure. With CUDA 11.1, it seems to work fine without
449 workaround while CUDA 10.2 as some ancient version have need the
450 workaround. Assuming CUDA 11.0 fixes it, emitting it could be
451 restricted to 'if (sm_ver2[0] < 8 && version2[0] < 7)' as sm_80 and
452 PTX ISA 7.0 are new in CUDA 11.0; for 11.1 it would be sm_86 and
453 PTX ISA 7.1. */
454 fprintf (out, "\n\t\".func __dummy$func2 ( );\"\n");
455 fprintf (out, "\t\".func __dummy$func2 ( )\"\n");
456 fprintf (out, "\t\"{\"\n");
457 fprintf (out, "\t\"}\"\n");
459 size_t fidx = 0;
460 for (id = ind_func_ids; id; id = id->next)
462 fprintf (out, "\t\".extern ");
463 const char *p = input + file_idx[fidx];
464 while (true)
466 p = strstr (p, needle);
467 if (!p)
469 fidx++;
470 if (fidx >= file_cnt)
471 break;
472 p = input + file_idx[fidx];
473 continue;
475 p += strlen (needle);
476 if (!startswith (p, id->ptx_name))
477 continue;
478 p += strlen (id->ptx_name);
479 if (*p != '\n')
480 continue;
481 p++;
482 /* Skip over any directives. */
483 while (!startswith (p, ".func"))
484 while (*p++ != ' ');
485 for (; *p != '\0' && *p != '\n'; p++)
486 fputc (*p, out);
487 break;
489 fprintf (out, "\"\n");
490 if (fidx == file_cnt)
491 fatal_error (input_location,
492 "Cannot find function declaration for %qs",
493 id->ptx_name);
496 fprintf (out, "\t\".visible .global .align 8 .u64 "
497 "$offload_ind_func_table[] = {");
498 for (comma = "", id = ind_func_ids; id; comma = ",", id = id->next)
499 fprintf (out, "%s\"\n\t\t\"%s", comma, id->ptx_name);
500 fprintf (out, "};\\n\";\n\n");
503 /* Dump out array of pointers to ptx object strings. */
504 fprintf (out, "static const struct ptx_obj {\n"
505 " const char *code;\n"
506 " __SIZE_TYPE__ size;\n"
507 "} ptx_objs[] = {");
508 for (comma = "", ix = 0; ix != obj_count; comma = ",", ix++)
509 fprintf (out, "%s\n\t{ptx_code_%u, sizeof (ptx_code_%u)}", comma, ix, ix);
510 fprintf (out, "\n};\n\n");
512 /* Dump out variable idents. */
513 fprintf (out, "static const char *const var_mappings[] = {");
514 for (comma = "", id = var_ids; id; comma = ",", id = id->next)
515 fprintf (out, "%s\n\t\"%s\"", comma, id->ptx_name);
516 fprintf (out, "\n};\n\n");
518 /* Dump out function idents. */
519 fprintf (out, "static const struct nvptx_fn {\n"
520 " const char *name;\n"
521 " unsigned short dim[%d];\n"
522 "} func_mappings[] = {\n", GOMP_DIM_MAX);
523 for (comma = "", id = func_ids; id; comma = ",", id = id->next)
524 fprintf (out, "%s\n\t{\"%s\"%s}", comma, id->ptx_name,
525 id->dim ? id->dim : "");
526 fprintf (out, "\n};\n\n");
528 /* Dump out indirect function idents. */
529 fprintf (out, "static const char *const ind_func_mappings[] = {");
530 for (comma = "", id = ind_func_ids; id; comma = ",", id = id->next)
531 fprintf (out, "%s\n\t\"%s\"", comma, id->ptx_name);
532 fprintf (out, "\n};\n\n");
534 fprintf (out,
535 "static const struct nvptx_data {\n"
536 " uintptr_t omp_requires_mask;\n"
537 " const struct ptx_obj *ptx_objs;\n"
538 " unsigned ptx_num;\n"
539 " const char *const *var_names;\n"
540 " unsigned var_num;\n"
541 " const struct nvptx_fn *fn_names;\n"
542 " unsigned fn_num;\n"
543 " unsigned ind_fn_num;\n"
544 "} nvptx_data = {\n"
545 " %d, ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n"
546 " var_mappings,"
547 " sizeof (var_mappings) / sizeof (var_mappings[0]),\n"
548 " func_mappings,"
549 " sizeof (func_mappings) / sizeof (func_mappings[0]),\n"
550 " sizeof (ind_func_mappings) / sizeof (ind_func_mappings[0])\n"
551 "};\n\n", omp_requires);
553 fprintf (out, "#ifdef __cplusplus\n"
554 "extern \"C\" {\n"
555 "#endif\n");
557 fprintf (out, "extern void GOMP_offload_register_ver"
558 " (unsigned, const void *, int, const void *);\n");
559 fprintf (out, "extern void GOMP_offload_unregister_ver"
560 " (unsigned, const void *, int, const void *);\n");
562 fprintf (out, "#ifdef __cplusplus\n"
563 "}\n"
564 "#endif\n");
566 fprintf (out, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
568 fprintf (out, "static __attribute__((constructor)) void init (void)\n"
569 "{\n"
570 " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
571 " %d/*NVIDIA_PTX*/, &nvptx_data);\n"
572 "};\n",
573 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
574 GOMP_DEVICE_NVIDIA_PTX);
576 fprintf (out, "static __attribute__((destructor)) void fini (void)\n"
577 "{\n"
578 " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
579 " %d/*NVIDIA_PTX*/, &nvptx_data);\n"
580 "};\n",
581 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
582 GOMP_DEVICE_NVIDIA_PTX);
585 static void
586 compile_native (const char *infile, const char *outfile, const char *compiler,
587 bool fPIC, bool fpic)
589 const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
590 if (!collect_gcc_options)
591 fatal_error (input_location,
592 "environment variable COLLECT_GCC_OPTIONS must be set");
594 struct obstack argv_obstack;
595 obstack_init (&argv_obstack);
596 obstack_ptr_grow (&argv_obstack, compiler);
597 if (fPIC)
598 obstack_ptr_grow (&argv_obstack, "-fPIC");
599 if (fpic)
600 obstack_ptr_grow (&argv_obstack, "-fpic");
601 if (save_temps)
602 obstack_ptr_grow (&argv_obstack, "-save-temps");
603 if (verbose)
604 obstack_ptr_grow (&argv_obstack, "-v");
605 obstack_ptr_grow (&argv_obstack, "-dumpdir");
606 obstack_ptr_grow (&argv_obstack, "");
607 obstack_ptr_grow (&argv_obstack, "-dumpbase");
608 obstack_ptr_grow (&argv_obstack, ptx_dumpbase);
609 obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
610 obstack_ptr_grow (&argv_obstack, ".c");
611 if (!offload_abi_host_opts)
612 fatal_error (input_location,
613 "%<-foffload-abi-host-opts%> not specified.");
614 obstack_ptr_grow (&argv_obstack, offload_abi_host_opts);
615 obstack_ptr_grow (&argv_obstack, infile);
616 obstack_ptr_grow (&argv_obstack, "-c");
617 obstack_ptr_grow (&argv_obstack, "-o");
618 obstack_ptr_grow (&argv_obstack, outfile);
619 obstack_ptr_grow (&argv_obstack, NULL);
621 const char **new_argv = XOBFINISH (&argv_obstack, const char **);
622 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true,
623 ".gccnative_args");
624 obstack_free (&argv_obstack, NULL);
628 main (int argc, char **argv)
630 FILE *in = stdin;
631 FILE *out = stdout;
632 const char *outname = 0;
634 progname = tool_name;
635 gcc_init_libintl ();
636 diagnostic_initialize (global_dc, 0);
637 diagnostic_color_init (global_dc);
639 if (atexit (mkoffload_cleanup) != 0)
640 fatal_error (input_location, "atexit failed");
642 char *collect_gcc = getenv ("COLLECT_GCC");
643 if (collect_gcc == NULL)
644 fatal_error (input_location, "COLLECT_GCC must be set.");
645 const char *gcc_path = dirname (ASTRDUP (collect_gcc));
646 const char *gcc_exec = basename (ASTRDUP (collect_gcc));
648 size_t len = (strlen (gcc_path) + 1
649 + strlen (GCC_INSTALL_NAME)
650 + 1);
651 char *driver = XALLOCAVEC (char, len);
653 if (strcmp (gcc_exec, collect_gcc) == 0)
654 /* collect_gcc has no path, so it was found in PATH. Make sure we also
655 find accel-gcc in PATH. */
656 gcc_path = NULL;
658 int driver_used = 0;
659 if (gcc_path != NULL)
660 driver_used = sprintf (driver, "%s/", gcc_path);
661 sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME);
663 bool found = false;
664 if (gcc_path == NULL)
665 found = true;
666 else if (access_check (driver, X_OK) == 0)
667 found = true;
668 else
670 /* Don't use alloca pointer with XRESIZEVEC. */
671 driver = NULL;
672 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */
673 char **paths = NULL;
674 unsigned n_paths;
675 n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
676 for (unsigned i = 0; i < n_paths; i++)
678 len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1;
679 driver = XRESIZEVEC (char, driver, len);
680 sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME);
681 if (access_check (driver, X_OK) == 0)
683 found = true;
684 break;
687 free_array_of_ptrs ((void **) paths, n_paths);
690 if (!found)
691 fatal_error (input_location,
692 "offload compiler %s not found (consider using %<-B%>)",
693 GCC_INSTALL_NAME);
695 /* We may be called with all the arguments stored in some file and
696 passed with @file. Expand them into argv before processing. */
697 expandargv (&argc, &argv);
699 /* Scan the argument vector. */
700 bool fopenmp = false;
701 bool fopenacc = false;
702 bool fPIC = false;
703 bool fpic = false;
704 for (int i = 1; i < argc; i++)
706 #define STR "-foffload-abi="
707 if (startswith (argv[i], STR))
709 if (strcmp (argv[i] + strlen (STR), "lp64") == 0)
710 offload_abi = OFFLOAD_ABI_LP64;
711 else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0)
712 offload_abi = OFFLOAD_ABI_ILP32;
713 else
714 fatal_error (input_location,
715 "unrecognizable argument of option " STR);
717 #undef STR
718 else if (startswith (argv[i], "-foffload-abi-host-opts="))
720 if (offload_abi_host_opts)
721 fatal_error (input_location,
722 "%<-foffload-abi-host-opts%> specified "
723 "multiple times");
724 offload_abi_host_opts
725 = argv[i] + strlen ("-foffload-abi-host-opts=");
727 else if (strcmp (argv[i], "-fopenmp") == 0)
728 fopenmp = true;
729 else if (strcmp (argv[i], "-fopenacc") == 0)
730 fopenacc = true;
731 else if (strcmp (argv[i], "-fPIC") == 0)
732 fPIC = true;
733 else if (strcmp (argv[i], "-fpic") == 0)
734 fpic = true;
735 else if (strcmp (argv[i], "-save-temps") == 0)
736 save_temps = true;
737 else if (strcmp (argv[i], "-v") == 0)
738 verbose = true;
739 else if (strcmp (argv[i], "-dumpbase") == 0
740 && i + 1 < argc)
741 dumppfx = argv[++i];
742 /* Translate host into offloading libraries. */
743 else if (strcmp (argv[i], "-l_GCC_gfortran") == 0
744 || strcmp (argv[i], "-l_GCC_m") == 0)
746 /* Elide '_GCC_'. */
747 size_t i_dst = strlen ("-l");
748 size_t i_src = strlen ("-l_GCC_");
749 char c;
751 c = argv[i][i_dst++] = argv[i][i_src++];
752 while (c != '\0');
755 if (!(fopenacc ^ fopenmp))
756 fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
757 "must be set");
759 struct obstack argv_obstack;
760 obstack_init (&argv_obstack);
761 obstack_ptr_grow (&argv_obstack, driver);
762 if (save_temps)
763 obstack_ptr_grow (&argv_obstack, "-save-temps");
764 if (verbose)
765 obstack_ptr_grow (&argv_obstack, "-v");
766 obstack_ptr_grow (&argv_obstack, "-xlto");
767 switch (offload_abi)
769 case OFFLOAD_ABI_LP64:
770 obstack_ptr_grow (&argv_obstack, "-m64");
771 break;
772 case OFFLOAD_ABI_ILP32:
773 obstack_ptr_grow (&argv_obstack, "-m32");
774 break;
775 default:
776 gcc_unreachable ();
778 if (fopenmp)
779 obstack_ptr_grow (&argv_obstack, "-mgomp");
781 for (int ix = 1; ix != argc; ix++)
783 if (!strcmp (argv[ix], "-o") && ix + 1 != argc)
784 outname = argv[++ix];
785 else
786 obstack_ptr_grow (&argv_obstack, argv[ix]);
789 if (!dumppfx)
790 dumppfx = outname;
792 ptx_dumpbase = concat (dumppfx, ".c", NULL);
793 if (save_temps)
794 ptx_cfile_name = ptx_dumpbase;
795 else
796 ptx_cfile_name = make_temp_file (".c");
798 out = fopen (ptx_cfile_name, "w");
799 if (!out)
800 fatal_error (input_location, "cannot open '%s'", ptx_cfile_name);
802 /* PR libgomp/65099: Currently, we only support offloading in 64-bit
803 configurations. */
804 if (offload_abi == OFFLOAD_ABI_LP64)
806 char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
807 if (save_temps)
808 ptx_name = mko_dumpbase;
809 else
810 ptx_name = make_temp_file (".mkoffload");
811 obstack_ptr_grow (&argv_obstack, "-dumpdir");
812 obstack_ptr_grow (&argv_obstack, "");
813 obstack_ptr_grow (&argv_obstack, "-dumpbase");
814 obstack_ptr_grow (&argv_obstack, mko_dumpbase);
815 obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
816 obstack_ptr_grow (&argv_obstack, "");
817 obstack_ptr_grow (&argv_obstack, "-o");
818 obstack_ptr_grow (&argv_obstack, ptx_name);
819 obstack_ptr_grow (&argv_obstack, NULL);
820 const char **new_argv = XOBFINISH (&argv_obstack, const char **);
822 char *execpath = getenv ("GCC_EXEC_PREFIX");
823 char *cpath = getenv ("COMPILER_PATH");
824 char *lpath = getenv ("LIBRARY_PATH");
825 unsetenv ("GCC_EXEC_PREFIX");
826 unsetenv ("COMPILER_PATH");
827 unsetenv ("LIBRARY_PATH");
829 if (save_temps)
830 omp_requires_file = concat (dumppfx, ".mkoffload.omp_requires", NULL);
831 else
832 omp_requires_file = make_temp_file (".mkoffload.omp_requires");
834 xputenv (concat ("GCC_OFFLOAD_OMP_REQUIRES_FILE=", omp_requires_file, NULL));
835 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true,
836 ".gcc_args");
837 obstack_free (&argv_obstack, NULL);
838 unsetenv("GCC_OFFLOAD_OMP_REQUIRES_FILE");
840 xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL));
841 xputenv (concat ("COMPILER_PATH=", cpath, NULL));
842 xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
844 in = fopen (omp_requires_file, "rb");
845 if (!in)
846 fatal_error (input_location, "cannot open omp_requires file %qs",
847 omp_requires_file);
848 uint32_t omp_requires;
849 if (fread (&omp_requires, sizeof (omp_requires), 1, in) != 1)
850 fatal_error (input_location, "cannot read omp_requires file %qs",
851 omp_requires_file);
852 fclose (in);
854 in = fopen (ptx_name, "r");
855 if (!in)
856 fatal_error (input_location, "cannot open intermediate ptx file");
858 process (in, out, omp_requires);
859 fclose (in);
862 fclose (out);
864 compile_native (ptx_cfile_name, outname, collect_gcc, fPIC, fpic);
866 return 0;