]>
Commit | Line | Data |
---|---|---|
1f83528e TS |
1 | /* Offload image generation tool for PTX. |
2 | ||
a5544970 | 3 | Copyright (C) 2014-2019 Free Software Foundation, Inc. |
1f83528e TS |
4 | |
5 | Contributed by Nathan Sidwell <nathan@codesourcery.com> and | |
6 | Bernd Schmidt <bernds@codesourcery.com>. | |
7 | ||
8 | This file is part of GCC. | |
9 | ||
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. | |
14 | ||
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. | |
19 | ||
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/>. */ | |
23 | ||
24 | /* Munges PTX assembly into a C source file defining the PTX code as a | |
25 | string. | |
26 | ||
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. */ | |
29 | ||
8fcc61f8 RS |
30 | #define IN_TARGET_CODE 1 |
31 | ||
1f83528e TS |
32 | #include "config.h" |
33 | #include "system.h" | |
34 | #include "coretypes.h" | |
1f83528e | 35 | #include "obstack.h" |
ce888a99 | 36 | #include "diagnostic.h" |
e11c4407 AM |
37 | #include "intl.h" |
38 | #include <libgen.h> | |
1f83528e | 39 | #include "collect-utils.h" |
e6f229ca | 40 | #include "gomp-constants.h" |
1f83528e TS |
41 | |
42 | const char tool_name[] = "nvptx mkoffload"; | |
43 | ||
44 | #define COMMENT_PREFIX "#" | |
45 | ||
1f83528e TS |
46 | struct id_map |
47 | { | |
48 | id_map *next; | |
49 | char *ptx_name; | |
50 | }; | |
51 | ||
1f83528e TS |
52 | static id_map *func_ids, **funcs_tail = &func_ids; |
53 | static id_map *var_ids, **vars_tail = &var_ids; | |
54 | ||
55 | /* Files to unlink. */ | |
56 | static const char *ptx_name; | |
57 | static const char *ptx_cfile_name; | |
58 | ||
ae15100c | 59 | enum offload_abi offload_abi = OFFLOAD_ABI_UNSET; |
f82a9d90 | 60 | |
1f83528e TS |
61 | /* Delete tempfiles. */ |
62 | ||
4314a3ef TS |
63 | void |
64 | tool_cleanup (bool from_signal ATTRIBUTE_UNUSED) | |
65 | { | |
66 | if (ptx_cfile_name) | |
67 | maybe_unlink (ptx_cfile_name); | |
68 | if (ptx_name) | |
69 | maybe_unlink (ptx_name); | |
70 | } | |
71 | ||
72 | static void | |
73 | mkoffload_cleanup (void) | |
74 | { | |
75 | tool_cleanup (false); | |
76 | } | |
77 | ||
78 | /* Unlink FILE unless requested otherwise. */ | |
1f83528e TS |
79 | |
80 | void | |
81 | maybe_unlink (const char *file) | |
82 | { | |
4314a3ef | 83 | if (!save_temps) |
1f83528e TS |
84 | { |
85 | if (unlink_if_ordinary (file) | |
86 | && errno != ENOENT) | |
40fecdd6 | 87 | fatal_error (input_location, "deleting file %s: %m", file); |
1f83528e | 88 | } |
4314a3ef | 89 | else if (verbose) |
1f83528e TS |
90 | fprintf (stderr, "[Leaving %s]\n", file); |
91 | } | |
92 | ||
1f83528e TS |
93 | /* Add or change the value of an environment variable, outputting the |
94 | change to standard error if in verbose mode. */ | |
95 | static void | |
96 | xputenv (const char *string) | |
97 | { | |
98 | if (verbose) | |
99 | fprintf (stderr, "%s\n", string); | |
100 | putenv (CONST_CAST (char *, string)); | |
101 | } | |
102 | ||
103 | ||
104 | static void | |
105 | record_id (const char *p1, id_map ***where) | |
106 | { | |
107 | const char *end = strchr (p1, '\n'); | |
108 | if (!end) | |
40fecdd6 | 109 | fatal_error (input_location, "malformed ptx file"); |
1f83528e TS |
110 | |
111 | id_map *v = XNEW (id_map); | |
112 | size_t len = end - p1; | |
113 | v->ptx_name = XNEWVEC (char, len + 1); | |
114 | memcpy (v->ptx_name, p1, len); | |
115 | v->ptx_name[len] = '\0'; | |
116 | v->next = NULL; | |
117 | id_map **tail = *where; | |
118 | *tail = v; | |
119 | *where = &v->next; | |
120 | } | |
121 | ||
122 | /* Read the whole input file. It will be NUL terminated (but | |
123 | remember, there could be a NUL in the file itself. */ | |
124 | ||
125 | static const char * | |
113020dc | 126 | read_file (FILE *stream, size_t *plen) |
1f83528e TS |
127 | { |
128 | size_t alloc = 16384; | |
129 | size_t base = 0; | |
130 | char *buffer; | |
131 | ||
132 | if (!fseek (stream, 0, SEEK_END)) | |
133 | { | |
134 | /* Get the file size. */ | |
135 | long s = ftell (stream); | |
136 | if (s >= 0) | |
137 | alloc = s + 100; | |
138 | fseek (stream, 0, SEEK_SET); | |
139 | } | |
140 | buffer = XNEWVEC (char, alloc); | |
141 | ||
142 | for (;;) | |
143 | { | |
144 | size_t n = fread (buffer + base, 1, alloc - base - 1, stream); | |
145 | ||
146 | if (!n) | |
147 | break; | |
148 | base += n; | |
149 | if (base + 1 == alloc) | |
150 | { | |
151 | alloc *= 2; | |
152 | buffer = XRESIZEVEC (char, buffer, alloc); | |
153 | } | |
154 | } | |
155 | buffer[base] = 0; | |
113020dc | 156 | *plen = base; |
1f83528e TS |
157 | return buffer; |
158 | } | |
159 | ||
865fc32a TS |
160 | /* Parse STR, saving found tokens into PVALUES and return their number. |
161 | Tokens are assumed to be delimited by ':'. */ | |
162 | static unsigned | |
163 | parse_env_var (const char *str, char ***pvalues) | |
164 | { | |
165 | const char *curval, *nextval; | |
166 | char **values; | |
167 | unsigned num = 1, i; | |
168 | ||
169 | curval = strchr (str, ':'); | |
170 | while (curval) | |
171 | { | |
172 | num++; | |
173 | curval = strchr (curval + 1, ':'); | |
174 | } | |
175 | ||
176 | values = (char **) xmalloc (num * sizeof (char *)); | |
177 | curval = str; | |
178 | nextval = strchr (curval, ':'); | |
179 | if (nextval == NULL) | |
180 | nextval = strchr (curval, '\0'); | |
181 | ||
182 | for (i = 0; i < num; i++) | |
183 | { | |
184 | int l = nextval - curval; | |
185 | values[i] = (char *) xmalloc (l + 1); | |
186 | memcpy (values[i], curval, l); | |
187 | values[i][l] = 0; | |
188 | curval = nextval + 1; | |
189 | nextval = strchr (curval, ':'); | |
190 | if (nextval == NULL) | |
191 | nextval = strchr (curval, '\0'); | |
192 | } | |
193 | *pvalues = values; | |
194 | return num; | |
195 | } | |
196 | ||
197 | /* Auxiliary function that frees elements of PTR and PTR itself. | |
198 | N is number of elements to be freed. If PTR is NULL, nothing is freed. | |
199 | If an element is NULL, subsequent elements are not freed. */ | |
200 | static void | |
201 | free_array_of_ptrs (void **ptr, unsigned n) | |
202 | { | |
203 | unsigned i; | |
204 | if (!ptr) | |
205 | return; | |
206 | for (i = 0; i < n; i++) | |
207 | { | |
208 | if (!ptr[i]) | |
209 | break; | |
210 | free (ptr[i]); | |
211 | } | |
212 | free (ptr); | |
213 | return; | |
214 | } | |
215 | ||
216 | /* Check whether NAME can be accessed in MODE. This is like access, | |
217 | except that it never considers directories to be executable. */ | |
218 | static int | |
219 | access_check (const char *name, int mode) | |
220 | { | |
221 | if (mode == X_OK) | |
222 | { | |
223 | struct stat st; | |
224 | ||
225 | if (stat (name, &st) < 0 || S_ISDIR (st.st_mode)) | |
226 | return -1; | |
227 | } | |
228 | ||
229 | return access (name, mode); | |
230 | } | |
231 | ||
1f83528e TS |
232 | static void |
233 | process (FILE *in, FILE *out) | |
234 | { | |
113020dc TS |
235 | size_t len = 0; |
236 | const char *input = read_file (in, &len); | |
3e32ee19 NS |
237 | const char *comma; |
238 | id_map const *id; | |
cc3cd79b NS |
239 | unsigned obj_count = 0; |
240 | unsigned ix; | |
1f83528e | 241 | |
113020dc TS |
242 | /* Dump out char arrays for each PTX object file. These are |
243 | terminated by a NUL. */ | |
244 | for (size_t i = 0; i != len;) | |
245 | { | |
246 | char c; | |
1f83528e | 247 | |
113020dc TS |
248 | fprintf (out, "static const char ptx_code_%u[] =\n\t\"", obj_count++); |
249 | while ((c = input[i++])) | |
250 | { | |
251 | switch (c) | |
252 | { | |
253 | case '\r': | |
254 | continue; | |
255 | case '\n': | |
256 | fprintf (out, "\\n\"\n\t\""); | |
257 | /* Look for mappings on subsequent lines. */ | |
258 | while (strncmp (input + i, "//:", 3) == 0) | |
259 | { | |
260 | i += 3; | |
261 | ||
262 | if (strncmp (input + i, "VAR_MAP ", 8) == 0) | |
263 | record_id (input + i + 8, &vars_tail); | |
264 | else if (strncmp (input + i, "FUNC_MAP ", 9) == 0) | |
265 | record_id (input + i + 9, &funcs_tail); | |
266 | else | |
267 | abort (); | |
268 | /* Skip to next line. */ | |
269 | while (input[i++] != '\n') | |
270 | continue; | |
271 | } | |
272 | continue; | |
273 | case '"': | |
274 | case '\\': | |
275 | putc ('\\', out); | |
276 | break; | |
277 | default: | |
278 | break; | |
279 | } | |
280 | putc (c, out); | |
281 | } | |
282 | fprintf (out, "\";\n\n"); | |
283 | } | |
a4cb876d | 284 | |
cc3cd79b NS |
285 | /* Dump out array of pointers to ptx object strings. */ |
286 | fprintf (out, "static const struct ptx_obj {\n" | |
287 | " const char *code;\n" | |
288 | " __SIZE_TYPE__ size;\n" | |
289 | "} ptx_objs[] = {"); | |
290 | for (comma = "", ix = 0; ix != obj_count; comma = ",", ix++) | |
291 | fprintf (out, "%s\n\t{ptx_code_%u, sizeof (ptx_code_%u)}", comma, ix, ix); | |
292 | fprintf (out, "\n};\n\n"); | |
293 | ||
294 | /* Dump out variable idents. */ | |
3e32ee19 NS |
295 | fprintf (out, "static const char *const var_mappings[] = {"); |
296 | for (comma = "", id = var_ids; id; comma = ",", id = id->next) | |
297 | fprintf (out, "%s\n\t%s", comma, id->ptx_name); | |
298 | fprintf (out, "\n};\n\n"); | |
299 | ||
cc3cd79b | 300 | /* Dump out function idents. */ |
3e32ee19 NS |
301 | fprintf (out, "static const struct nvptx_fn {\n" |
302 | " const char *name;\n" | |
cc3cd79b NS |
303 | " unsigned short dim[%d];\n" |
304 | "} func_mappings[] = {\n", GOMP_DIM_MAX); | |
3e32ee19 NS |
305 | for (comma = "", id = func_ids; id; comma = ",", id = id->next) |
306 | fprintf (out, "%s\n\t{%s}", comma, id->ptx_name); | |
307 | fprintf (out, "\n};\n\n"); | |
1f83528e | 308 | |
a4cb876d | 309 | fprintf (out, |
afb2d80b | 310 | "static const struct nvptx_tdata {\n" |
cc3cd79b NS |
311 | " const struct ptx_obj *ptx_objs;\n" |
312 | " unsigned ptx_num;\n" | |
a4cb876d | 313 | " const char *const *var_names;\n" |
cc3cd79b | 314 | " unsigned var_num;\n" |
3e32ee19 | 315 | " const struct nvptx_fn *fn_names;\n" |
cc3cd79b | 316 | " unsigned fn_num;\n" |
a4cb876d | 317 | "} target_data = {\n" |
cc3cd79b | 318 | " ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n" |
a4cb876d NS |
319 | " var_mappings," |
320 | " sizeof (var_mappings) / sizeof (var_mappings[0]),\n" | |
321 | " func_mappings," | |
322 | " sizeof (func_mappings) / sizeof (func_mappings[0])\n" | |
323 | "};\n\n"); | |
1f83528e | 324 | |
852b55f9 NS |
325 | fprintf (out, "#ifdef __cplusplus\n" |
326 | "extern \"C\" {\n" | |
327 | "#endif\n"); | |
22be2349 | 328 | |
2a21ff19 NS |
329 | fprintf (out, "extern void GOMP_offload_register_ver" |
330 | " (unsigned, const void *, int, const void *);\n"); | |
331 | fprintf (out, "extern void GOMP_offload_unregister_ver" | |
332 | " (unsigned, const void *, int, const void *);\n"); | |
22be2349 | 333 | |
852b55f9 NS |
334 | fprintf (out, "#ifdef __cplusplus\n" |
335 | "}\n" | |
336 | "#endif\n"); | |
1f83528e | 337 | |
ebe4a560 | 338 | fprintf (out, "extern const void *const __OFFLOAD_TABLE__[];\n\n"); |
22be2349 NS |
339 | |
340 | fprintf (out, "static __attribute__((constructor)) void init (void)\n" | |
341 | "{\n" | |
2a21ff19 | 342 | " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__," |
3ae48177 | 343 | " %d/*NVIDIA_PTX*/, &target_data);\n" |
2a21ff19 NS |
344 | "};\n", |
345 | GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX), | |
346 | GOMP_DEVICE_NVIDIA_PTX); | |
22be2349 NS |
347 | |
348 | fprintf (out, "static __attribute__((destructor)) void fini (void)\n" | |
349 | "{\n" | |
2a21ff19 | 350 | " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__," |
3ae48177 | 351 | " %d/*NVIDIA_PTX*/, &target_data);\n" |
2a21ff19 NS |
352 | "};\n", |
353 | GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX), | |
354 | GOMP_DEVICE_NVIDIA_PTX); | |
1f83528e TS |
355 | } |
356 | ||
357 | static void | |
358 | compile_native (const char *infile, const char *outfile, const char *compiler) | |
359 | { | |
360 | const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS"); | |
361 | if (!collect_gcc_options) | |
40fecdd6 JM |
362 | fatal_error (input_location, |
363 | "environment variable COLLECT_GCC_OPTIONS must be set"); | |
1f83528e TS |
364 | |
365 | struct obstack argv_obstack; | |
366 | obstack_init (&argv_obstack); | |
367 | obstack_ptr_grow (&argv_obstack, compiler); | |
4314a3ef TS |
368 | if (save_temps) |
369 | obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
0fe78d19 TS |
370 | if (verbose) |
371 | obstack_ptr_grow (&argv_obstack, "-v"); | |
ae15100c TS |
372 | switch (offload_abi) |
373 | { | |
374 | case OFFLOAD_ABI_LP64: | |
375 | obstack_ptr_grow (&argv_obstack, "-m64"); | |
376 | break; | |
377 | case OFFLOAD_ABI_ILP32: | |
378 | obstack_ptr_grow (&argv_obstack, "-m32"); | |
379 | break; | |
380 | default: | |
381 | gcc_unreachable (); | |
382 | } | |
1f83528e TS |
383 | obstack_ptr_grow (&argv_obstack, infile); |
384 | obstack_ptr_grow (&argv_obstack, "-c"); | |
385 | obstack_ptr_grow (&argv_obstack, "-o"); | |
386 | obstack_ptr_grow (&argv_obstack, outfile); | |
387 | obstack_ptr_grow (&argv_obstack, NULL); | |
388 | ||
389 | const char **new_argv = XOBFINISH (&argv_obstack, const char **); | |
390 | fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); | |
391 | obstack_free (&argv_obstack, NULL); | |
392 | } | |
393 | ||
394 | int | |
395 | main (int argc, char **argv) | |
396 | { | |
397 | FILE *in = stdin; | |
398 | FILE *out = stdout; | |
399 | const char *outname = 0; | |
400 | ||
ce888a99 TS |
401 | progname = "mkoffload"; |
402 | diagnostic_initialize (global_dc, 0); | |
403 | ||
4314a3ef TS |
404 | if (atexit (mkoffload_cleanup) != 0) |
405 | fatal_error (input_location, "atexit failed"); | |
406 | ||
1f83528e TS |
407 | char *collect_gcc = getenv ("COLLECT_GCC"); |
408 | if (collect_gcc == NULL) | |
40fecdd6 | 409 | fatal_error (input_location, "COLLECT_GCC must be set."); |
1f83528e TS |
410 | const char *gcc_path = dirname (ASTRDUP (collect_gcc)); |
411 | const char *gcc_exec = basename (ASTRDUP (collect_gcc)); | |
412 | ||
413 | size_t len = (strlen (gcc_path) + 1 | |
414 | + strlen (GCC_INSTALL_NAME) | |
415 | + 1); | |
416 | char *driver = XALLOCAVEC (char, len); | |
417 | ||
418 | if (strcmp (gcc_exec, collect_gcc) == 0) | |
419 | /* collect_gcc has no path, so it was found in PATH. Make sure we also | |
420 | find accel-gcc in PATH. */ | |
421 | gcc_path = NULL; | |
422 | ||
423 | int driver_used = 0; | |
424 | if (gcc_path != NULL) | |
425 | driver_used = sprintf (driver, "%s/", gcc_path); | |
426 | sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME); | |
427 | ||
865fc32a TS |
428 | bool found = false; |
429 | if (gcc_path == NULL) | |
430 | found = true; | |
431 | else if (access_check (driver, X_OK) == 0) | |
432 | found = true; | |
433 | else | |
434 | { | |
435 | /* Don't use alloca pointer with XRESIZEVEC. */ | |
436 | driver = NULL; | |
437 | /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */ | |
438 | char **paths = NULL; | |
439 | unsigned n_paths; | |
440 | n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths); | |
441 | for (unsigned i = 0; i < n_paths; i++) | |
442 | { | |
443 | len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1; | |
444 | driver = XRESIZEVEC (char, driver, len); | |
445 | sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME); | |
446 | if (access_check (driver, X_OK) == 0) | |
447 | { | |
448 | found = true; | |
449 | break; | |
450 | } | |
451 | } | |
452 | free_array_of_ptrs ((void **) paths, n_paths); | |
453 | } | |
454 | ||
455 | if (!found) | |
456 | fatal_error (input_location, | |
8ec60bac TV |
457 | "offload compiler %s not found (consider using '-B')", |
458 | GCC_INSTALL_NAME); | |
865fc32a | 459 | |
1f83528e TS |
460 | /* We may be called with all the arguments stored in some file and |
461 | passed with @file. Expand them into argv before processing. */ | |
462 | expandargv (&argc, &argv); | |
463 | ||
ae15100c | 464 | /* Scan the argument vector. */ |
d4852cd4 | 465 | bool fopenmp = false; |
5012919d | 466 | bool fopenacc = false; |
ae15100c TS |
467 | for (int i = 1; i < argc; i++) |
468 | { | |
469 | #define STR "-foffload-abi=" | |
470 | if (strncmp (argv[i], STR, strlen (STR)) == 0) | |
471 | { | |
472 | if (strcmp (argv[i] + strlen (STR), "lp64") == 0) | |
473 | offload_abi = OFFLOAD_ABI_LP64; | |
474 | else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0) | |
475 | offload_abi = OFFLOAD_ABI_ILP32; | |
476 | else | |
477 | fatal_error (input_location, | |
478 | "unrecognizable argument of option " STR); | |
479 | } | |
480 | #undef STR | |
d4852cd4 TS |
481 | else if (strcmp (argv[i], "-fopenmp") == 0) |
482 | fopenmp = true; | |
5012919d AM |
483 | else if (strcmp (argv[i], "-fopenacc") == 0) |
484 | fopenacc = true; | |
4314a3ef TS |
485 | else if (strcmp (argv[i], "-save-temps") == 0) |
486 | save_temps = true; | |
0fe78d19 TS |
487 | else if (strcmp (argv[i], "-v") == 0) |
488 | verbose = true; | |
ae15100c | 489 | } |
5012919d AM |
490 | if (!(fopenacc ^ fopenmp)) |
491 | fatal_error (input_location, "either -fopenacc or -fopenmp must be set"); | |
f82a9d90 | 492 | |
1f83528e TS |
493 | struct obstack argv_obstack; |
494 | obstack_init (&argv_obstack); | |
495 | obstack_ptr_grow (&argv_obstack, driver); | |
4314a3ef TS |
496 | if (save_temps) |
497 | obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
0fe78d19 TS |
498 | if (verbose) |
499 | obstack_ptr_grow (&argv_obstack, "-v"); | |
1f83528e | 500 | obstack_ptr_grow (&argv_obstack, "-xlto"); |
ae15100c TS |
501 | switch (offload_abi) |
502 | { | |
503 | case OFFLOAD_ABI_LP64: | |
504 | obstack_ptr_grow (&argv_obstack, "-m64"); | |
505 | break; | |
506 | case OFFLOAD_ABI_ILP32: | |
507 | obstack_ptr_grow (&argv_obstack, "-m32"); | |
508 | break; | |
509 | default: | |
510 | gcc_unreachable (); | |
511 | } | |
5012919d AM |
512 | if (fopenmp) |
513 | obstack_ptr_grow (&argv_obstack, "-mgomp"); | |
1f83528e TS |
514 | |
515 | for (int ix = 1; ix != argc; ix++) | |
516 | { | |
517 | if (!strcmp (argv[ix], "-o") && ix + 1 != argc) | |
518 | outname = argv[++ix]; | |
519 | else | |
520 | obstack_ptr_grow (&argv_obstack, argv[ix]); | |
521 | } | |
522 | ||
1f83528e TS |
523 | ptx_cfile_name = make_temp_file (".c"); |
524 | ||
525 | out = fopen (ptx_cfile_name, "w"); | |
526 | if (!out) | |
40fecdd6 | 527 | fatal_error (input_location, "cannot open '%s'", ptx_cfile_name); |
1f83528e | 528 | |
a92defda | 529 | /* PR libgomp/65099: Currently, we only support offloading in 64-bit |
e210b51b AM |
530 | configurations. */ |
531 | if (offload_abi == OFFLOAD_ABI_LP64) | |
a92defda TS |
532 | { |
533 | ptx_name = make_temp_file (".mkoffload"); | |
534 | obstack_ptr_grow (&argv_obstack, "-o"); | |
535 | obstack_ptr_grow (&argv_obstack, ptx_name); | |
536 | obstack_ptr_grow (&argv_obstack, NULL); | |
537 | const char **new_argv = XOBFINISH (&argv_obstack, const char **); | |
538 | ||
539 | char *execpath = getenv ("GCC_EXEC_PREFIX"); | |
540 | char *cpath = getenv ("COMPILER_PATH"); | |
541 | char *lpath = getenv ("LIBRARY_PATH"); | |
542 | unsetenv ("GCC_EXEC_PREFIX"); | |
543 | unsetenv ("COMPILER_PATH"); | |
544 | unsetenv ("LIBRARY_PATH"); | |
545 | ||
546 | fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); | |
547 | obstack_free (&argv_obstack, NULL); | |
548 | ||
549 | xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL)); | |
550 | xputenv (concat ("COMPILER_PATH=", cpath, NULL)); | |
551 | xputenv (concat ("LIBRARY_PATH=", lpath, NULL)); | |
552 | ||
553 | in = fopen (ptx_name, "r"); | |
554 | if (!in) | |
555 | fatal_error (input_location, "cannot open intermediate ptx file"); | |
556 | ||
557 | process (in, out); | |
558 | } | |
559 | ||
1f83528e TS |
560 | fclose (out); |
561 | ||
562 | compile_native (ptx_cfile_name, outname, collect_gcc); | |
563 | ||
1f83528e TS |
564 | return 0; |
565 | } |