]>
Commit | Line | Data |
---|---|---|
d7f09764 | 1 | /* Wrapper to call lto. Used by collect2 and the linker plugin. |
818ab71a | 2 | Copyright (C) 2009-2016 Free Software Foundation, Inc. |
d7f09764 DN |
3 | |
4 | Factored out of collect2 by Rafael Espindola <espindola@google.com> | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 3, or (at your option) any later | |
11 | version. | |
12 | ||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GCC; see the file COPYING3. If not see | |
20 | <http://www.gnu.org/licenses/>. */ | |
21 | ||
22 | ||
23 | /* This program is passed a gcc, a list of gcc arguments and a list of | |
24 | object files containing IL. It scans the argument list to check if | |
25 | we are in whopr mode or not modifies the arguments and needed and | |
26 | prints a list of output files on stdout. | |
27 | ||
28 | Example: | |
29 | ||
30 | $ lto-wrapper gcc/xgcc -B gcc a.o b.o -o test -flto | |
31 | ||
32 | The above will print something like | |
33 | /tmp/ccwbQ8B2.lto.o | |
34 | ||
014d92e1 | 35 | If WHOPR is used instead, more than one file might be produced |
d7f09764 DN |
36 | ./ccXj2DTk.lto.ltrans.o |
37 | ./ccCJuXGv.lto.ltrans.o | |
38 | */ | |
39 | ||
40 | #include "config.h" | |
41 | #include "system.h" | |
10692477 | 42 | #include "coretypes.h" |
d7f09764 | 43 | #include "intl.h" |
2691e6d7 | 44 | #include "diagnostic.h" |
48cf395b | 45 | #include "obstack.h" |
f31c0018 RG |
46 | #include "opts.h" |
47 | #include "options.h" | |
52a35ef7 | 48 | #include "simple-object.h" |
4000360e | 49 | #include "lto-section-names.h" |
a185856a | 50 | #include "collect-utils.h" |
d7f09764 | 51 | |
fc8b3540 IV |
52 | /* Environment variable, used for passing the names of offload targets from GCC |
53 | driver to lto-wrapper. */ | |
54 | #define OFFLOAD_TARGET_NAMES_ENV "OFFLOAD_TARGET_NAMES" | |
55 | ||
d7f09764 | 56 | enum lto_mode_d { |
cf96bae7 RG |
57 | LTO_MODE_NONE, /* Not doing LTO. */ |
58 | LTO_MODE_LTO, /* Normal LTO. */ | |
59 | LTO_MODE_WHOPR /* WHOPR. */ | |
d7f09764 DN |
60 | }; |
61 | ||
62 | /* Current LTO mode. */ | |
63 | static enum lto_mode_d lto_mode = LTO_MODE_NONE; | |
64 | ||
b1b07c92 RG |
65 | static char *ltrans_output_file; |
66 | static char *flto_out; | |
50ee30d5 RG |
67 | static unsigned int nr; |
68 | static char **input_names; | |
69 | static char **output_names; | |
fc8b3540 IV |
70 | static char **offload_names; |
71 | static const char *offloadbegin, *offloadend; | |
50ee30d5 | 72 | static char *makefile; |
b1b07c92 | 73 | |
a185856a | 74 | const char tool_name[] = "lto-wrapper"; |
b1b07c92 | 75 | |
a185856a | 76 | /* Delete tempfiles. Called from utils_cleanup. */ |
b1b07c92 | 77 | |
a185856a | 78 | void |
5f0ad6a5 | 79 | tool_cleanup (bool) |
b1b07c92 | 80 | { |
396717c9 RG |
81 | unsigned int i; |
82 | ||
396717c9 | 83 | if (ltrans_output_file) |
a185856a | 84 | maybe_unlink (ltrans_output_file); |
396717c9 | 85 | if (flto_out) |
a185856a | 86 | maybe_unlink (flto_out); |
396717c9 | 87 | if (makefile) |
a185856a | 88 | maybe_unlink (makefile); |
396717c9 | 89 | for (i = 0; i < nr; ++i) |
8aea79e6 | 90 | { |
a185856a | 91 | maybe_unlink (input_names[i]); |
396717c9 | 92 | if (output_names[i]) |
a185856a | 93 | maybe_unlink (output_names[i]); |
8aea79e6 | 94 | } |
396717c9 RG |
95 | } |
96 | ||
97 | static void | |
a185856a | 98 | lto_wrapper_cleanup (void) |
d7f09764 | 99 | { |
5f0ad6a5 | 100 | utils_cleanup (false); |
d7f09764 DN |
101 | } |
102 | ||
d7f09764 DN |
103 | /* Unlink a temporary LTRANS file unless requested otherwise. */ |
104 | ||
a185856a BS |
105 | void |
106 | maybe_unlink (const char *file) | |
d7f09764 | 107 | { |
608508a6 | 108 | if (!save_temps) |
d7f09764 | 109 | { |
62116e60 RG |
110 | if (unlink_if_ordinary (file) |
111 | && errno != ENOENT) | |
40fecdd6 | 112 | fatal_error (input_location, "deleting LTRANS file %s: %m", file); |
d7f09764 | 113 | } |
eba14fca | 114 | else if (verbose) |
d7f09764 DN |
115 | fprintf (stderr, "[Leaving LTRANS %s]\n", file); |
116 | } | |
117 | ||
48cf395b RB |
118 | /* Template of LTRANS dumpbase suffix. */ |
119 | #define DUMPBASE_SUFFIX ".ltrans18446744073709551615" | |
d7f09764 | 120 | |
f31c0018 RG |
121 | /* Create decoded options from the COLLECT_GCC and COLLECT_GCC_OPTIONS |
122 | environment according to LANG_MASK. */ | |
123 | ||
124 | static void | |
125 | get_options_from_collect_gcc_options (const char *collect_gcc, | |
126 | const char *collect_gcc_options, | |
127 | unsigned int lang_mask, | |
128 | struct cl_decoded_option **decoded_options, | |
129 | unsigned int *decoded_options_count) | |
130 | { | |
969d578c | 131 | struct obstack argv_obstack; |
f31c0018 RG |
132 | char *argv_storage; |
133 | const char **argv; | |
969d578c RG |
134 | int j, k, argc; |
135 | ||
f31c0018 | 136 | argv_storage = xstrdup (collect_gcc_options); |
969d578c RG |
137 | obstack_init (&argv_obstack); |
138 | obstack_ptr_grow (&argv_obstack, collect_gcc); | |
139 | ||
140 | for (j = 0, k = 0; argv_storage[j] != '\0'; ++j) | |
f31c0018 RG |
141 | { |
142 | if (argv_storage[j] == '\'') | |
143 | { | |
969d578c RG |
144 | obstack_ptr_grow (&argv_obstack, &argv_storage[k]); |
145 | ++j; | |
146 | do | |
147 | { | |
148 | if (argv_storage[j] == '\0') | |
40fecdd6 | 149 | fatal_error (input_location, "malformed COLLECT_GCC_OPTIONS"); |
969d578c RG |
150 | else if (strncmp (&argv_storage[j], "'\\''", 4) == 0) |
151 | { | |
152 | argv_storage[k++] = '\''; | |
153 | j += 4; | |
154 | } | |
155 | else if (argv_storage[j] == '\'') | |
156 | break; | |
157 | else | |
158 | argv_storage[k++] = argv_storage[j++]; | |
159 | } | |
160 | while (1); | |
161 | argv_storage[k++] = '\0'; | |
f31c0018 RG |
162 | } |
163 | } | |
969d578c RG |
164 | |
165 | obstack_ptr_grow (&argv_obstack, NULL); | |
166 | argc = obstack_object_size (&argv_obstack) / sizeof (void *) - 1; | |
167 | argv = XOBFINISH (&argv_obstack, const char **); | |
f31c0018 RG |
168 | |
169 | decode_cmdline_options_to_array (argc, (const char **)argv, | |
170 | lang_mask, | |
171 | decoded_options, decoded_options_count); | |
969d578c | 172 | obstack_free (&argv_obstack, NULL); |
f31c0018 RG |
173 | } |
174 | ||
52a35ef7 RG |
175 | /* Append OPTION to the options array DECODED_OPTIONS with size |
176 | DECODED_OPTIONS_COUNT. */ | |
177 | ||
178 | static void | |
179 | append_option (struct cl_decoded_option **decoded_options, | |
180 | unsigned int *decoded_options_count, | |
181 | struct cl_decoded_option *option) | |
182 | { | |
183 | ++*decoded_options_count; | |
184 | *decoded_options | |
185 | = (struct cl_decoded_option *) | |
186 | xrealloc (*decoded_options, | |
187 | (*decoded_options_count | |
188 | * sizeof (struct cl_decoded_option))); | |
189 | memcpy (&(*decoded_options)[*decoded_options_count - 1], option, | |
190 | sizeof (struct cl_decoded_option)); | |
191 | } | |
192 | ||
193 | /* Try to merge and complain about options FDECODED_OPTIONS when applied | |
194 | ontop of DECODED_OPTIONS. */ | |
195 | ||
196 | static void | |
197 | merge_and_complain (struct cl_decoded_option **decoded_options, | |
198 | unsigned int *decoded_options_count, | |
199 | struct cl_decoded_option *fdecoded_options, | |
200 | unsigned int fdecoded_options_count) | |
201 | { | |
202 | unsigned int i, j; | |
203 | ||
204 | /* ??? Merge options from files. Most cases can be | |
205 | handled by either unioning or intersecting | |
206 | (for example -fwrapv is a case for unioning, | |
207 | -ffast-math is for intersection). Most complaints | |
208 | about real conflicts between different options can | |
209 | be deferred to the compiler proper. Options that | |
210 | we can neither safely handle by intersection nor | |
211 | unioning would need to be complained about here. | |
212 | Ideally we'd have a flag in the opt files that | |
213 | tells whether to union or intersect or reject. | |
214 | In absence of that it's unclear what a good default is. | |
215 | It's also difficult to get positional handling correct. */ | |
216 | ||
217 | /* The following does what the old LTO option code did, | |
218 | union all target and a selected set of common options. */ | |
219 | for (i = 0; i < fdecoded_options_count; ++i) | |
220 | { | |
221 | struct cl_decoded_option *foption = &fdecoded_options[i]; | |
222 | switch (foption->opt_index) | |
223 | { | |
169d8507 L |
224 | case OPT_SPECIAL_unknown: |
225 | case OPT_SPECIAL_ignore: | |
226 | case OPT_SPECIAL_program_name: | |
227 | case OPT_SPECIAL_input_file: | |
228 | break; | |
229 | ||
52a35ef7 RG |
230 | default: |
231 | if (!(cl_options[foption->opt_index].flags & CL_TARGET)) | |
232 | break; | |
233 | ||
234 | /* Fallthru. */ | |
eb472171 CLT |
235 | case OPT_fdiagnostics_show_caret: |
236 | case OPT_fdiagnostics_show_option: | |
237 | case OPT_fdiagnostics_show_location_: | |
238 | case OPT_fshow_column: | |
52a35ef7 RG |
239 | case OPT_fPIC: |
240 | case OPT_fpic: | |
585d0088 | 241 | case OPT_fPIE: |
52a35ef7 RG |
242 | case OPT_fpie: |
243 | case OPT_fcommon: | |
244 | case OPT_fexceptions: | |
2a5145b0 | 245 | case OPT_fnon_call_exceptions: |
aad038ca | 246 | case OPT_fgnu_tm: |
52a35ef7 RG |
247 | /* Do what the old LTO code did - collect exactly one option |
248 | setting per OPT code, we pick the first we encounter. | |
249 | ??? This doesn't make too much sense, but when it doesn't | |
250 | then we should complain. */ | |
251 | for (j = 0; j < *decoded_options_count; ++j) | |
252 | if ((*decoded_options)[j].opt_index == foption->opt_index) | |
253 | break; | |
254 | if (j == *decoded_options_count) | |
255 | append_option (decoded_options, decoded_options_count, foption); | |
256 | break; | |
8bb50e5c | 257 | |
4094757e RB |
258 | case OPT_ftrapv: |
259 | case OPT_fstrict_overflow: | |
5d1a0108 RB |
260 | case OPT_ffp_contract_: |
261 | /* For selected options we can merge conservatively. */ | |
262 | for (j = 0; j < *decoded_options_count; ++j) | |
263 | if ((*decoded_options)[j].opt_index == foption->opt_index) | |
264 | break; | |
265 | if (j == *decoded_options_count) | |
266 | append_option (decoded_options, decoded_options_count, foption); | |
4094757e RB |
267 | /* FP_CONTRACT_OFF < FP_CONTRACT_ON < FP_CONTRACT_FAST, |
268 | -fno-trapv < -ftrapv, | |
269 | -fno-strict-overflow < -fstrict-overflow */ | |
5d1a0108 RB |
270 | else if (foption->value < (*decoded_options)[j].value) |
271 | (*decoded_options)[j] = *foption; | |
272 | break; | |
273 | ||
a35c1ac7 EB |
274 | case OPT_fmath_errno: |
275 | case OPT_fsigned_zeros: | |
276 | case OPT_ftrapping_math: | |
4094757e | 277 | case OPT_fwrapv: |
1506ae0e | 278 | case OPT_fopenmp: |
a0c88d06 | 279 | case OPT_fopenacc: |
8e9b2773 | 280 | case OPT_fcheck_pointer_bounds: |
4094757e RB |
281 | /* For selected options we can merge conservatively. */ |
282 | for (j = 0; j < *decoded_options_count; ++j) | |
283 | if ((*decoded_options)[j].opt_index == foption->opt_index) | |
284 | break; | |
285 | if (j == *decoded_options_count) | |
286 | append_option (decoded_options, decoded_options_count, foption); | |
a35c1ac7 EB |
287 | /* -fmath-errno > -fno-math-errno, |
288 | -fsigned-zeros > -fno-signed-zeros, | |
289 | -ftrapping-math -> -fno-trapping-math, | |
290 | -fwrapv > -fno-wrapv. */ | |
4094757e RB |
291 | else if (foption->value > (*decoded_options)[j].value) |
292 | (*decoded_options)[j] = *foption; | |
293 | break; | |
294 | ||
8bb50e5c RG |
295 | case OPT_freg_struct_return: |
296 | case OPT_fpcc_struct_return: | |
f42c637e | 297 | case OPT_fshort_double: |
8bb50e5c RG |
298 | for (j = 0; j < *decoded_options_count; ++j) |
299 | if ((*decoded_options)[j].opt_index == foption->opt_index) | |
300 | break; | |
301 | if (j == *decoded_options_count) | |
40fecdd6 JM |
302 | fatal_error (input_location, |
303 | "Option %s not used consistently in all LTO input" | |
ffb1f5ef | 304 | " files", foption->orig_option_with_args_text); |
8bb50e5c | 305 | break; |
f3ba16d0 | 306 | |
c713ddc0 BS |
307 | case OPT_foffload_abi_: |
308 | for (j = 0; j < *decoded_options_count; ++j) | |
309 | if ((*decoded_options)[j].opt_index == foption->opt_index) | |
310 | break; | |
21c0a521 DM |
311 | if (j == *decoded_options_count) |
312 | append_option (decoded_options, decoded_options_count, foption); | |
313 | else if (foption->value != (*decoded_options)[j].value) | |
314 | fatal_error (input_location, | |
315 | "Option %s not used consistently in all LTO input" | |
316 | " files", foption->orig_option_with_args_text); | |
317 | break; | |
c713ddc0 | 318 | |
f3ba16d0 RB |
319 | case OPT_O: |
320 | case OPT_Ofast: | |
321 | case OPT_Og: | |
322 | case OPT_Os: | |
323 | for (j = 0; j < *decoded_options_count; ++j) | |
324 | if ((*decoded_options)[j].opt_index == OPT_O | |
325 | || (*decoded_options)[j].opt_index == OPT_Ofast | |
326 | || (*decoded_options)[j].opt_index == OPT_Og | |
327 | || (*decoded_options)[j].opt_index == OPT_Os) | |
328 | break; | |
329 | if (j == *decoded_options_count) | |
330 | append_option (decoded_options, decoded_options_count, foption); | |
331 | else if ((*decoded_options)[j].opt_index == foption->opt_index | |
332 | && foption->opt_index != OPT_O) | |
333 | /* Exact same options get merged. */ | |
334 | ; | |
335 | else | |
336 | { | |
337 | /* For mismatched option kinds preserve the optimization | |
338 | level only, thus merge it as -On. This also handles | |
339 | merging of same optimization level -On. */ | |
340 | int level = 0; | |
341 | switch (foption->opt_index) | |
342 | { | |
343 | case OPT_O: | |
344 | if (foption->arg[0] == '\0') | |
345 | level = MAX (level, 1); | |
346 | else | |
347 | level = MAX (level, atoi (foption->arg)); | |
348 | break; | |
349 | case OPT_Ofast: | |
350 | level = MAX (level, 3); | |
351 | break; | |
352 | case OPT_Og: | |
353 | level = MAX (level, 1); | |
354 | break; | |
355 | case OPT_Os: | |
356 | level = MAX (level, 2); | |
357 | break; | |
358 | default: | |
359 | gcc_unreachable (); | |
360 | } | |
361 | switch ((*decoded_options)[j].opt_index) | |
362 | { | |
363 | case OPT_O: | |
364 | if ((*decoded_options)[j].arg[0] == '\0') | |
365 | level = MAX (level, 1); | |
366 | else | |
367 | level = MAX (level, atoi ((*decoded_options)[j].arg)); | |
368 | break; | |
369 | case OPT_Ofast: | |
370 | level = MAX (level, 3); | |
371 | break; | |
372 | case OPT_Og: | |
373 | level = MAX (level, 1); | |
374 | break; | |
375 | case OPT_Os: | |
376 | level = MAX (level, 2); | |
377 | break; | |
378 | default: | |
379 | gcc_unreachable (); | |
380 | } | |
381 | (*decoded_options)[j].opt_index = OPT_O; | |
382 | char *tem; | |
582f770b | 383 | tem = xasprintf ("-O%d", level); |
f3ba16d0 RB |
384 | (*decoded_options)[j].arg = &tem[2]; |
385 | (*decoded_options)[j].canonical_option[0] = tem; | |
386 | (*decoded_options)[j].value = 1; | |
387 | } | |
388 | break; | |
c713ddc0 BS |
389 | |
390 | case OPT_foffload_: | |
391 | append_option (decoded_options, decoded_options_count, foption); | |
392 | break; | |
52a35ef7 RG |
393 | } |
394 | } | |
395 | } | |
f31c0018 | 396 | |
fc8b3540 IV |
397 | /* Auxiliary function that frees elements of PTR and PTR itself. |
398 | N is number of elements to be freed. If PTR is NULL, nothing is freed. | |
399 | If an element is NULL, subsequent elements are not freed. */ | |
400 | ||
401 | static void ** | |
402 | free_array_of_ptrs (void **ptr, unsigned n) | |
403 | { | |
404 | if (!ptr) | |
405 | return NULL; | |
406 | for (unsigned i = 0; i < n; i++) | |
407 | { | |
408 | if (!ptr[i]) | |
409 | break; | |
410 | free (ptr[i]); | |
411 | } | |
412 | free (ptr); | |
413 | return NULL; | |
414 | } | |
415 | ||
416 | /* Parse STR, saving found tokens into PVALUES and return their number. | |
417 | Tokens are assumed to be delimited by ':'. If APPEND is non-null, | |
418 | append it to every token we find. */ | |
419 | ||
420 | static unsigned | |
421 | parse_env_var (const char *str, char ***pvalues, const char *append) | |
422 | { | |
423 | const char *curval, *nextval; | |
424 | char **values; | |
425 | unsigned num = 1, i; | |
426 | ||
427 | curval = strchr (str, ':'); | |
428 | while (curval) | |
429 | { | |
430 | num++; | |
431 | curval = strchr (curval + 1, ':'); | |
432 | } | |
433 | ||
434 | values = (char**) xmalloc (num * sizeof (char*)); | |
435 | curval = str; | |
b08dec2f DH |
436 | nextval = strchr (curval, ':'); |
437 | if (nextval == NULL) | |
438 | nextval = strchr (curval, '\0'); | |
fc8b3540 IV |
439 | |
440 | int append_len = append ? strlen (append) : 0; | |
441 | for (i = 0; i < num; i++) | |
442 | { | |
443 | int l = nextval - curval; | |
444 | values[i] = (char*) xmalloc (l + 1 + append_len); | |
445 | memcpy (values[i], curval, l); | |
446 | values[i][l] = 0; | |
447 | if (append) | |
448 | strcat (values[i], append); | |
449 | curval = nextval + 1; | |
b08dec2f DH |
450 | nextval = strchr (curval, ':'); |
451 | if (nextval == NULL) | |
452 | nextval = strchr (curval, '\0'); | |
fc8b3540 IV |
453 | } |
454 | *pvalues = values; | |
455 | return num; | |
456 | } | |
457 | ||
c713ddc0 BS |
458 | /* Append options OPTS from lto or offload_lto sections to ARGV_OBSTACK. */ |
459 | ||
460 | static void | |
461 | append_compiler_options (obstack *argv_obstack, struct cl_decoded_option *opts, | |
462 | unsigned int count) | |
463 | { | |
464 | /* Append compiler driver arguments as far as they were merged. */ | |
465 | for (unsigned int j = 1; j < count; ++j) | |
466 | { | |
467 | struct cl_decoded_option *option = &opts[j]; | |
468 | ||
469 | /* File options have been properly filtered by lto-opts.c. */ | |
470 | switch (option->opt_index) | |
471 | { | |
472 | /* Drop arguments that we want to take from the link line. */ | |
473 | case OPT_flto_: | |
474 | case OPT_flto: | |
475 | case OPT_flto_partition_: | |
476 | continue; | |
477 | ||
478 | default: | |
479 | break; | |
480 | } | |
481 | ||
482 | /* For now do what the original LTO option code was doing - pass | |
483 | on any CL_TARGET flag and a few selected others. */ | |
484 | switch (option->opt_index) | |
485 | { | |
eb472171 CLT |
486 | case OPT_fdiagnostics_show_caret: |
487 | case OPT_fdiagnostics_show_option: | |
488 | case OPT_fdiagnostics_show_location_: | |
489 | case OPT_fshow_column: | |
c713ddc0 BS |
490 | case OPT_fPIC: |
491 | case OPT_fpic: | |
492 | case OPT_fPIE: | |
493 | case OPT_fpie: | |
494 | case OPT_fcommon: | |
495 | case OPT_fexceptions: | |
496 | case OPT_fnon_call_exceptions: | |
497 | case OPT_fgnu_tm: | |
498 | case OPT_freg_struct_return: | |
499 | case OPT_fpcc_struct_return: | |
500 | case OPT_fshort_double: | |
501 | case OPT_ffp_contract_: | |
502 | case OPT_fmath_errno: | |
503 | case OPT_fsigned_zeros: | |
504 | case OPT_ftrapping_math: | |
505 | case OPT_fwrapv: | |
1506ae0e | 506 | case OPT_fopenmp: |
a0c88d06 | 507 | case OPT_fopenacc: |
c713ddc0 BS |
508 | case OPT_ftrapv: |
509 | case OPT_fstrict_overflow: | |
510 | case OPT_foffload_abi_: | |
511 | case OPT_O: | |
512 | case OPT_Ofast: | |
513 | case OPT_Og: | |
514 | case OPT_Os: | |
8e9b2773 | 515 | case OPT_fcheck_pointer_bounds: |
c713ddc0 BS |
516 | break; |
517 | ||
518 | default: | |
519 | if (!(cl_options[option->opt_index].flags & CL_TARGET)) | |
520 | continue; | |
521 | } | |
522 | ||
523 | /* Pass the option on. */ | |
524 | for (unsigned int i = 0; i < option->canonical_option_num_elements; ++i) | |
525 | obstack_ptr_grow (argv_obstack, option->canonical_option[i]); | |
526 | } | |
527 | } | |
528 | ||
529 | /* Append linker options OPTS to ARGV_OBSTACK. */ | |
530 | ||
531 | static void | |
532 | append_linker_options (obstack *argv_obstack, struct cl_decoded_option *opts, | |
533 | unsigned int count) | |
534 | { | |
535 | /* Append linker driver arguments. Compiler options from the linker | |
536 | driver arguments will override / merge with those from the compiler. */ | |
537 | for (unsigned int j = 1; j < count; ++j) | |
538 | { | |
539 | struct cl_decoded_option *option = &opts[j]; | |
540 | ||
541 | /* Do not pass on frontend specific flags not suitable for lto. */ | |
542 | if (!(cl_options[option->opt_index].flags | |
543 | & (CL_COMMON|CL_TARGET|CL_DRIVER|CL_LTO))) | |
544 | continue; | |
545 | ||
546 | switch (option->opt_index) | |
547 | { | |
548 | case OPT_o: | |
549 | case OPT_flto_: | |
550 | case OPT_flto: | |
551 | /* We've handled these LTO options, do not pass them on. */ | |
552 | continue; | |
553 | ||
554 | case OPT_freg_struct_return: | |
555 | case OPT_fpcc_struct_return: | |
556 | case OPT_fshort_double: | |
557 | /* Ignore these, they are determined by the input files. | |
558 | ??? We fail to diagnose a possible mismatch here. */ | |
559 | continue; | |
560 | ||
561 | default: | |
562 | break; | |
563 | } | |
564 | ||
565 | /* Pass the option on. */ | |
566 | for (unsigned int i = 0; i < option->canonical_option_num_elements; ++i) | |
567 | obstack_ptr_grow (argv_obstack, option->canonical_option[i]); | |
568 | } | |
569 | } | |
570 | ||
571 | /* Extract options for TARGET offload compiler from OPTIONS and append | |
572 | them to ARGV_OBSTACK. */ | |
573 | ||
574 | static void | |
575 | append_offload_options (obstack *argv_obstack, const char *target, | |
576 | struct cl_decoded_option *options, | |
577 | unsigned int options_count) | |
578 | { | |
579 | for (unsigned i = 0; i < options_count; i++) | |
580 | { | |
581 | const char *cur, *next, *opts; | |
582 | char **argv; | |
583 | unsigned argc; | |
584 | struct cl_decoded_option *option = &options[i]; | |
585 | ||
586 | if (option->opt_index != OPT_foffload_) | |
587 | continue; | |
588 | ||
589 | /* If option argument starts with '-' then no target is specified. That | |
590 | means offload options are specified for all targets, so we need to | |
591 | append them. */ | |
592 | if (option->arg[0] == '-') | |
593 | opts = option->arg; | |
594 | else | |
595 | { | |
596 | opts = strchr (option->arg, '='); | |
64186aad TS |
597 | /* If there are offload targets specified, but no actual options, |
598 | there is nothing to do here. */ | |
c713ddc0 BS |
599 | if (!opts) |
600 | continue; | |
601 | ||
602 | cur = option->arg; | |
603 | ||
604 | while (cur < opts) | |
605 | { | |
b08dec2f DH |
606 | next = strchr (cur, ','); |
607 | if (next == NULL) | |
191ec640 | 608 | next = opts; |
c713ddc0 BS |
609 | next = (next > opts) ? opts : next; |
610 | ||
64186aad | 611 | /* Are we looking for this offload target? */ |
c713ddc0 BS |
612 | if (strlen (target) == (size_t) (next - cur) |
613 | && strncmp (target, cur, next - cur) == 0) | |
614 | break; | |
615 | ||
64186aad | 616 | /* Skip the comma or equal sign. */ |
c713ddc0 BS |
617 | cur = next + 1; |
618 | } | |
619 | ||
620 | if (cur >= opts) | |
621 | continue; | |
622 | ||
623 | opts++; | |
624 | } | |
625 | ||
626 | argv = buildargv (opts); | |
627 | for (argc = 0; argv[argc]; argc++) | |
628 | obstack_ptr_grow (argv_obstack, argv[argc]); | |
629 | } | |
630 | } | |
631 | ||
fc8b3540 IV |
632 | /* Check whether NAME can be accessed in MODE. This is like access, |
633 | except that it never considers directories to be executable. */ | |
634 | ||
635 | static int | |
636 | access_check (const char *name, int mode) | |
637 | { | |
638 | if (mode == X_OK) | |
639 | { | |
640 | struct stat st; | |
641 | ||
642 | if (stat (name, &st) < 0 | |
643 | || S_ISDIR (st.st_mode)) | |
644 | return -1; | |
645 | } | |
646 | ||
647 | return access (name, mode); | |
648 | } | |
649 | ||
650 | /* Prepare a target image for offload TARGET, using mkoffload tool from | |
651 | COMPILER_PATH. Return the name of the resultant object file. */ | |
652 | ||
653 | static char * | |
654 | compile_offload_image (const char *target, const char *compiler_path, | |
c713ddc0 BS |
655 | unsigned in_argc, char *in_argv[], |
656 | struct cl_decoded_option *compiler_opts, | |
657 | unsigned int compiler_opt_count, | |
658 | struct cl_decoded_option *linker_opts, | |
659 | unsigned int linker_opt_count) | |
fc8b3540 IV |
660 | { |
661 | char *filename = NULL; | |
662 | char **argv; | |
663 | char *suffix | |
664 | = XALLOCAVEC (char, sizeof ("/accel//mkoffload") + strlen (target)); | |
665 | strcpy (suffix, "/accel/"); | |
666 | strcat (suffix, target); | |
667 | strcat (suffix, "/mkoffload"); | |
668 | ||
669 | char **paths = NULL; | |
670 | unsigned n_paths = parse_env_var (compiler_path, &paths, suffix); | |
671 | ||
672 | const char *compiler = NULL; | |
673 | for (unsigned i = 0; i < n_paths; i++) | |
674 | if (access_check (paths[i], X_OK) == 0) | |
675 | { | |
676 | compiler = paths[i]; | |
677 | break; | |
678 | } | |
679 | ||
680 | if (compiler) | |
681 | { | |
682 | /* Generate temporary output file name. */ | |
683 | filename = make_temp_file (".target.o"); | |
684 | ||
685 | struct obstack argv_obstack; | |
686 | obstack_init (&argv_obstack); | |
687 | obstack_ptr_grow (&argv_obstack, compiler); | |
4314a3ef TS |
688 | if (save_temps) |
689 | obstack_ptr_grow (&argv_obstack, "-save-temps"); | |
0fe78d19 TS |
690 | if (verbose) |
691 | obstack_ptr_grow (&argv_obstack, "-v"); | |
fc8b3540 IV |
692 | obstack_ptr_grow (&argv_obstack, "-o"); |
693 | obstack_ptr_grow (&argv_obstack, filename); | |
694 | ||
c713ddc0 | 695 | /* Append names of input object files. */ |
443743fd | 696 | for (unsigned i = 0; i < in_argc; i++) |
fc8b3540 | 697 | obstack_ptr_grow (&argv_obstack, in_argv[i]); |
fc8b3540 | 698 | |
c713ddc0 BS |
699 | /* Append options from offload_lto sections. */ |
700 | append_compiler_options (&argv_obstack, compiler_opts, | |
701 | compiler_opt_count); | |
702 | ||
703 | /* Append options specified by -foffload last. In case of conflicting | |
704 | options we expect offload compiler to choose the latest. */ | |
705 | append_offload_options (&argv_obstack, target, compiler_opts, | |
706 | compiler_opt_count); | |
707 | append_offload_options (&argv_obstack, target, linker_opts, | |
708 | linker_opt_count); | |
709 | ||
710 | obstack_ptr_grow (&argv_obstack, NULL); | |
fc8b3540 IV |
711 | argv = XOBFINISH (&argv_obstack, char **); |
712 | fork_execute (argv[0], argv, true); | |
713 | obstack_free (&argv_obstack, NULL); | |
714 | } | |
715 | ||
716 | free_array_of_ptrs ((void **) paths, n_paths); | |
717 | return filename; | |
718 | } | |
719 | ||
720 | ||
721 | /* The main routine dealing with offloading. | |
722 | The routine builds a target image for each offload target. IN_ARGC and | |
723 | IN_ARGV specify options and input object files. As all of them could contain | |
724 | target sections, we pass them all to target compilers. */ | |
725 | ||
726 | static void | |
c713ddc0 BS |
727 | compile_images_for_offload_targets (unsigned in_argc, char *in_argv[], |
728 | struct cl_decoded_option *compiler_opts, | |
729 | unsigned int compiler_opt_count, | |
730 | struct cl_decoded_option *linker_opts, | |
731 | unsigned int linker_opt_count) | |
fc8b3540 IV |
732 | { |
733 | char **names = NULL; | |
734 | const char *target_names = getenv (OFFLOAD_TARGET_NAMES_ENV); | |
735 | if (!target_names) | |
736 | return; | |
737 | unsigned num_targets = parse_env_var (target_names, &names, NULL); | |
738 | ||
b2b40051 | 739 | int next_name_entry = 0; |
fc8b3540 IV |
740 | const char *compiler_path = getenv ("COMPILER_PATH"); |
741 | if (!compiler_path) | |
742 | goto out; | |
743 | ||
744 | /* Prepare an image for each target and save the name of the resultant object | |
745 | file to the OFFLOAD_NAMES array. It is terminated by a NULL entry. */ | |
746 | offload_names = XCNEWVEC (char *, num_targets + 1); | |
747 | for (unsigned i = 0; i < num_targets; i++) | |
748 | { | |
b2b40051 MJ |
749 | /* HSA does not use LTO-like streaming and a different compiler, skip |
750 | it. */ | |
751 | if (strcmp (names[i], "hsa") == 0) | |
752 | continue; | |
753 | ||
754 | offload_names[next_name_entry] | |
c713ddc0 BS |
755 | = compile_offload_image (names[i], compiler_path, in_argc, in_argv, |
756 | compiler_opts, compiler_opt_count, | |
757 | linker_opts, linker_opt_count); | |
b2b40051 | 758 | if (!offload_names[next_name_entry]) |
40fecdd6 JM |
759 | fatal_error (input_location, |
760 | "problem with building target image for %s\n", names[i]); | |
b2b40051 | 761 | next_name_entry++; |
fc8b3540 IV |
762 | } |
763 | ||
764 | out: | |
765 | free_array_of_ptrs ((void **) names, num_targets); | |
766 | } | |
767 | ||
768 | /* Copy a file from SRC to DEST. */ | |
769 | ||
770 | static void | |
771 | copy_file (const char *dest, const char *src) | |
772 | { | |
773 | FILE *d = fopen (dest, "wb"); | |
774 | FILE *s = fopen (src, "rb"); | |
775 | char buffer[512]; | |
776 | while (!feof (s)) | |
777 | { | |
778 | size_t len = fread (buffer, 1, 512, s); | |
779 | if (ferror (s) != 0) | |
40fecdd6 | 780 | fatal_error (input_location, "reading input file"); |
fc8b3540 IV |
781 | if (len > 0) |
782 | { | |
783 | fwrite (buffer, 1, len, d); | |
784 | if (ferror (d) != 0) | |
40fecdd6 | 785 | fatal_error (input_location, "writing output file"); |
fc8b3540 IV |
786 | } |
787 | } | |
788 | } | |
789 | ||
790 | /* Find the crtoffloadbegin.o and crtoffloadend.o files in LIBRARY_PATH, make | |
791 | copies and store the names of the copies in offloadbegin and offloadend. */ | |
792 | ||
793 | static void | |
794 | find_offloadbeginend (void) | |
795 | { | |
796 | char **paths = NULL; | |
797 | const char *library_path = getenv ("LIBRARY_PATH"); | |
798 | if (!library_path) | |
799 | return; | |
800 | unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffloadbegin.o"); | |
801 | ||
802 | unsigned i; | |
803 | for (i = 0; i < n_paths; i++) | |
804 | if (access_check (paths[i], R_OK) == 0) | |
805 | { | |
806 | size_t len = strlen (paths[i]); | |
807 | char *tmp = xstrdup (paths[i]); | |
808 | strcpy (paths[i] + len - strlen ("begin.o"), "end.o"); | |
809 | if (access_check (paths[i], R_OK) != 0) | |
40fecdd6 JM |
810 | fatal_error (input_location, |
811 | "installation error, can't find crtoffloadend.o"); | |
fc8b3540 IV |
812 | /* The linker will delete the filenames we give it, so make |
813 | copies. */ | |
814 | offloadbegin = make_temp_file (".o"); | |
815 | offloadend = make_temp_file (".o"); | |
816 | copy_file (offloadbegin, tmp); | |
817 | copy_file (offloadend, paths[i]); | |
818 | free (tmp); | |
819 | break; | |
820 | } | |
821 | if (i == n_paths) | |
40fecdd6 JM |
822 | fatal_error (input_location, |
823 | "installation error, can't find crtoffloadbegin.o"); | |
fc8b3540 IV |
824 | |
825 | free_array_of_ptrs ((void **) paths, n_paths); | |
826 | } | |
827 | ||
c713ddc0 BS |
828 | /* A subroutine of run_gcc. Examine the open file FD for lto sections with |
829 | name prefix PREFIX, at FILE_OFFSET, and store any options we find in OPTS | |
830 | and OPT_COUNT. Return true if we found a matchingn section, false | |
831 | otherwise. COLLECT_GCC holds the value of the environment variable with | |
832 | the same name. */ | |
833 | ||
834 | static bool | |
835 | find_and_merge_options (int fd, off_t file_offset, const char *prefix, | |
836 | struct cl_decoded_option **opts, | |
837 | unsigned int *opt_count, const char *collect_gcc) | |
838 | { | |
839 | off_t offset, length; | |
840 | char *data; | |
841 | char *fopts; | |
842 | const char *errmsg; | |
843 | int err; | |
844 | struct cl_decoded_option *fdecoded_options = *opts; | |
845 | unsigned int fdecoded_options_count = *opt_count; | |
846 | ||
847 | simple_object_read *sobj; | |
848 | sobj = simple_object_start_read (fd, file_offset, "__GNU_LTO", | |
849 | &errmsg, &err); | |
850 | if (!sobj) | |
851 | return false; | |
852 | ||
853 | char *secname = XALLOCAVEC (char, strlen (prefix) + sizeof (".opts")); | |
854 | strcpy (secname, prefix); | |
855 | strcat (secname, ".opts"); | |
856 | if (!simple_object_find_section (sobj, secname, &offset, &length, | |
857 | &errmsg, &err)) | |
858 | { | |
859 | simple_object_release_read (sobj); | |
860 | return false; | |
861 | } | |
862 | ||
863 | lseek (fd, file_offset + offset, SEEK_SET); | |
864 | data = (char *)xmalloc (length); | |
865 | read (fd, data, length); | |
866 | fopts = data; | |
867 | do | |
868 | { | |
869 | struct cl_decoded_option *f2decoded_options; | |
870 | unsigned int f2decoded_options_count; | |
871 | get_options_from_collect_gcc_options (collect_gcc, | |
872 | fopts, CL_LANG_ALL, | |
873 | &f2decoded_options, | |
874 | &f2decoded_options_count); | |
875 | if (!fdecoded_options) | |
876 | { | |
877 | fdecoded_options = f2decoded_options; | |
878 | fdecoded_options_count = f2decoded_options_count; | |
879 | } | |
880 | else | |
881 | merge_and_complain (&fdecoded_options, | |
882 | &fdecoded_options_count, | |
883 | f2decoded_options, f2decoded_options_count); | |
884 | ||
885 | fopts += strlen (fopts) + 1; | |
886 | } | |
887 | while (fopts - data < length); | |
888 | ||
889 | free (data); | |
890 | simple_object_release_read (sobj); | |
891 | *opts = fdecoded_options; | |
892 | *opt_count = fdecoded_options_count; | |
893 | return true; | |
894 | } | |
895 | ||
d7f09764 DN |
896 | /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */ |
897 | ||
898 | static void | |
899 | run_gcc (unsigned argc, char *argv[]) | |
900 | { | |
cf96bae7 | 901 | unsigned i, j; |
d7f09764 DN |
902 | const char **new_argv; |
903 | const char **argv_ptr; | |
d7f09764 | 904 | char *list_option_full = NULL; |
cf96bae7 | 905 | const char *linker_output = NULL; |
f31c0018 | 906 | const char *collect_gcc, *collect_gcc_options; |
c04b6b38 | 907 | int parallel = 0; |
a478ffff | 908 | int jobserver = 0; |
014d92e1 | 909 | bool no_partition = false; |
52a35ef7 | 910 | struct cl_decoded_option *fdecoded_options = NULL; |
c713ddc0 | 911 | struct cl_decoded_option *offload_fdecoded_options = NULL; |
52a35ef7 | 912 | unsigned int fdecoded_options_count = 0; |
c713ddc0 | 913 | unsigned int offload_fdecoded_options_count = 0; |
f31c0018 RG |
914 | struct cl_decoded_option *decoded_options; |
915 | unsigned int decoded_options_count; | |
ef6f874e RG |
916 | struct obstack argv_obstack; |
917 | int new_head_argc; | |
fc8b3540 IV |
918 | bool have_lto = false; |
919 | bool have_offload = false; | |
443743fd IV |
920 | unsigned lto_argc = 0, offload_argc = 0; |
921 | char **lto_argv, **offload_argv; | |
cf96bae7 RG |
922 | |
923 | /* Get the driver and options. */ | |
924 | collect_gcc = getenv ("COLLECT_GCC"); | |
925 | if (!collect_gcc) | |
40fecdd6 JM |
926 | fatal_error (input_location, |
927 | "environment variable COLLECT_GCC must be set"); | |
cf96bae7 RG |
928 | collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS"); |
929 | if (!collect_gcc_options) | |
40fecdd6 JM |
930 | fatal_error (input_location, |
931 | "environment variable COLLECT_GCC_OPTIONS must be set"); | |
f31c0018 RG |
932 | get_options_from_collect_gcc_options (collect_gcc, collect_gcc_options, |
933 | CL_LANG_ALL, | |
934 | &decoded_options, | |
935 | &decoded_options_count); | |
cf96bae7 | 936 | |
443743fd IV |
937 | /* Allocate arrays for input object files with LTO or offload IL, |
938 | and for possible preceding arguments. */ | |
939 | lto_argv = XNEWVEC (char *, argc); | |
940 | offload_argv = XNEWVEC (char *, argc); | |
941 | ||
52a35ef7 RG |
942 | /* Look at saved options in the IL files. */ |
943 | for (i = 1; i < argc; ++i) | |
944 | { | |
c713ddc0 | 945 | char *p; |
52a35ef7 | 946 | int fd; |
c713ddc0 | 947 | off_t file_offset = 0; |
52a35ef7 | 948 | long loffset; |
52a35ef7 | 949 | int consumed; |
52a35ef7 | 950 | char *filename = argv[i]; |
c713ddc0 | 951 | |
52a35ef7 RG |
952 | if ((p = strrchr (argv[i], '@')) |
953 | && p != argv[i] | |
954 | && sscanf (p, "@%li%n", &loffset, &consumed) >= 1 | |
955 | && strlen (p) == (unsigned int) consumed) | |
956 | { | |
957 | filename = XNEWVEC (char, p - argv[i] + 1); | |
958 | memcpy (filename, argv[i], p - argv[i]); | |
959 | filename[p - argv[i]] = '\0'; | |
960 | file_offset = (off_t) loffset; | |
961 | } | |
1473ab9a | 962 | fd = open (filename, O_RDONLY | O_BINARY); |
52a35ef7 | 963 | if (fd == -1) |
443743fd IV |
964 | { |
965 | lto_argv[lto_argc++] = argv[i]; | |
966 | continue; | |
967 | } | |
968 | ||
969 | if (find_and_merge_options (fd, file_offset, LTO_SECTION_NAME_PREFIX, | |
970 | &fdecoded_options, &fdecoded_options_count, | |
971 | collect_gcc)) | |
972 | { | |
973 | have_lto = true; | |
974 | lto_argv[lto_argc++] = argv[i]; | |
975 | } | |
976 | ||
977 | if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX, | |
978 | &offload_fdecoded_options, | |
979 | &offload_fdecoded_options_count, collect_gcc)) | |
980 | { | |
981 | have_offload = true; | |
982 | offload_argv[offload_argc++] = argv[i]; | |
983 | } | |
52a35ef7 | 984 | |
52a35ef7 RG |
985 | close (fd); |
986 | } | |
987 | ||
cf96bae7 | 988 | /* Initalize the common arguments for the driver. */ |
ef6f874e RG |
989 | obstack_init (&argv_obstack); |
990 | obstack_ptr_grow (&argv_obstack, collect_gcc); | |
991 | obstack_ptr_grow (&argv_obstack, "-xlto"); | |
992 | obstack_ptr_grow (&argv_obstack, "-c"); | |
52a35ef7 | 993 | |
c713ddc0 BS |
994 | append_compiler_options (&argv_obstack, fdecoded_options, |
995 | fdecoded_options_count); | |
996 | append_linker_options (&argv_obstack, decoded_options, decoded_options_count); | |
52a35ef7 | 997 | |
c713ddc0 | 998 | /* Scan linker driver arguments for things that are of relevance to us. */ |
f31c0018 RG |
999 | for (j = 1; j < decoded_options_count; ++j) |
1000 | { | |
1001 | struct cl_decoded_option *option = &decoded_options[j]; | |
f31c0018 RG |
1002 | switch (option->opt_index) |
1003 | { | |
1004 | case OPT_o: | |
1005 | linker_output = option->arg; | |
c713ddc0 | 1006 | break; |
f31c0018 RG |
1007 | |
1008 | case OPT_save_temps: | |
608508a6 | 1009 | save_temps = 1; |
f31c0018 RG |
1010 | break; |
1011 | ||
1012 | case OPT_v: | |
cf96bae7 | 1013 | verbose = 1; |
f31c0018 | 1014 | break; |
cf96bae7 | 1015 | |
783dab6b RB |
1016 | case OPT_flto_partition_: |
1017 | if (strcmp (option->arg, "none") == 0) | |
1018 | no_partition = true; | |
f31c0018 RG |
1019 | break; |
1020 | ||
1021 | case OPT_flto_: | |
1022 | if (strcmp (option->arg, "jobserver") == 0) | |
1023 | { | |
1024 | jobserver = 1; | |
1025 | parallel = 1; | |
1026 | } | |
1027 | else | |
1028 | { | |
1029 | parallel = atoi (option->arg); | |
1030 | if (parallel <= 1) | |
1031 | parallel = 0; | |
1032 | } | |
1033 | /* Fallthru. */ | |
1034 | ||
1035 | case OPT_flto: | |
1036 | lto_mode = LTO_MODE_WHOPR; | |
c713ddc0 | 1037 | break; |
8bb50e5c | 1038 | |
f31c0018 RG |
1039 | default: |
1040 | break; | |
1041 | } | |
f31c0018 RG |
1042 | } |
1043 | ||
014d92e1 JH |
1044 | if (no_partition) |
1045 | { | |
1046 | lto_mode = LTO_MODE_LTO; | |
1047 | jobserver = 0; | |
1048 | parallel = 0; | |
1049 | } | |
cf96bae7 RG |
1050 | |
1051 | if (linker_output) | |
1052 | { | |
1053 | char *output_dir, *base, *name; | |
dd3b31fb | 1054 | bool bit_bucket = strcmp (linker_output, HOST_BIT_BUCKET) == 0; |
d7f09764 | 1055 | |
cf96bae7 RG |
1056 | output_dir = xstrdup (linker_output); |
1057 | base = output_dir; | |
1058 | for (name = base; *name; name++) | |
1059 | if (IS_DIR_SEPARATOR (*name)) | |
1060 | base = name + 1; | |
1061 | *base = '\0'; | |
1062 | ||
1063 | linker_output = &linker_output[base - output_dir]; | |
1064 | if (*output_dir == '\0') | |
1065 | { | |
1066 | static char current_dir[] = { '.', DIR_SEPARATOR, '\0' }; | |
1067 | output_dir = current_dir; | |
1068 | } | |
dd3b31fb L |
1069 | if (!bit_bucket) |
1070 | { | |
ef6f874e RG |
1071 | obstack_ptr_grow (&argv_obstack, "-dumpdir"); |
1072 | obstack_ptr_grow (&argv_obstack, output_dir); | |
dd3b31fb | 1073 | } |
cf96bae7 | 1074 | |
ef6f874e | 1075 | obstack_ptr_grow (&argv_obstack, "-dumpbase"); |
cf96bae7 | 1076 | } |
ef6f874e RG |
1077 | |
1078 | /* Remember at which point we can scrub args to re-use the commons. */ | |
1079 | new_head_argc = obstack_object_size (&argv_obstack) / sizeof (void *); | |
d7f09764 | 1080 | |
fc8b3540 IV |
1081 | if (have_offload) |
1082 | { | |
443743fd IV |
1083 | compile_images_for_offload_targets (offload_argc, offload_argv, |
1084 | offload_fdecoded_options, | |
c713ddc0 BS |
1085 | offload_fdecoded_options_count, |
1086 | decoded_options, | |
1087 | decoded_options_count); | |
fc8b3540 IV |
1088 | if (offload_names) |
1089 | { | |
1090 | find_offloadbeginend (); | |
1091 | for (i = 0; offload_names[i]; i++) | |
1092 | printf ("%s\n", offload_names[i]); | |
1093 | free_array_of_ptrs ((void **) offload_names, i); | |
1094 | } | |
1095 | } | |
1096 | ||
1097 | if (offloadbegin) | |
1098 | printf ("%s\n", offloadbegin); | |
1099 | ||
1100 | /* If object files contain offload sections, but do not contain LTO sections, | |
1101 | then there is no need to perform a link-time recompilation, i.e. | |
1102 | lto-wrapper is used only for a compilation of offload images. */ | |
1103 | if (have_offload && !have_lto) | |
1104 | { | |
1105 | for (i = 1; i < argc; ++i) | |
cdde47a6 TV |
1106 | if (strncmp (argv[i], "-fresolution=", |
1107 | sizeof ("-fresolution=") - 1) != 0 | |
1108 | && strncmp (argv[i], "-flinker-output=", | |
1109 | sizeof ("-flinker-output=") - 1) != 0) | |
fc8b3540 IV |
1110 | { |
1111 | char *out_file; | |
1112 | /* Can be ".o" or ".so". */ | |
1113 | char *ext = strrchr (argv[i], '.'); | |
1114 | if (ext == NULL) | |
1115 | out_file = make_temp_file (""); | |
1116 | else | |
1117 | out_file = make_temp_file (ext); | |
1118 | /* The linker will delete the files we give it, so make copies. */ | |
1119 | copy_file (out_file, argv[i]); | |
1120 | printf ("%s\n", out_file); | |
1121 | } | |
1122 | goto finish; | |
1123 | } | |
1124 | ||
d7f09764 DN |
1125 | if (lto_mode == LTO_MODE_LTO) |
1126 | { | |
1127 | flto_out = make_temp_file (".lto.o"); | |
cf96bae7 | 1128 | if (linker_output) |
ef6f874e RG |
1129 | obstack_ptr_grow (&argv_obstack, linker_output); |
1130 | obstack_ptr_grow (&argv_obstack, "-o"); | |
1131 | obstack_ptr_grow (&argv_obstack, flto_out); | |
d7f09764 | 1132 | } |
be286227 | 1133 | else |
d7f09764 DN |
1134 | { |
1135 | const char *list_option = "-fltrans-output-list="; | |
1136 | size_t list_option_len = strlen (list_option); | |
1137 | char *tmp; | |
1138 | ||
cf96bae7 RG |
1139 | if (linker_output) |
1140 | { | |
1141 | char *dumpbase = (char *) xmalloc (strlen (linker_output) | |
b5611987 | 1142 | + sizeof (".wpa") + 1); |
cf96bae7 RG |
1143 | strcpy (dumpbase, linker_output); |
1144 | strcat (dumpbase, ".wpa"); | |
ef6f874e | 1145 | obstack_ptr_grow (&argv_obstack, dumpbase); |
cf96bae7 RG |
1146 | } |
1147 | ||
608508a6 | 1148 | if (linker_output && save_temps) |
b5611987 RG |
1149 | { |
1150 | ltrans_output_file = (char *) xmalloc (strlen (linker_output) | |
1151 | + sizeof (".ltrans.out") + 1); | |
1152 | strcpy (ltrans_output_file, linker_output); | |
1153 | strcat (ltrans_output_file, ".ltrans.out"); | |
1154 | } | |
1155 | else | |
1156 | ltrans_output_file = make_temp_file (".ltrans.out"); | |
d7f09764 DN |
1157 | list_option_full = (char *) xmalloc (sizeof (char) * |
1158 | (strlen (ltrans_output_file) + list_option_len + 1)); | |
1159 | tmp = list_option_full; | |
1160 | ||
ef6f874e | 1161 | obstack_ptr_grow (&argv_obstack, tmp); |
d7f09764 DN |
1162 | strcpy (tmp, list_option); |
1163 | tmp += list_option_len; | |
1164 | strcpy (tmp, ltrans_output_file); | |
1165 | ||
f300e7b8 JH |
1166 | if (jobserver) |
1167 | obstack_ptr_grow (&argv_obstack, xstrdup ("-fwpa=jobserver")); | |
1168 | else if (parallel > 1) | |
1169 | { | |
1170 | char buf[256]; | |
1171 | sprintf (buf, "-fwpa=%i", parallel); | |
1172 | obstack_ptr_grow (&argv_obstack, xstrdup (buf)); | |
1173 | } | |
1174 | else | |
1175 | obstack_ptr_grow (&argv_obstack, "-fwpa"); | |
d7f09764 | 1176 | } |
d7f09764 | 1177 | |
073a8998 | 1178 | /* Append the input objects and possible preceding arguments. */ |
443743fd IV |
1179 | for (i = 0; i < lto_argc; ++i) |
1180 | obstack_ptr_grow (&argv_obstack, lto_argv[i]); | |
ef6f874e | 1181 | obstack_ptr_grow (&argv_obstack, NULL); |
d7f09764 | 1182 | |
ef6f874e RG |
1183 | new_argv = XOBFINISH (&argv_obstack, const char **); |
1184 | argv_ptr = &new_argv[new_head_argc]; | |
5f0ad6a5 | 1185 | fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true); |
48cf395b | 1186 | |
d7f09764 DN |
1187 | if (lto_mode == LTO_MODE_LTO) |
1188 | { | |
c3284718 | 1189 | printf ("%s\n", flto_out); |
d7f09764 DN |
1190 | free (flto_out); |
1191 | flto_out = NULL; | |
1192 | } | |
be286227 | 1193 | else |
d7f09764 DN |
1194 | { |
1195 | FILE *stream = fopen (ltrans_output_file, "r"); | |
c04b6b38 | 1196 | FILE *mstream = NULL; |
4559db79 | 1197 | struct obstack env_obstack; |
d7f09764 DN |
1198 | |
1199 | if (!stream) | |
40fecdd6 | 1200 | fatal_error (input_location, "fopen: %s: %m", ltrans_output_file); |
d7f09764 | 1201 | |
50ee30d5 | 1202 | /* Parse the list of LTRANS inputs from the WPA stage. */ |
4559db79 | 1203 | obstack_init (&env_obstack); |
50ee30d5 | 1204 | nr = 0; |
48cf395b RB |
1205 | for (;;) |
1206 | { | |
1207 | const unsigned piece = 32; | |
50ee30d5 | 1208 | char *output_name = NULL; |
48cf395b RB |
1209 | char *buf, *input_name = (char *)xmalloc (piece); |
1210 | size_t len; | |
1211 | ||
1212 | buf = input_name; | |
1213 | cont: | |
1214 | if (!fgets (buf, piece, stream)) | |
1215 | break; | |
1216 | len = strlen (input_name); | |
1217 | if (input_name[len - 1] != '\n') | |
1218 | { | |
1219 | input_name = (char *)xrealloc (input_name, len + piece); | |
1220 | buf = input_name + len; | |
1221 | goto cont; | |
1222 | } | |
1223 | input_name[len - 1] = '\0'; | |
1224 | ||
1225 | if (input_name[0] == '*') | |
c04b6b38 | 1226 | output_name = &input_name[1]; |
48cf395b | 1227 | |
c04b6b38 RG |
1228 | nr++; |
1229 | input_names = (char **)xrealloc (input_names, nr * sizeof (char *)); | |
1230 | output_names = (char **)xrealloc (output_names, nr * sizeof (char *)); | |
1231 | input_names[nr-1] = input_name; | |
1232 | output_names[nr-1] = output_name; | |
1233 | } | |
50ee30d5 | 1234 | fclose (stream); |
a185856a | 1235 | maybe_unlink (ltrans_output_file); |
50ee30d5 RG |
1236 | ltrans_output_file = NULL; |
1237 | ||
1238 | if (parallel) | |
1239 | { | |
1240 | makefile = make_temp_file (".mk"); | |
1241 | mstream = fopen (makefile, "w"); | |
1242 | } | |
1243 | ||
1244 | /* Execute the LTRANS stage for each input file (or prepare a | |
1245 | makefile to invoke this in parallel). */ | |
1246 | for (i = 0; i < nr; ++i) | |
1247 | { | |
1248 | char *output_name; | |
1249 | char *input_name = input_names[i]; | |
1250 | /* If it's a pass-through file do nothing. */ | |
1251 | if (output_names[i]) | |
1252 | continue; | |
1253 | ||
1254 | /* Replace the .o suffix with a .ltrans.o suffix and write | |
1255 | the resulting name to the LTRANS output list. */ | |
50ee30d5 RG |
1256 | obstack_grow (&env_obstack, input_name, strlen (input_name) - 2); |
1257 | obstack_grow (&env_obstack, ".ltrans.o", sizeof (".ltrans.o")); | |
1258 | output_name = XOBFINISH (&env_obstack, char *); | |
1259 | ||
1260 | /* Adjust the dumpbase if the linker output file was seen. */ | |
1261 | if (linker_output) | |
1262 | { | |
1263 | char *dumpbase | |
1264 | = (char *) xmalloc (strlen (linker_output) | |
c3284718 | 1265 | + sizeof (DUMPBASE_SUFFIX) + 1); |
50ee30d5 | 1266 | snprintf (dumpbase, |
c3284718 | 1267 | strlen (linker_output) + sizeof (DUMPBASE_SUFFIX), |
b5611987 | 1268 | "%s.ltrans%u", linker_output, i); |
50ee30d5 RG |
1269 | argv_ptr[0] = dumpbase; |
1270 | } | |
1271 | ||
1272 | argv_ptr[1] = "-fltrans"; | |
1273 | argv_ptr[2] = "-o"; | |
1274 | argv_ptr[3] = output_name; | |
1275 | argv_ptr[4] = input_name; | |
1276 | argv_ptr[5] = NULL; | |
1277 | if (parallel) | |
1278 | { | |
1279 | fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]); | |
1280 | for (j = 1; new_argv[j] != NULL; ++j) | |
1281 | fprintf (mstream, " '%s'", new_argv[j]); | |
1282 | fprintf (mstream, "\n"); | |
9d69847d RG |
1283 | /* If we are not preserving the ltrans input files then |
1284 | truncate them as soon as we have processed it. This | |
1285 | reduces temporary disk-space usage. */ | |
608508a6 | 1286 | if (! save_temps) |
9d69847d RG |
1287 | fprintf (mstream, "\t@-touch -r %s %s.tem > /dev/null 2>&1 " |
1288 | "&& mv %s.tem %s\n", | |
1289 | input_name, input_name, input_name, input_name); | |
50ee30d5 RG |
1290 | } |
1291 | else | |
9d69847d | 1292 | { |
5f0ad6a5 BS |
1293 | fork_execute (new_argv[0], CONST_CAST (char **, new_argv), |
1294 | true); | |
a185856a | 1295 | maybe_unlink (input_name); |
9d69847d | 1296 | } |
50ee30d5 RG |
1297 | |
1298 | output_names[i] = output_name; | |
1299 | } | |
c04b6b38 RG |
1300 | if (parallel) |
1301 | { | |
1302 | struct pex_obj *pex; | |
1303 | char jobs[32]; | |
a478ffff | 1304 | |
c04b6b38 RG |
1305 | fprintf (mstream, "all:"); |
1306 | for (i = 0; i < nr; ++i) | |
1307 | fprintf (mstream, " \\\n\t%s", output_names[i]); | |
1308 | fprintf (mstream, "\n"); | |
1309 | fclose (mstream); | |
a478ffff AK |
1310 | if (!jobserver) |
1311 | { | |
1312 | /* Avoid passing --jobserver-fd= and similar flags | |
1313 | unless jobserver mode is explicitly enabled. */ | |
1314 | putenv (xstrdup ("MAKEFLAGS=")); | |
1315 | putenv (xstrdup ("MFLAGS=")); | |
1316 | } | |
5767217f RW |
1317 | new_argv[0] = getenv ("MAKE"); |
1318 | if (!new_argv[0]) | |
1319 | new_argv[0] = "make"; | |
c04b6b38 RG |
1320 | new_argv[1] = "-f"; |
1321 | new_argv[2] = makefile; | |
a478ffff AK |
1322 | i = 3; |
1323 | if (!jobserver) | |
1324 | { | |
1325 | snprintf (jobs, 31, "-j%d", parallel); | |
1326 | new_argv[i++] = jobs; | |
1327 | } | |
1328 | new_argv[i++] = "all"; | |
1329 | new_argv[i++] = NULL; | |
5f0ad6a5 BS |
1330 | pex = collect_execute (new_argv[0], CONST_CAST (char **, new_argv), |
1331 | NULL, NULL, PEX_SEARCH, false); | |
1332 | do_wait (new_argv[0], pex); | |
a185856a | 1333 | maybe_unlink (makefile); |
50ee30d5 | 1334 | makefile = NULL; |
9d69847d | 1335 | for (i = 0; i < nr; ++i) |
a185856a | 1336 | maybe_unlink (input_names[i]); |
c04b6b38 RG |
1337 | } |
1338 | for (i = 0; i < nr; ++i) | |
1339 | { | |
1340 | fputs (output_names[i], stdout); | |
48cf395b | 1341 | putc ('\n', stdout); |
c04b6b38 | 1342 | free (input_names[i]); |
48cf395b | 1343 | } |
50ee30d5 | 1344 | nr = 0; |
c04b6b38 RG |
1345 | free (output_names); |
1346 | free (input_names); | |
d7f09764 | 1347 | free (list_option_full); |
4559db79 | 1348 | obstack_free (&env_obstack, NULL); |
d7f09764 | 1349 | } |
ef6f874e | 1350 | |
fc8b3540 IV |
1351 | finish: |
1352 | if (offloadend) | |
1353 | printf ("%s\n", offloadend); | |
1354 | ||
443743fd IV |
1355 | XDELETE (lto_argv); |
1356 | XDELETE (offload_argv); | |
ef6f874e | 1357 | obstack_free (&argv_obstack, NULL); |
d7f09764 DN |
1358 | } |
1359 | ||
1360 | ||
1361 | /* Entry point. */ | |
1362 | ||
1363 | int | |
1364 | main (int argc, char *argv[]) | |
1365 | { | |
2691e6d7 JM |
1366 | const char *p; |
1367 | ||
de5672fc | 1368 | init_opts_obstack (); |
dc357798 | 1369 | |
2691e6d7 JM |
1370 | p = argv[0] + strlen (argv[0]); |
1371 | while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) | |
1372 | --p; | |
1373 | progname = p; | |
1374 | ||
1375 | xmalloc_set_program_name (progname); | |
1376 | ||
d7f09764 DN |
1377 | gcc_init_libintl (); |
1378 | ||
2691e6d7 JM |
1379 | diagnostic_initialize (global_dc, 0); |
1380 | ||
877088b7 | 1381 | if (atexit (lto_wrapper_cleanup) != 0) |
40fecdd6 | 1382 | fatal_error (input_location, "atexit failed"); |
877088b7 | 1383 | |
396717c9 RG |
1384 | if (signal (SIGINT, SIG_IGN) != SIG_IGN) |
1385 | signal (SIGINT, fatal_signal); | |
1386 | #ifdef SIGHUP | |
1387 | if (signal (SIGHUP, SIG_IGN) != SIG_IGN) | |
1388 | signal (SIGHUP, fatal_signal); | |
1389 | #endif | |
1390 | if (signal (SIGTERM, SIG_IGN) != SIG_IGN) | |
1391 | signal (SIGTERM, fatal_signal); | |
1392 | #ifdef SIGPIPE | |
1393 | if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) | |
1394 | signal (SIGPIPE, fatal_signal); | |
1395 | #endif | |
1396 | #ifdef SIGCHLD | |
1397 | /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will | |
1398 | receive the signal. A different setting is inheritable */ | |
1399 | signal (SIGCHLD, SIG_DFL); | |
1400 | #endif | |
1401 | ||
d7f09764 DN |
1402 | /* We may be called with all the arguments stored in some file and |
1403 | passed with @file. Expand them into argv before processing. */ | |
1404 | expandargv (&argc, &argv); | |
f31c0018 | 1405 | |
cf96bae7 | 1406 | run_gcc (argc, argv); |
d7f09764 DN |
1407 | |
1408 | return 0; | |
1409 | } |