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 /* Build arguments for compiler pass. */ 632 struct obstack cc_argv_obstack; 633 obstack_init (&cc_argv_obstack); 634 obstack_ptr_grow (&cc_argv_obstack, driver); 635 obstack_ptr_grow (&cc_argv_obstack, "-S"); 636 637 if (save_temps) 638 obstack_ptr_grow (&cc_argv_obstack, "-save-temps"); 639 if (verbose) 640 obstack_ptr_grow (&cc_argv_obstack, "-v"); 641 obstack_ptr_grow (&cc_argv_obstack, abi); 642 obstack_ptr_grow (&cc_argv_obstack, "-xlto"); 643 if (fopenmp) 644 obstack_ptr_grow (&cc_argv_obstack, "-mgomp"); 645 646 for (int ix = 1; ix != argc; ix++) 647 { 648 if (!strcmp (argv[ix], "-o") && ix + 1 != argc) 649 outname = argv[++ix]; 650 else 651 { 652 obstack_ptr_grow (&cc_argv_obstack, argv[ix]); 653 654 if (argv[ix][0] != '-') 655 offloadsrc = argv[ix]; 656 } 657 } 658 659 gcn_cfile_name = make_temp_file (".c"); 660 661 cfile = fopen (gcn_cfile_name, "w"); 662 if (!cfile) 663 fatal_error (input_location, "cannot open '%s'", gcn_cfile_name); 664 665 /* Currently, we only support offloading in 64-bit configurations. */ 666 if (offload_abi == OFFLOAD_ABI_LP64) 667 { 668 gcn_s1_name = make_temp_file (".mkoffload.1.s"); 669 gcn_s2_name = make_temp_file (".mkoffload.2.s"); 670 gcn_o_name = make_temp_file (".mkoffload.hsaco"); 671 672 obstack_ptr_grow (&cc_argv_obstack, "-o"); 673 obstack_ptr_grow (&cc_argv_obstack, gcn_s1_name); 674 obstack_ptr_grow (&cc_argv_obstack, 675 concat ("-mlocal-symbol-id=", offloadsrc, NULL)); 676 obstack_ptr_grow (&cc_argv_obstack, NULL); 677 const char **cc_argv = XOBFINISH (&cc_argv_obstack, const char **); 678 679 /* Build arguments for assemble/link pass. */ 680 struct obstack ld_argv_obstack; 681 obstack_init (&ld_argv_obstack); 682 obstack_ptr_grow (&ld_argv_obstack, driver); 683 obstack_ptr_grow (&ld_argv_obstack, gcn_s2_name); 684 obstack_ptr_grow (&ld_argv_obstack, "-lgomp"); 685 686 for (int i = 1; i < argc; i++) 687 if (strncmp (argv[i], "-l", 2) == 0 688 || strncmp (argv[i], "-Wl", 3) == 0 689 || strncmp (argv[i], "-march", 6) == 0) 690 obstack_ptr_grow (&ld_argv_obstack, argv[i]); 691 692 obstack_ptr_grow (&ld_argv_obstack, "-o"); 693 obstack_ptr_grow (&ld_argv_obstack, gcn_o_name); 694 obstack_ptr_grow (&ld_argv_obstack, NULL); 695 const char **ld_argv = XOBFINISH (&ld_argv_obstack, const char **); 696 697 /* Clean up unhelpful environment variables. */ 698 char *execpath = getenv ("GCC_EXEC_PREFIX"); 699 char *cpath = getenv ("COMPILER_PATH"); 700 char *lpath = getenv ("LIBRARY_PATH"); 701 unsetenv ("GCC_EXEC_PREFIX"); 702 unsetenv ("COMPILER_PATH"); 703 unsetenv ("LIBRARY_PATH"); 704 705 /* Run the compiler pass. */ 706 fork_execute (cc_argv[0], CONST_CAST (char **, cc_argv), true); 707 obstack_free (&cc_argv_obstack, NULL); 708 709 in = fopen (gcn_s1_name, "r"); 710 if (!in) 711 fatal_error (input_location, "cannot open intermediate gcn asm file"); 712 713 out = fopen (gcn_s2_name, "w"); 714 if (!out) 715 fatal_error (input_location, "cannot open '%s'", gcn_s2_name); 716 717 process_asm (in, out, cfile); 718 719 fclose (in); 720 fclose (out); 721 722 /* Run the assemble/link pass. */ 723 fork_execute (ld_argv[0], CONST_CAST (char **, ld_argv), true); 724 obstack_free (&ld_argv_obstack, NULL); 725 726 in = fopen (gcn_o_name, "r"); 727 if (!in) 728 fatal_error (input_location, "cannot open intermediate gcn obj file"); 729 730 process_obj (in, cfile); 731 732 fclose (in); 733 734 xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL)); 735 xputenv (concat ("COMPILER_PATH=", cpath, NULL)); 736 xputenv (concat ("LIBRARY_PATH=", lpath, NULL)); 737 } 738 739 fclose (cfile); 740 741 compile_native (gcn_cfile_name, outname, collect_gcc); 742 743 return 0; 744 } 745