X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Flto%2Flto.c;h=de53a09f87dac70b2a9b2090afea2db09f76783a;hb=22c1d3019e6a942f8f11eb6cb3ec036343e8b6e3;hp=056d249a161c76f2f4e8a1786cd8101a554ae25b;hpb=7bfefa9d2c82e804ef4e59772f4060ac325bf99a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 056d249a161..de53a09f87d 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -1,5 +1,5 @@ /* Top-level LTO routines. - Copyright 2009 Free Software Foundation, Inc. + Copyright 2009, 2010 Free Software Foundation, Inc. Contributed by CodeSourcery, Inc. This file is part of GCC. @@ -46,7 +46,17 @@ along with GCC; see the file COPYING3. If not see /* This needs to be included after config.h. Otherwise, _GNU_SOURCE will not be defined in time to set __USE_GNU in the system headers, and strsignal will not be declared. */ +#if HAVE_MMAP_FILE #include +#endif + +/* Handle opening elf files on hosts, such as Windows, that may use + text file handling that will break binary access. */ + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + DEF_VEC_P(bitmap); DEF_VEC_ALLOC_P(bitmap,heap); @@ -244,19 +254,37 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data, /* Set the current decl state to be the global state. */ decl_data->current_decl_state = decl_data->global_decl_state; - /* After each CU is read register and possibly merge global - symbols and their types. */ - lto_register_deferred_decls_in_symtab (data_in); - lto_data_in_delete (data_in); } +/* strtoll is not portable. */ +int64_t +lto_parse_hex (const char *p) { + uint64_t ret = 0; + for (; *p != '\0'; ++p) + { + char c = *p; + unsigned char part; + ret <<= 4; + if (c >= '0' && c <= '9') + part = c - '0'; + else if (c >= 'a' && c <= 'f') + part = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + part = c - 'A' + 10; + else + internal_error ("could not parse hex number"); + ret |= part; + } + return ret; +} + /* Read resolution for file named FILE_NAME. The resolution is read from RESOLUTION. An array with the symbol resolution is returned. The array size is written to SIZE. */ static VEC(ld_plugin_symbol_resolution_t,heap) * -lto_resolution_read (FILE *resolution, const char *file_name) +lto_resolution_read (FILE *resolution, lto_file *file) { /* We require that objects in the resolution file are in the same order as the lto1 command line. */ @@ -270,15 +298,27 @@ lto_resolution_read (FILE *resolution, const char *file_name) if (!resolution) return NULL; - name_len = strlen (file_name); + name_len = strlen (file->filename); obj_name = XNEWVEC (char, name_len + 1); fscanf (resolution, " "); /* Read white space. */ fread (obj_name, sizeof (char), name_len, resolution); obj_name[name_len] = '\0'; - if (strcmp (obj_name, file_name) != 0) + if (strcmp (obj_name, file->filename) != 0) internal_error ("unexpected file name %s in linker resolution file. " - "Expected %s", obj_name, file_name); + "Expected %s", obj_name, file->filename); + if (file->offset != 0) + { + int t; + char offset_p[17]; + int64_t offset; + t = fscanf (resolution, "@0x%16s", offset_p); + if (t != 1) + internal_error ("could not parse file offset"); + offset = lto_parse_hex (offset_p); + if (offset != file->offset) + internal_error ("unexpected offset"); + } free (obj_name); @@ -286,6 +326,7 @@ lto_resolution_read (FILE *resolution, const char *file_name) for (i = 0; i < num_symbols; i++) { + int t; unsigned index; char r_str[27]; enum ld_plugin_symbol_resolution r; @@ -293,7 +334,9 @@ lto_resolution_read (FILE *resolution, const char *file_name) unsigned int lto_resolution_str_len = sizeof (lto_resolution_str) / sizeof (char *); - fscanf (resolution, "%u %26s", &index, r_str); + t = fscanf (resolution, "%u %26s %*[^\n]\n", &index, r_str); + if (t != 2) + internal_error ("Invalid line in the resolution file."); if (index > max_index) max_index = index; @@ -305,12 +348,11 @@ lto_resolution_read (FILE *resolution, const char *file_name) break; } } - if (j >= lto_resolution_str_len) - internal_error ("tried to read past the end of the linker resolution " - "file"); + if (j == lto_resolution_str_len) + internal_error ("Invalid resolution in the resolution file."); VEC_safe_grow_cleared (ld_plugin_symbol_resolution_t, heap, ret, - index + 1); + max_index + 1); VEC_replace (ld_plugin_symbol_resolution_t, ret, index, r); } @@ -332,11 +374,10 @@ lto_file_read (lto_file *file, FILE *resolution_file) size_t len; VEC(ld_plugin_symbol_resolution_t,heap) *resolutions; - resolutions = lto_resolution_read (resolution_file, file->filename); + resolutions = lto_resolution_read (resolution_file, file); file_data = XCNEW (struct lto_file_decl_data); file_data->file_name = file->filename; - file_data->fd = -1; file_data->section_hash_table = lto_elf_build_section_table (file); file_data->renaming_hash_table = lto_create_renaming_table (); @@ -365,17 +406,33 @@ lto_read_section_data (struct lto_file_decl_data *file_data, intptr_t offset, size_t len) { char *result; + static int fd = -1; + static char *fd_name; #if LTO_MMAP_IO intptr_t computed_len; intptr_t computed_offset; intptr_t diff; #endif - if (file_data->fd == -1) - file_data->fd = open (file_data->file_name, O_RDONLY); - - if (file_data->fd == -1) - return NULL; + /* Keep a single-entry file-descriptor cache. The last file we + touched will get closed at exit. + ??? Eventually we want to add a more sophisticated larger cache + or rather fix function body streaming to not stream them in + practically random order. */ + if (fd != -1 + && strcmp (fd_name, file_data->file_name) != 0) + { + free (fd_name); + close (fd); + fd = -1; + } + if (fd == -1) + { + fd_name = xstrdup (file_data->file_name); + fd = open (file_data->file_name, O_RDONLY|O_BINARY); + if (fd == -1) + return NULL; + } #if LTO_MMAP_IO if (!page_mask) @@ -389,26 +446,17 @@ lto_read_section_data (struct lto_file_decl_data *file_data, computed_len = len + diff; result = (char *) mmap (NULL, computed_len, PROT_READ, MAP_PRIVATE, - file_data->fd, computed_offset); + fd, computed_offset); if (result == MAP_FAILED) - { - close (file_data->fd); - return NULL; - } + return NULL; return result + diff; #else result = (char *) xmalloc (len); - if (result == NULL) - { - close (file_data->fd); - return NULL; - } - if (lseek (file_data->fd, offset, SEEK_SET) != offset - || read (file_data->fd, result, len) != (ssize_t) len) + if (lseek (fd, offset, SEEK_SET) != offset + || read (fd, result, len) != (ssize_t) len) { free (result); - close (file_data->fd); return NULL; } @@ -451,7 +499,7 @@ get_section_data (struct lto_file_decl_data *file_data, starts at OFFSET and has LEN bytes. */ static void -free_section_data (struct lto_file_decl_data *file_data, +free_section_data (struct lto_file_decl_data *file_data ATTRIBUTE_UNUSED, enum lto_section_type section_type ATTRIBUTE_UNUSED, const char *name ATTRIBUTE_UNUSED, const char *offset, size_t len ATTRIBUTE_UNUSED) @@ -462,9 +510,6 @@ free_section_data (struct lto_file_decl_data *file_data, intptr_t diff; #endif - if (file_data->fd == -1) - return; - #if LTO_MMAP_IO computed_offset = ((intptr_t) offset) & page_mask; diff = (intptr_t) offset - computed_offset; @@ -1032,6 +1077,8 @@ lto_wpa_write_files (void) return output_files; } +/* Template of LTRANS dumpbase suffix. */ +#define DUMPBASE_SUFFIX ".ltrans18446744073709551615" /* Perform local transformations (LTRANS) on the files in the NULL-terminated FILES array. These should have been written previously by @@ -1051,6 +1098,8 @@ lto_execute_ltrans (char *const *files) int err; int status; FILE *ltrans_output_list_stream = NULL; + bool seen_dumpbase = false; + char *dumpbase_suffix = NULL; timevar_push (TV_WHOPR_WPA_LTRANS_EXEC); @@ -1089,13 +1138,26 @@ lto_execute_ltrans (char *const *files) ++j; obstack_init (&env_obstack); obstack_grow (&env_obstack, &collect_gcc_options[i], j - i); - obstack_1grow (&env_obstack, 0); + if (seen_dumpbase) + obstack_grow (&env_obstack, DUMPBASE_SUFFIX, + sizeof (DUMPBASE_SUFFIX)); + else + obstack_1grow (&env_obstack, 0); option = XOBFINISH (&env_obstack, char *); + if (seen_dumpbase) + { + dumpbase_suffix = option + 7 + j - i; + seen_dumpbase = false; + } /* LTRANS does not need -fwpa nor -fltrans-*. */ if (strncmp (option, "-fwpa", 5) != 0 && strncmp (option, "-fltrans-", 9) != 0) - *argv_ptr++ = option; + { + if (strncmp (option, "-dumpbase", 9) == 0) + seen_dumpbase = true; + *argv_ptr++ = option; + } } *argv_ptr++ = "-fltrans"; @@ -1153,6 +1215,11 @@ lto_execute_ltrans (char *const *files) argv_ptr[2] = files[i]; argv_ptr[3] = NULL; + /* Append a sequence number to -dumpbase for LTRANS. */ + if (dumpbase_suffix) + snprintf (dumpbase_suffix, sizeof (DUMPBASE_SUFFIX) - 7, + "%lu", (unsigned long) i); + /* Execute the driver. */ pex = pex_init (0, "lto1", NULL); if (pex == NULL) @@ -1195,7 +1262,6 @@ lto_execute_ltrans (char *const *files) typedef struct { - struct pointer_set_t *free_list; struct pointer_set_t *seen; } lto_fixup_data_t; @@ -1340,7 +1406,7 @@ static void lto_fixup_field_decl (tree t, void *data) { lto_fixup_decl_common (t, data); - gcc_assert (no_fixup_p (DECL_FIELD_OFFSET (t))); + LTO_FIXUP_SUBTREE (DECL_FIELD_OFFSET (t)); LTO_FIXUP_SUBTREE (DECL_BIT_FIELD_TYPE (t)); LTO_FIXUP_SUBTREE (DECL_QUALIFIER (t)); gcc_assert (no_fixup_p (DECL_FIELD_BIT_OFFSET (t))); @@ -1530,8 +1596,6 @@ lto_fixup_tree (tree *tp, int *walk_subtrees, void *data) lto_mark_nothrow_fndecl (prevailing); } - pointer_set_insert (fixup_data->free_list, t); - /* Also replace t with prevailing defintion. We don't want to insert the other defintion in the seen set as we want to replace all instances of it. */ @@ -1640,20 +1704,6 @@ lto_fixup_state_aux (void **slot, void *aux) return 1; } -/* A callback to pointer_set_traverse. Frees the tree pointed by p. Removes - from it from the UID -> DECL mapping. */ - -static bool -free_decl (const void *p, void *data ATTRIBUTE_UNUSED) -{ - const_tree ct = (const_tree) p; - tree t = CONST_CAST_TREE (ct); - - lto_symtab_clear_resolution (t); - - return true; -} - /* Fix the decls from all FILES. Replaces each decl with the corresponding prevailing one. */ @@ -1662,11 +1712,9 @@ lto_fixup_decls (struct lto_file_decl_data **files) { unsigned int i; tree decl; - struct pointer_set_t *free_list = pointer_set_create (); struct pointer_set_t *seen = pointer_set_create (); lto_fixup_data_t data; - data.free_list = free_list; data.seen = seen; for (i = 0; files[i]; i++) { @@ -1685,8 +1733,6 @@ lto_fixup_decls (struct lto_file_decl_data **files) VEC_replace (tree, lto_global_var_decls, i, decl); } - pointer_set_traverse (free_list, free_decl, NULL); - pointer_set_destroy (free_list); pointer_set_destroy (seen); } @@ -1735,15 +1781,12 @@ lto_read_all_file_options (void) file_data = XCNEW (struct lto_file_decl_data); file_data->file_name = file->filename; - file_data->fd = -1; file_data->section_hash_table = lto_elf_build_section_table (file); lto_read_file_options (file_data); lto_elf_file_close (file); htab_delete (file_data->section_hash_table); - if (file_data->fd != -1) - close (file_data->fd); free (file_data); } @@ -1763,6 +1806,7 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) unsigned int i, last_file_ix; struct lto_file_decl_data **all_file_decl_data; FILE *resolution; + struct cgraph_node *node; lto_stats.num_input_files = nfiles; @@ -1780,7 +1824,10 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) unsigned num_objects; resolution = fopen (resolution_file_name, "r"); - gcc_assert (resolution != NULL); + if (resolution == NULL) + fatal_error ("could not open symbol resolution file: %s", + xstrerror (errno)); + t = fscanf (resolution, "%u", &num_objects); gcc_assert (t == 1); @@ -1821,60 +1868,43 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) /* Read the callgraph. */ input_cgraph (); - ipa_read_summaries (); - - timevar_push (TV_IPA_LTO_DECL_IO); + /* Merge global decls. */ + lto_symtab_merge_decls (); + /* Fixup all decls and types and free the type hash tables. */ lto_fixup_decls (all_file_decl_data); + free_gimple_type_tables (); - /* See if we have multiple decls for a symbol and choose the largest - one to generate the common. */ - for (i = 0; i < VEC_length (tree, lto_global_var_decls); ++i) - { - tree decl = VEC_index (tree, lto_global_var_decls, i); - tree prev_decl = NULL_TREE; - tree size; - - if (TREE_CODE (decl) != VAR_DECL - || !DECL_LANG_SPECIFIC (decl)) - continue; - - /* Find the preceeding decl of the largest one. */ - size = DECL_SIZE (decl); - do - { - tree next = (tree) DECL_LANG_SPECIFIC (decl); - if (tree_int_cst_lt (size, DECL_SIZE (next))) - { - size = DECL_SIZE (next); - prev_decl = decl; - } - decl = next; - } - while (DECL_LANG_SPECIFIC (decl)); + /* Read the IPA summary data. */ + ipa_read_summaries (); - /* If necessary move the largest decl to the front of the - chain. */ - if (prev_decl != NULL_TREE) - { - decl = (tree) DECL_LANG_SPECIFIC (prev_decl); - DECL_LANG_SPECIFIC (prev_decl) = DECL_LANG_SPECIFIC (decl); - DECL_LANG_SPECIFIC (decl) - = (struct lang_decl *) VEC_index (tree, lto_global_var_decls, i); - VEC_replace (tree, lto_global_var_decls, i, decl); - } + /* Finally merge the cgraph according to the decl merging decisions. */ + lto_symtab_merge_cgraph_nodes (); + + /* Mark cgraph nodes needed in the merged cgraph + This normally happens in whole-program pass, but for + ltrans the pass was already run at WPA phase. + + FIXME: This is not valid way to do so; nodes can be needed + for non-obvious reasons. We should stream the flags from WPA + phase. */ + if (flag_ltrans) + for (node = cgraph_nodes; node; node = node->next) + { + if (!node->global.inlined_to + && cgraph_decide_is_function_needed (node, node->decl)) + cgraph_mark_needed_node (node); + /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization + summaries computed and needs to apply changes. At the moment WHOPR only + supports inlining, so we can push it here by hand. In future we need to stream + this field into ltrans compilation. */ + if (node->analyzed) + VEC_safe_push (ipa_opt_pass, heap, + node->ipa_transforms_to_apply, + (ipa_opt_pass)&pass_ipa_inline); + } - /* Mark everything apart from the first var as written out and - unlink the chain. */ - decl = VEC_index (tree, lto_global_var_decls, i); - while (DECL_LANG_SPECIFIC (decl)) - { - tree next = (tree) DECL_LANG_SPECIFIC (decl); - DECL_LANG_SPECIFIC (decl) = NULL; - decl = next; - TREE_ASM_WRITTEN (decl) = true; - } - } + timevar_push (TV_IPA_LTO_DECL_IO); /* FIXME lto. This loop needs to be changed to use the pass manager to call the ipa passes directly. */