]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/gcn/mkoffload.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / config / gcn / mkoffload.cc
1 /* Offload image generation tool for AMD GCN.
2
3 Copyright (C) 2014-2024 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 #include "simple-object.h"
37 #include "elf.h"
38
39 /* These probably won't (all) be in elf.h for a while. */
40 #undef EM_AMDGPU
41 #define EM_AMDGPU 0xe0;
42
43 #undef ELFOSABI_AMDGPU_HSA
44 #define ELFOSABI_AMDGPU_HSA 64
45 #undef ELFABIVERSION_AMDGPU_HSA_V3
46 #define ELFABIVERSION_AMDGPU_HSA_V3 1
47 #undef ELFABIVERSION_AMDGPU_HSA_V4
48 #define ELFABIVERSION_AMDGPU_HSA_V4 2
49
50 #undef EF_AMDGPU_MACH_AMDGCN_GFX803
51 #define EF_AMDGPU_MACH_AMDGCN_GFX803 0x2a
52 #undef EF_AMDGPU_MACH_AMDGCN_GFX900
53 #define EF_AMDGPU_MACH_AMDGCN_GFX900 0x2c
54 #undef EF_AMDGPU_MACH_AMDGCN_GFX906
55 #define EF_AMDGPU_MACH_AMDGCN_GFX906 0x2f
56 #undef EF_AMDGPU_MACH_AMDGCN_GFX908
57 #define EF_AMDGPU_MACH_AMDGCN_GFX908 0x30
58 #undef EF_AMDGPU_MACH_AMDGCN_GFX90a
59 #define EF_AMDGPU_MACH_AMDGCN_GFX90a 0x3f
60 #undef EF_AMDGPU_MACH_AMDGCN_GFX1030
61 #define EF_AMDGPU_MACH_AMDGCN_GFX1030 0x36
62
63 #define EF_AMDGPU_FEATURE_XNACK_V4 0x300 /* Mask. */
64 #define EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 0x000
65 #define EF_AMDGPU_FEATURE_XNACK_ANY_V4 0x100
66 #define EF_AMDGPU_FEATURE_XNACK_OFF_V4 0x200
67 #define EF_AMDGPU_FEATURE_XNACK_ON_V4 0x300
68
69 #define EF_AMDGPU_FEATURE_SRAMECC_V4 0xc00 /* Mask. */
70 #define EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 0x000
71 #define EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 0x400
72 #define EF_AMDGPU_FEATURE_SRAMECC_OFF_V4 0x800
73 #define EF_AMDGPU_FEATURE_SRAMECC_ON_V4 0xc00
74
75 #define SET_XNACK_ON(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_XNACK_V4) \
76 | EF_AMDGPU_FEATURE_XNACK_ON_V4)
77 #define SET_XNACK_ANY(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_XNACK_V4) \
78 | EF_AMDGPU_FEATURE_XNACK_ANY_V4)
79 #define SET_XNACK_OFF(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_XNACK_V4) \
80 | EF_AMDGPU_FEATURE_XNACK_OFF_V4)
81 #define TEST_XNACK_ANY(VAR) ((VAR & EF_AMDGPU_FEATURE_XNACK_V4) \
82 == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
83 #define TEST_XNACK_ON(VAR) ((VAR & EF_AMDGPU_FEATURE_XNACK_V4) \
84 == EF_AMDGPU_FEATURE_XNACK_ON_V4)
85 #define TEST_XNACK_OFF(VAR) ((VAR & EF_AMDGPU_FEATURE_XNACK_V4) \
86 == EF_AMDGPU_FEATURE_XNACK_OFF_V4)
87
88 #define SET_SRAM_ECC_ON(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_SRAMECC_V4) \
89 | EF_AMDGPU_FEATURE_SRAMECC_ON_V4)
90 #define SET_SRAM_ECC_ANY(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_SRAMECC_V4) \
91 | EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
92 #define SET_SRAM_ECC_OFF(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_SRAMECC_V4) \
93 | EF_AMDGPU_FEATURE_SRAMECC_OFF_V4)
94 #define SET_SRAM_ECC_UNSUPPORTED(VAR) \
95 VAR = ((VAR & ~EF_AMDGPU_FEATURE_SRAMECC_V4) \
96 | EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4)
97 #define TEST_SRAM_ECC_ANY(VAR) ((VAR & EF_AMDGPU_FEATURE_SRAMECC_V4) \
98 == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
99 #define TEST_SRAM_ECC_ON(VAR) ((VAR & EF_AMDGPU_FEATURE_SRAMECC_V4) \
100 == EF_AMDGPU_FEATURE_SRAMECC_ON_V4)
101
102 #ifndef R_AMDGPU_NONE
103 #define R_AMDGPU_NONE 0
104 #define R_AMDGPU_ABS32_LO 1 /* (S + A) & 0xFFFFFFFF */
105 #define R_AMDGPU_ABS32_HI 2 /* (S + A) >> 32 */
106 #define R_AMDGPU_ABS64 3 /* S + A */
107 #define R_AMDGPU_REL32 4 /* S + A - P */
108 #define R_AMDGPU_REL64 5 /* S + A - P */
109 #define R_AMDGPU_ABS32 6 /* S + A */
110 #define R_AMDGPU_GOTPCREL 7 /* G + GOT + A - P */
111 #define R_AMDGPU_GOTPCREL32_LO 8 /* (G + GOT + A - P) & 0xFFFFFFFF */
112 #define R_AMDGPU_GOTPCREL32_HI 9 /* (G + GOT + A - P) >> 32 */
113 #define R_AMDGPU_REL32_LO 10 /* (S + A - P) & 0xFFFFFFFF */
114 #define R_AMDGPU_REL32_HI 11 /* (S + A - P) >> 32 */
115 #define R_AMDGPU_RELATIVE64 13 /* B + A */
116 #endif
117
118 const char tool_name[] = "gcn mkoffload";
119
120 static const char *gcn_dumpbase;
121 static struct obstack files_to_cleanup;
122
123 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
124 uint32_t elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX803; // Default GPU architecture.
125 uint32_t elf_flags =
126 (EF_AMDGPU_FEATURE_XNACK_ANY_V4 | EF_AMDGPU_FEATURE_SRAMECC_ANY_V4);
127
128 static int gcn_stack_size = 0; /* Zero means use default. */
129
130 /* Delete tempfiles. */
131
132 void
133 tool_cleanup (bool from_signal ATTRIBUTE_UNUSED)
134 {
135 obstack_ptr_grow (&files_to_cleanup, NULL);
136 const char **files = XOBFINISH (&files_to_cleanup, const char **);
137 for (int i = 0; files[i]; i++)
138 maybe_unlink (files[i]);
139 }
140
141 static void
142 mkoffload_cleanup (void)
143 {
144 tool_cleanup (false);
145 }
146
147 /* Unlink FILE unless requested otherwise. */
148
149 void
150 maybe_unlink (const char *file)
151 {
152 if (!save_temps)
153 {
154 if (unlink_if_ordinary (file) && errno != ENOENT)
155 fatal_error (input_location, "deleting file %s: %m", file);
156 }
157 else if (verbose)
158 fprintf (stderr, "[Leaving %s]\n", file);
159 }
160
161 /* Add or change the value of an environment variable, outputting the
162 change to standard error if in verbose mode. */
163
164 static void
165 xputenv (const char *string)
166 {
167 if (verbose)
168 fprintf (stderr, "%s\n", string);
169 putenv (CONST_CAST (char *, string));
170 }
171
172 /* Read the whole input file. It will be NUL terminated (but
173 remember, there could be a NUL in the file itself. */
174
175 static const char *
176 read_file (FILE *stream, size_t *plen)
177 {
178 size_t alloc = 16384;
179 size_t base = 0;
180 char *buffer;
181
182 if (!fseek (stream, 0, SEEK_END))
183 {
184 /* Get the file size. */
185 long s = ftell (stream);
186 if (s >= 0)
187 alloc = s + 100;
188 fseek (stream, 0, SEEK_SET);
189 }
190 buffer = XNEWVEC (char, alloc);
191
192 for (;;)
193 {
194 size_t n = fread (buffer + base, 1, alloc - base - 1, stream);
195
196 if (!n)
197 break;
198 base += n;
199 if (base + 1 == alloc)
200 {
201 alloc *= 2;
202 buffer = XRESIZEVEC (char, buffer, alloc);
203 }
204 }
205 buffer[base] = 0;
206 *plen = base;
207 return buffer;
208 }
209
210 /* Parse STR, saving found tokens into PVALUES and return their number.
211 Tokens are assumed to be delimited by ':'. */
212
213 static unsigned
214 parse_env_var (const char *str, char ***pvalues)
215 {
216 const char *curval, *nextval;
217 char **values;
218 unsigned num = 1, i;
219
220 curval = strchr (str, ':');
221 while (curval)
222 {
223 num++;
224 curval = strchr (curval + 1, ':');
225 }
226
227 values = (char **) xmalloc (num * sizeof (char *));
228 curval = str;
229 nextval = strchr (curval, ':');
230 if (nextval == NULL)
231 nextval = strchr (curval, '\0');
232
233 for (i = 0; i < num; i++)
234 {
235 int l = nextval - curval;
236 values[i] = (char *) xmalloc (l + 1);
237 memcpy (values[i], curval, l);
238 values[i][l] = 0;
239 curval = nextval + 1;
240 nextval = strchr (curval, ':');
241 if (nextval == NULL)
242 nextval = strchr (curval, '\0');
243 }
244 *pvalues = values;
245 return num;
246 }
247
248 /* Auxiliary function that frees elements of PTR and PTR itself.
249 N is number of elements to be freed. If PTR is NULL, nothing is freed.
250 If an element is NULL, subsequent elements are not freed. */
251
252 static void
253 free_array_of_ptrs (void **ptr, unsigned n)
254 {
255 unsigned i;
256 if (!ptr)
257 return;
258 for (i = 0; i < n; i++)
259 {
260 if (!ptr[i])
261 break;
262 free (ptr[i]);
263 }
264 free (ptr);
265 return;
266 }
267
268 /* Check whether NAME can be accessed in MODE. This is like access,
269 except that it never considers directories to be executable. */
270
271 static int
272 access_check (const char *name, int mode)
273 {
274 if (mode == X_OK)
275 {
276 struct stat st;
277
278 if (stat (name, &st) < 0 || S_ISDIR (st.st_mode))
279 return -1;
280 }
281
282 return access (name, mode);
283 }
284
285 /* Copy the early-debug-info from the incoming LTO object to a new object
286 that will be linked into the output HSACO file. The host relocations
287 must be translated into GCN relocations, and any global undefined symbols
288 must be weakened (so as not to have the debug info try to pull in host
289 junk).
290
291 Returns true if the file was created, false otherwise. */
292
293 static bool
294 copy_early_debug_info (const char *infile, const char *outfile)
295 {
296 const char *errmsg;
297 int err;
298
299 /* The simple_object code can handle extracting the debug sections.
300 This code is based on that in lto-wrapper.cc. */
301 int infd = open (infile, O_RDONLY | O_BINARY);
302 if (infd == -1)
303 return false;
304 simple_object_read *inobj = simple_object_start_read (infd, 0,
305 "__GNU_LTO",
306 &errmsg, &err);
307 if (!inobj)
308 return false;
309
310 off_t off, len;
311 if (simple_object_find_section (inobj, ".gnu.debuglto_.debug_info",
312 &off, &len, &errmsg, &err) != 1)
313 {
314 simple_object_release_read (inobj);
315 close (infd);
316 return false;
317 }
318
319 errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err, true);
320 if (errmsg)
321 {
322 unlink_if_ordinary (outfile);
323 return false;
324 }
325
326 simple_object_release_read (inobj);
327 close (infd);
328
329 /* Open the file we just created for some adjustments.
330 The simple_object code can't do this, so we do it manually. */
331 FILE *outfd = fopen (outfile, "r+b");
332 if (!outfd)
333 return false;
334
335 Elf64_Ehdr ehdr;
336 if (fread (&ehdr, sizeof (ehdr), 1, outfd) != 1)
337 {
338 fclose (outfd);
339 return true;
340 }
341
342 /* We only support host relocations of x86_64, for now. */
343 gcc_assert (ehdr.e_machine == EM_X86_64);
344
345 /* Fiji devices use HSACOv3 regardless of the assembler. */
346 uint32_t elf_flags_actual = (elf_arch == EF_AMDGPU_MACH_AMDGCN_GFX803
347 ? 0 : elf_flags);
348 /* GFX900 devices don't support the sramecc attribute even if
349 a buggy assembler thinks it does. This must match gcn-hsa.h */
350 if (elf_arch == EF_AMDGPU_MACH_AMDGCN_GFX900)
351 SET_SRAM_ECC_UNSUPPORTED (elf_flags_actual);
352
353 /* Patch the correct elf architecture flag into the file. */
354 ehdr.e_ident[7] = ELFOSABI_AMDGPU_HSA;
355 ehdr.e_ident[8] = (elf_arch == EF_AMDGPU_MACH_AMDGCN_GFX803
356 ? ELFABIVERSION_AMDGPU_HSA_V3
357 : ELFABIVERSION_AMDGPU_HSA_V4);
358 ehdr.e_type = ET_REL;
359 ehdr.e_machine = EM_AMDGPU;
360 ehdr.e_flags = elf_arch | elf_flags_actual;
361
362 /* Load the section headers so we can walk them later. */
363 Elf64_Shdr *sections = (Elf64_Shdr *)xmalloc (sizeof (Elf64_Shdr)
364 * ehdr.e_shnum);
365 if (fseek (outfd, ehdr.e_shoff, SEEK_SET) == -1
366 || fread (sections, sizeof (Elf64_Shdr), ehdr.e_shnum,
367 outfd) != ehdr.e_shnum)
368 {
369 free (sections);
370 fclose (outfd);
371 return true;
372 }
373
374 /* Convert the host relocations to target relocations. */
375 for (int i = 0; i < ehdr.e_shnum; i++)
376 {
377 if (sections[i].sh_type != SHT_RELA)
378 continue;
379
380 char *data = (char *)xmalloc (sections[i].sh_size);
381 if (fseek (outfd, sections[i].sh_offset, SEEK_SET) == -1
382 || fread (data, sections[i].sh_size, 1, outfd) != 1)
383 {
384 free (data);
385 continue;
386 }
387
388 for (size_t offset = 0;
389 offset < sections[i].sh_size;
390 offset += sections[i].sh_entsize)
391 {
392 Elf64_Rela *reloc = (Elf64_Rela *) (data + offset);
393
394 /* Map the host relocations to GCN relocations.
395 Only relocations that can appear in DWARF need be handled. */
396 switch (ELF64_R_TYPE (reloc->r_info))
397 {
398 case R_X86_64_32:
399 case R_X86_64_32S:
400 reloc->r_info = ELF32_R_INFO(ELF32_R_SYM(reloc->r_info),
401 R_AMDGPU_ABS32);
402 break;
403 case R_X86_64_PC32:
404 reloc->r_info = ELF32_R_INFO(ELF32_R_SYM(reloc->r_info),
405 R_AMDGPU_REL32);
406 break;
407 case R_X86_64_PC64:
408 reloc->r_info = ELF32_R_INFO(ELF32_R_SYM(reloc->r_info),
409 R_AMDGPU_REL64);
410 break;
411 case R_X86_64_64:
412 reloc->r_info = ELF32_R_INFO(ELF32_R_SYM(reloc->r_info),
413 R_AMDGPU_ABS64);
414 break;
415 case R_X86_64_RELATIVE:
416 reloc->r_info = ELF32_R_INFO(ELF32_R_SYM(reloc->r_info),
417 R_AMDGPU_RELATIVE64);
418 break;
419 default:
420 gcc_unreachable ();
421 }
422 }
423
424 /* Write back our relocation changes. */
425 if (fseek (outfd, sections[i].sh_offset, SEEK_SET) != -1)
426 fwrite (data, sections[i].sh_size, 1, outfd);
427
428 free (data);
429 }
430
431 /* Weaken any global undefined symbols that would pull in unwanted
432 objects. */
433 for (int i = 0; i < ehdr.e_shnum; i++)
434 {
435 if (sections[i].sh_type != SHT_SYMTAB)
436 continue;
437
438 char *data = (char *)xmalloc (sections[i].sh_size);
439 if (fseek (outfd, sections[i].sh_offset, SEEK_SET) == -1
440 || fread (data, sections[i].sh_size, 1, outfd) != 1)
441 {
442 free (data);
443 continue;
444 }
445
446 for (size_t offset = 0;
447 offset < sections[i].sh_size;
448 offset += sections[i].sh_entsize)
449 {
450 Elf64_Sym *sym = (Elf64_Sym *) (data + offset);
451 int type = ELF64_ST_TYPE (sym->st_info);
452 int bind = ELF64_ST_BIND (sym->st_info);
453
454 if (bind == STB_GLOBAL && sym->st_shndx == 0)
455 sym->st_info = ELF64_ST_INFO (STB_WEAK, type);
456 }
457
458 /* Write back our symbol changes. */
459 if (fseek (outfd, sections[i].sh_offset, SEEK_SET) != -1)
460 fwrite (data, sections[i].sh_size, 1, outfd);
461
462 free (data);
463 }
464 free (sections);
465
466 /* Write back our header changes. */
467 rewind (outfd);
468 fwrite (&ehdr, sizeof (ehdr), 1, outfd);
469
470 fclose (outfd);
471 return true;
472 }
473
474 /* CDNA2 devices have twice as many VGPRs compared to older devices,
475 but the AVGPRS are allocated from the same pool. */
476
477 static int
478 isa_has_combined_avgprs (int isa)
479 {
480 switch (isa)
481 {
482 case EF_AMDGPU_MACH_AMDGCN_GFX803:
483 case EF_AMDGPU_MACH_AMDGCN_GFX900:
484 case EF_AMDGPU_MACH_AMDGCN_GFX906:
485 case EF_AMDGPU_MACH_AMDGCN_GFX908:
486 case EF_AMDGPU_MACH_AMDGCN_GFX1030:
487 return false;
488 case EF_AMDGPU_MACH_AMDGCN_GFX90a:
489 return true;
490 }
491 fatal_error (input_location, "unhandled ISA in isa_has_combined_avgprs");
492 }
493
494 /* Parse an input assembler file, extract the offload tables etc.,
495 and output (1) the assembler code, minus the tables (which can contain
496 problematic relocations), and (2) a C file with the offload tables
497 encoded as structured data. */
498
499 static void
500 process_asm (FILE *in, FILE *out, FILE *cfile)
501 {
502 int fn_count = 0, var_count = 0, ind_fn_count = 0;
503 int dims_count = 0, regcount_count = 0;
504 struct obstack fns_os, dims_os, regcounts_os;
505 obstack_init (&fns_os);
506 obstack_init (&dims_os);
507 obstack_init (&regcounts_os);
508
509 struct oaccdims
510 {
511 int d[3];
512 char *name;
513 } dim;
514
515 struct regcount
516 {
517 int sgpr_count;
518 int vgpr_count;
519 int avgpr_count;
520 char *kernel_name;
521 } regcount = { -1, -1, NULL };
522
523 /* Always add _init_array and _fini_array as kernels. */
524 obstack_ptr_grow (&fns_os, xstrdup ("_init_array"));
525 obstack_ptr_grow (&fns_os, xstrdup ("_fini_array"));
526 fn_count += 2;
527
528 char buf[1000];
529 enum
530 { IN_CODE,
531 IN_METADATA,
532 IN_VARS,
533 IN_FUNCS,
534 IN_IND_FUNCS,
535 } state = IN_CODE;
536 while (fgets (buf, sizeof (buf), in))
537 {
538 switch (state)
539 {
540 case IN_CODE:
541 {
542 if (sscanf (buf, " ;; OPENACC-DIMS: %d, %d, %d : %ms\n",
543 &dim.d[0], &dim.d[1], &dim.d[2], &dim.name) == 4)
544 {
545 obstack_grow (&dims_os, &dim, sizeof (dim));
546 dims_count++;
547 }
548
549 break;
550 }
551 case IN_METADATA:
552 {
553 if (sscanf (buf, " - .name: %ms\n", &regcount.kernel_name) == 1)
554 break;
555 else if (sscanf (buf, " .sgpr_count: %d\n",
556 &regcount.sgpr_count) == 1)
557 {
558 gcc_assert (regcount.kernel_name);
559 break;
560 }
561 else if (sscanf (buf, " .vgpr_count: %d\n",
562 &regcount.vgpr_count) == 1)
563 {
564 gcc_assert (regcount.kernel_name);
565 break;
566 }
567 else if (sscanf (buf, " .agpr_count: %d\n",
568 &regcount.avgpr_count) == 1)
569 {
570 gcc_assert (regcount.kernel_name);
571 break;
572 }
573
574 break;
575 }
576 case IN_VARS:
577 {
578 char *varname;
579 unsigned varsize;
580 if (sscanf (buf, " .8byte %ms\n", &varname))
581 {
582 fputs (buf, out);
583 fgets (buf, sizeof (buf), in);
584 if (!sscanf (buf, " .8byte %u\n", &varsize))
585 abort ();
586 var_count++;
587 }
588 break;
589 }
590 case IN_FUNCS:
591 {
592 char *funcname;
593 if (sscanf (buf, "\t.8byte\t%ms\n", &funcname))
594 {
595 fputs (buf, out);
596 obstack_ptr_grow (&fns_os, funcname);
597 fn_count++;
598 continue;
599 }
600 break;
601 }
602 case IN_IND_FUNCS:
603 {
604 char *funcname;
605 if (sscanf (buf, "\t.8byte\t%ms\n", &funcname))
606 {
607 fputs (buf, out);
608 ind_fn_count++;
609 continue;
610 }
611 break;
612 }
613 }
614
615 char dummy;
616 if (sscanf (buf, " .section .gnu.offload_vars%c", &dummy) > 0)
617 {
618 state = IN_VARS;
619
620 /* Add a global symbol to allow plugin-gcn.c to locate the table
621 at runtime. It can't use the "offload_var_table.N" emitted by
622 the compiler because a) they're not global, and b) there's one
623 for each input file combined into the binary. */
624 fputs (buf, out);
625 fputs ("\t.global .offload_var_table\n"
626 "\t.type .offload_var_table, @object\n"
627 ".offload_var_table:\n",
628 out);
629 }
630 else if (sscanf (buf, " .section .gnu.offload_funcs%c", &dummy) > 0)
631 {
632 state = IN_FUNCS;
633 /* Likewise for .gnu.offload_vars; used for reverse offload. */
634 fputs (buf, out);
635 fputs ("\t.global .offload_func_table\n"
636 "\t.type .offload_func_table, @object\n"
637 ".offload_func_table:\n",
638 out);
639 }
640 else if (sscanf (buf, " .section .gnu.offload_ind_funcs%c", &dummy) > 0)
641 {
642 state = IN_IND_FUNCS;
643 fputs (buf, out);
644 fputs ("\t.global .offload_ind_func_table\n"
645 "\t.type .offload_ind_func_table, @object\n"
646 ".offload_ind_func_table:\n",
647 out);
648 }
649 else if (sscanf (buf, " .amdgpu_metadata%c", &dummy) > 0)
650 {
651 state = IN_METADATA;
652 regcount.kernel_name = NULL;
653 regcount.sgpr_count = regcount.vgpr_count = -1;
654 }
655 else if (sscanf (buf, " .section %c", &dummy) > 0
656 || sscanf (buf, " .text%c", &dummy) > 0
657 || sscanf (buf, " .bss%c", &dummy) > 0
658 || sscanf (buf, " .data%c", &dummy) > 0
659 || sscanf (buf, " .ident %c", &dummy) > 0)
660 state = IN_CODE;
661 else if (sscanf (buf, " .end_amdgpu_metadata%c", &dummy) > 0)
662 {
663 state = IN_CODE;
664 gcc_assert (regcount.kernel_name != NULL
665 && regcount.sgpr_count >= 0
666 && regcount.vgpr_count >= 0);
667 obstack_grow (&regcounts_os, &regcount, sizeof (regcount));
668 regcount_count++;
669 regcount.kernel_name = NULL;
670 regcount.sgpr_count = regcount.vgpr_count = -1;
671 }
672
673 if (state == IN_CODE || state == IN_METADATA || state == IN_VARS)
674 fputs (buf, out);
675 }
676
677 char **fns = XOBFINISH (&fns_os, char **);
678 struct oaccdims *dims = XOBFINISH (&dims_os, struct oaccdims *);
679 struct regcount *regcounts = XOBFINISH (&regcounts_os, struct regcount *);
680
681 fprintf (cfile, "#include <stdlib.h>\n");
682 fprintf (cfile, "#include <stdint.h>\n");
683 fprintf (cfile, "#include <stdbool.h>\n\n");
684
685 fprintf (cfile, "static const int gcn_num_vars = %d;\n\n", var_count);
686 fprintf (cfile, "static const int gcn_num_ind_funcs = %d;\n\n", ind_fn_count);
687
688 /* Dump out function idents. */
689 fprintf (cfile, "static const struct hsa_kernel_description {\n"
690 " const char *name;\n"
691 " int oacc_dims[3];\n"
692 " int sgpr_count;\n"
693 " int vgpr_count;\n"
694 "} gcn_kernels[] = {\n ");
695 dim.d[0] = dim.d[1] = dim.d[2] = 0;
696 const char *comma;
697 int i;
698 for (comma = "", i = 0; i < fn_count; comma = ",\n ", i++)
699 {
700 /* Find if we recorded dimensions for this function. */
701 int *d = dim.d; /* Previously zeroed. */
702 int sgpr_count = 0;
703 int vgpr_count = 0;
704 for (int j = 0; j < dims_count; j++)
705 if (strcmp (fns[i], dims[j].name) == 0)
706 {
707 d = dims[j].d;
708 break;
709 }
710 for (int j = 0; j < regcount_count; j++)
711 if (strcmp (fns[i], regcounts[j].kernel_name) == 0)
712 {
713 sgpr_count = regcounts[j].sgpr_count;
714 vgpr_count = regcounts[j].vgpr_count;
715 if (isa_has_combined_avgprs (elf_arch))
716 vgpr_count += regcounts[j].avgpr_count;
717 break;
718 }
719
720 fprintf (cfile, "%s{\"%s\", {%d, %d, %d}, %d, %d}", comma,
721 fns[i], d[0], d[1], d[2], sgpr_count, vgpr_count);
722
723 free (fns[i]);
724 }
725 fprintf (cfile, "\n};\n\n");
726
727 /* Set the stack size if the user configured a value. */
728 if (gcn_stack_size)
729 fprintf (cfile,
730 "static __attribute__((constructor))\n"
731 "void configure_stack_size (void)\n"
732 "{\n"
733 " const char *val = getenv (\"GCN_STACK_SIZE\");\n"
734 " if (!val || val[0] == '\\0')\n"
735 " setenv (\"GCN_STACK_SIZE\", \"%d\", true);\n"
736 "}\n\n",
737 gcn_stack_size);
738
739 obstack_free (&fns_os, NULL);
740 for (i = 0; i < dims_count; i++)
741 free (dims[i].name);
742 for (i = 0; i < regcount_count; i++)
743 free (regcounts[i].kernel_name);
744 obstack_free (&dims_os, NULL);
745 obstack_free (&regcounts_os, NULL);
746 }
747
748 /* Embed an object file into a C source file. */
749
750 static void
751 process_obj (FILE *in, FILE *cfile, uint32_t omp_requires)
752 {
753 size_t len = 0;
754 const char *input = read_file (in, &len);
755
756 /* Dump out an array containing the binary.
757 FIXME: do this with objcopy. */
758 fprintf (cfile, "static unsigned char gcn_code[] = {");
759 for (size_t i = 0; i < len; i += 17)
760 {
761 fprintf (cfile, "\n\t");
762 for (size_t j = i; j < i + 17 && j < len; j++)
763 fprintf (cfile, "%3u,", (unsigned char) input[j]);
764 }
765 fprintf (cfile, "\n};\n\n");
766
767 fprintf (cfile,
768 "static const struct gcn_image {\n"
769 " size_t size;\n"
770 " void *image;\n"
771 "} gcn_image = {\n"
772 " %zu,\n"
773 " gcn_code\n"
774 "};\n\n",
775 len);
776
777 fprintf (cfile,
778 "static const struct gcn_data {\n"
779 " uintptr_t omp_requires_mask;\n"
780 " const struct gcn_image *gcn_image;\n"
781 " unsigned kernel_count;\n"
782 " const struct hsa_kernel_description *kernel_infos;\n"
783 " unsigned ind_func_count;\n"
784 " unsigned global_variable_count;\n"
785 "} gcn_data = {\n"
786 " %d,\n"
787 " &gcn_image,\n"
788 " sizeof (gcn_kernels) / sizeof (gcn_kernels[0]),\n"
789 " gcn_kernels,\n"
790 " gcn_num_ind_funcs,\n"
791 " gcn_num_vars\n"
792 "};\n\n", omp_requires);
793
794 fprintf (cfile,
795 "#ifdef __cplusplus\n"
796 "extern \"C\" {\n"
797 "#endif\n"
798 "extern void GOMP_offload_register_ver"
799 " (unsigned, const void *, int, const void *);\n"
800 "extern void GOMP_offload_unregister_ver"
801 " (unsigned, const void *, int, const void *);\n"
802 "#ifdef __cplusplus\n"
803 "}\n"
804 "#endif\n\n");
805
806 fprintf (cfile, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
807
808 fprintf (cfile, "static __attribute__((constructor)) void init (void)\n"
809 "{\n"
810 " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
811 " %d/*GCN*/, &gcn_data);\n"
812 "};\n",
813 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_GCN),
814 GOMP_DEVICE_GCN);
815
816 fprintf (cfile, "static __attribute__((destructor)) void fini (void)\n"
817 "{\n"
818 " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
819 " %d/*GCN*/, &gcn_data);\n"
820 "};\n",
821 GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_GCN),
822 GOMP_DEVICE_GCN);
823 }
824
825 /* Compile a C file using the host compiler. */
826
827 static void
828 compile_native (const char *infile, const char *outfile, const char *compiler,
829 bool fPIC, bool fpic)
830 {
831 const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
832 if (!collect_gcc_options)
833 fatal_error (input_location,
834 "environment variable COLLECT_GCC_OPTIONS must be set");
835
836 struct obstack argv_obstack;
837 obstack_init (&argv_obstack);
838 obstack_ptr_grow (&argv_obstack, compiler);
839 if (fPIC)
840 obstack_ptr_grow (&argv_obstack, "-fPIC");
841 if (fpic)
842 obstack_ptr_grow (&argv_obstack, "-fpic");
843 if (save_temps)
844 obstack_ptr_grow (&argv_obstack, "-save-temps");
845 if (verbose)
846 obstack_ptr_grow (&argv_obstack, "-v");
847 obstack_ptr_grow (&argv_obstack, "-dumpdir");
848 obstack_ptr_grow (&argv_obstack, "");
849 obstack_ptr_grow (&argv_obstack, "-dumpbase");
850 obstack_ptr_grow (&argv_obstack, gcn_dumpbase);
851 obstack_ptr_grow (&argv_obstack, "-dumpbase-ext");
852 obstack_ptr_grow (&argv_obstack, ".c");
853 switch (offload_abi)
854 {
855 case OFFLOAD_ABI_LP64:
856 obstack_ptr_grow (&argv_obstack, "-m64");
857 break;
858 case OFFLOAD_ABI_ILP32:
859 obstack_ptr_grow (&argv_obstack, "-m32");
860 break;
861 default:
862 gcc_unreachable ();
863 }
864 obstack_ptr_grow (&argv_obstack, infile);
865 obstack_ptr_grow (&argv_obstack, "-c");
866 obstack_ptr_grow (&argv_obstack, "-o");
867 obstack_ptr_grow (&argv_obstack, outfile);
868 obstack_ptr_grow (&argv_obstack, NULL);
869
870 const char **new_argv = XOBFINISH (&argv_obstack, const char **);
871 fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true,
872 ".gccnative_args");
873 obstack_free (&argv_obstack, NULL);
874 }
875
876 int
877 main (int argc, char **argv)
878 {
879 FILE *in = stdin;
880 FILE *out = stdout;
881 FILE *cfile = stdout;
882 const char *outname = 0;
883
884 progname = tool_name;
885 diagnostic_initialize (global_dc, 0);
886
887 obstack_init (&files_to_cleanup);
888 if (atexit (mkoffload_cleanup) != 0)
889 fatal_error (input_location, "atexit failed");
890
891 char *collect_gcc = getenv ("COLLECT_GCC");
892 if (collect_gcc == NULL)
893 fatal_error (input_location, "COLLECT_GCC must be set.");
894 const char *gcc_path = dirname (ASTRDUP (collect_gcc));
895 const char *gcc_exec = basename (ASTRDUP (collect_gcc));
896
897 size_t len = (strlen (gcc_path) + 1 + strlen (GCC_INSTALL_NAME) + 1);
898 char *driver = XALLOCAVEC (char, len);
899
900 if (strcmp (gcc_exec, collect_gcc) == 0)
901 /* collect_gcc has no path, so it was found in PATH. Make sure we also
902 find accel-gcc in PATH. */
903 gcc_path = NULL;
904
905 int driver_used = 0;
906 if (gcc_path != NULL)
907 driver_used = sprintf (driver, "%s/", gcc_path);
908 sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME);
909
910 bool found = false;
911 if (gcc_path == NULL)
912 found = true;
913 else if (access_check (driver, X_OK) == 0)
914 found = true;
915 else
916 {
917 /* Don't use alloca pointer with XRESIZEVEC. */
918 driver = NULL;
919 /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */
920 char **paths = NULL;
921 unsigned n_paths;
922 n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
923 for (unsigned i = 0; i < n_paths; i++)
924 {
925 len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1;
926 driver = XRESIZEVEC (char, driver, len);
927 sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME);
928 if (access_check (driver, X_OK) == 0)
929 {
930 found = true;
931 break;
932 }
933 }
934 free_array_of_ptrs ((void **) paths, n_paths);
935 }
936
937 if (!found)
938 fatal_error (input_location,
939 "offload compiler %s not found", GCC_INSTALL_NAME);
940
941 /* We may be called with all the arguments stored in some file and
942 passed with @file. Expand them into argv before processing. */
943 expandargv (&argc, &argv);
944
945 /* Scan the argument vector. */
946 bool fopenmp = false;
947 bool fopenacc = false;
948 bool fPIC = false;
949 bool fpic = false;
950 for (int i = 1; i < argc; i++)
951 {
952 #define STR "-foffload-abi="
953 if (startswith (argv[i], STR))
954 {
955 if (strcmp (argv[i] + strlen (STR), "lp64") == 0)
956 offload_abi = OFFLOAD_ABI_LP64;
957 else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0)
958 offload_abi = OFFLOAD_ABI_ILP32;
959 else
960 fatal_error (input_location,
961 "unrecognizable argument of option " STR);
962 }
963 #undef STR
964 else if (strcmp (argv[i], "-fopenmp") == 0)
965 fopenmp = true;
966 else if (strcmp (argv[i], "-fopenacc") == 0)
967 fopenacc = true;
968 else if (strcmp (argv[i], "-fPIC") == 0)
969 fPIC = true;
970 else if (strcmp (argv[i], "-fpic") == 0)
971 fpic = true;
972 else if (strcmp (argv[i], "-mxnack=on") == 0)
973 SET_XNACK_ON (elf_flags);
974 else if (strcmp (argv[i], "-mxnack=any") == 0)
975 SET_XNACK_ANY (elf_flags);
976 else if (strcmp (argv[i], "-mxnack=off") == 0)
977 SET_XNACK_OFF (elf_flags);
978 else if (strcmp (argv[i], "-msram-ecc=on") == 0)
979 SET_SRAM_ECC_ON (elf_flags);
980 else if (strcmp (argv[i], "-msram-ecc=any") == 0)
981 SET_SRAM_ECC_ANY (elf_flags);
982 else if (strcmp (argv[i], "-msram-ecc=off") == 0)
983 SET_SRAM_ECC_OFF (elf_flags);
984 else if (strcmp (argv[i], "-save-temps") == 0)
985 save_temps = true;
986 else if (strcmp (argv[i], "-v") == 0)
987 verbose = true;
988 else if (strcmp (argv[i], "-dumpbase") == 0
989 && i + 1 < argc)
990 dumppfx = argv[++i];
991 else if (strcmp (argv[i], "-march=fiji") == 0)
992 elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX803;
993 else if (strcmp (argv[i], "-march=gfx900") == 0)
994 elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX900;
995 else if (strcmp (argv[i], "-march=gfx906") == 0)
996 elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX906;
997 else if (strcmp (argv[i], "-march=gfx908") == 0)
998 elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX908;
999 else if (strcmp (argv[i], "-march=gfx90a") == 0)
1000 elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX90a;
1001 else if (strcmp (argv[i], "-march=gfx1030") == 0)
1002 elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX1030;
1003 #define STR "-mstack-size="
1004 else if (startswith (argv[i], STR))
1005 gcn_stack_size = atoi (argv[i] + strlen (STR));
1006 #undef STR
1007 /* Translate host into offloading libraries. */
1008 else if (strcmp (argv[i], "-l_GCC_gfortran") == 0
1009 || strcmp (argv[i], "-l_GCC_m") == 0)
1010 {
1011 /* Elide '_GCC_'. */
1012 size_t i_dst = strlen ("-l");
1013 size_t i_src = strlen ("-l_GCC_");
1014 char c;
1015 do
1016 c = argv[i][i_dst++] = argv[i][i_src++];
1017 while (c != '\0');
1018 }
1019 }
1020
1021 if (!(fopenacc ^ fopenmp))
1022 fatal_error (input_location, "either -fopenacc or -fopenmp must be set");
1023
1024 const char *abi;
1025 switch (offload_abi)
1026 {
1027 case OFFLOAD_ABI_LP64:
1028 abi = "-m64";
1029 break;
1030 case OFFLOAD_ABI_ILP32:
1031 abi = "-m32";
1032 break;
1033 default:
1034 gcc_unreachable ();
1035 }
1036
1037 /* Build arguments for compiler pass. */
1038 struct obstack cc_argv_obstack;
1039 obstack_init (&cc_argv_obstack);
1040 obstack_ptr_grow (&cc_argv_obstack, driver);
1041 obstack_ptr_grow (&cc_argv_obstack, "-S");
1042
1043 if (save_temps)
1044 obstack_ptr_grow (&cc_argv_obstack, "-save-temps");
1045 if (verbose)
1046 obstack_ptr_grow (&cc_argv_obstack, "-v");
1047 obstack_ptr_grow (&cc_argv_obstack, abi);
1048 obstack_ptr_grow (&cc_argv_obstack, "-xlto");
1049 if (fopenmp)
1050 obstack_ptr_grow (&cc_argv_obstack, "-mgomp");
1051
1052 for (int ix = 1; ix != argc; ix++)
1053 {
1054 if (!strcmp (argv[ix], "-o") && ix + 1 != argc)
1055 outname = argv[++ix];
1056 else
1057 obstack_ptr_grow (&cc_argv_obstack, argv[ix]);
1058 }
1059
1060 if (!dumppfx)
1061 dumppfx = outname;
1062
1063 gcn_dumpbase = concat (dumppfx, ".c", NULL);
1064
1065 const char *gcn_cfile_name;
1066 if (save_temps)
1067 gcn_cfile_name = gcn_dumpbase;
1068 else
1069 gcn_cfile_name = make_temp_file (".c");
1070 obstack_ptr_grow (&files_to_cleanup, gcn_cfile_name);
1071
1072 cfile = fopen (gcn_cfile_name, "w");
1073 if (!cfile)
1074 fatal_error (input_location, "cannot open '%s'", gcn_cfile_name);
1075
1076 /* Currently, we only support offloading in 64-bit configurations. */
1077 if (offload_abi == OFFLOAD_ABI_LP64)
1078 {
1079 const char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL);
1080 const char *hsaco_dumpbase = concat (dumppfx, ".mkoffload.hsaco", NULL);
1081
1082 const char *gcn_s1_name;
1083 const char *gcn_s2_name;
1084 const char *gcn_o_name;
1085 if (save_temps)
1086 {
1087 gcn_s1_name = concat (mko_dumpbase, ".1.s", NULL);
1088 gcn_s2_name = concat (mko_dumpbase, ".2.s", NULL);
1089 gcn_o_name = hsaco_dumpbase;
1090 }
1091 else
1092 {
1093 gcn_s1_name = make_temp_file (".mkoffload.1.s");
1094 gcn_s2_name = make_temp_file (".mkoffload.2.s");
1095 gcn_o_name = make_temp_file (".mkoffload.hsaco");
1096 }
1097 obstack_ptr_grow (&files_to_cleanup, gcn_s1_name);
1098 obstack_ptr_grow (&files_to_cleanup, gcn_s2_name);
1099 obstack_ptr_grow (&files_to_cleanup, gcn_o_name);
1100
1101 obstack_ptr_grow (&cc_argv_obstack, "-dumpdir");
1102 obstack_ptr_grow (&cc_argv_obstack, "");
1103 obstack_ptr_grow (&cc_argv_obstack, "-dumpbase");
1104 obstack_ptr_grow (&cc_argv_obstack, mko_dumpbase);
1105 obstack_ptr_grow (&cc_argv_obstack, "-dumpbase-ext");
1106 obstack_ptr_grow (&cc_argv_obstack, "");
1107
1108 obstack_ptr_grow (&cc_argv_obstack, "-o");
1109 obstack_ptr_grow (&cc_argv_obstack, gcn_s1_name);
1110 obstack_ptr_grow (&cc_argv_obstack, NULL);
1111 const char **cc_argv = XOBFINISH (&cc_argv_obstack, const char **);
1112
1113 /* Build arguments for assemble/link pass. */
1114 struct obstack ld_argv_obstack;
1115 obstack_init (&ld_argv_obstack);
1116 obstack_ptr_grow (&ld_argv_obstack, driver);
1117
1118 /* Extract early-debug information from the input objects.
1119 This loop finds all the inputs that end ".o" and aren't the output. */
1120 int dbgcount = 0;
1121 for (int ix = 1; ix != argc; ix++)
1122 {
1123 if (!strcmp (argv[ix], "-o") && ix + 1 != argc)
1124 ++ix;
1125 else
1126 {
1127 if (strcmp (argv[ix] + strlen(argv[ix]) - 2, ".o") == 0)
1128 {
1129 char *dbgobj;
1130 if (save_temps)
1131 {
1132 char buf[10];
1133 sprintf (buf, "%d", dbgcount++);
1134 dbgobj = concat (dumppfx, ".mkoffload.dbg", buf, ".o", NULL);
1135 }
1136 else
1137 dbgobj = make_temp_file (".mkoffload.dbg.o");
1138 obstack_ptr_grow (&files_to_cleanup, dbgobj);
1139
1140 /* If the copy fails then just ignore it. */
1141 if (copy_early_debug_info (argv[ix], dbgobj))
1142 {
1143 obstack_ptr_grow (&ld_argv_obstack, dbgobj);
1144 obstack_ptr_grow (&files_to_cleanup, dbgobj);
1145 }
1146 else
1147 free (dbgobj);
1148 }
1149 }
1150 }
1151 obstack_ptr_grow (&ld_argv_obstack, gcn_s2_name);
1152 obstack_ptr_grow (&ld_argv_obstack, "-lgomp");
1153 obstack_ptr_grow (&ld_argv_obstack,
1154 (TEST_XNACK_ON (elf_flags) ? "-mxnack=on"
1155 : TEST_XNACK_ANY (elf_flags) ? "-mxnack=any"
1156 : "-mxnack=off"));
1157 obstack_ptr_grow (&ld_argv_obstack,
1158 (TEST_SRAM_ECC_ON (elf_flags) ? "-msram-ecc=on"
1159 : TEST_SRAM_ECC_ANY (elf_flags) ? "-msram-ecc=any"
1160 : "-msram-ecc=off"));
1161 if (verbose)
1162 obstack_ptr_grow (&ld_argv_obstack, "-v");
1163
1164 if (save_temps)
1165 obstack_ptr_grow (&ld_argv_obstack, "-save-temps");
1166
1167 for (int i = 1; i < argc; i++)
1168 if (startswith (argv[i], "-l")
1169 || startswith (argv[i], "-Wl")
1170 || startswith (argv[i], "-march"))
1171 obstack_ptr_grow (&ld_argv_obstack, argv[i]);
1172
1173 obstack_ptr_grow (&cc_argv_obstack, "-dumpdir");
1174 obstack_ptr_grow (&cc_argv_obstack, "");
1175 obstack_ptr_grow (&cc_argv_obstack, "-dumpbase");
1176 obstack_ptr_grow (&cc_argv_obstack, hsaco_dumpbase);
1177 obstack_ptr_grow (&cc_argv_obstack, "-dumpbase-ext");
1178 obstack_ptr_grow (&cc_argv_obstack, "");
1179
1180 obstack_ptr_grow (&ld_argv_obstack, "-o");
1181 obstack_ptr_grow (&ld_argv_obstack, gcn_o_name);
1182 obstack_ptr_grow (&ld_argv_obstack, NULL);
1183 const char **ld_argv = XOBFINISH (&ld_argv_obstack, const char **);
1184
1185 /* Clean up unhelpful environment variables. */
1186 char *execpath = getenv ("GCC_EXEC_PREFIX");
1187 char *cpath = getenv ("COMPILER_PATH");
1188 char *lpath = getenv ("LIBRARY_PATH");
1189 unsetenv ("GCC_EXEC_PREFIX");
1190 unsetenv ("COMPILER_PATH");
1191 unsetenv ("LIBRARY_PATH");
1192
1193 char *omp_requires_file;
1194 if (save_temps)
1195 omp_requires_file = concat (dumppfx, ".mkoffload.omp_requires", NULL);
1196 else
1197 omp_requires_file = make_temp_file (".mkoffload.omp_requires");
1198 obstack_ptr_grow (&files_to_cleanup, omp_requires_file);
1199
1200 /* Run the compiler pass. */
1201 xputenv (concat ("GCC_OFFLOAD_OMP_REQUIRES_FILE=", omp_requires_file, NULL));
1202 fork_execute (cc_argv[0], CONST_CAST (char **, cc_argv), true, ".gcc_args");
1203 obstack_free (&cc_argv_obstack, NULL);
1204 unsetenv("GCC_OFFLOAD_OMP_REQUIRES_FILE");
1205
1206 in = fopen (omp_requires_file, "rb");
1207 if (!in)
1208 fatal_error (input_location, "cannot open omp_requires file %qs",
1209 omp_requires_file);
1210 uint32_t omp_requires;
1211 if (fread (&omp_requires, sizeof (omp_requires), 1, in) != 1)
1212 fatal_error (input_location, "cannot read omp_requires file %qs",
1213 omp_requires_file);
1214 fclose (in);
1215
1216 in = fopen (gcn_s1_name, "r");
1217 if (!in)
1218 fatal_error (input_location, "cannot open intermediate gcn asm file");
1219
1220 out = fopen (gcn_s2_name, "w");
1221 if (!out)
1222 fatal_error (input_location, "cannot open '%s'", gcn_s2_name);
1223
1224 process_asm (in, out, cfile);
1225
1226 fclose (in);
1227 fclose (out);
1228
1229 /* Run the assemble/link pass. */
1230 fork_execute (ld_argv[0], CONST_CAST (char **, ld_argv), true, ".ld_args");
1231 obstack_free (&ld_argv_obstack, NULL);
1232
1233 in = fopen (gcn_o_name, "r");
1234 if (!in)
1235 fatal_error (input_location, "cannot open intermediate gcn obj file");
1236
1237 process_obj (in, cfile, omp_requires);
1238
1239 fclose (in);
1240
1241 xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL));
1242 xputenv (concat ("COMPILER_PATH=", cpath, NULL));
1243 xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
1244 }
1245
1246 fclose (cfile);
1247
1248 compile_native (gcn_cfile_name, outname, collect_gcc, fPIC, fpic);
1249
1250 return 0;
1251 }