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
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
;
65 /* Delete tempfiles. */
68 tool_cleanup (bool from_signal ATTRIBUTE_UNUSED
)
71 maybe_unlink (ptx_cfile_name
);
73 maybe_unlink (ptx_name
);
74 if (omp_requires_file
)
75 maybe_unlink (omp_requires_file
);
79 mkoffload_cleanup (void)
84 /* Unlink FILE unless requested otherwise. */
87 maybe_unlink (const char *file
)
91 if (unlink_if_ordinary (file
)
93 fatal_error (input_location
, "deleting file %s: %m", file
);
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. */
102 xputenv (const char *string
)
105 fprintf (stderr
, "%s\n", string
);
106 putenv (CONST_CAST (char *, string
));
111 record_id (const char *p1
, id_map
***where
)
113 gcc_assert (p1
[0] == '"');
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';
129 v
->dim
= XNEWVEC (char, len
+ 1);
130 memcpy (v
->dim
, p1
, len
);
136 id_map
**tail
= *where
;
141 /* Read the whole input file. It will be NUL terminated (but
142 remember, there could be a NUL in the file itself. */
145 read_file (FILE *stream
, size_t *plen
)
147 size_t alloc
= 16384;
151 if (!fseek (stream
, 0, SEEK_END
))
153 /* Get the file size. */
154 long s
= ftell (stream
);
157 fseek (stream
, 0, SEEK_SET
);
159 buffer
= XNEWVEC (char, alloc
);
163 size_t n
= fread (buffer
+ base
, 1, alloc
- base
- 1, stream
);
168 if (base
+ 1 == alloc
)
171 buffer
= XRESIZEVEC (char, buffer
, alloc
);
179 /* Parse STR, saving found tokens into PVALUES and return their number.
180 Tokens are assumed to be delimited by ':'. */
182 parse_env_var (const char *str
, char ***pvalues
)
184 const char *curval
, *nextval
;
188 curval
= strchr (str
, ':');
192 curval
= strchr (curval
+ 1, ':');
195 values
= (char **) xmalloc (num
* sizeof (char *));
197 nextval
= strchr (curval
, ':');
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
);
207 curval
= nextval
+ 1;
208 nextval
= strchr (curval
, ':');
210 nextval
= strchr (curval
, '\0');
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. */
220 free_array_of_ptrs (void **ptr
, unsigned n
)
225 for (i
= 0; i
< n
; i
++)
235 /* Check whether NAME can be accessed in MODE. This is like access,
236 except that it never considers directories to be executable. */
238 access_check (const char *name
, int mode
)
244 if (stat (name
, &st
) < 0 || S_ISDIR (st
.st_mode
))
248 return access (name
, mode
);
252 process (FILE *in
, FILE *out
, uint32_t omp_requires
)
255 const char *input
= read_file (in
, &len
);
258 unsigned obj_count
= 0;
260 const char *sm_ver
= NULL
, *version
= NULL
;
261 const char *sm_ver2
= NULL
, *version2
= NULL
;
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
;)
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
++]))
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_");
290 if (UNLIKELY (startswith (input
+ i
, ".version ")))
292 version
= input
+ i
+ strlen (".version ");
295 while (startswith (input
+ i
, "//:"))
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
);
313 /* Skip to next line. */
314 while (input
[i
++] != '\n')
327 fprintf (out
, "\";\n\n");
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
343 ftruncate (fileno (out
), 0);
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
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");
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
387 if (!endswith (id
->ptx_name
, "$nohost")
388 && !strstr (id
->ptx_name
, "$nohost$"))
390 fprintf (out
, "\t\".extern ");
391 const char *p
= input
+ file_idx
[fidx
];
394 p
= strstr (p
, needle
);
398 if (fidx
>= file_cnt
)
400 p
= input
+ file_idx
[fidx
];
403 p
+= strlen (needle
);
404 if (!startswith (p
, id
->ptx_name
))
406 p
+= strlen (id
->ptx_name
);
410 gcc_assert (startswith (p
, ".visible "));
411 p
+= strlen (".visible ");
412 for (; *p
!= '\0' && *p
!= '\n'; p
++)
416 fprintf (out
, "\"\n");
417 if (fidx
== file_cnt
)
418 fatal_error (input_location
,
419 "Cannot find function declaration for %qs",
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");
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
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");
459 for (id
= ind_func_ids
; id
; id
= id
->next
)
461 fprintf (out
, "\t\".extern ");
462 const char *p
= input
+ file_idx
[fidx
];
465 p
= strstr (p
, needle
);
469 if (fidx
>= file_cnt
)
471 p
= input
+ file_idx
[fidx
];
474 p
+= strlen (needle
);
475 if (!startswith (p
, id
->ptx_name
))
477 p
+= strlen (id
->ptx_name
);
481 /* Skip over any directives. */
482 while (!startswith (p
, ".func"))
484 for (; *p
!= '\0' && *p
!= '\n'; p
++)
488 fprintf (out
, "\"\n");
489 if (fidx
== file_cnt
)
490 fatal_error (input_location
,
491 "Cannot find function declaration for %qs",
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"
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");
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"
544 " %d, ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n"
546 " sizeof (var_mappings) / sizeof (var_mappings[0]),\n"
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"
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"
565 fprintf (out
, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
567 fprintf (out
, "static __attribute__((constructor)) void init (void)\n"
569 " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
570 " %d/*NVIDIA_PTX*/, &nvptx_data);\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"
577 " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
578 " %d/*NVIDIA_PTX*/, &nvptx_data);\n"
580 GOMP_VERSION_PACK (GOMP_VERSION
, GOMP_VERSION_NVIDIA_PTX
),
581 GOMP_DEVICE_NVIDIA_PTX
);
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
);
597 obstack_ptr_grow (&argv_obstack
, "-fPIC");
599 obstack_ptr_grow (&argv_obstack
, "-fpic");
601 obstack_ptr_grow (&argv_obstack
, "-save-temps");
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");
612 case OFFLOAD_ABI_LP64
:
613 obstack_ptr_grow (&argv_obstack
, "-m64");
615 case OFFLOAD_ABI_ILP32
:
616 obstack_ptr_grow (&argv_obstack
, "-m32");
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,
630 obstack_free (&argv_obstack
, NULL
);
634 main (int argc
, char **argv
)
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
)
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. */
663 if (gcc_path
!= NULL
)
664 driver_used
= sprintf (driver
, "%s/", gcc_path
);
665 sprintf (driver
+ driver_used
, "%s", GCC_INSTALL_NAME
);
668 if (gcc_path
== NULL
)
670 else if (access_check (driver
, X_OK
) == 0)
674 /* Don't use alloca pointer with XRESIZEVEC. */
676 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */
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)
691 free_array_of_ptrs ((void **) paths
, n_paths
);
695 fatal_error (input_location
,
696 "offload compiler %s not found (consider using %<-B%>)",
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;
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
;
718 fatal_error (input_location
,
719 "unrecognizable argument of option " STR
);
722 else if (strcmp (argv
[i
], "-fopenmp") == 0)
724 else if (strcmp (argv
[i
], "-fopenacc") == 0)
726 else if (strcmp (argv
[i
], "-fPIC") == 0)
728 else if (strcmp (argv
[i
], "-fpic") == 0)
730 else if (strcmp (argv
[i
], "-save-temps") == 0)
732 else if (strcmp (argv
[i
], "-v") == 0)
734 else if (strcmp (argv
[i
], "-dumpbase") == 0
737 /* Translate host into offloading libraries. */
738 else if (strcmp (argv
[i
], "-l_GCC_gfortran") == 0
739 || strcmp (argv
[i
], "-l_GCC_m") == 0)
742 size_t i_dst
= strlen ("-l");
743 size_t i_src
= strlen ("-l_GCC_");
746 c
= argv
[i
][i_dst
++] = argv
[i
][i_src
++];
750 if (!(fopenacc
^ fopenmp
))
751 fatal_error (input_location
, "either %<-fopenacc%> or %<-fopenmp%> "
754 struct obstack argv_obstack
;
755 obstack_init (&argv_obstack
);
756 obstack_ptr_grow (&argv_obstack
, driver
);
758 obstack_ptr_grow (&argv_obstack
, "-save-temps");
760 obstack_ptr_grow (&argv_obstack
, "-v");
761 obstack_ptr_grow (&argv_obstack
, "-xlto");
764 case OFFLOAD_ABI_LP64
:
765 obstack_ptr_grow (&argv_obstack
, "-m64");
767 case OFFLOAD_ABI_ILP32
:
768 obstack_ptr_grow (&argv_obstack
, "-m32");
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
];
781 obstack_ptr_grow (&argv_obstack
, argv
[ix
]);
787 ptx_dumpbase
= concat (dumppfx
, ".c", NULL
);
789 ptx_cfile_name
= ptx_dumpbase
;
791 ptx_cfile_name
= make_temp_file (".c");
793 out
= fopen (ptx_cfile_name
, "w");
795 fatal_error (input_location
, "cannot open '%s'", ptx_cfile_name
);
797 /* PR libgomp/65099: Currently, we only support offloading in 64-bit
799 if (offload_abi
== OFFLOAD_ABI_LP64
)
801 char *mko_dumpbase
= concat (dumppfx
, ".mkoffload", NULL
);
803 ptx_name
= mko_dumpbase
;
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");
825 omp_requires_file
= concat (dumppfx
, ".mkoffload.omp_requires", NULL
);
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,
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");
841 fatal_error (input_location
, "cannot open omp_requires file %qs",
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",
849 in
= fopen (ptx_name
, "r");
851 fatal_error (input_location
, "cannot open intermediate ptx file");
853 process (in
, out
, omp_requires
);
859 compile_native (ptx_cfile_name
, outname
, collect_gcc
, fPIC
, fpic
);