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