1 /* Offload image generation tool for PTX.
3 Copyright (C) 2014-2016 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. */
32 #include "coretypes.h"
34 #include "diagnostic.h"
37 #include "collect-utils.h"
38 #include "gomp-constants.h"
40 const char tool_name
[] = "nvptx mkoffload";
42 #define COMMENT_PREFIX "#"
50 static id_map
*func_ids
, **funcs_tail
= &func_ids
;
51 static id_map
*var_ids
, **vars_tail
= &var_ids
;
53 /* Files to unlink. */
54 static const char *ptx_name
;
55 static const char *ptx_cfile_name
;
57 enum offload_abi offload_abi
= OFFLOAD_ABI_UNSET
;
59 /* Delete tempfiles. */
62 tool_cleanup (bool from_signal ATTRIBUTE_UNUSED
)
65 maybe_unlink (ptx_cfile_name
);
67 maybe_unlink (ptx_name
);
71 mkoffload_cleanup (void)
76 /* Unlink FILE unless requested otherwise. */
79 maybe_unlink (const char *file
)
83 if (unlink_if_ordinary (file
)
85 fatal_error (input_location
, "deleting file %s: %m", file
);
88 fprintf (stderr
, "[Leaving %s]\n", file
);
91 /* Add or change the value of an environment variable, outputting the
92 change to standard error if in verbose mode. */
94 xputenv (const char *string
)
97 fprintf (stderr
, "%s\n", string
);
98 putenv (CONST_CAST (char *, string
));
103 record_id (const char *p1
, id_map
***where
)
105 const char *end
= strchr (p1
, '\n');
107 fatal_error (input_location
, "malformed ptx file");
109 id_map
*v
= XNEW (id_map
);
110 size_t len
= end
- p1
;
111 v
->ptx_name
= XNEWVEC (char, len
+ 1);
112 memcpy (v
->ptx_name
, p1
, len
);
113 v
->ptx_name
[len
] = '\0';
115 id_map
**tail
= *where
;
120 /* Read the whole input file. It will be NUL terminated (but
121 remember, there could be a NUL in the file itself. */
124 read_file (FILE *stream
, size_t *plen
)
126 size_t alloc
= 16384;
130 if (!fseek (stream
, 0, SEEK_END
))
132 /* Get the file size. */
133 long s
= ftell (stream
);
136 fseek (stream
, 0, SEEK_SET
);
138 buffer
= XNEWVEC (char, alloc
);
142 size_t n
= fread (buffer
+ base
, 1, alloc
- base
- 1, stream
);
147 if (base
+ 1 == alloc
)
150 buffer
= XRESIZEVEC (char, buffer
, alloc
);
158 /* Parse STR, saving found tokens into PVALUES and return their number.
159 Tokens are assumed to be delimited by ':'. */
161 parse_env_var (const char *str
, char ***pvalues
)
163 const char *curval
, *nextval
;
167 curval
= strchr (str
, ':');
171 curval
= strchr (curval
+ 1, ':');
174 values
= (char **) xmalloc (num
* sizeof (char *));
176 nextval
= strchr (curval
, ':');
178 nextval
= strchr (curval
, '\0');
180 for (i
= 0; i
< num
; i
++)
182 int l
= nextval
- curval
;
183 values
[i
] = (char *) xmalloc (l
+ 1);
184 memcpy (values
[i
], curval
, l
);
186 curval
= nextval
+ 1;
187 nextval
= strchr (curval
, ':');
189 nextval
= strchr (curval
, '\0');
195 /* Auxiliary function that frees elements of PTR and PTR itself.
196 N is number of elements to be freed. If PTR is NULL, nothing is freed.
197 If an element is NULL, subsequent elements are not freed. */
199 free_array_of_ptrs (void **ptr
, unsigned n
)
204 for (i
= 0; i
< n
; i
++)
214 /* Check whether NAME can be accessed in MODE. This is like access,
215 except that it never considers directories to be executable. */
217 access_check (const char *name
, int mode
)
223 if (stat (name
, &st
) < 0 || S_ISDIR (st
.st_mode
))
227 return access (name
, mode
);
231 process (FILE *in
, FILE *out
)
234 const char *input
= read_file (in
, &len
);
237 unsigned obj_count
= 0;
240 /* Dump out char arrays for each PTX object file. These are
241 terminated by a NUL. */
242 for (size_t i
= 0; i
!= len
;)
246 fprintf (out
, "static const char ptx_code_%u[] =\n\t\"", obj_count
++);
247 while ((c
= input
[i
++]))
254 fprintf (out
, "\\n\"\n\t\"");
255 /* Look for mappings on subsequent lines. */
256 while (strncmp (input
+ i
, "//:", 3) == 0)
260 if (strncmp (input
+ i
, "VAR_MAP ", 8) == 0)
261 record_id (input
+ i
+ 8, &vars_tail
);
262 else if (strncmp (input
+ i
, "FUNC_MAP ", 9) == 0)
263 record_id (input
+ i
+ 9, &funcs_tail
);
266 /* Skip to next line. */
267 while (input
[i
++] != '\n')
280 fprintf (out
, "\";\n\n");
283 /* Dump out array of pointers to ptx object strings. */
284 fprintf (out
, "static const struct ptx_obj {\n"
285 " const char *code;\n"
286 " __SIZE_TYPE__ size;\n"
288 for (comma
= "", ix
= 0; ix
!= obj_count
; comma
= ",", ix
++)
289 fprintf (out
, "%s\n\t{ptx_code_%u, sizeof (ptx_code_%u)}", comma
, ix
, ix
);
290 fprintf (out
, "\n};\n\n");
292 /* Dump out variable idents. */
293 fprintf (out
, "static const char *const var_mappings[] = {");
294 for (comma
= "", id
= var_ids
; id
; comma
= ",", id
= id
->next
)
295 fprintf (out
, "%s\n\t%s", comma
, id
->ptx_name
);
296 fprintf (out
, "\n};\n\n");
298 /* Dump out function idents. */
299 fprintf (out
, "static const struct nvptx_fn {\n"
300 " const char *name;\n"
301 " unsigned short dim[%d];\n"
302 "} func_mappings[] = {\n", GOMP_DIM_MAX
);
303 for (comma
= "", id
= func_ids
; id
; comma
= ",", id
= id
->next
)
304 fprintf (out
, "%s\n\t{%s}", comma
, id
->ptx_name
);
305 fprintf (out
, "\n};\n\n");
308 "static const struct nvptx_tdata {\n"
309 " const struct ptx_obj *ptx_objs;\n"
310 " unsigned ptx_num;\n"
311 " const char *const *var_names;\n"
312 " unsigned var_num;\n"
313 " const struct nvptx_fn *fn_names;\n"
314 " unsigned fn_num;\n"
315 "} target_data = {\n"
316 " ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n"
318 " sizeof (var_mappings) / sizeof (var_mappings[0]),\n"
320 " sizeof (func_mappings) / sizeof (func_mappings[0])\n"
323 fprintf (out
, "#ifdef __cplusplus\n"
327 fprintf (out
, "extern void GOMP_offload_register_ver"
328 " (unsigned, const void *, int, const void *);\n");
329 fprintf (out
, "extern void GOMP_offload_unregister_ver"
330 " (unsigned, const void *, int, const void *);\n");
332 fprintf (out
, "#ifdef __cplusplus\n"
336 fprintf (out
, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
338 fprintf (out
, "static __attribute__((constructor)) void init (void)\n"
340 " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
341 "%d/*NVIDIA_PTX*/, &target_data);\n"
343 GOMP_VERSION_PACK (GOMP_VERSION
, GOMP_VERSION_NVIDIA_PTX
),
344 GOMP_DEVICE_NVIDIA_PTX
);
346 fprintf (out
, "static __attribute__((destructor)) void fini (void)\n"
348 " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
349 "%d/*NVIDIA_PTX*/, &target_data);\n"
351 GOMP_VERSION_PACK (GOMP_VERSION
, GOMP_VERSION_NVIDIA_PTX
),
352 GOMP_DEVICE_NVIDIA_PTX
);
356 compile_native (const char *infile
, const char *outfile
, const char *compiler
)
358 const char *collect_gcc_options
= getenv ("COLLECT_GCC_OPTIONS");
359 if (!collect_gcc_options
)
360 fatal_error (input_location
,
361 "environment variable COLLECT_GCC_OPTIONS must be set");
363 struct obstack argv_obstack
;
364 obstack_init (&argv_obstack
);
365 obstack_ptr_grow (&argv_obstack
, compiler
);
367 obstack_ptr_grow (&argv_obstack
, "-save-temps");
369 obstack_ptr_grow (&argv_obstack
, "-v");
372 case OFFLOAD_ABI_LP64
:
373 obstack_ptr_grow (&argv_obstack
, "-m64");
375 case OFFLOAD_ABI_ILP32
:
376 obstack_ptr_grow (&argv_obstack
, "-m32");
381 obstack_ptr_grow (&argv_obstack
, infile
);
382 obstack_ptr_grow (&argv_obstack
, "-c");
383 obstack_ptr_grow (&argv_obstack
, "-o");
384 obstack_ptr_grow (&argv_obstack
, outfile
);
385 obstack_ptr_grow (&argv_obstack
, NULL
);
387 const char **new_argv
= XOBFINISH (&argv_obstack
, const char **);
388 fork_execute (new_argv
[0], CONST_CAST (char **, new_argv
), true);
389 obstack_free (&argv_obstack
, NULL
);
393 main (int argc
, char **argv
)
397 const char *outname
= 0;
399 progname
= "mkoffload";
400 diagnostic_initialize (global_dc
, 0);
402 if (atexit (mkoffload_cleanup
) != 0)
403 fatal_error (input_location
, "atexit failed");
405 char *collect_gcc
= getenv ("COLLECT_GCC");
406 if (collect_gcc
== NULL
)
407 fatal_error (input_location
, "COLLECT_GCC must be set.");
408 const char *gcc_path
= dirname (ASTRDUP (collect_gcc
));
409 const char *gcc_exec
= basename (ASTRDUP (collect_gcc
));
411 size_t len
= (strlen (gcc_path
) + 1
412 + strlen (GCC_INSTALL_NAME
)
414 char *driver
= XALLOCAVEC (char, len
);
416 if (strcmp (gcc_exec
, collect_gcc
) == 0)
417 /* collect_gcc has no path, so it was found in PATH. Make sure we also
418 find accel-gcc in PATH. */
422 if (gcc_path
!= NULL
)
423 driver_used
= sprintf (driver
, "%s/", gcc_path
);
424 sprintf (driver
+ driver_used
, "%s", GCC_INSTALL_NAME
);
427 if (gcc_path
== NULL
)
429 else if (access_check (driver
, X_OK
) == 0)
433 /* Don't use alloca pointer with XRESIZEVEC. */
435 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */
438 n_paths
= parse_env_var (getenv ("COMPILER_PATH"), &paths
);
439 for (unsigned i
= 0; i
< n_paths
; i
++)
441 len
= strlen (paths
[i
]) + 1 + strlen (GCC_INSTALL_NAME
) + 1;
442 driver
= XRESIZEVEC (char, driver
, len
);
443 sprintf (driver
, "%s/%s", paths
[i
], GCC_INSTALL_NAME
);
444 if (access_check (driver
, X_OK
) == 0)
450 free_array_of_ptrs ((void **) paths
, n_paths
);
454 fatal_error (input_location
,
455 "offload compiler %s not found", GCC_INSTALL_NAME
);
457 /* We may be called with all the arguments stored in some file and
458 passed with @file. Expand them into argv before processing. */
459 expandargv (&argc
, &argv
);
461 /* Scan the argument vector. */
462 bool fopenmp
= false;
463 for (int i
= 1; i
< argc
; i
++)
465 #define STR "-foffload-abi="
466 if (strncmp (argv
[i
], STR
, strlen (STR
)) == 0)
468 if (strcmp (argv
[i
] + strlen (STR
), "lp64") == 0)
469 offload_abi
= OFFLOAD_ABI_LP64
;
470 else if (strcmp (argv
[i
] + strlen (STR
), "ilp32") == 0)
471 offload_abi
= OFFLOAD_ABI_ILP32
;
473 fatal_error (input_location
,
474 "unrecognizable argument of option " STR
);
477 else if (strcmp (argv
[i
], "-fopenmp") == 0)
479 else if (strcmp (argv
[i
], "-save-temps") == 0)
481 else if (strcmp (argv
[i
], "-v") == 0)
485 struct obstack argv_obstack
;
486 obstack_init (&argv_obstack
);
487 obstack_ptr_grow (&argv_obstack
, driver
);
489 obstack_ptr_grow (&argv_obstack
, "-save-temps");
491 obstack_ptr_grow (&argv_obstack
, "-v");
492 obstack_ptr_grow (&argv_obstack
, "-xlto");
495 case OFFLOAD_ABI_LP64
:
496 obstack_ptr_grow (&argv_obstack
, "-m64");
498 case OFFLOAD_ABI_ILP32
:
499 obstack_ptr_grow (&argv_obstack
, "-m32");
505 for (int ix
= 1; ix
!= argc
; ix
++)
507 if (!strcmp (argv
[ix
], "-o") && ix
+ 1 != argc
)
508 outname
= argv
[++ix
];
510 obstack_ptr_grow (&argv_obstack
, argv
[ix
]);
513 ptx_cfile_name
= make_temp_file (".c");
515 out
= fopen (ptx_cfile_name
, "w");
517 fatal_error (input_location
, "cannot open '%s'", ptx_cfile_name
);
519 /* PR libgomp/65099: Currently, we only support offloading in 64-bit
520 configurations. PR target/67822: OpenMP offloading to nvptx fails. */
521 if (offload_abi
== OFFLOAD_ABI_LP64
&& !fopenmp
)
523 ptx_name
= make_temp_file (".mkoffload");
524 obstack_ptr_grow (&argv_obstack
, "-o");
525 obstack_ptr_grow (&argv_obstack
, ptx_name
);
526 obstack_ptr_grow (&argv_obstack
, NULL
);
527 const char **new_argv
= XOBFINISH (&argv_obstack
, const char **);
529 char *execpath
= getenv ("GCC_EXEC_PREFIX");
530 char *cpath
= getenv ("COMPILER_PATH");
531 char *lpath
= getenv ("LIBRARY_PATH");
532 unsetenv ("GCC_EXEC_PREFIX");
533 unsetenv ("COMPILER_PATH");
534 unsetenv ("LIBRARY_PATH");
536 fork_execute (new_argv
[0], CONST_CAST (char **, new_argv
), true);
537 obstack_free (&argv_obstack
, NULL
);
539 xputenv (concat ("GCC_EXEC_PREFIX=", execpath
, NULL
));
540 xputenv (concat ("COMPILER_PATH=", cpath
, NULL
));
541 xputenv (concat ("LIBRARY_PATH=", lpath
, NULL
));
543 in
= fopen (ptx_name
, "r");
545 fatal_error (input_location
, "cannot open intermediate ptx file");
552 compile_native (ptx_cfile_name
, outname
, collect_gcc
);