1 1.1 mrg /* Offload image generation tool for PTX. 2 1.1 mrg 3 1.1 mrg Copyright (C) 2014-2022 Free Software Foundation, Inc. 4 1.1 mrg 5 1.1 mrg Contributed by Nathan Sidwell <nathan (at) codesourcery.com> and 6 1.1 mrg Bernd Schmidt <bernds (at) codesourcery.com>. 7 1.1 mrg 8 1.1 mrg This file is part of GCC. 9 1.1 mrg 10 1.1 mrg GCC is free software; you can redistribute it and/or modify it 11 1.1 mrg under the terms of the GNU General Public License as published 12 1.1 mrg by the Free Software Foundation; either version 3, or (at your 13 1.1 mrg option) any later version. 14 1.1 mrg 15 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT 16 1.1 mrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 18 1.1 mrg License for more details. 19 1.1 mrg 20 1.1 mrg You should have received a copy of the GNU General Public License 21 1.1 mrg along with GCC; see the file COPYING3. If not see 22 1.1 mrg <http://www.gnu.org/licenses/>. */ 23 1.1 mrg 24 1.1 mrg /* Munges PTX assembly into a C source file defining the PTX code as a 25 1.1 mrg string. 26 1.1 mrg 27 1.1 mrg This is not a complete assembler. We presume the source is well 28 1.1 mrg formed from the compiler and can die horribly if it is not. */ 29 1.1 mrg 30 1.1 mrg #define IN_TARGET_CODE 1 31 1.1 mrg 32 1.1 mrg #include "config.h" 33 1.1 mrg #include "system.h" 34 1.1 mrg #include "coretypes.h" 35 1.1 mrg #include "obstack.h" 36 1.1 mrg #include "diagnostic.h" 37 1.1 mrg #include "intl.h" 38 1.1 mrg #include <libgen.h> 39 1.1 mrg #include "collect-utils.h" 40 1.1 mrg #include "gomp-constants.h" 41 1.1 mrg 42 1.1 mrg const char tool_name[] = "nvptx mkoffload"; 43 1.1 mrg 44 1.1 mrg #define COMMENT_PREFIX "#" 45 1.1 mrg 46 1.1 mrg struct id_map 47 1.1 mrg { 48 1.1 mrg id_map *next; 49 1.1 mrg char *ptx_name; 50 1.1 mrg }; 51 1.1 mrg 52 1.1 mrg static id_map *func_ids, **funcs_tail = &func_ids; 53 1.1 mrg static id_map *var_ids, **vars_tail = &var_ids; 54 1.1 mrg 55 1.1 mrg /* Files to unlink. */ 56 1.1 mrg static const char *ptx_name; 57 1.1 mrg static const char *ptx_cfile_name; 58 1.1 mrg static const char *ptx_dumpbase; 59 1.1 mrg 60 1.1 mrg enum offload_abi offload_abi = OFFLOAD_ABI_UNSET; 61 1.1 mrg 62 1.1 mrg /* Delete tempfiles. */ 63 1.1 mrg 64 1.1 mrg void 65 1.1 mrg tool_cleanup (bool from_signal ATTRIBUTE_UNUSED) 66 1.1 mrg { 67 1.1 mrg if (ptx_cfile_name) 68 1.1 mrg maybe_unlink (ptx_cfile_name); 69 1.1 mrg if (ptx_name) 70 1.1 mrg maybe_unlink (ptx_name); 71 1.1 mrg } 72 1.1 mrg 73 1.1 mrg static void 74 1.1 mrg mkoffload_cleanup (void) 75 1.1 mrg { 76 1.1 mrg tool_cleanup (false); 77 1.1 mrg } 78 1.1 mrg 79 1.1 mrg /* Unlink FILE unless requested otherwise. */ 80 1.1 mrg 81 1.1 mrg void 82 1.1 mrg maybe_unlink (const char *file) 83 1.1 mrg { 84 1.1 mrg if (!save_temps) 85 1.1 mrg { 86 1.1 mrg if (unlink_if_ordinary (file) 87 1.1 mrg && errno != ENOENT) 88 1.1 mrg fatal_error (input_location, "deleting file %s: %m", file); 89 1.1 mrg } 90 1.1 mrg else if (verbose) 91 1.1 mrg fprintf (stderr, "[Leaving %s]\n", file); 92 1.1 mrg } 93 1.1 mrg 94 1.1 mrg /* Add or change the value of an environment variable, outputting the 95 1.1 mrg change to standard error if in verbose mode. */ 96 1.1 mrg static void 97 1.1 mrg xputenv (const char *string) 98 1.1 mrg { 99 1.1 mrg if (verbose) 100 1.1 mrg fprintf (stderr, "%s\n", string); 101 1.1 mrg putenv (CONST_CAST (char *, string)); 102 1.1 mrg } 103 1.1 mrg 104 1.1 mrg 105 1.1 mrg static void 106 1.1 mrg record_id (const char *p1, id_map ***where) 107 1.1 mrg { 108 1.1 mrg const char *end = strchr (p1, '\n'); 109 1.1 mrg if (!end) 110 1.1 mrg fatal_error (input_location, "malformed ptx file"); 111 1.1 mrg 112 1.1 mrg id_map *v = XNEW (id_map); 113 1.1 mrg size_t len = end - p1; 114 1.1 mrg v->ptx_name = XNEWVEC (char, len + 1); 115 1.1 mrg memcpy (v->ptx_name, p1, len); 116 1.1 mrg v->ptx_name[len] = '\0'; 117 1.1 mrg v->next = NULL; 118 1.1 mrg id_map **tail = *where; 119 1.1 mrg *tail = v; 120 1.1 mrg *where = &v->next; 121 1.1 mrg } 122 1.1 mrg 123 1.1 mrg /* Read the whole input file. It will be NUL terminated (but 124 1.1 mrg remember, there could be a NUL in the file itself. */ 125 1.1 mrg 126 1.1 mrg static const char * 127 1.1 mrg read_file (FILE *stream, size_t *plen) 128 1.1 mrg { 129 1.1 mrg size_t alloc = 16384; 130 1.1 mrg size_t base = 0; 131 1.1 mrg char *buffer; 132 1.1 mrg 133 1.1 mrg if (!fseek (stream, 0, SEEK_END)) 134 1.1 mrg { 135 1.1 mrg /* Get the file size. */ 136 1.1 mrg long s = ftell (stream); 137 1.1 mrg if (s >= 0) 138 1.1 mrg alloc = s + 100; 139 1.1 mrg fseek (stream, 0, SEEK_SET); 140 1.1 mrg } 141 1.1 mrg buffer = XNEWVEC (char, alloc); 142 1.1 mrg 143 1.1 mrg for (;;) 144 1.1 mrg { 145 1.1 mrg size_t n = fread (buffer + base, 1, alloc - base - 1, stream); 146 1.1 mrg 147 1.1 mrg if (!n) 148 1.1 mrg break; 149 1.1 mrg base += n; 150 1.1 mrg if (base + 1 == alloc) 151 1.1 mrg { 152 1.1 mrg alloc *= 2; 153 1.1 mrg buffer = XRESIZEVEC (char, buffer, alloc); 154 1.1 mrg } 155 1.1 mrg } 156 1.1 mrg buffer[base] = 0; 157 1.1 mrg *plen = base; 158 1.1 mrg return buffer; 159 1.1 mrg } 160 1.1 mrg 161 1.1 mrg /* Parse STR, saving found tokens into PVALUES and return their number. 162 1.1 mrg Tokens are assumed to be delimited by ':'. */ 163 1.1 mrg static unsigned 164 1.1 mrg parse_env_var (const char *str, char ***pvalues) 165 1.1 mrg { 166 1.1 mrg const char *curval, *nextval; 167 1.1 mrg char **values; 168 1.1 mrg unsigned num = 1, i; 169 1.1 mrg 170 1.1 mrg curval = strchr (str, ':'); 171 1.1 mrg while (curval) 172 1.1 mrg { 173 1.1 mrg num++; 174 1.1 mrg curval = strchr (curval + 1, ':'); 175 1.1 mrg } 176 1.1 mrg 177 1.1 mrg values = (char **) xmalloc (num * sizeof (char *)); 178 1.1 mrg curval = str; 179 1.1 mrg nextval = strchr (curval, ':'); 180 1.1 mrg if (nextval == NULL) 181 1.1 mrg nextval = strchr (curval, '\0'); 182 1.1 mrg 183 1.1 mrg for (i = 0; i < num; i++) 184 1.1 mrg { 185 1.1 mrg int l = nextval - curval; 186 1.1 mrg values[i] = (char *) xmalloc (l + 1); 187 1.1 mrg memcpy (values[i], curval, l); 188 1.1 mrg values[i][l] = 0; 189 1.1 mrg curval = nextval + 1; 190 1.1 mrg nextval = strchr (curval, ':'); 191 1.1 mrg if (nextval == NULL) 192 1.1 mrg nextval = strchr (curval, '\0'); 193 1.1 mrg } 194 1.1 mrg *pvalues = values; 195 1.1 mrg return num; 196 1.1 mrg } 197 1.1 mrg 198 1.1 mrg /* Auxiliary function that frees elements of PTR and PTR itself. 199 1.1 mrg N is number of elements to be freed. If PTR is NULL, nothing is freed. 200 1.1 mrg If an element is NULL, subsequent elements are not freed. */ 201 1.1 mrg static void 202 1.1 mrg free_array_of_ptrs (void **ptr, unsigned n) 203 1.1 mrg { 204 1.1 mrg unsigned i; 205 1.1 mrg if (!ptr) 206 1.1 mrg return; 207 1.1 mrg for (i = 0; i < n; i++) 208 1.1 mrg { 209 1.1 mrg if (!ptr[i]) 210 1.1 mrg break; 211 1.1 mrg free (ptr[i]); 212 1.1 mrg } 213 1.1 mrg free (ptr); 214 1.1 mrg return; 215 1.1 mrg } 216 1.1 mrg 217 1.1 mrg /* Check whether NAME can be accessed in MODE. This is like access, 218 1.1 mrg except that it never considers directories to be executable. */ 219 1.1 mrg static int 220 1.1 mrg access_check (const char *name, int mode) 221 1.1 mrg { 222 1.1 mrg if (mode == X_OK) 223 1.1 mrg { 224 1.1 mrg struct stat st; 225 1.1 mrg 226 1.1 mrg if (stat (name, &st) < 0 || S_ISDIR (st.st_mode)) 227 1.1 mrg return -1; 228 1.1 mrg } 229 1.1 mrg 230 1.1 mrg return access (name, mode); 231 1.1 mrg } 232 1.1 mrg 233 1.1 mrg static void 234 1.1 mrg process (FILE *in, FILE *out) 235 1.1 mrg { 236 1.1 mrg size_t len = 0; 237 1.1 mrg const char *input = read_file (in, &len); 238 1.1 mrg const char *comma; 239 1.1 mrg id_map const *id; 240 1.1 mrg unsigned obj_count = 0; 241 1.1 mrg unsigned ix; 242 1.1 mrg 243 1.1 mrg /* Dump out char arrays for each PTX object file. These are 244 1.1 mrg terminated by a NUL. */ 245 1.1 mrg for (size_t i = 0; i != len;) 246 1.1 mrg { 247 1.1 mrg char c; 248 1.1 mrg 249 1.1 mrg fprintf (out, "static const char ptx_code_%u[] =\n\t\"", obj_count++); 250 1.1 mrg while ((c = input[i++])) 251 1.1 mrg { 252 1.1 mrg switch (c) 253 1.1 mrg { 254 1.1 mrg case '\r': 255 1.1 mrg continue; 256 1.1 mrg case '\n': 257 1.1 mrg fprintf (out, "\\n\"\n\t\""); 258 1.1 mrg /* Look for mappings on subsequent lines. */ 259 1.1 mrg while (startswith (input + i, "//:")) 260 1.1 mrg { 261 1.1 mrg i += 3; 262 1.1 mrg 263 1.1 mrg if (startswith (input + i, "VAR_MAP ")) 264 1.1 mrg record_id (input + i + 8, &vars_tail); 265 1.1 mrg else if (startswith (input + i, "FUNC_MAP ")) 266 1.1 mrg record_id (input + i + 9, &funcs_tail); 267 1.1 mrg else 268 1.1 mrg abort (); 269 1.1 mrg /* Skip to next line. */ 270 1.1 mrg while (input[i++] != '\n') 271 1.1 mrg continue; 272 1.1 mrg } 273 1.1 mrg continue; 274 1.1 mrg case '"': 275 1.1 mrg case '\\': 276 1.1 mrg putc ('\\', out); 277 1.1 mrg break; 278 1.1 mrg default: 279 1.1 mrg break; 280 1.1 mrg } 281 1.1 mrg putc (c, out); 282 1.1 mrg } 283 1.1 mrg fprintf (out, "\";\n\n"); 284 1.1 mrg } 285 1.1 mrg 286 1.1 mrg /* Dump out array of pointers to ptx object strings. */ 287 1.1 mrg fprintf (out, "static const struct ptx_obj {\n" 288 1.1 mrg " const char *code;\n" 289 1.1 mrg " __SIZE_TYPE__ size;\n" 290 1.1 mrg "} ptx_objs[] = {"); 291 1.1 mrg for (comma = "", ix = 0; ix != obj_count; comma = ",", ix++) 292 1.1 mrg fprintf (out, "%s\n\t{ptx_code_%u, sizeof (ptx_code_%u)}", comma, ix, ix); 293 1.1 mrg fprintf (out, "\n};\n\n"); 294 1.1 mrg 295 1.1 mrg /* Dump out variable idents. */ 296 1.1 mrg fprintf (out, "static const char *const var_mappings[] = {"); 297 1.1 mrg for (comma = "", id = var_ids; id; comma = ",", id = id->next) 298 1.1 mrg fprintf (out, "%s\n\t%s", comma, id->ptx_name); 299 1.1 mrg fprintf (out, "\n};\n\n"); 300 1.1 mrg 301 1.1 mrg /* Dump out function idents. */ 302 1.1 mrg fprintf (out, "static const struct nvptx_fn {\n" 303 1.1 mrg " const char *name;\n" 304 1.1 mrg " unsigned short dim[%d];\n" 305 1.1 mrg "} func_mappings[] = {\n", GOMP_DIM_MAX); 306 1.1 mrg for (comma = "", id = func_ids; id; comma = ",", id = id->next) 307 1.1 mrg fprintf (out, "%s\n\t{%s}", comma, id->ptx_name); 308 1.1 mrg fprintf (out, "\n};\n\n"); 309 1.1 mrg 310 1.1 mrg fprintf (out, 311 1.1 mrg "static const struct nvptx_tdata {\n" 312 1.1 mrg " const struct ptx_obj *ptx_objs;\n" 313 1.1 mrg " unsigned ptx_num;\n" 314 1.1 mrg " const char *const *var_names;\n" 315 1.1 mrg " unsigned var_num;\n" 316 1.1 mrg " const struct nvptx_fn *fn_names;\n" 317 1.1 mrg " unsigned fn_num;\n" 318 1.1 mrg "} target_data = {\n" 319 1.1 mrg " ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n" 320 1.1 mrg " var_mappings," 321 1.1 mrg " sizeof (var_mappings) / sizeof (var_mappings[0]),\n" 322 1.1 mrg " func_mappings," 323 1.1 mrg " sizeof (func_mappings) / sizeof (func_mappings[0])\n" 324 1.1 mrg "};\n\n"); 325 1.1 mrg 326 1.1 mrg fprintf (out, "#ifdef __cplusplus\n" 327 1.1 mrg "extern \"C\" {\n" 328 1.1 mrg "#endif\n"); 329 1.1 mrg 330 1.1 mrg fprintf (out, "extern void GOMP_offload_register_ver" 331 1.1 mrg " (unsigned, const void *, int, const void *);\n"); 332 1.1 mrg fprintf (out, "extern void GOMP_offload_unregister_ver" 333 1.1 mrg " (unsigned, const void *, int, const void *);\n"); 334 1.1 mrg 335 1.1 mrg fprintf (out, "#ifdef __cplusplus\n" 336 1.1 mrg "}\n" 337 1.1 mrg "#endif\n"); 338 1.1 mrg 339 1.1 mrg fprintf (out, "extern const void *const __OFFLOAD_TABLE__[];\n\n"); 340 1.1 mrg 341 1.1 mrg fprintf (out, "static __attribute__((constructor)) void init (void)\n" 342 1.1 mrg "{\n" 343 1.1 mrg " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__," 344 1.1 mrg " %d/*NVIDIA_PTX*/, &target_data);\n" 345 1.1 mrg "};\n", 346 1.1 mrg GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX), 347 1.1 mrg GOMP_DEVICE_NVIDIA_PTX); 348 1.1 mrg 349 1.1 mrg fprintf (out, "static __attribute__((destructor)) void fini (void)\n" 350 1.1 mrg "{\n" 351 1.1 mrg " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__," 352 1.1 mrg " %d/*NVIDIA_PTX*/, &target_data);\n" 353 1.1 mrg "};\n", 354 1.1 mrg GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX), 355 1.1 mrg GOMP_DEVICE_NVIDIA_PTX); 356 1.1 mrg } 357 1.1 mrg 358 1.1 mrg static void 359 1.1 mrg compile_native (const char *infile, const char *outfile, const char *compiler, 360 1.1 mrg bool fPIC, bool fpic) 361 1.1 mrg { 362 1.1 mrg const char *collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS"); 363 1.1 mrg if (!collect_gcc_options) 364 1.1 mrg fatal_error (input_location, 365 1.1 mrg "environment variable COLLECT_GCC_OPTIONS must be set"); 366 1.1 mrg 367 1.1 mrg struct obstack argv_obstack; 368 1.1 mrg obstack_init (&argv_obstack); 369 1.1 mrg obstack_ptr_grow (&argv_obstack, compiler); 370 1.1 mrg if (fPIC) 371 1.1 mrg obstack_ptr_grow (&argv_obstack, "-fPIC"); 372 1.1 mrg if (fpic) 373 1.1 mrg obstack_ptr_grow (&argv_obstack, "-fpic"); 374 1.1 mrg if (save_temps) 375 1.1 mrg obstack_ptr_grow (&argv_obstack, "-save-temps"); 376 1.1 mrg if (verbose) 377 1.1 mrg obstack_ptr_grow (&argv_obstack, "-v"); 378 1.1 mrg obstack_ptr_grow (&argv_obstack, "-dumpdir"); 379 1.1 mrg obstack_ptr_grow (&argv_obstack, ""); 380 1.1 mrg obstack_ptr_grow (&argv_obstack, "-dumpbase"); 381 1.1 mrg obstack_ptr_grow (&argv_obstack, ptx_dumpbase); 382 1.1 mrg obstack_ptr_grow (&argv_obstack, "-dumpbase-ext"); 383 1.1 mrg obstack_ptr_grow (&argv_obstack, ".c"); 384 1.1 mrg switch (offload_abi) 385 1.1 mrg { 386 1.1 mrg case OFFLOAD_ABI_LP64: 387 1.1 mrg obstack_ptr_grow (&argv_obstack, "-m64"); 388 1.1 mrg break; 389 1.1 mrg case OFFLOAD_ABI_ILP32: 390 1.1 mrg obstack_ptr_grow (&argv_obstack, "-m32"); 391 1.1 mrg break; 392 1.1 mrg default: 393 1.1 mrg gcc_unreachable (); 394 1.1 mrg } 395 1.1 mrg obstack_ptr_grow (&argv_obstack, infile); 396 1.1 mrg obstack_ptr_grow (&argv_obstack, "-c"); 397 1.1 mrg obstack_ptr_grow (&argv_obstack, "-o"); 398 1.1 mrg obstack_ptr_grow (&argv_obstack, outfile); 399 1.1 mrg obstack_ptr_grow (&argv_obstack, NULL); 400 1.1 mrg 401 1.1 mrg const char **new_argv = XOBFINISH (&argv_obstack, const char **); 402 1.1 mrg fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true, 403 1.1 mrg ".gccnative_args"); 404 1.1 mrg obstack_free (&argv_obstack, NULL); 405 1.1 mrg } 406 1.1 mrg 407 1.1 mrg int 408 1.1 mrg main (int argc, char **argv) 409 1.1 mrg { 410 1.1 mrg FILE *in = stdin; 411 1.1 mrg FILE *out = stdout; 412 1.1 mrg const char *outname = 0; 413 1.1 mrg 414 1.1 mrg progname = "mkoffload"; 415 1.1 mrg diagnostic_initialize (global_dc, 0); 416 1.1 mrg 417 1.1 mrg if (atexit (mkoffload_cleanup) != 0) 418 1.1 mrg fatal_error (input_location, "atexit failed"); 419 1.1 mrg 420 1.1 mrg char *collect_gcc = getenv ("COLLECT_GCC"); 421 1.1 mrg if (collect_gcc == NULL) 422 1.1 mrg fatal_error (input_location, "COLLECT_GCC must be set."); 423 1.1 mrg const char *gcc_path = dirname (ASTRDUP (collect_gcc)); 424 1.1 mrg const char *gcc_exec = basename (ASTRDUP (collect_gcc)); 425 1.1 mrg 426 1.1 mrg size_t len = (strlen (gcc_path) + 1 427 1.1 mrg + strlen (GCC_INSTALL_NAME) 428 1.1 mrg + 1); 429 1.1 mrg char *driver = XALLOCAVEC (char, len); 430 1.1 mrg 431 1.1 mrg if (strcmp (gcc_exec, collect_gcc) == 0) 432 1.1 mrg /* collect_gcc has no path, so it was found in PATH. Make sure we also 433 1.1 mrg find accel-gcc in PATH. */ 434 1.1 mrg gcc_path = NULL; 435 1.1 mrg 436 1.1 mrg int driver_used = 0; 437 1.1 mrg if (gcc_path != NULL) 438 1.1 mrg driver_used = sprintf (driver, "%s/", gcc_path); 439 1.1 mrg sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME); 440 1.1 mrg 441 1.1 mrg bool found = false; 442 1.1 mrg if (gcc_path == NULL) 443 1.1 mrg found = true; 444 1.1 mrg else if (access_check (driver, X_OK) == 0) 445 1.1 mrg found = true; 446 1.1 mrg else 447 1.1 mrg { 448 1.1 mrg /* Don't use alloca pointer with XRESIZEVEC. */ 449 1.1 mrg driver = NULL; 450 1.1 mrg /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME. */ 451 1.1 mrg char **paths = NULL; 452 1.1 mrg unsigned n_paths; 453 1.1 mrg n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths); 454 1.1 mrg for (unsigned i = 0; i < n_paths; i++) 455 1.1 mrg { 456 1.1 mrg len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1; 457 1.1 mrg driver = XRESIZEVEC (char, driver, len); 458 1.1 mrg sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME); 459 1.1 mrg if (access_check (driver, X_OK) == 0) 460 1.1 mrg { 461 1.1 mrg found = true; 462 1.1 mrg break; 463 1.1 mrg } 464 1.1 mrg } 465 1.1 mrg free_array_of_ptrs ((void **) paths, n_paths); 466 1.1 mrg } 467 1.1 mrg 468 1.1 mrg if (!found) 469 1.1 mrg fatal_error (input_location, 470 1.1 mrg "offload compiler %s not found (consider using %<-B%>)", 471 1.1 mrg GCC_INSTALL_NAME); 472 1.1 mrg 473 1.1 mrg /* We may be called with all the arguments stored in some file and 474 1.1 mrg passed with @file. Expand them into argv before processing. */ 475 1.1 mrg expandargv (&argc, &argv); 476 1.1 mrg 477 1.1 mrg /* Scan the argument vector. */ 478 1.1 mrg bool fopenmp = false; 479 1.1 mrg bool fopenacc = false; 480 1.1 mrg bool fPIC = false; 481 1.1 mrg bool fpic = false; 482 1.1 mrg for (int i = 1; i < argc; i++) 483 1.1 mrg { 484 1.1 mrg #define STR "-foffload-abi=" 485 1.1 mrg if (startswith (argv[i], STR)) 486 1.1 mrg { 487 1.1 mrg if (strcmp (argv[i] + strlen (STR), "lp64") == 0) 488 1.1 mrg offload_abi = OFFLOAD_ABI_LP64; 489 1.1 mrg else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0) 490 1.1 mrg offload_abi = OFFLOAD_ABI_ILP32; 491 1.1 mrg else 492 1.1 mrg fatal_error (input_location, 493 1.1 mrg "unrecognizable argument of option " STR); 494 1.1 mrg } 495 1.1 mrg #undef STR 496 1.1 mrg else if (strcmp (argv[i], "-fopenmp") == 0) 497 1.1 mrg fopenmp = true; 498 1.1 mrg else if (strcmp (argv[i], "-fopenacc") == 0) 499 1.1 mrg fopenacc = true; 500 1.1 mrg else if (strcmp (argv[i], "-fPIC") == 0) 501 1.1 mrg fPIC = true; 502 1.1 mrg else if (strcmp (argv[i], "-fpic") == 0) 503 1.1 mrg fpic = true; 504 1.1 mrg else if (strcmp (argv[i], "-save-temps") == 0) 505 1.1 mrg save_temps = true; 506 1.1 mrg else if (strcmp (argv[i], "-v") == 0) 507 1.1 mrg verbose = true; 508 1.1 mrg else if (strcmp (argv[i], "-dumpbase") == 0 509 1.1 mrg && i + 1 < argc) 510 1.1 mrg dumppfx = argv[++i]; 511 1.1 mrg } 512 1.1 mrg if (!(fopenacc ^ fopenmp)) 513 1.1 mrg fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> " 514 1.1 mrg "must be set"); 515 1.1 mrg 516 1.1 mrg struct obstack argv_obstack; 517 1.1 mrg obstack_init (&argv_obstack); 518 1.1 mrg obstack_ptr_grow (&argv_obstack, driver); 519 1.1 mrg if (save_temps) 520 1.1 mrg obstack_ptr_grow (&argv_obstack, "-save-temps"); 521 1.1 mrg if (verbose) 522 1.1 mrg obstack_ptr_grow (&argv_obstack, "-v"); 523 1.1 mrg obstack_ptr_grow (&argv_obstack, "-xlto"); 524 1.1 mrg switch (offload_abi) 525 1.1 mrg { 526 1.1 mrg case OFFLOAD_ABI_LP64: 527 1.1 mrg obstack_ptr_grow (&argv_obstack, "-m64"); 528 1.1 mrg break; 529 1.1 mrg case OFFLOAD_ABI_ILP32: 530 1.1 mrg obstack_ptr_grow (&argv_obstack, "-m32"); 531 1.1 mrg break; 532 1.1 mrg default: 533 1.1 mrg gcc_unreachable (); 534 1.1 mrg } 535 1.1 mrg if (fopenmp) 536 1.1 mrg obstack_ptr_grow (&argv_obstack, "-mgomp"); 537 1.1 mrg 538 1.1 mrg for (int ix = 1; ix != argc; ix++) 539 1.1 mrg { 540 1.1 mrg if (!strcmp (argv[ix], "-o") && ix + 1 != argc) 541 1.1 mrg outname = argv[++ix]; 542 1.1 mrg else 543 1.1 mrg obstack_ptr_grow (&argv_obstack, argv[ix]); 544 1.1 mrg } 545 1.1 mrg 546 1.1 mrg if (!dumppfx) 547 1.1 mrg dumppfx = outname; 548 1.1 mrg 549 1.1 mrg ptx_dumpbase = concat (dumppfx, ".c", NULL); 550 1.1 mrg if (save_temps) 551 1.1 mrg ptx_cfile_name = ptx_dumpbase; 552 1.1 mrg else 553 1.1 mrg ptx_cfile_name = make_temp_file (".c"); 554 1.1 mrg 555 1.1 mrg out = fopen (ptx_cfile_name, "w"); 556 1.1 mrg if (!out) 557 1.1 mrg fatal_error (input_location, "cannot open '%s'", ptx_cfile_name); 558 1.1 mrg 559 1.1 mrg /* PR libgomp/65099: Currently, we only support offloading in 64-bit 560 1.1 mrg configurations. */ 561 1.1 mrg if (offload_abi == OFFLOAD_ABI_LP64) 562 1.1 mrg { 563 1.1 mrg char *mko_dumpbase = concat (dumppfx, ".mkoffload", NULL); 564 1.1 mrg if (save_temps) 565 1.1 mrg ptx_name = mko_dumpbase; 566 1.1 mrg else 567 1.1 mrg ptx_name = make_temp_file (".mkoffload"); 568 1.1 mrg obstack_ptr_grow (&argv_obstack, "-dumpdir"); 569 1.1 mrg obstack_ptr_grow (&argv_obstack, ""); 570 1.1 mrg obstack_ptr_grow (&argv_obstack, "-dumpbase"); 571 1.1 mrg obstack_ptr_grow (&argv_obstack, mko_dumpbase); 572 1.1 mrg obstack_ptr_grow (&argv_obstack, "-dumpbase-ext"); 573 1.1 mrg obstack_ptr_grow (&argv_obstack, ""); 574 1.1 mrg obstack_ptr_grow (&argv_obstack, "-o"); 575 1.1 mrg obstack_ptr_grow (&argv_obstack, ptx_name); 576 1.1 mrg obstack_ptr_grow (&argv_obstack, NULL); 577 1.1 mrg const char **new_argv = XOBFINISH (&argv_obstack, const char **); 578 1.1 mrg 579 1.1 mrg char *execpath = getenv ("GCC_EXEC_PREFIX"); 580 1.1 mrg char *cpath = getenv ("COMPILER_PATH"); 581 1.1 mrg char *lpath = getenv ("LIBRARY_PATH"); 582 1.1 mrg unsetenv ("GCC_EXEC_PREFIX"); 583 1.1 mrg unsetenv ("COMPILER_PATH"); 584 1.1 mrg unsetenv ("LIBRARY_PATH"); 585 1.1 mrg 586 1.1 mrg fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true, 587 1.1 mrg ".gcc_args"); 588 1.1 mrg obstack_free (&argv_obstack, NULL); 589 1.1 mrg 590 1.1 mrg xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL)); 591 1.1 mrg xputenv (concat ("COMPILER_PATH=", cpath, NULL)); 592 1.1 mrg xputenv (concat ("LIBRARY_PATH=", lpath, NULL)); 593 1.1 mrg 594 1.1 mrg in = fopen (ptx_name, "r"); 595 1.1 mrg if (!in) 596 1.1 mrg fatal_error (input_location, "cannot open intermediate ptx file"); 597 1.1 mrg 598 1.1 mrg process (in, out); 599 1.1 mrg fclose (in); 600 1.1 mrg } 601 1.1 mrg 602 1.1 mrg fclose (out); 603 1.1 mrg 604 1.1 mrg compile_native (ptx_cfile_name, outname, collect_gcc, fPIC, fpic); 605 1.1 mrg 606 1.1 mrg return 0; 607 1.1 mrg } 608