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
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
34 #include "coretypes.h"
36 #include "diagnostic.h"
39 #include "collect-utils.h"
40 #include "gomp-constants.h"
42 const char tool_name
[] = "nvptx mkoffload";
44 #define COMMENT_PREFIX "#"
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. */
69 tool_cleanup (bool from_signal ATTRIBUTE_UNUSED
)
72 maybe_unlink (ptx_cfile_name
);
74 maybe_unlink (ptx_name
);
75 if (omp_requires_file
)
76 maybe_unlink (omp_requires_file
);
80 mkoffload_cleanup (void)
85 /* Unlink FILE unless requested otherwise. */
88 maybe_unlink (const char *file
)
92 if (unlink_if_ordinary (file
)
94 fatal_error (input_location
, "deleting file %s: %m", file
);
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. */
103 xputenv (const char *string
)
106 fprintf (stderr
, "%s\n", string
);
107 putenv (CONST_CAST (char *, string
));
112 record_id (const char *p1
, id_map
***where
)
114 gcc_assert (p1
[0] == '"');
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';
130 v
->dim
= XNEWVEC (char, len
+ 1);
131 memcpy (v
->dim
, p1
, len
);
137 id_map
**tail
= *where
;
142 /* Read the whole input file. It will be NUL terminated (but
143 remember, there could be a NUL in the file itself. */
146 read_file (FILE *stream
, size_t *plen
)
148 size_t alloc
= 16384;
152 if (!fseek (stream
, 0, SEEK_END
))
154 /* Get the file size. */
155 long s
= ftell (stream
);
158 fseek (stream
, 0, SEEK_SET
);
160 buffer
= XNEWVEC (char, alloc
);
164 size_t n
= fread (buffer
+ base
, 1, alloc
- base
- 1, stream
);
169 if (base
+ 1 == alloc
)
172 buffer
= XRESIZEVEC (char, buffer
, alloc
);
180 /* Parse STR, saving found tokens into PVALUES and return their number.
181 Tokens are assumed to be delimited by ':'. */
183 parse_env_var (const char *str
, char ***pvalues
)
185 const char *curval
, *nextval
;
189 curval
= strchr (str
, ':');
193 curval
= strchr (curval
+ 1, ':');
196 values
= (char **) xmalloc (num
* sizeof (char *));
198 nextval
= strchr (curval
, ':');
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
);
208 curval
= nextval
+ 1;
209 nextval
= strchr (curval
, ':');
211 nextval
= strchr (curval
, '\0');
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. */
221 free_array_of_ptrs (void **ptr
, unsigned n
)
226 for (i
= 0; i
< n
; i
++)
236 /* Check whether NAME can be accessed in MODE. This is like access,
237 except that it never considers directories to be executable. */
239 access_check (const char *name
, int mode
)
245 if (stat (name
, &st
) < 0 || S_ISDIR (st
.st_mode
))
249 return access (name
, mode
);
253 process (FILE *in
, FILE *out
, uint32_t omp_requires
)
256 const char *input
= read_file (in
, &len
);
259 unsigned obj_count
= 0;
261 const char *sm_ver
= NULL
, *version
= NULL
;
262 const char *sm_ver2
= NULL
, *version2
= NULL
;
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
;)
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
++]))
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_");
291 if (UNLIKELY (startswith (input
+ i
, ".version ")))
293 version
= input
+ i
+ strlen (".version ");
296 while (startswith (input
+ i
, "//:"))
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
);
314 /* Skip to next line. */
315 while (input
[i
++] != '\n')
328 fprintf (out
, "\";\n\n");
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
344 ftruncate (fileno (out
), 0);
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
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");
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
388 if (!endswith (id
->ptx_name
, "$nohost")
389 && !strstr (id
->ptx_name
, "$nohost$"))
391 fprintf (out
, "\t\".extern ");
392 const char *p
= input
+ file_idx
[fidx
];
395 p
= strstr (p
, needle
);
399 if (fidx
>= file_cnt
)
401 p
= input
+ file_idx
[fidx
];
404 p
+= strlen (needle
);
405 if (!startswith (p
, id
->ptx_name
))
407 p
+= strlen (id
->ptx_name
);
411 gcc_assert (startswith (p
, ".visible "));
412 p
+= strlen (".visible ");
413 for (; *p
!= '\0' && *p
!= '\n'; p
++)
417 fprintf (out
, "\"\n");
418 if (fidx
== file_cnt
)
419 fatal_error (input_location
,
420 "Cannot find function declaration for %qs",
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");
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
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");
460 for (id
= ind_func_ids
; id
; id
= id
->next
)
462 fprintf (out
, "\t\".extern ");
463 const char *p
= input
+ file_idx
[fidx
];
466 p
= strstr (p
, needle
);
470 if (fidx
>= file_cnt
)
472 p
= input
+ file_idx
[fidx
];
475 p
+= strlen (needle
);
476 if (!startswith (p
, id
->ptx_name
))
478 p
+= strlen (id
->ptx_name
);
482 /* Skip over any directives. */
483 while (!startswith (p
, ".func"))
485 for (; *p
!= '\0' && *p
!= '\n'; p
++)
489 fprintf (out
, "\"\n");
490 if (fidx
== file_cnt
)
491 fatal_error (input_location
,
492 "Cannot find function declaration for %qs",
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"
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");
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"
545 " %d, ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n"
547 " sizeof (var_mappings) / sizeof (var_mappings[0]),\n"
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"
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"
566 fprintf (out
, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
568 fprintf (out
, "static __attribute__((constructor)) void init (void)\n"
570 " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
571 " %d/*NVIDIA_PTX*/, &nvptx_data);\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"
578 " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
579 " %d/*NVIDIA_PTX*/, &nvptx_data);\n"
581 GOMP_VERSION_PACK (GOMP_VERSION
, GOMP_VERSION_NVIDIA_PTX
),
582 GOMP_DEVICE_NVIDIA_PTX
);
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
);
598 obstack_ptr_grow (&argv_obstack
, "-fPIC");
600 obstack_ptr_grow (&argv_obstack
, "-fpic");
602 obstack_ptr_grow (&argv_obstack
, "-save-temps");
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,
624 obstack_free (&argv_obstack
, NULL
);
628 main (int argc
, char **argv
)
632 const char *outname
= 0;
634 progname
= tool_name
;
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
)
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. */
659 if (gcc_path
!= NULL
)
660 driver_used
= sprintf (driver
, "%s/", gcc_path
);
661 sprintf (driver
+ driver_used
, "%s", GCC_INSTALL_NAME
);
664 if (gcc_path
== NULL
)
666 else if (access_check (driver
, X_OK
) == 0)
670 /* Don't use alloca pointer with XRESIZEVEC. */
672 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */
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)
687 free_array_of_ptrs ((void **) paths
, n_paths
);
691 fatal_error (input_location
,
692 "offload compiler %s not found (consider using %<-B%>)",
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;
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
;
714 fatal_error (input_location
,
715 "unrecognizable argument of option " 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 "
724 offload_abi_host_opts
725 = argv
[i
] + strlen ("-foffload-abi-host-opts=");
727 else if (strcmp (argv
[i
], "-fopenmp") == 0)
729 else if (strcmp (argv
[i
], "-fopenacc") == 0)
731 else if (strcmp (argv
[i
], "-fPIC") == 0)
733 else if (strcmp (argv
[i
], "-fpic") == 0)
735 else if (strcmp (argv
[i
], "-save-temps") == 0)
737 else if (strcmp (argv
[i
], "-v") == 0)
739 else if (strcmp (argv
[i
], "-dumpbase") == 0
742 /* Translate host into offloading libraries. */
743 else if (strcmp (argv
[i
], "-l_GCC_gfortran") == 0
744 || strcmp (argv
[i
], "-l_GCC_m") == 0)
747 size_t i_dst
= strlen ("-l");
748 size_t i_src
= strlen ("-l_GCC_");
751 c
= argv
[i
][i_dst
++] = argv
[i
][i_src
++];
755 if (!(fopenacc
^ fopenmp
))
756 fatal_error (input_location
, "either %<-fopenacc%> or %<-fopenmp%> "
759 struct obstack argv_obstack
;
760 obstack_init (&argv_obstack
);
761 obstack_ptr_grow (&argv_obstack
, driver
);
763 obstack_ptr_grow (&argv_obstack
, "-save-temps");
765 obstack_ptr_grow (&argv_obstack
, "-v");
766 obstack_ptr_grow (&argv_obstack
, "-xlto");
769 case OFFLOAD_ABI_LP64
:
770 obstack_ptr_grow (&argv_obstack
, "-m64");
772 case OFFLOAD_ABI_ILP32
:
773 obstack_ptr_grow (&argv_obstack
, "-m32");
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
];
786 obstack_ptr_grow (&argv_obstack
, argv
[ix
]);
792 ptx_dumpbase
= concat (dumppfx
, ".c", NULL
);
794 ptx_cfile_name
= ptx_dumpbase
;
796 ptx_cfile_name
= make_temp_file (".c");
798 out
= fopen (ptx_cfile_name
, "w");
800 fatal_error (input_location
, "cannot open '%s'", ptx_cfile_name
);
802 /* PR libgomp/65099: Currently, we only support offloading in 64-bit
804 if (offload_abi
== OFFLOAD_ABI_LP64
)
806 char *mko_dumpbase
= concat (dumppfx
, ".mkoffload", NULL
);
808 ptx_name
= mko_dumpbase
;
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");
830 omp_requires_file
= concat (dumppfx
, ".mkoffload.omp_requires", NULL
);
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,
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");
846 fatal_error (input_location
, "cannot open omp_requires file %qs",
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",
854 in
= fopen (ptx_name
, "r");
856 fatal_error (input_location
, "cannot open intermediate ptx file");
858 process (in
, out
, omp_requires
);
864 compile_native (ptx_cfile_name
, outname
, collect_gcc
, fPIC
, fpic
);