Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/gcn/mkoffload.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* Offload image generation tool for AMD GCN. | |
2 | |
3 Copyright (C) 2014-2020 Free Software Foundation, Inc. | |
4 | |
5 This file is part of GCC. | |
6 | |
7 GCC is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published | |
9 by the Free Software Foundation; either version 3, or (at your | |
10 option) any later version. | |
11 | |
12 GCC is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
15 License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GCC; see the file COPYING3. If not see | |
19 <http://www.gnu.org/licenses/>. */ | |
20 | |
21 /* Munges GCN assembly into a C source file defining the GCN code as a | |
22 string. | |
23 | |
24 This is not a complete assembler. We presume the source is well | |
25 formed from the compiler and can die horribly if it is not. */ | |
26 | |
27 #include "config.h" | |
28 #include "system.h" | |
29 #include "coretypes.h" | |
30 #include "obstack.h" | |
31 #include "diagnostic.h" | |
32 #include "intl.h" | |
33 #include <libgen.h> | |
34 #include "collect-utils.h" | |
35 #include "gomp-constants.h" | |
36 | |
37 const char tool_name[] = "gcn mkoffload"; | |
38 | |
39 /* Files to unlink. */ | |
40 static const char *gcn_s1_name; | |
41 static const char *gcn_s2_name; | |
42 static const char *gcn_o_name; | |
43 static const char *gcn_cfile_name; | |
44 | |
45 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET; | |
46 | |
47 /* Delete tempfiles. */ | |
48 | |
49 void | |
50 tool_cleanup (bool from_signal ATTRIBUTE_UNUSED) | |
51 { | |
52 if (gcn_cfile_name) | |
53 maybe_unlink (gcn_cfile_name); | |
54 if (gcn_s1_name) | |
55 maybe_unlink (gcn_s1_name); | |
56 if (gcn_s2_name) | |
57 maybe_unlink (gcn_s2_name); | |
58 if (gcn_o_name) | |
59 maybe_unlink (gcn_o_name); | |
60 } | |
61 | |
62 static void | |
63 mkoffload_cleanup (void) | |
64 { | |
65 tool_cleanup (false); | |
66 } | |
67 | |
68 /* Unlink FILE unless requested otherwise. */ | |
69 | |
70 void | |
71 maybe_unlink (const char *file) | |
72 { | |
73 if (!save_temps) | |
74 { | |
75 if (unlink_if_ordinary (file) && errno != ENOENT) | |
76 fatal_error (input_location, "deleting file %s: %m", file); | |
77 } | |
78 else if (verbose) | |
79 fprintf (stderr, "[Leaving %s]\n", file); | |
80 } | |
81 | |
82 /* Add or change the value of an environment variable, outputting the | |
83 change to standard error if in verbose mode. */ | |
84 | |
85 static void | |
86 xputenv (const char *string) | |
87 { | |
88 if (verbose) | |
89 fprintf (stderr, "%s\n", string); | |
90 putenv (CONST_CAST (char *, string)); | |
91 } | |
92 | |
93 /* Read the whole input file. It will be NUL terminated (but | |
94 remember, there could be a NUL in the file itself. */ | |
95 | |
96 static const char * | |
97 read_file (FILE *stream, size_t *plen) | |
98 { | |
99 size_t alloc = 16384; | |
100 size_t base = 0; | |
101 char *buffer; | |
102 | |
103 if (!fseek (stream, 0, SEEK_END)) | |
104 { | |
105 /* Get the file size. */ | |
106 long s = ftell (stream); | |
107 if (s >= 0) | |
108 alloc = s + 100; | |
109 fseek (stream, 0, SEEK_SET); | |
110 } | |
111 buffer = XNEWVEC (char, alloc); | |
112 | |
113 for (;;) | |
114 { | |
115 size_t n = fread (buffer + base, 1, alloc - base - 1, stream); | |
116 | |
117 if (!n) | |
118 break; | |
119 base += n; | |
120 if (base + 1 == alloc) | |
121 { | |
122 alloc *= 2; | |
123 buffer = XRESIZEVEC (char, buffer, alloc); | |
124 } | |
125 } | |
126 buffer[base] = 0; | |
127 *plen = base; | |
128 return buffer; | |
129 } | |
130 | |
131 /* Parse STR, saving found tokens into PVALUES and return their number. | |
132 Tokens are assumed to be delimited by ':'. */ | |
133 | |
134 static unsigned | |
135 parse_env_var (const char *str, char ***pvalues) | |
136 { | |
137 const char *curval, *nextval; | |
138 char **values; | |
139 unsigned num = 1, i; | |
140 | |
141 curval = strchr (str, ':'); | |
142 while (curval) | |
143 { | |
144 num++; | |
145 curval = strchr (curval + 1, ':'); | |
146 } | |
147 | |
148 values = (char **) xmalloc (num * sizeof (char *)); | |
149 curval = str; | |
150 nextval = strchr (curval, ':'); | |
151 if (nextval == NULL) | |
152 nextval = strchr (curval, '\0'); | |
153 | |
154 for (i = 0; i < num; i++) | |
155 { | |
156 int l = nextval - curval; | |
157 values[i] = (char *) xmalloc (l + 1); | |
158 memcpy (values[i], curval, l); | |
159 values[i][l] = 0; | |
160 curval = nextval + 1; | |
161 nextval = strchr (curval, ':'); | |
162 if (nextval == NULL) | |
163 nextval = strchr (curval, '\0'); | |
164 } | |
165 *pvalues = values; | |
166 return num; | |
167 } | |
168 | |
169 /* Auxiliary function that frees elements of PTR and PTR itself. | |
170 N is number of elements to be freed. If PTR is NULL, nothing is freed. | |
171 If an element is NULL, subsequent elements are not freed. */ | |
172 | |
173 static void | |
174 free_array_of_ptrs (void **ptr, unsigned n) | |
175 { | |
176 unsigned i; | |
177 if (!ptr) | |
178 return; | |
179 for (i = 0; i < n; i++) | |
180 { | |
181 if (!ptr[i]) | |
182 break; | |
183 free (ptr[i]); | |
184 } | |
185 free (ptr); | |
186 return; | |
187 } | |
188 | |
189 /* Check whether NAME can be accessed in MODE. This is like access, | |
190 except that it never considers directories to be executable. */ | |
191 | |
192 static int | |
193 access_check (const char *name, int mode) | |
194 { | |
195 if (mode == X_OK) | |
196 { | |
197 struct stat st; | |
198 | |
199 if (stat (name, &st) < 0 || S_ISDIR (st.st_mode)) | |
200 return -1; | |
201 } | |
202 | |
203 return access (name, mode); | |
204 } | |
205 | |
206 /* Parse an input assembler file, extract the offload tables etc., | |
207 and output (1) the assembler code, minus the tables (which can contain | |
208 problematic relocations), and (2) a C file with the offload tables | |
209 encoded as structured data. */ | |
210 | |
211 static void | |
212 process_asm (FILE *in, FILE *out, FILE *cfile) | |
213 { | |
214 int fn_count = 0, var_count = 0, dims_count = 0, regcount_count = 0; | |
215 struct obstack fns_os, vars_os, varsizes_os, dims_os, regcounts_os; | |
216 obstack_init (&fns_os); | |
217 obstack_init (&vars_os); | |
218 obstack_init (&varsizes_os); | |
219 obstack_init (&dims_os); | |
220 obstack_init (®counts_os); | |
221 | |
222 struct oaccdims | |
223 { | |
224 int d[3]; | |
225 char *name; | |
226 } dim; | |
227 | |
228 struct regcount | |
229 { | |
230 int sgpr_count; | |
231 int vgpr_count; | |
232 char *kernel_name; | |
233 } regcount; | |
234 | |
235 /* Always add _init_array and _fini_array as kernels. */ | |
236 obstack_ptr_grow (&fns_os, xstrdup ("_init_array")); | |
237 obstack_ptr_grow (&fns_os, xstrdup ("_fini_array")); | |
238 fn_count += 2; | |
239 | |
240 char buf[1000]; | |
241 enum { IN_CODE, IN_AMD_KERNEL_CODE_T, IN_VARS, IN_FUNCS } state = IN_CODE; | |
242 while (fgets (buf, sizeof (buf), in)) | |
243 { | |
244 switch (state) | |
245 { | |
246 case IN_CODE: | |
247 { | |
248 if (sscanf (buf, " ;; OPENACC-DIMS: %d, %d, %d : %ms\n", | |
249 &dim.d[0], &dim.d[1], &dim.d[2], &dim.name) == 4) | |
250 { | |
251 obstack_grow (&dims_os, &dim, sizeof (dim)); | |
252 dims_count++; | |
253 } | |
254 else if (sscanf (buf, " .amdgpu_hsa_kernel %ms\n", | |
255 ®count.kernel_name) == 1) | |
256 break; | |
257 | |
258 break; | |
259 } | |
260 case IN_AMD_KERNEL_CODE_T: | |
261 { | |
262 gcc_assert (regcount.kernel_name); | |
263 if (sscanf (buf, " wavefront_sgpr_count = %d\n", | |
264 ®count.sgpr_count) == 1) | |
265 break; | |
266 else if (sscanf (buf, " workitem_vgpr_count = %d\n", | |
267 ®count.vgpr_count) == 1) | |
268 break; | |
269 | |
270 break; | |
271 } | |
272 case IN_VARS: | |
273 { | |
274 char *varname; | |
275 unsigned varsize; | |
276 if (sscanf (buf, " .8byte %ms\n", &varname)) | |
277 { | |
278 obstack_ptr_grow (&vars_os, varname); | |
279 fgets (buf, sizeof (buf), in); | |
280 if (!sscanf (buf, " .8byte %u\n", &varsize)) | |
281 abort (); | |
282 obstack_int_grow (&varsizes_os, varsize); | |
283 var_count++; | |
284 | |
285 /* The HSA Runtime cannot locate the symbol if it is not | |
286 exported from the kernel. */ | |
287 fprintf (out, "\t.global %s\n", varname); | |
288 } | |
289 break; | |
290 } | |
291 case IN_FUNCS: | |
292 { | |
293 char *funcname; | |
294 if (sscanf (buf, "\t.8byte\t%ms\n", &funcname)) | |
295 { | |
296 obstack_ptr_grow (&fns_os, funcname); | |
297 fn_count++; | |
298 continue; | |
299 } | |
300 break; | |
301 } | |
302 } | |
303 | |
304 char dummy; | |
305 if (sscanf (buf, " .section .gnu.offload_vars%c", &dummy) > 0) | |
306 state = IN_VARS; | |
307 else if (sscanf (buf, " .section .gnu.offload_funcs%c", &dummy) > 0) | |
308 state = IN_FUNCS; | |
309 else if (sscanf (buf, " .amd_kernel_code_%c", &dummy) > 0) | |
310 { | |
311 state = IN_AMD_KERNEL_CODE_T; | |
312 regcount.sgpr_count = regcount.vgpr_count = -1; | |
313 } | |
314 else if (sscanf (buf, " .section %c", &dummy) > 0 | |
315 || sscanf (buf, " .text%c", &dummy) > 0 | |
316 || sscanf (buf, " .bss%c", &dummy) > 0 | |
317 || sscanf (buf, " .data%c", &dummy) > 0 | |
318 || sscanf (buf, " .ident %c", &dummy) > 0) | |
319 state = IN_CODE; | |
320 else if (sscanf (buf, " .end_amd_kernel_code_%c", &dummy) > 0) | |
321 { | |
322 state = IN_CODE; | |
323 gcc_assert (regcount.kernel_name != NULL | |
324 && regcount.sgpr_count >= 0 | |
325 && regcount.vgpr_count >= 0); | |
326 obstack_grow (®counts_os, ®count, sizeof (regcount)); | |
327 regcount_count++; | |
328 regcount.kernel_name = NULL; | |
329 regcount.sgpr_count = regcount.vgpr_count = -1; | |
330 } | |
331 | |
332 if (state == IN_CODE || state == IN_AMD_KERNEL_CODE_T) | |
333 fputs (buf, out); | |
334 } | |
335 | |
336 char **fns = XOBFINISH (&fns_os, char **); | |
337 struct oaccdims *dims = XOBFINISH (&dims_os, struct oaccdims *); | |
338 struct regcount *regcounts = XOBFINISH (®counts_os, struct regcount *); | |
339 | |
340 fprintf (cfile, "#include <stdlib.h>\n"); | |
341 fprintf (cfile, "#include <stdbool.h>\n\n"); | |
342 | |
343 char **vars = XOBFINISH (&vars_os, char **); | |
344 unsigned *varsizes = XOBFINISH (&varsizes_os, unsigned *); | |
345 fprintf (cfile, | |
346 "static const struct global_var_info {\n" | |
347 " const char *name;\n" | |
348 " void *address;\n" | |
349 "} vars[] = {\n"); | |
350 int i; | |
351 for (i = 0; i < var_count; ++i) | |
352 { | |
353 const char *sep = i < var_count - 1 ? "," : " "; | |
354 fprintf (cfile, " { \"%s\", NULL }%s /* size: %u */\n", vars[i], sep, | |
355 varsizes[i]); | |
356 } | |
357 fprintf (cfile, "};\n\n"); | |
358 | |
359 obstack_free (&vars_os, NULL); | |
360 obstack_free (&varsizes_os, NULL); | |
361 | |
362 /* Dump out function idents. */ | |
363 fprintf (cfile, "static const struct hsa_kernel_description {\n" | |
364 " const char *name;\n" | |
365 " int oacc_dims[3];\n" | |
366 " int sgpr_count;\n" | |
367 " int vgpr_count;\n" | |
368 "} gcn_kernels[] = {\n "); | |
369 dim.d[0] = dim.d[1] = dim.d[2] = 0; | |
370 const char *comma; | |
371 for (comma = "", i = 0; i < fn_count; comma = ",\n ", i++) | |
372 { | |
373 /* Find if we recorded dimensions for this function. */ | |
374 int *d = dim.d; /* Previously zeroed. */ | |
375 int sgpr_count = 0; | |
376 int vgpr_count = 0; | |
377 for (int j = 0; j < dims_count; j++) | |
378 if (strcmp (fns[i], dims[j].name) == 0) | |
379 { | |
380 d = dims[j].d; | |
381 break; | |
382 } | |
383 for (int j = 0; j < regcount_count; j++) | |
384 if (strcmp (fns[i], regcounts[j].kernel_name) == 0) | |
385 { | |
386 sgpr_count = regcounts[j].sgpr_count; | |
387 vgpr_count = regcounts[j].vgpr_count; | |
388 break; | |
389 } | |
390 | |
391 fprintf (cfile, "%s{\"%s\", {%d, %d, %d}, %d, %d}", comma, | |
392 fns[i], d[0], d[1], d[2], sgpr_count, vgpr_count); | |
393 | |
394 free (fns[i]); | |
395 } | |
396 fprintf (cfile, "\n};\n\n"); | |
397 | |
398 obstack_free (&fns_os, NULL); | |
399 for (i = 0; i < dims_count; i++) | |
400 free (dims[i].name); | |
401 for (i = 0; i < regcount_count; i++) | |
402 free (regcounts[i].kernel_name); | |
403 obstack_free (&dims_os, NULL); | |
404 obstack_free (®counts_os, NULL); | |
405 } | |
406 | |
407 /* Embed an object file into a C source file. */ | |
408 | |
409 static void | |
410 process_obj (FILE *in, FILE *cfile) | |
411 { | |
412 size_t len = 0; | |
413 const char *input = read_file (in, &len); | |
414 | |
415 /* Dump out an array containing the binary. | |
416 FIXME: do this with objcopy. */ | |
417 fprintf (cfile, "static unsigned char gcn_code[] = {"); | |
418 for (size_t i = 0; i < len; i += 17) | |
419 { | |
420 fprintf (cfile, "\n\t"); | |
421 for (size_t j = i; j < i + 17 && j < len; j++) | |
422 fprintf (cfile, "%3u,", (unsigned char) input[j]); | |
423 } | |
424 fprintf (cfile, "\n};\n\n"); | |
425 | |
426 fprintf (cfile, | |
427 "static const struct gcn_image {\n" | |
428 " size_t size;\n" | |
429 " void *image;\n" | |
430 "} gcn_image = {\n" | |
431 " %zu,\n" | |
432 " gcn_code\n" | |
433 "};\n\n", | |
434 len); | |
435 | |
436 fprintf (cfile, | |
437 "static const struct gcn_image_desc {\n" | |
438 " const struct gcn_image *gcn_image;\n" | |
439 " unsigned kernel_count;\n" | |
440 " const struct hsa_kernel_description *kernel_infos;\n" | |
441 " unsigned global_variable_count;\n" | |
442 " const struct global_var_info *global_variables;\n" | |
443 "} target_data = {\n" | |
444 " &gcn_image,\n" | |
445 " sizeof (gcn_kernels) / sizeof (gcn_kernels[0]),\n" | |
446 " gcn_kernels,\n" | |
447 " sizeof (vars) / sizeof (vars[0]),\n" | |
448 " vars\n" | |
449 "};\n\n"); | |
450 | |
451 fprintf (cfile, | |
452 "#ifdef __cplusplus\n" | |
453 "extern \"C\" {\n" | |
454 "#endif\n" | |
455 "extern void GOMP_offload_register_ver" | |
456 " (unsigned, const void *, int, const void *);\n" | |
457 "extern void GOMP_offload_unregister_ver" | |
458 " (unsigned, const void *, int, const void *);\n" | |
459 "#ifdef __cplusplus\n" | |
460 "}\n" | |
461 "#endif\n\n"); | |
462 | |
463 fprintf (cfile, "extern const void *const __OFFLOAD_TABLE__[];\n\n"); | |
464 | |
465 fprintf (cfile, "static __attribute__((constructor)) void init (void)\n" | |
466 "{\n" | |
467 " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__," | |
468 " %d/*GCN*/, &target_data);\n" | |
469 "};\n", | |
470 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_GCN), | |
471 GOMP_DEVICE_GCN); | |
472 | |
473 fprintf (cfile, "static __attribute__((destructor)) void fini (void)\n" | |
474 "{\n" | |
475 " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__," | |
476 " %d/*GCN*/, &target_data);\n" | |
477 "};\n", | |
478 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_GCN), | |
479 GOMP_DEVICE_GCN); | |
480 } | |
481 | |
482 /* Compile a C file using the host compiler. */ | |
483 | |
484 static void | |
485 compile_native (const char *infile, const char *outfile, const char *compiler) | |
486 { | |
487 const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS"); | |
488 if (!collect_gcc_options) | |
489 fatal_error (input_location, | |
490 "environment variable COLLECT_GCC_OPTIONS must be set"); | |
491 | |
492 struct obstack argv_obstack; | |
493 obstack_init (&argv_obstack); | |
494 obstack_ptr_grow (&argv_obstack, compiler); | |
495 if (save_temps) | |
496 obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
497 if (verbose) | |
498 obstack_ptr_grow (&argv_obstack, "-v"); | |
499 switch (offload_abi) | |
500 { | |
501 case OFFLOAD_ABI_LP64: | |
502 obstack_ptr_grow (&argv_obstack, "-m64"); | |
503 break; | |
504 case OFFLOAD_ABI_ILP32: | |
505 obstack_ptr_grow (&argv_obstack, "-m32"); | |
506 break; | |
507 default: | |
508 gcc_unreachable (); | |
509 } | |
510 obstack_ptr_grow (&argv_obstack, infile); | |
511 obstack_ptr_grow (&argv_obstack, "-c"); | |
512 obstack_ptr_grow (&argv_obstack, "-o"); | |
513 obstack_ptr_grow (&argv_obstack, outfile); | |
514 obstack_ptr_grow (&argv_obstack, NULL); | |
515 | |
516 const char **new_argv = XOBFINISH (&argv_obstack, const char **); | |
517 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); | |
518 obstack_free (&argv_obstack, NULL); | |
519 } | |
520 | |
521 int | |
522 main (int argc, char **argv) | |
523 { | |
524 FILE *in = stdin; | |
525 FILE *out = stdout; | |
526 FILE *cfile = stdout; | |
527 const char *outname = 0, *offloadsrc = 0; | |
528 | |
529 progname = "mkoffload"; | |
530 diagnostic_initialize (global_dc, 0); | |
531 | |
532 if (atexit (mkoffload_cleanup) != 0) | |
533 fatal_error (input_location, "atexit failed"); | |
534 | |
535 char *collect_gcc = getenv ("COLLECT_GCC"); | |
536 if (collect_gcc == NULL) | |
537 fatal_error (input_location, "COLLECT_GCC must be set."); | |
538 const char *gcc_path = dirname (ASTRDUP (collect_gcc)); | |
539 const char *gcc_exec = basename (ASTRDUP (collect_gcc)); | |
540 | |
541 size_t len = (strlen (gcc_path) + 1 + strlen (GCC_INSTALL_NAME) + 1); | |
542 char *driver = XALLOCAVEC (char, len); | |
543 | |
544 if (strcmp (gcc_exec, collect_gcc) == 0) | |
545 /* collect_gcc has no path, so it was found in PATH. Make sure we also | |
546 find accel-gcc in PATH. */ | |
547 gcc_path = NULL; | |
548 | |
549 int driver_used = 0; | |
550 if (gcc_path != NULL) | |
551 driver_used = sprintf (driver, "%s/", gcc_path); | |
552 sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME); | |
553 | |
554 bool found = false; | |
555 if (gcc_path == NULL) | |
556 found = true; | |
557 else if (access_check (driver, X_OK) == 0) | |
558 found = true; | |
559 else | |
560 { | |
561 /* Don't use alloca pointer with XRESIZEVEC. */ | |
562 driver = NULL; | |
563 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */ | |
564 char **paths = NULL; | |
565 unsigned n_paths; | |
566 n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths); | |
567 for (unsigned i = 0; i < n_paths; i++) | |
568 { | |
569 len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1; | |
570 driver = XRESIZEVEC (char, driver, len); | |
571 sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME); | |
572 if (access_check (driver, X_OK) == 0) | |
573 { | |
574 found = true; | |
575 break; | |
576 } | |
577 } | |
578 free_array_of_ptrs ((void **) paths, n_paths); | |
579 } | |
580 | |
581 if (!found) | |
582 fatal_error (input_location, | |
583 "offload compiler %s not found", GCC_INSTALL_NAME); | |
584 | |
585 /* We may be called with all the arguments stored in some file and | |
586 passed with @file. Expand them into argv before processing. */ | |
587 expandargv (&argc, &argv); | |
588 | |
589 /* Scan the argument vector. */ | |
590 bool fopenmp = false; | |
591 bool fopenacc = false; | |
592 for (int i = 1; i < argc; i++) | |
593 { | |
594 #define STR "-foffload-abi=" | |
595 if (strncmp (argv[i], STR, strlen (STR)) == 0) | |
596 { | |
597 if (strcmp (argv[i] + strlen (STR), "lp64") == 0) | |
598 offload_abi = OFFLOAD_ABI_LP64; | |
599 else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0) | |
600 offload_abi = OFFLOAD_ABI_ILP32; | |
601 else | |
602 fatal_error (input_location, | |
603 "unrecognizable argument of option " STR); | |
604 } | |
605 #undef STR | |
606 else if (strcmp (argv[i], "-fopenmp") == 0) | |
607 fopenmp = true; | |
608 else if (strcmp (argv[i], "-fopenacc") == 0) | |
609 fopenacc = true; | |
610 else if (strcmp (argv[i], "-save-temps") == 0) | |
611 save_temps = true; | |
612 else if (strcmp (argv[i], "-v") == 0) | |
613 verbose = true; | |
614 } | |
615 if (!(fopenacc ^ fopenmp)) | |
616 fatal_error (input_location, "either -fopenacc or -fopenmp must be set"); | |
617 | |
618 const char *abi; | |
619 switch (offload_abi) | |
620 { | |
621 case OFFLOAD_ABI_LP64: | |
622 abi = "-m64"; | |
623 break; | |
624 case OFFLOAD_ABI_ILP32: | |
625 abi = "-m32"; | |
626 break; | |
627 default: | |
628 gcc_unreachable (); | |
629 } | |
630 | |
631 gcn_s1_name = make_temp_file (".mkoffload.1.s"); | |
632 gcn_s2_name = make_temp_file (".mkoffload.2.s"); | |
633 gcn_o_name = make_temp_file (".mkoffload.hsaco"); | |
634 gcn_cfile_name = make_temp_file (".c"); | |
635 | |
636 /* Build arguments for compiler pass. */ | |
637 struct obstack cc_argv_obstack; | |
638 obstack_init (&cc_argv_obstack); | |
639 obstack_ptr_grow (&cc_argv_obstack, driver); | |
640 obstack_ptr_grow (&cc_argv_obstack, "-S"); | |
641 | |
642 if (save_temps) | |
643 obstack_ptr_grow (&cc_argv_obstack, "-save-temps"); | |
644 if (verbose) | |
645 obstack_ptr_grow (&cc_argv_obstack, "-v"); | |
646 obstack_ptr_grow (&cc_argv_obstack, abi); | |
647 obstack_ptr_grow (&cc_argv_obstack, "-xlto"); | |
648 if (fopenmp) | |
649 obstack_ptr_grow (&cc_argv_obstack, "-mgomp"); | |
650 | |
651 for (int ix = 1; ix != argc; ix++) | |
652 { | |
653 if (!strcmp (argv[ix], "-o") && ix + 1 != argc) | |
654 outname = argv[++ix]; | |
655 else | |
656 { | |
657 obstack_ptr_grow (&cc_argv_obstack, argv[ix]); | |
658 | |
659 if (argv[ix][0] != '-') | |
660 offloadsrc = argv[ix]; | |
661 } | |
662 } | |
663 | |
664 obstack_ptr_grow (&cc_argv_obstack, "-o"); | |
665 obstack_ptr_grow (&cc_argv_obstack, gcn_s1_name); | |
666 obstack_ptr_grow (&cc_argv_obstack, | |
667 concat ("-mlocal-symbol-id=", offloadsrc, NULL)); | |
668 obstack_ptr_grow (&cc_argv_obstack, NULL); | |
669 const char **cc_argv = XOBFINISH (&cc_argv_obstack, const char **); | |
670 | |
671 /* Build arguments for assemble/link pass. */ | |
672 struct obstack ld_argv_obstack; | |
673 obstack_init (&ld_argv_obstack); | |
674 obstack_ptr_grow (&ld_argv_obstack, driver); | |
675 obstack_ptr_grow (&ld_argv_obstack, gcn_s2_name); | |
676 obstack_ptr_grow (&ld_argv_obstack, "-lgomp"); | |
677 | |
678 for (int i = 1; i < argc; i++) | |
679 if (strncmp (argv[i], "-l", 2) == 0 | |
680 || strncmp (argv[i], "-Wl", 3) == 0 | |
681 || strncmp (argv[i], "-march", 6) == 0) | |
682 obstack_ptr_grow (&ld_argv_obstack, argv[i]); | |
683 | |
684 obstack_ptr_grow (&ld_argv_obstack, "-o"); | |
685 obstack_ptr_grow (&ld_argv_obstack, gcn_o_name); | |
686 obstack_ptr_grow (&ld_argv_obstack, NULL); | |
687 const char **ld_argv = XOBFINISH (&ld_argv_obstack, const char **); | |
688 | |
689 /* Clean up unhelpful environment variables. */ | |
690 char *execpath = getenv ("GCC_EXEC_PREFIX"); | |
691 char *cpath = getenv ("COMPILER_PATH"); | |
692 char *lpath = getenv ("LIBRARY_PATH"); | |
693 unsetenv ("GCC_EXEC_PREFIX"); | |
694 unsetenv ("COMPILER_PATH"); | |
695 unsetenv ("LIBRARY_PATH"); | |
696 | |
697 /* Run the compiler pass. */ | |
698 fork_execute (cc_argv[0], CONST_CAST (char **, cc_argv), true); | |
699 obstack_free (&cc_argv_obstack, NULL); | |
700 | |
701 in = fopen (gcn_s1_name, "r"); | |
702 if (!in) | |
703 fatal_error (input_location, "cannot open intermediate gcn asm file"); | |
704 | |
705 out = fopen (gcn_s2_name, "w"); | |
706 if (!out) | |
707 fatal_error (input_location, "cannot open '%s'", gcn_s2_name); | |
708 | |
709 cfile = fopen (gcn_cfile_name, "w"); | |
710 if (!cfile) | |
711 fatal_error (input_location, "cannot open '%s'", gcn_cfile_name); | |
712 | |
713 process_asm (in, out, cfile); | |
714 | |
715 fclose (in); | |
716 fclose (out); | |
717 | |
718 /* Run the assemble/link pass. */ | |
719 fork_execute (ld_argv[0], CONST_CAST (char **, ld_argv), true); | |
720 obstack_free (&ld_argv_obstack, NULL); | |
721 | |
722 in = fopen (gcn_o_name, "r"); | |
723 if (!in) | |
724 fatal_error (input_location, "cannot open intermediate gcn obj file"); | |
725 | |
726 process_obj (in, cfile); | |
727 | |
728 fclose (in); | |
729 fclose (cfile); | |
730 | |
731 xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL)); | |
732 xputenv (concat ("COMPILER_PATH=", cpath, NULL)); | |
733 xputenv (concat ("LIBRARY_PATH=", lpath, NULL)); | |
734 | |
735 compile_native (gcn_cfile_name, outname, collect_gcc); | |
736 | |
737 return 0; | |
738 } |