]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nvptx/mkoffload.c
gcc/
[thirdparty/gcc.git] / gcc / config / nvptx / mkoffload.c
1 /* Offload image generation tool for PTX.
2
3 Copyright (C) 2014-2015 Free Software Foundation, Inc.
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
30 #include "config.h"
31 #include "system.h"
32 #include "coretypes.h"
33 #include "intl.h"
34 #include <libgen.h>
35 #include "obstack.h"
36 #include "diagnostic.h"
37 #include "collect-utils.h"
38 #include "gomp-constants.h"
39
40 const char tool_name[] = "nvptx mkoffload";
41
42 #define COMMENT_PREFIX "#"
43
44 typedef enum Kind
45 {
46 /* 0-ff used for single char tokens */
47 K_symbol = 0x100, /* a symbol */
48 K_label, /* a label defn (i.e. symbol:) */
49 K_ident, /* other ident */
50 K_dotted, /* dotted identifier */
51 K_number,
52 K_string,
53 K_comment
54 } Kind;
55
56 typedef struct Token
57 {
58 unsigned short kind : 12;
59 unsigned short space : 1; /* preceded by space */
60 unsigned short end : 1; /* succeeded by end of line */
61 /* Length of token */
62 unsigned short len;
63
64 /* Token itself */
65 char const *ptr;
66 } Token;
67
68 /* statement info */
69 typedef enum Vis
70 {
71 V_dot = 0, /* random pseudo */
72 V_var = 1, /* var decl/defn */
73 V_func = 2, /* func decl/defn */
74 V_insn = 3, /* random insn */
75 V_label = 4, /* label defn */
76 V_comment = 5,
77 V_pred = 6, /* predicate */
78 V_mask = 0x7,
79 V_global = 0x08, /* globalize */
80 V_weak = 0x10, /* weakly globalize */
81 V_no_eol = 0x20, /* no end of line */
82 V_prefix_comment = 0x40 /* prefixed comment */
83 } Vis;
84
85 typedef struct Stmt
86 {
87 struct Stmt *next;
88 Token *tokens;
89 unsigned char vis;
90 unsigned len : 12;
91 unsigned sym : 12;
92 } Stmt;
93
94 struct id_map
95 {
96 id_map *next;
97 char *ptx_name;
98 };
99
100 static const char *read_file (FILE *);
101 static Token *tokenize (const char *);
102
103 static void write_token (FILE *, const Token *);
104 static void write_tokens (FILE *, const Token *, unsigned, int);
105
106 static Stmt *alloc_stmt (unsigned, Token *, Token *, const Token *);
107 #define alloc_comment(S,E) alloc_stmt (V_comment, S, E, 0)
108 #define append_stmt(V, S) ((S)->next = *(V), *(V) = (S))
109 static Stmt *rev_stmts (Stmt *);
110 static void write_stmt (FILE *, const Stmt *);
111 static void write_stmts (FILE *, const Stmt *);
112
113 static Token *parse_insn (Token *);
114 static Token *parse_list_nosemi (Token *);
115 static Token *parse_init (Token *);
116 static Token *parse_file (Token *);
117
118 static Stmt *decls;
119 static Stmt *vars;
120 static Stmt *fns;
121
122 static id_map *func_ids, **funcs_tail = &func_ids;
123 static id_map *var_ids, **vars_tail = &var_ids;
124
125 /* Files to unlink. */
126 static const char *ptx_name;
127 static const char *ptx_cfile_name;
128
129 /* Delete tempfiles. */
130
131 /* Unlink a temporary file unless requested otherwise. */
132
133 void
134 maybe_unlink (const char *file)
135 {
136 if (! debug)
137 {
138 if (unlink_if_ordinary (file)
139 && errno != ENOENT)
140 fatal_error (input_location, "deleting file %s: %m", file);
141 }
142 else
143 fprintf (stderr, "[Leaving %s]\n", file);
144 }
145
146 void
147 tool_cleanup (bool)
148 {
149 }
150
151 /* Add or change the value of an environment variable, outputting the
152 change to standard error if in verbose mode. */
153 static void
154 xputenv (const char *string)
155 {
156 if (verbose)
157 fprintf (stderr, "%s\n", string);
158 putenv (CONST_CAST (char *, string));
159 }
160
161
162 static void
163 record_id (const char *p1, id_map ***where)
164 {
165 const char *end = strchr (p1, '\n');
166 if (!end)
167 fatal_error (input_location, "malformed ptx file");
168
169 id_map *v = XNEW (id_map);
170 size_t len = end - p1;
171 v->ptx_name = XNEWVEC (char, len + 1);
172 memcpy (v->ptx_name, p1, len);
173 v->ptx_name[len] = '\0';
174 v->next = NULL;
175 id_map **tail = *where;
176 *tail = v;
177 *where = &v->next;
178 }
179
180 /* Read the whole input file. It will be NUL terminated (but
181 remember, there could be a NUL in the file itself. */
182
183 static const char *
184 read_file (FILE *stream)
185 {
186 size_t alloc = 16384;
187 size_t base = 0;
188 char *buffer;
189
190 if (!fseek (stream, 0, SEEK_END))
191 {
192 /* Get the file size. */
193 long s = ftell (stream);
194 if (s >= 0)
195 alloc = s + 100;
196 fseek (stream, 0, SEEK_SET);
197 }
198 buffer = XNEWVEC (char, alloc);
199
200 for (;;)
201 {
202 size_t n = fread (buffer + base, 1, alloc - base - 1, stream);
203
204 if (!n)
205 break;
206 base += n;
207 if (base + 1 == alloc)
208 {
209 alloc *= 2;
210 buffer = XRESIZEVEC (char, buffer, alloc);
211 }
212 }
213 buffer[base] = 0;
214 return buffer;
215 }
216
217 /* Read a token, advancing ptr.
218 If we read a comment, append it to the comments block. */
219
220 static Token *
221 tokenize (const char *ptr)
222 {
223 unsigned alloc = 1000;
224 unsigned num = 0;
225 Token *toks = XNEWVEC (Token, alloc);
226 int in_comment = 0;
227 int not_comment = 0;
228
229 for (;; num++)
230 {
231 const char *base;
232 unsigned kind;
233 int ws = 0;
234 int eol = 0;
235
236 again:
237 base = ptr;
238 if (in_comment)
239 goto block_comment;
240 switch (kind = *ptr++)
241 {
242 default:
243 break;
244
245 case '\n':
246 eol = 1;
247 /* Fall through */
248 case ' ':
249 case '\t':
250 case '\r':
251 case '\v':
252 /* White space */
253 ws = not_comment;
254 goto again;
255
256 case '/':
257 {
258 if (*ptr == '/')
259 {
260 /* line comment. Do not include trailing \n */
261 base += 2;
262 for (; *ptr; ptr++)
263 if (*ptr == '\n')
264 break;
265 kind = K_comment;
266 }
267 else if (*ptr == '*')
268 {
269 /* block comment */
270 base += 2;
271 ptr++;
272
273 block_comment:
274 eol = in_comment;
275 in_comment = 1;
276 for (; *ptr; ptr++)
277 {
278 if (*ptr == '\n')
279 {
280 ptr++;
281 break;
282 }
283 if (ptr[0] == '*' && ptr[1] == '/')
284 {
285 in_comment = 2;
286 ptr += 2;
287 break;
288 }
289 }
290 kind = K_comment;
291 }
292 else
293 break;
294 }
295 break;
296
297 case '"':
298 /* quoted string */
299 kind = K_string;
300 while (*ptr)
301 if (*ptr == '"')
302 {
303 ptr++;
304 break;
305 }
306 else if (*ptr++ == '\\')
307 ptr++;
308 break;
309
310 case '.':
311 if (*ptr < '0' || *ptr > '9')
312 {
313 kind = K_dotted;
314 ws = not_comment;
315 goto ident;
316 }
317 /* FALLTHROUGH */
318 case '0'...'9':
319 kind = K_number;
320 goto ident;
321 break;
322
323 case '$': /* local labels. */
324 case '%': /* register names, pseudoes etc */
325 kind = K_ident;
326 goto ident;
327
328 case 'a'...'z':
329 case 'A'...'Z':
330 case '_':
331 kind = K_symbol; /* possible symbol name */
332 ident:
333 for (; *ptr; ptr++)
334 {
335 if (*ptr >= 'A' && *ptr <= 'Z')
336 continue;
337 if (*ptr >= 'a' && *ptr <= 'z')
338 continue;
339 if (*ptr >= '0' && *ptr <= '9')
340 continue;
341 if (*ptr == '_' || *ptr == '$')
342 continue;
343 if (*ptr == '.' && kind != K_dotted)
344 /* Idents starting with a dot, cannot have internal dots. */
345 continue;
346 if ((*ptr == '+' || *ptr == '-')
347 && kind == K_number
348 && (ptr[-1] == 'e' || ptr[-1] == 'E'
349 || ptr[-1] == 'p' || ptr[-1] == 'P'))
350 /* exponent */
351 continue;
352 break;
353 }
354 if (*ptr == ':')
355 {
356 ptr++;
357 kind = K_label;
358 }
359 break;
360 }
361
362 if (alloc == num)
363 {
364 alloc *= 2;
365 toks = XRESIZEVEC (Token, toks, alloc);
366 }
367 Token *tok = toks + num;
368
369 tok->kind = kind;
370 tok->space = ws;
371 tok->end = 0;
372 tok->ptr = base;
373 tok->len = ptr - base - in_comment;
374 in_comment &= 1;
375 not_comment = kind != K_comment;
376 if (eol && num)
377 tok[-1].end = 1;
378 if (!kind)
379 break;
380 }
381
382 return toks;
383 }
384
385 /* Write an encoded token. */
386
387 static void
388 write_token (FILE *out, Token const *tok)
389 {
390 if (tok->space)
391 fputc (' ', out);
392
393 switch (tok->kind)
394 {
395 case K_string:
396 {
397 const char *c = tok->ptr + 1;
398 size_t len = tok->len - 2;
399
400 fputs ("\\\"", out);
401 while (len)
402 {
403 const char *bs = (const char *)memchr (c, '\\', len);
404 size_t l = bs ? bs - c : len;
405
406 fprintf (out, "%.*s", (int)l, c);
407 len -= l;
408 c += l;
409 if (bs)
410 {
411 fputs ("\\\\", out);
412 len--, c++;
413 }
414 }
415 fputs ("\\\"", out);
416 }
417 break;
418
419 default:
420 /* All other tokens shouldn't have anything magic in them */
421 fprintf (out, "%.*s", tok->len, tok->ptr);
422 break;
423 }
424 if (tok->end)
425 fputs ("\\n", out);
426 }
427
428 static void
429 write_tokens (FILE *out, Token const *toks, unsigned len, int spc)
430 {
431 fputs ("\t\"", out);
432 for (; len--; toks++)
433 write_token (out, toks);
434 if (spc)
435 fputs (" ", out);
436 fputs ("\"", out);
437 }
438
439 static Stmt *
440 alloc_stmt (unsigned vis, Token *tokens, Token *end, Token const *sym)
441 {
442 static unsigned alloc = 0;
443 static Stmt *heap = 0;
444
445 if (!alloc)
446 {
447 alloc = 1000;
448 heap = XNEWVEC (Stmt, alloc);
449 }
450
451 Stmt *stmt = heap++;
452 alloc--;
453
454 tokens->space = 0;
455 stmt->next = 0;
456 stmt->vis = vis;
457 stmt->tokens = tokens;
458 stmt->len = end - tokens;
459 stmt->sym = sym ? sym - tokens : ~0;
460
461 return stmt;
462 }
463
464 static Stmt *
465 rev_stmts (Stmt *stmt)
466 {
467 Stmt *prev = 0;
468 Stmt *next;
469
470 while (stmt)
471 {
472 next = stmt->next;
473 stmt->next = prev;
474 prev = stmt;
475 stmt = next;
476 }
477
478 return prev;
479 }
480
481 static void
482 write_stmt (FILE *out, const Stmt *stmt)
483 {
484 if ((stmt->vis & V_mask) != V_comment)
485 {
486 write_tokens (out, stmt->tokens, stmt->len,
487 (stmt->vis & V_mask) == V_pred);
488 fputs (stmt->vis & V_no_eol ? "\t" : "\n", out);
489 }
490 }
491
492 static void
493 write_stmts (FILE *out, const Stmt *stmts)
494 {
495 for (; stmts; stmts = stmts->next)
496 write_stmt (out, stmts);
497 }
498
499 static Token *
500 parse_insn (Token *tok)
501 {
502 unsigned depth = 0;
503
504 do
505 {
506 Stmt *stmt;
507 Token *sym = 0;
508 unsigned s = V_insn;
509 Token *start = tok;
510
511 switch (tok++->kind)
512 {
513 case K_comment:
514 while (tok->kind == K_comment)
515 tok++;
516 stmt = alloc_comment (start, tok);
517 append_stmt (&fns, stmt);
518 continue;
519
520 case '{':
521 depth++;
522 break;
523
524 case '}':
525 depth--;
526 break;
527
528 case K_label:
529 if (tok[-1].ptr[0] != '$')
530 sym = tok - 1;
531 tok[-1].end = 1;
532 s = V_label;
533 break;
534
535 case '@':
536 tok->space = 0;
537 if (tok->kind == '!')
538 tok++;
539 if (tok->kind == K_symbol)
540 sym = tok;
541 tok++;
542 s = V_pred;
543 break;
544
545 default:
546 for (; tok->kind != ';'; tok++)
547 {
548 if (tok->kind == ',')
549 tok[1].space = 0;
550 else if (tok->kind == K_symbol)
551 sym = tok;
552 }
553 tok++->end = 1;
554 break;
555 }
556
557 stmt = alloc_stmt (s, start, tok, sym);
558 append_stmt (&fns, stmt);
559
560 if (!tok[-1].end && tok[0].kind == K_comment)
561 {
562 stmt->vis |= V_no_eol;
563 stmt = alloc_comment (tok, tok + 1);
564 append_stmt (&fns, stmt);
565 tok++;
566 }
567 }
568 while (depth);
569
570 return tok;
571 }
572
573 /* comma separated list of tokens */
574
575 static Token *
576 parse_list_nosemi (Token *tok)
577 {
578 Token *start = tok;
579
580 do
581 if (!(++tok)->kind)
582 break;
583 while ((++tok)->kind == ',');
584
585 tok[-1].end = 1;
586 Stmt *stmt = alloc_stmt (V_dot, start, tok, 0);
587 append_stmt (&decls, stmt);
588
589 return tok;
590 }
591
592 #define is_keyword(T,S) \
593 (sizeof (S) == (T)->len && !memcmp ((T)->ptr + 1, (S), (T)->len - 1))
594
595 static Token *
596 parse_init (Token *tok)
597 {
598 for (;;)
599 {
600 Token *start = tok;
601 Token const *sym = 0;
602 Stmt *stmt;
603
604 if (tok->kind == K_comment)
605 {
606 while (tok->kind == K_comment)
607 tok++;
608 stmt = alloc_comment (start, tok);
609 append_stmt (&vars, stmt);
610 start = tok;
611 }
612
613 if (tok->kind == '{')
614 tok[1].space = 0;
615 for (; tok->kind != ',' && tok->kind != ';'; tok++)
616 if (tok->kind == K_symbol)
617 sym = tok;
618 tok[1].space = 0;
619 int end = tok++->kind == ';';
620 stmt = alloc_stmt (V_insn, start, tok, sym);
621 append_stmt (&vars, stmt);
622 if (!tok[-1].end && tok->kind == K_comment)
623 {
624 stmt->vis |= V_no_eol;
625 stmt = alloc_comment (tok, tok + 1);
626 append_stmt (&vars, stmt);
627 tok++;
628 }
629 if (end)
630 break;
631 }
632 return tok;
633 }
634
635 static Token *
636 parse_file (Token *tok)
637 {
638 Stmt *comment = 0;
639
640 if (tok->kind == K_comment)
641 {
642 Token *start = tok;
643
644 while (tok->kind == K_comment)
645 {
646 if (strncmp (tok->ptr, ":VAR_MAP ", 9) == 0)
647 record_id (tok->ptr + 9, &vars_tail);
648 if (strncmp (tok->ptr, ":FUNC_MAP ", 10) == 0)
649 record_id (tok->ptr + 10, &funcs_tail);
650 tok++;
651 }
652 comment = alloc_comment (start, tok);
653 comment->vis |= V_prefix_comment;
654 }
655
656 if (tok->kind == K_dotted)
657 {
658 if (is_keyword (tok, "version")
659 || is_keyword (tok, "target")
660 || is_keyword (tok, "address_size"))
661 {
662 if (comment)
663 append_stmt (&decls, comment);
664 tok = parse_list_nosemi (tok);
665 }
666 else
667 {
668 unsigned vis = 0;
669 const Token *def = 0;
670 unsigned is_decl = 0;
671 Token *start;
672
673 for (start = tok;
674 tok->kind && tok->kind != '=' && tok->kind != K_comment
675 && tok->kind != '{' && tok->kind != ';'; tok++)
676 {
677 if (is_keyword (tok, "global")
678 || is_keyword (tok, "const"))
679 vis |= V_var;
680 else if (is_keyword (tok, "func")
681 || is_keyword (tok, "entry"))
682 vis |= V_func;
683 else if (is_keyword (tok, "visible"))
684 vis |= V_global;
685 else if (is_keyword (tok, "extern"))
686 is_decl = 1;
687 else if (is_keyword (tok, "weak"))
688 vis |= V_weak;
689 if (tok->kind == '(')
690 {
691 tok[1].space = 0;
692 tok[0].space = 1;
693 }
694 else if (tok->kind == ')' && tok[1].kind != ';')
695 tok[1].space = 1;
696
697 if (tok->kind == K_symbol)
698 def = tok;
699 }
700
701 if (!tok->kind)
702 {
703 /* end of file */
704 if (comment)
705 append_stmt (&fns, comment);
706 }
707 else if (tok->kind == '{'
708 || tok->kind == K_comment)
709 {
710 /* function defn */
711 Stmt *stmt = alloc_stmt (vis, start, tok, def);
712 if (comment)
713 {
714 append_stmt (&fns, comment);
715 stmt->vis |= V_prefix_comment;
716 }
717 append_stmt (&fns, stmt);
718 tok = parse_insn (tok);
719 }
720 else
721 {
722 int assign = tok->kind == '=';
723
724 tok++->end = 1;
725 if ((vis & V_mask) == V_var && !is_decl)
726 {
727 /* variable */
728 Stmt *stmt = alloc_stmt (vis, start, tok, def);
729 if (comment)
730 {
731 append_stmt (&vars, comment);
732 stmt->vis |= V_prefix_comment;
733 }
734 append_stmt (&vars, stmt);
735 if (assign)
736 tok = parse_init (tok);
737 }
738 else
739 {
740 /* declaration */
741 Stmt *stmt = alloc_stmt (vis, start, tok, 0);
742 if (comment)
743 {
744 append_stmt (&decls, comment);
745 stmt->vis |= V_prefix_comment;
746 }
747 append_stmt (&decls, stmt);
748 }
749 }
750 }
751 }
752 else
753 {
754 /* Something strange. Ignore it. */
755 if (comment)
756 append_stmt (&fns, comment);
757
758 do
759 tok++;
760 while (tok->kind && !tok->end);
761 }
762 return tok;
763 }
764
765 /* Parse STR, saving found tokens into PVALUES and return their number.
766 Tokens are assumed to be delimited by ':'. */
767 static unsigned
768 parse_env_var (const char *str, char ***pvalues)
769 {
770 const char *curval, *nextval;
771 char **values;
772 unsigned num = 1, i;
773
774 curval = strchr (str, ':');
775 while (curval)
776 {
777 num++;
778 curval = strchr (curval + 1, ':');
779 }
780
781 values = (char **) xmalloc (num * sizeof (char *));
782 curval = str;
783 nextval = strchr (curval, ':');
784 if (nextval == NULL)
785 nextval = strchr (curval, '\0');
786
787 for (i = 0; i < num; i++)
788 {
789 int l = nextval - curval;
790 values[i] = (char *) xmalloc (l + 1);
791 memcpy (values[i], curval, l);
792 values[i][l] = 0;
793 curval = nextval + 1;
794 nextval = strchr (curval, ':');
795 if (nextval == NULL)
796 nextval = strchr (curval, '\0');
797 }
798 *pvalues = values;
799 return num;
800 }
801
802 /* Auxiliary function that frees elements of PTR and PTR itself.
803 N is number of elements to be freed. If PTR is NULL, nothing is freed.
804 If an element is NULL, subsequent elements are not freed. */
805 static void
806 free_array_of_ptrs (void **ptr, unsigned n)
807 {
808 unsigned i;
809 if (!ptr)
810 return;
811 for (i = 0; i < n; i++)
812 {
813 if (!ptr[i])
814 break;
815 free (ptr[i]);
816 }
817 free (ptr);
818 return;
819 }
820
821 /* Check whether NAME can be accessed in MODE. This is like access,
822 except that it never considers directories to be executable. */
823 static int
824 access_check (const char *name, int mode)
825 {
826 if (mode == X_OK)
827 {
828 struct stat st;
829
830 if (stat (name, &st) < 0 || S_ISDIR (st.st_mode))
831 return -1;
832 }
833
834 return access (name, mode);
835 }
836
837 static void
838 process (FILE *in, FILE *out)
839 {
840 const char *input = read_file (in);
841 Token *tok = tokenize (input);
842 unsigned int nvars = 0, nfuncs = 0;
843
844 do
845 tok = parse_file (tok);
846 while (tok->kind);
847
848 fprintf (out, "static const char ptx_code[] = \n");
849 write_stmts (out, rev_stmts (decls));
850 write_stmts (out, rev_stmts (vars));
851 write_stmts (out, rev_stmts (fns));
852 fprintf (out, ";\n\n");
853 fprintf (out, "static const char *var_mappings[] = {\n");
854 for (id_map *id = var_ids; id; id = id->next, nvars++)
855 fprintf (out, "\t\"%s\"%s\n", id->ptx_name, id->next ? "," : "");
856 fprintf (out, "};\n\n");
857 fprintf (out, "static const char *func_mappings[] = {\n");
858 for (id_map *id = func_ids; id; id = id->next, nfuncs++)
859 fprintf (out, "\t\"%s\"%s\n", id->ptx_name, id->next ? "," : "");
860 fprintf (out, "};\n\n");
861
862 fprintf (out, "static const void *target_data[] = {\n");
863 fprintf (out, " ptx_code, (void*) %u, var_mappings, (void*) %u, "
864 "func_mappings\n", nvars, nfuncs);
865 fprintf (out, "};\n\n");
866
867 fprintf (out, "extern void GOMP_offload_register (const void *, int, void *);\n");
868
869 fprintf (out, "extern void *__OFFLOAD_TABLE__[];\n\n");
870 fprintf (out, "static __attribute__((constructor)) void init (void)\n{\n");
871 fprintf (out, " GOMP_offload_register (__OFFLOAD_TABLE__, %d,\n",
872 GOMP_DEVICE_NVIDIA_PTX);
873 fprintf (out, " &target_data);\n");
874 fprintf (out, "};\n");
875 }
876
877 static void
878 compile_native (const char *infile, const char *outfile, const char *compiler)
879 {
880 const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
881 if (!collect_gcc_options)
882 fatal_error (input_location,
883 "environment variable COLLECT_GCC_OPTIONS must be set");
884
885 struct obstack argv_obstack;
886 obstack_init (&argv_obstack);
887 obstack_ptr_grow (&argv_obstack, compiler);
888 obstack_ptr_grow (&argv_obstack, infile);
889 obstack_ptr_grow (&argv_obstack, "-c");
890 obstack_ptr_grow (&argv_obstack, "-o");
891 obstack_ptr_grow (&argv_obstack, outfile);
892 obstack_ptr_grow (&argv_obstack, NULL);
893
894 const char **new_argv = XOBFINISH (&argv_obstack, const char **);
895 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
896 obstack_free (&argv_obstack, NULL);
897 }
898
899 int
900 main (int argc, char **argv)
901 {
902 FILE *in = stdin;
903 FILE *out = stdout;
904 const char *outname = 0;
905
906 progname = "mkoffload";
907 diagnostic_initialize (global_dc, 0);
908
909 char *collect_gcc = getenv ("COLLECT_GCC");
910 if (collect_gcc == NULL)
911 fatal_error (input_location, "COLLECT_GCC must be set.");
912 const char *gcc_path = dirname (ASTRDUP (collect_gcc));
913 const char *gcc_exec = basename (ASTRDUP (collect_gcc));
914
915 size_t len = (strlen (gcc_path) + 1
916 + strlen (GCC_INSTALL_NAME)
917 + 1);
918 char *driver = XALLOCAVEC (char, len);
919
920 if (strcmp (gcc_exec, collect_gcc) == 0)
921 /* collect_gcc has no path, so it was found in PATH. Make sure we also
922 find accel-gcc in PATH. */
923 gcc_path = NULL;
924
925 int driver_used = 0;
926 if (gcc_path != NULL)
927 driver_used = sprintf (driver, "%s/", gcc_path);
928 sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME);
929
930 bool found = false;
931 if (gcc_path == NULL)
932 found = true;
933 else if (access_check (driver, X_OK) == 0)
934 found = true;
935 else
936 {
937 /* Don't use alloca pointer with XRESIZEVEC. */
938 driver = NULL;
939 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */
940 char **paths = NULL;
941 unsigned n_paths;
942 n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
943 for (unsigned i = 0; i < n_paths; i++)
944 {
945 len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1;
946 driver = XRESIZEVEC (char, driver, len);
947 sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME);
948 if (access_check (driver, X_OK) == 0)
949 {
950 found = true;
951 break;
952 }
953 }
954 free_array_of_ptrs ((void **) paths, n_paths);
955 }
956
957 if (!found)
958 fatal_error (input_location,
959 "offload compiler %s not found", GCC_INSTALL_NAME);
960
961 /* We may be called with all the arguments stored in some file and
962 passed with @file. Expand them into argv before processing. */
963 expandargv (&argc, &argv);
964
965 struct obstack argv_obstack;
966 obstack_init (&argv_obstack);
967 obstack_ptr_grow (&argv_obstack, driver);
968 obstack_ptr_grow (&argv_obstack, "-xlto");
969 obstack_ptr_grow (&argv_obstack, "-m64");
970 obstack_ptr_grow (&argv_obstack, "-S");
971
972 for (int ix = 1; ix != argc; ix++)
973 {
974 if (!strcmp (argv[ix], "-o") && ix + 1 != argc)
975 outname = argv[++ix];
976 else
977 obstack_ptr_grow (&argv_obstack, argv[ix]);
978 }
979
980 ptx_name = make_temp_file (".mkoffload");
981 obstack_ptr_grow (&argv_obstack, "-o");
982 obstack_ptr_grow (&argv_obstack, ptx_name);
983 obstack_ptr_grow (&argv_obstack, NULL);
984 const char **new_argv = XOBFINISH (&argv_obstack, const char **);
985
986 char *execpath = getenv ("GCC_EXEC_PREFIX");
987 char *cpath = getenv ("COMPILER_PATH");
988 char *lpath = getenv ("LIBRARY_PATH");
989 unsetenv ("GCC_EXEC_PREFIX");
990 unsetenv ("COMPILER_PATH");
991 unsetenv ("LIBRARY_PATH");
992
993 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
994 obstack_free (&argv_obstack, NULL);
995
996 xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL));
997 xputenv (concat ("COMPILER_PATH=", cpath, NULL));
998 xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
999
1000 in = fopen (ptx_name, "r");
1001 if (!in)
1002 fatal_error (input_location, "cannot open intermediate ptx file");
1003
1004 ptx_cfile_name = make_temp_file (".c");
1005
1006 out = fopen (ptx_cfile_name, "w");
1007 if (!out)
1008 fatal_error (input_location, "cannot open '%s'", ptx_cfile_name);
1009
1010 process (in, out);
1011 fclose (out);
1012
1013 compile_native (ptx_cfile_name, outname, collect_gcc);
1014
1015 utils_cleanup (false);
1016
1017 return 0;
1018 }