diff options
author | Diego Novillo <dnovillo@google.com> | 2009-04-22 17:47:46 +0000 |
---|---|---|
committer | Diego Novillo <dnovillo@google.com> | 2009-04-22 17:47:46 +0000 |
commit | cfecc360cc6660be7f66d0928a41a0703fc10f64 (patch) | |
tree | 24f41ee282b72f587bad3b298910b33a00d5be6f /gcc | |
parent | 1bf6547b5535b5691e591169907ea9db8fe60fa7 (diff) |
* lto-function-out.c (output_ssa_names): Do not emit
SSA names for memory symbols.
(output_tree_with_context): Call decl_function_context to
check if EXPR is a global symbol.
* lto-function-in.c: Do not include cpplib.h
(input_var_decl): Tidy.
* lto-cgraph.c (input_node): Tidy.
(input_cgraph_1): Tidy.
(input_cgraph): Call lto_mark_file_for_ltrans.
* lto-section-in.h: Include target.h and cgraph.h.
(struct lto_file_decl_data): Tidy.
Add field needs_ltrans_p.
(lto_file_needs_ltrans_p): New.
(lto_mark_file_for_ltrans): New.
(cgraph_node_set_needs_ltrans_p): New.
* Makefile.in (LTO_SECTION_IN_H): Add dependency on
TARGET_H and CGRAPH_H.
(LTO_SECTION_OUT_H): Fix incorrect dependencies.
(lto-function-in.o): Remove dependency on dwarf2asm.h and
dwarf2out.h.
lto/ChangeLog
* lto.c (free_section_data): Tidy.
(lto_1_to_1_map): Tidy.
(lto_add_all_inlinees): Tidy.
(prefix_name_with_star): New.
(get_filename_for_set): New.
(lto_wpa_write_files): Call cgraph_node_set_needs_ltrans_p
to determine what cgraph node sets to write.
Call get_filename_for_set to compute temporary file
names.
(lto_execute_ltrans): Do not execute LTRANS on files with
names that start with '*'.
Move logic to execute LTRANS together so that LTRANS is
invoked only if there are any files to compile.
(do_whole_program_analysis): Only remove output files
that do not start with '*'.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/lto@146606 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog.lto | 23 | ||||
-rw-r--r-- | gcc/Makefile.in | 7 | ||||
-rw-r--r-- | gcc/lto-cgraph.c | 8 | ||||
-rw-r--r-- | gcc/lto-function-in.c | 10 | ||||
-rw-r--r-- | gcc/lto-function-out.c | 8 | ||||
-rw-r--r-- | gcc/lto-section-in.h | 55 | ||||
-rw-r--r-- | gcc/lto/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/lto/lto.c | 283 |
8 files changed, 303 insertions, 109 deletions
diff --git a/gcc/ChangeLog.lto b/gcc/ChangeLog.lto index e9c23529edf..04abd5bf222 100644 --- a/gcc/ChangeLog.lto +++ b/gcc/ChangeLog.lto @@ -1,3 +1,26 @@ +2009-04-22 Diego Novillo <dnovillo@google.com> + + * lto-function-out.c (output_ssa_names): Do not emit + SSA names for memory symbols. + (output_tree_with_context): Call decl_function_context to + check if EXPR is a global symbol. + * lto-function-in.c: Do not include cpplib.h + (input_var_decl): Tidy. + * lto-cgraph.c (input_node): Tidy. + (input_cgraph_1): Tidy. + (input_cgraph): Call lto_mark_file_for_ltrans. + * lto-section-in.h: Include target.h and cgraph.h. + (struct lto_file_decl_data): Tidy. + Add field needs_ltrans_p. + (lto_file_needs_ltrans_p): New. + (lto_mark_file_for_ltrans): New. + (cgraph_node_set_needs_ltrans_p): New. + * Makefile.in (LTO_SECTION_IN_H): Add dependency on + TARGET_H and CGRAPH_H. + (LTO_SECTION_OUT_H): Fix incorrect dependencies. + (lto-function-in.o): Remove dependency on dwarf2asm.h and + dwarf2out.h. + 2009-04-20 Diego Novillo <dnovillo@google.com> Mainline merge @146424. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index acd335c5640..95dedca8179 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -881,8 +881,8 @@ DBGCNT_H = dbgcnt.h dbgcnt.def EBIMAP_H = ebitmap.h sbitmap.h LTO_TAGS_H = lto-tags.h tree.h sbitmap.h lto-header.h LTO_SECTION_H = lto-section.h lto-header.h -LTO_SECTION_IN_H = lto-section-in.h lto-header.h -LTO_SECTION_OUT_H = lto-section-in.h lto-section.h lto-header.h +LTO_SECTION_IN_H = lto-section-in.h lto-header.h $(TARGET_H) $(CGRAPH_H) +LTO_SECTION_OUT_H = lto-section-out.h lto-section.h lto-header.h LTO_TREE_IN_H = lto-tree-in.h $(LTO_SECTION_IN_H) $(PLUGIN_API_H) LTO_OPTS_H = lto-section-in.h lto-opts.h TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H) @@ -2094,8 +2094,7 @@ lto-function-in.o: lto-function-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) tree-iterator.h tree-pass.h \ tree-flow.h $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) except.h \ debug.h $(TIMEVAR_H) $(LTO_TAGS_H) lto-tree-flags.def $(LTO_TREE_IN_H) \ - lto-tree-tags.def $(LTO_SECTION_IN_H) output.h dwarf2asm.h dwarf2out.h \ - libfuncs.h lto-utils.h + lto-tree-tags.def $(LTO_SECTION_IN_H) output.h libfuncs.h lto-utils.h lto-function-out.o : lto-function-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \ $(VARRAY_H) $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) tree-iterator.h \ diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 97728243f1e..b1f4a611fad 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -457,7 +457,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, Return the node read or overwriten. */ static struct cgraph_node * -input_node (struct lto_file_decl_data* file_data, +input_node (struct lto_file_decl_data *file_data, struct lto_input_block *ib, enum LTO_cgraph_tags tag) { @@ -634,7 +634,7 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes) /* Input a cgraph from IB using the info in FILE_DATA. */ static void -input_cgraph_1 (struct lto_file_decl_data* file_data, +input_cgraph_1 (struct lto_file_decl_data *file_data, struct lto_input_block *ib) { enum LTO_cgraph_tags tag; @@ -717,6 +717,10 @@ input_cgraph (void) input_cgraph_1 (file_data, ib); lto_destroy_simple_input_block (file_data, LTO_section_cgraph, ib, data, len); + + /* Assume that every file read needs to be processed by LTRANS. */ + if (flag_wpa) + lto_mark_file_for_ltrans (file_data); } /* Clear out the aux field that was used to store enough state to diff --git a/gcc/lto-function-in.c b/gcc/lto-function-in.c index 363391d2604..37513a4bd92 100644 --- a/gcc/lto-function-in.c +++ b/gcc/lto-function-in.c @@ -52,7 +52,6 @@ Boston, MA 02110-1301, USA. */ #include "lto-section-in.h" #include "lto-tree-in.h" #include "lto-utils.h" -#include "cpplib.h" tree input_tree (struct lto_input_block *, struct data_in *); static tree input_tree_with_context (struct lto_input_block *ib, @@ -2826,12 +2825,9 @@ input_var_decl (struct lto_input_block *ib, struct data_in *data_in) SET_DECL_DEBUG_EXPR (decl, debug_expr); } - /* FIXME lto: Adapted from DWARF reader. Probably needs more thought. - We are only interested in variables with static storage duration. - I expected the test "DECL_FILE_SCOPE_P (decl)" to suffice below, but - it does not work. In particular, the context of a vtable is the - class to which it belongs. */ - if (!decl_function_context (decl)) + /* Register symbols with file or global scope to mark what input + file has their definition. */ + if (decl_function_context (decl) == NULL_TREE) { /* Variable has file scope, not local. Need to ensure static variables between different files don't clash unexpectedly. */ diff --git a/gcc/lto-function-out.c b/gcc/lto-function-out.c index bea2db0b35b..c85c495807f 100644 --- a/gcc/lto-function-out.c +++ b/gcc/lto-function-out.c @@ -1,4 +1,4 @@ -/* Write the gimple representation of a function and it's local +/* Write the gimple representation of a function and its local variables to a .o file. Copyright 2006, 2007, 2008 Free Software Foundation, Inc. @@ -1557,7 +1557,9 @@ output_ssa_names (struct output_block *ob, struct function *fn) { tree ptr = VEC_index (tree, SSANAMES (fn), i); - if (ptr == NULL_TREE || SSA_NAME_IN_FREE_LIST (ptr)) + if (ptr == NULL_TREE + || SSA_NAME_IN_FREE_LIST (ptr) + || !is_gimple_reg (ptr)) continue; output_uleb128 (ob, i); @@ -3307,7 +3309,7 @@ output_tree_with_context (struct output_block *ob, tree expr, tree fn) break; case VAR_DECL: - if (TREE_STATIC (expr) || DECL_EXTERNAL (expr)) + if (decl_function_context (expr) == NULL_TREE) output_var_decl (ob, expr); else /* We should not be seeing local variables here. */ diff --git a/gcc/lto-section-in.h b/gcc/lto-section-in.h index 1952da80984..a31eff23231 100644 --- a/gcc/lto-section-in.h +++ b/gcc/lto-section-in.h @@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_LTO_SECTION_IN_H #define GCC_LTO_SECTION_IN_H +#include "target.h" +#include "cgraph.h" #include "lto-header.h" struct lto_input_block @@ -51,10 +53,11 @@ struct lto_tree_ref_table { unsigned int size; /* Size of array. */ }; -/* Structure to hold states of input scope. */ -struct lto_in_decl_state { +/* Structure to hold states of input scope. */ +struct lto_in_decl_state +{ /* Array of lto_in_decl_buffers to store type and decls streams. */ - struct lto_tree_ref_table streams[LTO_N_DECL_STREAMS]; + struct lto_tree_ref_table streams[LTO_N_DECL_STREAMS]; /* If this in-decl state is associated with a function. FN_DECL point to the FUNCTION_DECL. */ @@ -70,21 +73,21 @@ typedef struct lto_in_decl_state *lto_in_decl_state_ptr; struct lto_file_decl_data { /* Decl state currently used. */ - struct lto_in_decl_state *current_decl_state; + struct lto_in_decl_state *current_decl_state; /* Decl state corresponding to regions outside of any functions in the compilation unit. */ - struct lto_in_decl_state *global_decl_state; + struct lto_in_decl_state *global_decl_state; /* Hash table maps lto-related section names to location in file. */ htab_t function_decl_states; - /* The .o file that these offsets relate to. - - FIXME!!! This will most likely have to be upgraded if the .o files - have been archived. */ + /* The .o file that these offsets relate to. */ const char *file_name; + /* Nonzero if this file should be recompiled with LTRANS. */ + unsigned needs_ltrans_p : 1; + /* If the file is open, this is the fd of the mapped section. This is -1 if the file has not yet been opened. */ int fd; @@ -216,4 +219,38 @@ extern struct lto_in_decl_state * extern void lto_debug_in_fun (struct lto_debug_context *, char); #endif +/* In lto-function-out.c */ +extern void lto_register_decl_definition (tree, struct lto_file_decl_data *); + +/* Return true if FILE needs to be compiled with LTRANS. */ + +static inline bool +lto_file_needs_ltrans_p (struct lto_file_decl_data *file) +{ + return file->needs_ltrans_p != 0; +} + +/* Mark FILE to be compiled with LTRANS. */ + +static inline void +lto_mark_file_for_ltrans (struct lto_file_decl_data *file) +{ + file->needs_ltrans_p = 1; +} + +/* Return true if any files in node set SET need to be compiled + with LTRANS. */ + +static inline bool +cgraph_node_set_needs_ltrans_p (cgraph_node_set set) +{ + cgraph_node_set_iterator csi; + + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + if (lto_file_needs_ltrans_p (csi_node (csi)->local.lto_file_data)) + return true; + + return false; +} + #endif /* GCC_LTO_SECTION_IN_H */ diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index dca7fb472ac..6e0d15ee791 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,21 @@ +2009-04-22 Diego Novillo <dnovillo@google.com> + + * lto.c (free_section_data): Tidy. + (lto_1_to_1_map): Tidy. + (lto_add_all_inlinees): Tidy. + (prefix_name_with_star): New. + (get_filename_for_set): New. + (lto_wpa_write_files): Call cgraph_node_set_needs_ltrans_p + to determine what cgraph node sets to write. + Call get_filename_for_set to compute temporary file + names. + (lto_execute_ltrans): Do not execute LTRANS on files with + names that start with '*'. + Move logic to execute LTRANS together so that LTRANS is + invoked only if there are any files to compile. + (do_whole_program_analysis): Only remove output files + that do not start with '*'. + 2009-04-06 Diego Novillo <dnovillo@google.com> * lto-lang.c (lto_post_options): Set flag_excess_precision_cmdline. diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index ef4901ef105..183abf6b61a 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -503,15 +503,16 @@ free_section_data (struct lto_file_decl_data *file_data, if (file_data->fd == -1) return; - computed_offset = ((intptr_t)offset) & page_mask; - diff = (intptr_t)offset - computed_offset; + computed_offset = ((intptr_t) offset) & page_mask; + diff = (intptr_t) offset - computed_offset; computed_len = len + diff; - munmap ((void *)computed_offset, computed_len); + munmap ((void *) computed_offset, computed_len); } /* Vector of all cgraph node sets. */ -static GTY (()) VEC(cgraph_node_set ,gc) *lto_cgraph_node_sets; +static GTY (()) VEC(cgraph_node_set, gc) *lto_cgraph_node_sets; + /* Group cgrah nodes by input files. This is used mainly for testing right now. */ @@ -548,7 +549,7 @@ lto_1_to_1_map (void) slot = pointer_map_contains (pmap, file_data); if (slot) - set = (cgraph_node_set) *slot; + set = (cgraph_node_set) *slot; else { set = cgraph_node_set_new (); @@ -556,6 +557,7 @@ lto_1_to_1_map (void) *slot = set; VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set); } + cgraph_node_set_add (set, node); } @@ -570,7 +572,7 @@ finish: /* Add inlined clone NODE and its master clone to SET, if NODE itself has - inlined callee, recursively add the callees. */ + inlined callees, recursively add the callees. */ static void lto_add_inline_clones (cgraph_node_set set, struct cgraph_node *node, @@ -594,8 +596,8 @@ lto_add_inline_clones (cgraph_node_set set, struct cgraph_node *node, } /* Compute the transitive closure of inlining of SET based on the - information in the callgraph. Returns a bitmap of decls indexed - by UID. */ + information in the callgraph. Returns a bitmap of decls that have + been inlined into SET indexed by UID. */ static bitmap lto_add_all_inlinees (cgraph_node_set set) @@ -644,6 +646,8 @@ lto_add_all_inlinees (cgraph_node_set set) } while (changed); + /* Transitively add to SET all the inline clones for every node that + has been inlined. */ for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) { node = csi_node (csi); @@ -789,6 +793,7 @@ lto_scan_statics_in_cgraph_node (struct cgraph_node *node, /* Return if the DECL of nodes has been visited before. */ if (bitmap_bit_p (context->seen_node_decls, DECL_UID (node->decl))) return; + bitmap_set_bit (context->seen_node_decls, DECL_UID (node->decl)); state = lto_get_function_in_decl_state (node->local.lto_file_data, @@ -834,7 +839,7 @@ lto_promote_cross_file_statics (void) cgraph_node_set set; cgraph_node_set_iterator csi; globalize_context_t context; - + memset (&context, 0, sizeof (context)); context.all_vars = lto_bitmap_alloc (); context.all_static_vars = lto_bitmap_alloc (); @@ -865,8 +870,76 @@ lto_promote_cross_file_statics (void) lto_bitmap_free (context.all_static_vars); } + +/* Given a file name FNAME, return a string with FNAME prefixed with '*'. */ + +static char * +prefix_name_with_star (const char *fname) +{ + char *star_fname; + size_t len; + + len = strlen (fname) + 1 + 1; + star_fname = XNEWVEC (char, len); + snprintf (star_fname, len, "*%s", fname); + + return star_fname; +} + +/* Return a file name associated with cgraph node set SET. This may + be a new temporary file name if SET needs to be processed by + LTRANS, or the original file name if all the nodes in SET belong to + the same input file. */ + +static char * +get_filename_for_set (cgraph_node_set set) +{ + char *fname = NULL; + static const size_t max_suffix_len = 100; + + if (cgraph_node_set_needs_ltrans_p (set)) + { + /* Create a new temporary file to store SET. To facilitate + debugging, use file names from SET as part of the new + temporary file name. */ + cgraph_node_set_iterator si; + struct pointer_set_t *pset = pointer_set_create (); + char *suffix = NULL; + for (si = csi_start (set); !csi_end_p (si); csi_next (&si)) + { + struct cgraph_node *n = csi_node (si); + const char *f = lbasename (n->local.lto_file_data->file_name); + if (!pointer_set_insert (pset, n->local.lto_file_data)) + suffix = reconcat (suffix, "-", f, suffix, NULL); + if (strlen (suffix) > max_suffix_len) + break; + } + pointer_set_destroy (pset); + suffix = reconcat (suffix, suffix, ".lto.o", NULL); + fname = make_cwd_temp_file (suffix); + + /* If suffix proved to be too long, try something smaller. */ + if (fname == NULL) + fname = make_cwd_temp_file (".lto.o"); + + gcc_assert (fname); + } + else + { + /* Since SET does not need to be processed by LTRANS, use + the original file name and mark it with a '*' prefix so that + lto_execute_ltrans knows not to send it to ltrans_driver. */ + cgraph_node_set_iterator si = csi_start (set); + struct cgraph_node *first = csi_node (si); + fname = prefix_name_with_star (first->local.lto_file_data->file_name); + } + + return fname; +} + static lto_file *current_lto_file; + /* Write all output files in WPA mode. Returns a NULL-terminated array of output file names. */ @@ -874,7 +947,7 @@ static char ** lto_wpa_write_files (void) { char **output_files; - unsigned i, n_sets; + unsigned i, n_sets, last_out_file_ix, num_out_files; lto_file *file; cgraph_node_set set; bitmap decls; @@ -882,7 +955,10 @@ lto_wpa_write_files (void) timevar_push (TV_WHOPR_WPA); - /* Include all inlined functions. */ + /* Include all inlined functions and determine what sets need to be + compiled by LTRANS. After this loop, only those sets that + contain callgraph nodes from more than one file will need to be + compiled by LTRANS. */ for (i = 0; VEC_iterate (cgraph_node_set, lto_cgraph_node_sets, i, set); i++) { decls = lto_add_all_inlinees (set); @@ -899,39 +975,48 @@ lto_wpa_write_files (void) timevar_push (TV_WHOPR_WPA_IO); - output_files = XNEWVEC (char *, VEC_length (cgraph_node_set, - lto_cgraph_node_sets) + 1); + /* The number of output files depends on the number of input files + and how many callgraph node sets we create. Reserve enough space + for the maximum of these two. */ + num_out_files = MAX (VEC_length (cgraph_node_set, lto_cgraph_node_sets), + num_in_fnames); + output_files = XNEWVEC (char *, num_out_files + 1); n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets); for (i = 0; i < n_sets; i++) { - char *temp_filename = make_cwd_temp_file (".lto.o"); + char *temp_filename; + set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i); + temp_filename = get_filename_for_set (set); output_files[i] = temp_filename; - file = lto_elf_file_open (temp_filename, true); - if (!file) - fatal_error ("lto_elf_file_open() failed"); + if (cgraph_node_set_needs_ltrans_p (set)) + { + /* Write all the nodes in SET to TEMP_FILENAME. */ + file = lto_elf_file_open (temp_filename, true); + if (!file) + fatal_error ("lto_elf_file_open() failed"); - lto_set_current_out_file (file); - lto_new_extern_inline_states (); + lto_set_current_out_file (file); + lto_new_extern_inline_states (); - decls = VEC_index (bitmap, inlined_decls, i); - lto_force_functions_extern_inline (decls); + decls = VEC_index (bitmap, inlined_decls, i); + lto_force_functions_extern_inline (decls); - /* Set AUX to 1 in the last LTRANS file. */ - set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i); - set->aux = (void*) ((intptr_t) (i == (n_sets - 1))); - ipa_write_summaries_of_cgraph_node_set (set); - lto_delete_extern_inline_states (); - - lto_set_current_out_file (NULL); - lto_elf_file_close (file); + ipa_write_summaries_of_cgraph_node_set (set); + lto_delete_extern_inline_states (); + + lto_set_current_out_file (NULL); + lto_elf_file_close (file); + } } + last_out_file_ix = n_sets; + lto_stats.num_output_files += n_sets; - output_files[i] = NULL; + output_files[last_out_file_ix] = NULL; for (i = 0; VEC_iterate (bitmap, inlined_decls, i, decls); i++) lto_bitmap_free (decls); @@ -967,31 +1052,6 @@ lto_execute_ltrans (char *const *files) timevar_push (TV_WHOPR_WPA_LTRANS_EXEC); - /* Set the CC environment variable. */ - env_val = getenv ("COLLECT_GCC"); - if (!env_val) - fatal_error ("environment variable COLLECT_GCC must be set"); - - obstack_init (&env_obstack); - obstack_grow (&env_obstack, "CC=", sizeof ("CC=") - 1); - obstack_grow (&env_obstack, env_val, strlen (env_val) + 1); - putenv (XOBFINISH (&env_obstack, char *)); - - /* Set the CFLAGS environment variable. */ - env_val = getenv ("COLLECT_GCC_OPTIONS"); - if (!env_val) - fatal_error ("environment variable COLLECT_GCC_OPTIONS must be set"); - - obstack_init (&env_obstack); - obstack_grow (&env_obstack, "CFLAGS=", sizeof ("CFLAGS=") - 1); - obstack_grow (&env_obstack, env_val, strlen (env_val)); - obstack_grow (&env_obstack, extra_cflags, strlen (extra_cflags) + 1); - putenv (XOBFINISH (&env_obstack, char *)); - - pex = pex_init (0, "lto1", NULL); - if (pex == NULL) - fatal_error ("pex_init failed: %s", xstrerror (errno)); - /* Initalize the arguments for the LTRANS driver. */ for (i = 0; files[i]; ++i); argv = XNEWVEC (char *, i + 2); @@ -1008,47 +1068,99 @@ lto_execute_ltrans (char *const *files) *argv_ptr++ = ltrans_driver; for (i = 0; files[i]; ++i) { - *argv_ptr++ = files[i]; - - /* Replace the .o suffix with a .ltrans.o suffix and write the resulting - name to the LTRANS output list. */ - if (ltrans_output_list_stream) + size_t len; + + /* If the file is prefixed with a '*', it means that we do not + need to re-compile it with LTRANS because it has not been + modified by WPA. Skip it from the command line to + ltrans-driver, but add it to ltrans_output_list_stream so it + is linked after we are done. */ + if (files[i][0] == '*') { - size_t len = strlen (files[i]) - 2; + size_t len = strlen (files[i]) - 1; + if (ltrans_output_list_stream) + if (fwrite (&files[i][1], 1, len, ltrans_output_list_stream) < len + || fwrite ("\n", 1, 1, ltrans_output_list_stream) < 1) + error ("writing to LTRANS output list %s: %m", + ltrans_output_list); + } + else + { + /* Otherwise, add FILES[I] to ltrans-driver's command line + and add the resulting file to LTRANS output list. */ + *argv_ptr++ = files[i]; + + /* Replace the .o suffix with a .ltrans.o suffix and write + the resulting name to the LTRANS output list. */ + if (ltrans_output_list_stream) + { + len = strlen (files[i]) - 2; - if (fwrite (files[i], 1, len, ltrans_output_list_stream) < len - || fwrite (".ltrans.o\n", 1, 10, ltrans_output_list_stream) < 10) - error ("writing to LTRANS output list %s: %m", ltrans_output_list); + if (fwrite (files[i], 1, len, ltrans_output_list_stream) < len + || fwrite (".ltrans.o\n", 1, 10, ltrans_output_list_stream) + < 10) + error ("writing to LTRANS output list %s: %m", + ltrans_output_list); + } } } + *argv_ptr++ = NULL; /* Close the LTRANS output list. */ if (ltrans_output_list_stream && fclose (ltrans_output_list_stream)) error ("closing LTRANS output list %s: %m", ltrans_output_list); - /* Execute the LTRANS driver. */ - errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL, NULL, - &err); - if (errmsg) - fatal_error ("%s: %s", errmsg, xstrerror (err)); - - if (!pex_get_status (pex, 1, &status)) - fatal_error ("can't get program status: %s", xstrerror (errno)); - - pex_free (pex); - - if (status) + /* If there are any files to compile, execute the LTRANS driver. */ + if (argv[1] != NULL) { - if (WIFSIGNALED (status)) + /* Set the CC environment variable. */ + env_val = getenv ("COLLECT_GCC"); + if (!env_val) + fatal_error ("environment variable COLLECT_GCC must be set"); + + obstack_init (&env_obstack); + obstack_grow (&env_obstack, "CC=", sizeof ("CC=") - 1); + obstack_grow (&env_obstack, env_val, strlen (env_val) + 1); + putenv (XOBFINISH (&env_obstack, char *)); + + /* Set the CFLAGS environment variable. */ + env_val = getenv ("COLLECT_GCC_OPTIONS"); + if (!env_val) + fatal_error ("environment variable COLLECT_GCC_OPTIONS must be set"); + + obstack_init (&env_obstack); + obstack_grow (&env_obstack, "CFLAGS=", sizeof ("CFLAGS=") - 1); + obstack_grow (&env_obstack, env_val, strlen (env_val)); + obstack_grow (&env_obstack, extra_cflags, strlen (extra_cflags) + 1); + putenv (XOBFINISH (&env_obstack, char *)); + + pex = pex_init (0, "lto1", NULL); + if (pex == NULL) + fatal_error ("pex_init failed: %s", xstrerror (errno)); + + errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL, NULL, + &err); + if (errmsg) + fatal_error ("%s: %s", errmsg, xstrerror (err)); + + if (!pex_get_status (pex, 1, &status)) + fatal_error ("can't get program status: %s", xstrerror (errno)); + + if (status) { - int sig = WTERMSIG (status); - fatal_error ("%s terminated with signal %d [%s]%s", - argv[0], sig, strsignal (sig), - WCOREDUMP (status) ? ", core dumped" : ""); + if (WIFSIGNALED (status)) + { + int sig = WTERMSIG (status); + fatal_error ("%s terminated with signal %d [%s]%s", + argv[0], sig, strsignal (sig), + WCOREDUMP (status) ? ", core dumped" : ""); + } + else + fatal_error ("%s terminated with status %d", argv[0], status); } - else - fatal_error ("%s terminated with status %d", argv[0], status); + + pex_free (pex); } timevar_pop (TV_WHOPR_WPA_LTRANS_EXEC); @@ -1677,9 +1789,12 @@ do_whole_program_analysis (void) for (i = 0; output_files[i]; ++i) { - lto_maybe_unlink (output_files[i]); + if (output_files[i][0] != '*') + lto_maybe_unlink (output_files[i]); + free (output_files[i]); } + XDELETEVEC (output_files); } |