diff options
author | Richard Guenther <rguenther@suse.de> | 2009-10-05 14:05:54 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2009-10-05 14:05:54 +0000 |
commit | 1a735925e30877491ac12ca78612e4de29c4bf0f (patch) | |
tree | 666c7b939b006e039aeec82b1397690b52070e18 /gcc | |
parent | e9d85fa6a7fdd48c00c02b8ad915a75d3b025708 (diff) | |
download | gcc-1a735925e30877491ac12ca78612e4de29c4bf0f.zip gcc-1a735925e30877491ac12ca78612e4de29c4bf0f.tar.gz gcc-1a735925e30877491ac12ca78612e4de29c4bf0f.tar.bz2 |
re PR lto/41552 (Undefined references with -flto, dependent on object file ordering)
2009-10-05 Richard Guenther <rguenther@suse.de>
PR lto/41552
PR lto/41487
* lto-symtab.c (struct lto_symtab_base_def): Remove.
(struct lto_symtab_identifier_def): Likewise.
(struct lto_symtab_decl_def): Likewise.
(struct lto_symtab_entry_def): New.
(lto_symtab_identifier_t): Rename to ...
(lto_symtab_entry_t): ... this.
(lto_symtab_decls): Remove.
(lto_symtab_base_hash): Rename to ...
(lto_symtab_entry_hash): ... this.
(lto_symtab_base_eq): Rename to ...
(lto_symtab_entry_eq): ... this.
(lto_symtab_base_marked_p): Rename to ...
(lto_symtab_entry_marked_p): ... this.
(lto_symtab_identifier_marked_p): Remove.
(lto_symtab_decl_marked_p): Likewise.
(lto_symtab_maybe_init_hash_tables): Rename to ...
(lto_symtab_maybe_init_hash_table): ... this.
(lto_symtab_set_resolution_and_file_data): Remove.
(lto_symtab_register_decl): New function.
(lto_symtab_get_identifier): Remove.
(lto_symtab_get): New function.
(lto_symtab_get_resolution): Adjust.
(lto_symtab_get_identifier_decl): Remove.
(lto_symtab_set_identifier_decl): Likewise.
(lto_symtab_merge_decl): Rename to ...
(lto_symtab_merge): ... this. Rewrite.
(lto_symtab_merge_var): Remove.
(lto_symtab_merge_fn): Likewise.
(lto_symtab_prevailing_decl): Adjust.
(lto_cgraph_replace_node): New function.
(lto_symtab_merge_decls_2): Likewise.
(lto_symtab_merge_decls_1): Likewise.
(lto_symtab_fixup_var_decls): Likewise.
(lto_symtab_resolve_symbols): Likewise.
(lto_symtab_merge_decls): Likewise.
(lto_symtab_prevailing_decl): Adjust.
(lto_symtab_get_symtab_def): Remove.
(lto_symtab_get_file_data): Likewise.
(lto_symtab_clear_resolution): Adjust.
(lto_symtab_clear_resolution): Likewise.
* lto-cgraph.c (input_edge): Do not merge cgraph nodes here.
(input_cgraph_1): Likewise.
* lto-streamer-in.c (get_resolution): Do not provide fake
symbol resolutions here.
(deferred_global_decls): Remove.
(lto_register_deferred_decls_in_symtab): Likewise.
(lto_register_var_decl_in_symtab): Change signature, register
variable via lto_symtab_register_decl.
(lto_register_function_decl_in_symtab): Likewise.
(lto_read_tree): Adjust.
* lto-streamer.h (lto_register_deferred_decls_in_symtab): Remove.
(lto_symtab_merge_var): Likewise.
(lto_symtab_merge_fn): Likewise.
(lto_symtab_register_decl): Declare.
(lto_symtab_merge_decls): Likewise.
lto/
* lto.c (lto_read_decls): Do not register deferred decls.
(read_cgraph_and_symbols): Delay symbol and cgraph merging
until after reading the IPA summaries.
* g++.dg/lto/20091002-1_0.C: Adjust flags.
* g++.dg/lto/20091004-1_0.C: New testcase.
* g++.dg/lto/20091004-1_1.C: Likewise.
* g++.dg/lto/20091004-2_0.C: Likewise.
* g++.dg/lto/20091004-2_1.C: Likewise.
* g++.dg/lto/20091004-3_0.C: Likewise.
* g++.dg/lto/20091004-3_1.C: Likewise.
From-SVN: r152450
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 60 | ||||
-rw-r--r-- | gcc/lto-cgraph.c | 49 | ||||
-rw-r--r-- | gcc/lto-streamer-in.c | 102 | ||||
-rw-r--r-- | gcc/lto-streamer.h | 8 | ||||
-rw-r--r-- | gcc/lto-symtab.c | 646 | ||||
-rw-r--r-- | gcc/lto/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/lto/lto.c | 65 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/20091002-1_0.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/20091004-1_0.C | 35 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/20091004-1_1.C | 26 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/20091004-2_0.C | 29 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/20091004-2_1.C | 32 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/20091004-3_0.C | 18 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/20091004-3_1.C | 16 |
15 files changed, 638 insertions, 470 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a5460f3..5da6b90 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,65 @@ 2009-10-05 Richard Guenther <rguenther@suse.de> + PR lto/41552 + PR lto/41487 + * lto-symtab.c (struct lto_symtab_base_def): Remove. + (struct lto_symtab_identifier_def): Likewise. + (struct lto_symtab_decl_def): Likewise. + (struct lto_symtab_entry_def): New. + (lto_symtab_identifier_t): Rename to ... + (lto_symtab_entry_t): ... this. + (lto_symtab_decls): Remove. + (lto_symtab_base_hash): Rename to ... + (lto_symtab_entry_hash): ... this. + (lto_symtab_base_eq): Rename to ... + (lto_symtab_entry_eq): ... this. + (lto_symtab_base_marked_p): Rename to ... + (lto_symtab_entry_marked_p): ... this. + (lto_symtab_identifier_marked_p): Remove. + (lto_symtab_decl_marked_p): Likewise. + (lto_symtab_maybe_init_hash_tables): Rename to ... + (lto_symtab_maybe_init_hash_table): ... this. + (lto_symtab_set_resolution_and_file_data): Remove. + (lto_symtab_register_decl): New function. + (lto_symtab_get_identifier): Remove. + (lto_symtab_get): New function. + (lto_symtab_get_resolution): Adjust. + (lto_symtab_get_identifier_decl): Remove. + (lto_symtab_set_identifier_decl): Likewise. + (lto_symtab_merge_decl): Rename to ... + (lto_symtab_merge): ... this. Rewrite. + (lto_symtab_merge_var): Remove. + (lto_symtab_merge_fn): Likewise. + (lto_symtab_prevailing_decl): Adjust. + (lto_cgraph_replace_node): New function. + (lto_symtab_merge_decls_2): Likewise. + (lto_symtab_merge_decls_1): Likewise. + (lto_symtab_fixup_var_decls): Likewise. + (lto_symtab_resolve_symbols): Likewise. + (lto_symtab_merge_decls): Likewise. + (lto_symtab_prevailing_decl): Adjust. + (lto_symtab_get_symtab_def): Remove. + (lto_symtab_get_file_data): Likewise. + (lto_symtab_clear_resolution): Adjust. + (lto_symtab_clear_resolution): Likewise. + * lto-cgraph.c (input_edge): Do not merge cgraph nodes here. + (input_cgraph_1): Likewise. + * lto-streamer-in.c (get_resolution): Do not provide fake + symbol resolutions here. + (deferred_global_decls): Remove. + (lto_register_deferred_decls_in_symtab): Likewise. + (lto_register_var_decl_in_symtab): Change signature, register + variable via lto_symtab_register_decl. + (lto_register_function_decl_in_symtab): Likewise. + (lto_read_tree): Adjust. + * lto-streamer.h (lto_register_deferred_decls_in_symtab): Remove. + (lto_symtab_merge_var): Likewise. + (lto_symtab_merge_fn): Likewise. + (lto_symtab_register_decl): Declare. + (lto_symtab_merge_decls): Likewise. + +2009-10-05 Richard Guenther <rguenther@suse.de> + PR tree-optimization/23821 * tree-vrp.c (vrp_finalize): Do not perform copy propagation. * tree-ssa-dom.c (cprop_operand): Do not propagate copies into diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index b11483c..47ccccd 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -527,8 +527,6 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes) unsigned int nest; cgraph_inline_failed_t inline_failed; struct bitpack_d *bp; - tree prevailing_callee; - tree prevailing_caller; enum ld_plugin_symbol_resolution caller_resolution; caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib)); @@ -539,8 +537,6 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes) if (callee == NULL || callee->decl == NULL_TREE) internal_error ("bytecode stream: no callee found while reading edge"); - caller_resolution = lto_symtab_get_resolution (caller->decl); - count = (gcov_type) lto_input_sleb128 (ib); bp = lto_input_bitpack (ib); @@ -550,37 +546,13 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes) freq = (int) bp_unpack_value (bp, HOST_BITS_PER_INT); nest = (unsigned) bp_unpack_value (bp, 30); - /* If the caller was preempted, don't create the edge. */ + /* If the caller was preempted, don't create the edge. + ??? Should we ever have edges from a preempted caller? */ + caller_resolution = lto_symtab_get_resolution (caller->decl); if (caller_resolution == LDPR_PREEMPTED_REG || caller_resolution == LDPR_PREEMPTED_IR) return; - prevailing_callee = lto_symtab_prevailing_decl (callee->decl); - - /* Make sure the caller is the prevailing decl. */ - prevailing_caller = lto_symtab_prevailing_decl (caller->decl); - - if (prevailing_callee != callee->decl) - { - struct lto_file_decl_data *file_data; - - /* We cannot replace a clone! */ - gcc_assert (callee == cgraph_node (callee->decl)); - - callee = cgraph_node (prevailing_callee); - gcc_assert (callee); - - /* If LGEN (cc1 or cc1plus) had nothing to do with the node, it - might not have created it. In this case, we just created a - new node in the above call to cgraph_node. Mark the file it - came from. */ - file_data = lto_symtab_get_file_data (prevailing_callee); - if (callee->local.lto_file_data) - gcc_assert (callee->local.lto_file_data == file_data); - else - callee->local.lto_file_data = file_data; - } - edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest); edge->lto_stmt_uid = stmt_id; edge->inline_failed = inline_failed; @@ -630,21 +602,6 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, node->global.inlined_to = NULL; } - for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++) - { - tree prevailing = lto_symtab_prevailing_decl (node->decl); - - if (prevailing != node->decl) - { - cgraph_remove_node (node); - VEC_replace (cgraph_node_ptr, nodes, i, NULL); - } - } - - for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++) - if (node && cgraph_decide_is_function_needed (node, node->decl)) - cgraph_mark_needed_node (node); - VEC_free (cgraph_node_ptr, heap, nodes); } diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index a8d2379..175a1e7 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1347,44 +1347,8 @@ get_resolution (struct data_in *data_in, unsigned index) return ret; } else - { - /* Fake symbol resolution if no resolution file was provided. */ - tree t = lto_streamer_cache_get (data_in->reader_cache, index); - - gcc_assert (TREE_PUBLIC (t)); - - /* There should be no DECL_ABSTRACT in the middle end. */ - gcc_assert (!DECL_ABSTRACT (t)); - - /* If T is a weak definition, we select the first one we see to - be the prevailing definition. */ - if (DECL_WEAK (t)) - { - tree prevailing_decl; - if (DECL_EXTERNAL (t)) - return LDPR_RESOLVED_IR; - - /* If this is the first time we see T, it won't have a - prevailing definition yet. */ - prevailing_decl = lto_symtab_prevailing_decl (t); - if (prevailing_decl == t - || prevailing_decl == NULL_TREE - || DECL_EXTERNAL (prevailing_decl)) - return LDPR_PREVAILING_DEF; - else - return LDPR_PREEMPTED_IR; - } - else - { - /* For non-weak definitions, extern declarations are assumed - to be resolved elsewhere (LDPR_RESOLVED_IR), otherwise T - is a prevailing definition. */ - if (DECL_EXTERNAL (t)) - return LDPR_RESOLVED_IR; - else - return LDPR_PREVAILING_DEF; - } - } + /* Delay resolution finding until decl merging. */ + return LDPR_UNKNOWN; } @@ -2243,55 +2207,13 @@ lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, } } -static VEC(tree, heap) *deferred_global_decls; - -/* Register the queued global decls with the symtab. DATA_IN contains - tables and descriptors for the file being read.*/ - -void -lto_register_deferred_decls_in_symtab (struct data_in *data_in) -{ - unsigned i; - tree decl; - - for (i = 0; VEC_iterate (tree, deferred_global_decls, i, decl); ++i) - { - enum ld_plugin_symbol_resolution resolution; - int ix; - - if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix)) - gcc_unreachable (); - - /* Register and adjust the decls type. */ - TREE_TYPE (decl) = gimple_register_type (TREE_TYPE (decl)); - - if (TREE_CODE (decl) == VAR_DECL) - { - gcc_assert (TREE_PUBLIC (decl)); - resolution = get_resolution (data_in, ix); - lto_symtab_merge_var (decl, resolution); - } - else if (TREE_CODE (decl) == FUNCTION_DECL) - { - gcc_assert (TREE_PUBLIC (decl) && !DECL_ABSTRACT (decl)); - resolution = get_resolution (data_in, ix); - lto_symtab_merge_fn (decl, resolution, data_in->file_data); - } - else - gcc_unreachable (); - } - - VEC_free (tree, heap, deferred_global_decls); - deferred_global_decls = NULL; -} - /* Register DECL with the global symbol table and change its name if necessary to avoid name clashes for static globals across different files. */ static void -lto_register_var_decl_in_symtab (tree decl) +lto_register_var_decl_in_symtab (struct data_in *data_in, tree decl) { /* Register symbols with file or global scope to mark what input file has their definition. */ @@ -2319,7 +2241,13 @@ lto_register_var_decl_in_symtab (tree decl) /* If this variable has already been declared, queue the declaration for merging. */ if (TREE_PUBLIC (decl)) - VEC_safe_push (tree, heap, deferred_global_decls, decl); + { + int ix; + if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix)) + gcc_unreachable (); + lto_symtab_register_decl (decl, get_resolution (data_in, ix), + data_in->file_data); + } } @@ -2380,7 +2308,13 @@ lto_register_function_decl_in_symtab (struct data_in *data_in, tree decl) /* If this variable has already been declared, queue the declaration for merging. */ if (TREE_PUBLIC (decl) && !DECL_ABSTRACT (decl)) - VEC_safe_push (tree, heap, deferred_global_decls, decl); + { + int ix; + if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix)) + gcc_unreachable (); + lto_symtab_register_decl (decl, get_resolution (data_in, ix), + data_in->file_data); + } } @@ -2481,7 +2415,7 @@ lto_read_tree (struct lto_input_block *ib, struct data_in *data_in, gcc_assert (!lto_stream_as_builtin_p (result)); if (TREE_CODE (result) == VAR_DECL) - lto_register_var_decl_in_symtab (result); + lto_register_var_decl_in_symtab (data_in, result); else if (TREE_CODE (result) == FUNCTION_DECL && !DECL_BUILT_IN (result)) lto_register_function_decl_in_symtab (data_in, result); diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index b156ff4..c4d66b7 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -823,7 +823,6 @@ extern struct data_in *lto_data_in_create (struct lto_file_decl_data *, const char *, unsigned, VEC(ld_plugin_symbol_resolution_t,heap) *); extern void lto_data_in_delete (struct data_in *); -extern void lto_register_deferred_decls_in_symtab (struct data_in *); /* In lto-streamer-out.c */ @@ -845,12 +844,11 @@ void input_cgraph (void); /* In lto-symtab.c. */ -extern void lto_symtab_merge_var (tree, enum ld_plugin_symbol_resolution); -extern void lto_symtab_merge_fn (tree, enum ld_plugin_symbol_resolution, - struct lto_file_decl_data *); +extern void lto_symtab_register_decl (tree, ld_plugin_symbol_resolution_t, + struct lto_file_decl_data *); +extern void lto_symtab_merge_decls (void); extern tree lto_symtab_prevailing_decl (tree decl); extern enum ld_plugin_symbol_resolution lto_symtab_get_resolution (tree decl); -struct lto_file_decl_data *lto_symtab_get_file_data (tree decl); extern void lto_symtab_clear_resolution (tree decl); diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c index 90a200f..85e3c6c 100644 --- a/gcc/lto-symtab.c +++ b/gcc/lto-symtab.c @@ -33,114 +33,80 @@ along with GCC; see the file COPYING3. If not see /* Vector to keep track of external variables we've seen so far. */ VEC(tree,gc) *lto_global_var_decls; -/* Base type for resolution map. It maps NODE to resolution. */ +/* Symbol table entry. */ -struct GTY(()) lto_symtab_base_def +struct GTY(()) lto_symtab_entry_def { - /* Key is either an IDENTIFIER or a DECL. */ - tree node; -}; -typedef struct lto_symtab_base_def *lto_symtab_base_t; - -struct GTY(()) lto_symtab_identifier_def -{ - struct lto_symtab_base_def base; + /* The symbol table entry key, an IDENTIFIER. */ + tree id; + /* The symbol table entry, a DECL. */ tree decl; -}; -typedef struct lto_symtab_identifier_def *lto_symtab_identifier_t; - -struct GTY(()) lto_symtab_decl_def -{ - struct lto_symtab_base_def base; - enum ld_plugin_symbol_resolution resolution; + /* LTO file-data and symbol resolution for this decl. */ struct lto_file_decl_data * GTY((skip (""))) file_data; + enum ld_plugin_symbol_resolution resolution; + /* Pointer to the next entry with the same key. Before decl merging + this links all symbols from the different TUs. After decl merging + this links merged but incompatible decls, thus all prevailing ones + remaining. */ + struct lto_symtab_entry_def *next; }; -typedef struct lto_symtab_decl_def *lto_symtab_decl_t; +typedef struct lto_symtab_entry_def *lto_symtab_entry_t; /* A poor man's symbol table. This hashes identifier to prevailing DECL if there is one. */ -static GTY ((if_marked ("lto_symtab_identifier_marked_p"), - param_is (struct lto_symtab_identifier_def))) +static GTY ((if_marked ("lto_symtab_entry_marked_p"), + param_is (struct lto_symtab_entry_def))) htab_t lto_symtab_identifiers; -static GTY ((if_marked ("lto_symtab_decl_marked_p"), - param_is (struct lto_symtab_decl_def))) - htab_t lto_symtab_decls; - -/* Return the hash value of an lto_symtab_base_t object pointed to by P. */ +/* Return the hash value of an lto_symtab_entry_t object pointed to by P. */ static hashval_t -lto_symtab_base_hash (const void *p) +lto_symtab_entry_hash (const void *p) { - const struct lto_symtab_base_def *base = - (const struct lto_symtab_base_def*) p; - return htab_hash_pointer (base->node); + const struct lto_symtab_entry_def *base = + (const struct lto_symtab_entry_def *) p; + return htab_hash_pointer (base->id); } -/* Return non-zero if P1 and P2 points to lto_symtab_base_def structs - corresponding to the same tree node. */ +/* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs + corresponding to the same symbol. */ static int -lto_symtab_base_eq (const void *p1, const void *p2) +lto_symtab_entry_eq (const void *p1, const void *p2) { - const struct lto_symtab_base_def *base1 = - (const struct lto_symtab_base_def *) p1; - const struct lto_symtab_base_def *base2 = - (const struct lto_symtab_base_def *) p2; - return (base1->node == base2->node); + const struct lto_symtab_entry_def *base1 = + (const struct lto_symtab_entry_def *) p1; + const struct lto_symtab_entry_def *base2 = + (const struct lto_symtab_entry_def *) p2; + return (base1->id == base2->id); } -/* Returns non-zero if P points to an lto_symtab_base_def struct that needs +/* Returns non-zero if P points to an lto_symtab_entry_def struct that needs to be marked for GC. */ static int -lto_symtab_base_marked_p (const void *p) +lto_symtab_entry_marked_p (const void *p) { - const struct lto_symtab_base_def *base = - (const struct lto_symtab_base_def *) p; + const struct lto_symtab_entry_def *base = + (const struct lto_symtab_entry_def *) p; - /* Keep this only if the key node is marked. */ - return ggc_marked_p (base->node); -} - -/* Returns non-zero if P points to an lto_symtab_identifier_def struct that - needs to be marked for GC. */ - -static int -lto_symtab_identifier_marked_p (const void *p) -{ - return lto_symtab_base_marked_p (p); -} - -/* Returns non-zero if P points to an lto_symtab_decl_def struct that needs - to be marked for GC. */ - -static int -lto_symtab_decl_marked_p (const void *p) -{ - return lto_symtab_base_marked_p (p); + /* Keep this only if the decl or the chain is marked. */ + return (ggc_marked_p (base->decl) + || (base->next && ggc_marked_p (base->next))); } -#define lto_symtab_identifier_eq lto_symtab_base_eq -#define lto_symtab_identifier_hash lto_symtab_base_hash -#define lto_symtab_decl_eq lto_symtab_base_eq -#define lto_symtab_decl_hash lto_symtab_base_hash - /* Lazily initialize resolution hash tables. */ static void -lto_symtab_maybe_init_hash_tables (void) +lto_symtab_maybe_init_hash_table (void) { - if (!lto_symtab_identifiers) - { - lto_symtab_identifiers = - htab_create_ggc (1021, lto_symtab_identifier_hash, - lto_symtab_identifier_eq, NULL); - lto_symtab_decls = - htab_create_ggc (1021, lto_symtab_decl_hash, - lto_symtab_decl_eq, NULL); - } + if (lto_symtab_identifiers) + return; + + lto_symtab_identifiers = + htab_create_ggc (1021, lto_symtab_entry_hash, + lto_symtab_entry_eq, NULL); } /* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be @@ -465,237 +431,366 @@ lto_symtab_compatible (tree old_decl, tree new_decl) return true; } +/* Registers DECL with the LTO symbol table as having resolution RESOLUTION + and read from FILE_DATA. */ -/* Marks decl DECL as having resolution RESOLUTION. */ - -static void -lto_symtab_set_resolution_and_file_data (tree decl, - ld_plugin_symbol_resolution_t - resolution, - struct lto_file_decl_data *file_data) +void +lto_symtab_register_decl (tree decl, + ld_plugin_symbol_resolution_t resolution, + struct lto_file_decl_data *file_data) { - lto_symtab_decl_t new_entry; + lto_symtab_entry_t new_entry; void **slot; - gcc_assert (decl); - - gcc_assert (TREE_PUBLIC (decl)); - gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !DECL_ABSTRACT (decl)); - - new_entry = GGC_CNEW (struct lto_symtab_decl_def); - new_entry->base.node = decl; + /* Check that declarations reaching this function do not have + properties inconsistent with having external linkage. If any of + these asertions fail, then the object file reader has failed to + detect these cases and issue appropriate error messages. */ + gcc_assert (decl + && TREE_PUBLIC (decl) + && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL) + && DECL_ASSEMBLER_NAME_SET_P (decl)); + if (TREE_CODE (decl) == VAR_DECL) + gcc_assert (!(DECL_EXTERNAL (decl) && DECL_INITIAL (decl))); + if (TREE_CODE (decl) == FUNCTION_DECL) + gcc_assert (!DECL_ABSTRACT (decl)); + + new_entry = GGC_CNEW (struct lto_symtab_entry_def); + new_entry->id = DECL_ASSEMBLER_NAME (decl); + new_entry->decl = decl; new_entry->resolution = resolution; new_entry->file_data = file_data; - lto_symtab_maybe_init_hash_tables (); - slot = htab_find_slot (lto_symtab_decls, new_entry, INSERT); - gcc_assert (!*slot); + lto_symtab_maybe_init_hash_table (); + slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT); + new_entry->next = (lto_symtab_entry_t) *slot; *slot = new_entry; } -/* Get the lto_symtab_identifier_def struct associated with ID - if there is one. If there is none and INSERT_P is true, create - a new one. */ +/* Get the lto_symtab_entry_def struct associated with ID + if there is one. */ -static lto_symtab_identifier_t -lto_symtab_get_identifier (tree id, bool insert_p) +static lto_symtab_entry_t +lto_symtab_get (tree id) { - struct lto_symtab_identifier_def temp; - lto_symtab_identifier_t symtab_id; + struct lto_symtab_entry_def temp; void **slot; - lto_symtab_maybe_init_hash_tables (); - temp.base.node = id; - slot = htab_find_slot (lto_symtab_identifiers, &temp, - insert_p ? INSERT : NO_INSERT); - if (insert_p) - { - if (*slot) - return (lto_symtab_identifier_t) *slot; - else - { - symtab_id = GGC_CNEW (struct lto_symtab_identifier_def); - symtab_id->base.node = id; - *slot = symtab_id; - return symtab_id; - } - } - else - return slot ? (lto_symtab_identifier_t) *slot : NULL; + lto_symtab_maybe_init_hash_table (); + temp.id = id; + slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT); + return slot ? (lto_symtab_entry_t) *slot : NULL; } -/* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE - if there is none. */ +/* Get the linker resolution for DECL. */ -static tree -lto_symtab_get_identifier_decl (tree id) +enum ld_plugin_symbol_resolution +lto_symtab_get_resolution (tree decl) { - lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false); - return symtab_id ? symtab_id->decl : NULL_TREE; -} + lto_symtab_entry_t e; -/* SET the associated DECL of an IDENTIFIER ID to be DECL. */ + gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); -static void -lto_symtab_set_identifier_decl (tree id, tree decl) -{ - lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, true); - symtab_id->decl = decl; + e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl)); + while (e && e->decl != decl) + e = e->next; + if (!e) + return LDPR_UNKNOWN; + + return e->resolution; } -/* Common helper function for merging variable and function declarations. - NEW_DECL is the newly found decl. RESOLUTION is the decl's resolution - provided by the linker. */ +/* Replace the cgraph node OLD_NODE with NEW_NODE in the cgraph, merging + all edges and removing the old node. */ static void -lto_symtab_merge_decl (tree new_decl, - enum ld_plugin_symbol_resolution resolution, - struct lto_file_decl_data *file_data) +lto_cgraph_replace_node (struct cgraph_node *old_node, + struct cgraph_node *new_node) { - tree old_decl; - tree name; - ld_plugin_symbol_resolution_t old_resolution; - - gcc_assert (TREE_CODE (new_decl) == VAR_DECL - || TREE_CODE (new_decl) == FUNCTION_DECL); - - gcc_assert (TREE_PUBLIC (new_decl)); - - gcc_assert (DECL_LANG_SPECIFIC (new_decl) == NULL); - - /* Check that declarations reaching this function do not have - properties inconsistent with having external linkage. If any of - these asertions fail, then the object file reader has failed to - detect these cases and issue appropriate error messages. */ - if (TREE_CODE (new_decl) == VAR_DECL) - gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl))); + struct cgraph_edge *e, *next; + + /* Merge node flags. */ + if (old_node->needed) + cgraph_mark_needed_node (new_node); + if (old_node->reachable) + cgraph_mark_reachable_node (new_node); + if (old_node->address_taken) + cgraph_mark_address_taken_node (new_node); + + /* Redirect all incoming edges. */ + for (e = old_node->callers; e; e = next) + { + next = e->next_caller; + cgraph_redirect_edge_callee (e, new_node); + } - /* Remember the resolution of this symbol. */ - lto_symtab_set_resolution_and_file_data (new_decl, resolution, file_data); + /* There are not supposed to be any outgoing edges from a node we + replace. Still this can happen for multiple instances of weak + functions. + ??? For now do what the old code did. Do not create edges for them. */ + for (e = old_node->callees; e; e = next) + { + next = e->next_callee; + cgraph_remove_edge (e); + } - /* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */ - gcc_assert (DECL_ASSEMBLER_NAME_SET_P (new_decl)); + /* Finally remove the replaced node. */ + cgraph_remove_node (old_node); +} - /* Retrieve the previous declaration. */ - name = DECL_ASSEMBLER_NAME (new_decl); - old_decl = lto_symtab_get_identifier_decl (name); +/* Merge two variable or function symbol table entries ENTRY1 and ENTRY2. + Return the prevailing one or NULL if a merge is not possible. */ - /* If there was no previous declaration, then there is nothing to - merge. */ - if (!old_decl) - { - lto_symtab_set_identifier_decl (name, new_decl); - VEC_safe_push (tree, gc, lto_global_var_decls, new_decl); - return; - } +static lto_symtab_entry_t +lto_symtab_merge (lto_symtab_entry_t entry1, lto_symtab_entry_t entry2) +{ + tree old_decl = entry1->decl; + tree new_decl = entry2->decl; + ld_plugin_symbol_resolution_t old_resolution = entry1->resolution; + ld_plugin_symbol_resolution_t new_resolution = entry2->resolution; + struct cgraph_node *old_node = NULL; + struct cgraph_node *new_node = NULL; /* Give ODR violation errors. */ - old_resolution = lto_symtab_get_resolution (old_decl); - if (resolution == LDPR_PREVAILING_DEF - || resolution == LDPR_PREVAILING_DEF_IRONLY) + if (new_resolution == LDPR_PREVAILING_DEF + || new_resolution == LDPR_PREVAILING_DEF_IRONLY) { if ((old_resolution == LDPR_PREVAILING_DEF || old_resolution == LDPR_PREVAILING_DEF_IRONLY) - && (old_resolution != resolution || flag_no_common)) + && (old_resolution != new_resolution || flag_no_common)) { error_at (DECL_SOURCE_LOCATION (new_decl), "%qD has already been defined", new_decl); inform (DECL_SOURCE_LOCATION (old_decl), "previously defined here"); - return; + return NULL; } } - /* The linker may ask us to combine two incompatible symbols. - Find a decl we can merge with or chain it in the list of decls - for that symbol. */ - while (old_decl - && !lto_symtab_compatible (old_decl, new_decl)) - old_decl = (tree) DECL_LANG_SPECIFIC (old_decl); - if (!old_decl) - { - old_decl = lto_symtab_get_identifier_decl (name); - while (DECL_LANG_SPECIFIC (old_decl) != NULL) - old_decl = (tree) DECL_LANG_SPECIFIC (old_decl); - DECL_LANG_SPECIFIC (old_decl) = (struct lang_decl *) new_decl; - return; - } + /* The linker may ask us to combine two incompatible symbols. */ + if (!lto_symtab_compatible (old_decl, new_decl)) + return NULL; + + if (TREE_CODE (old_decl) == FUNCTION_DECL) + old_node = cgraph_get_node (old_decl); + if (TREE_CODE (new_decl) == FUNCTION_DECL) + new_node = cgraph_get_node (new_decl); /* Merge decl state in both directions, we may still end up using the new decl. */ TREE_ADDRESSABLE (old_decl) |= TREE_ADDRESSABLE (new_decl); TREE_ADDRESSABLE (new_decl) |= TREE_ADDRESSABLE (old_decl); - gcc_assert (resolution != LDPR_UNKNOWN - && resolution != LDPR_UNDEF + gcc_assert (new_resolution != LDPR_UNKNOWN + && new_resolution != LDPR_UNDEF && old_resolution != LDPR_UNKNOWN && old_resolution != LDPR_UNDEF); - if (resolution == LDPR_PREVAILING_DEF - || resolution == LDPR_PREVAILING_DEF_IRONLY) + if (new_resolution == LDPR_PREVAILING_DEF + || new_resolution == LDPR_PREVAILING_DEF_IRONLY + || (!old_node && new_node)) { - tree decl; - gcc_assert (old_resolution == LDPR_PREEMPTED_IR + gcc_assert ((!old_node && new_node) + || old_resolution == LDPR_PREEMPTED_IR || old_resolution == LDPR_RESOLVED_IR - || (old_resolution == resolution && !flag_no_common)); - DECL_LANG_SPECIFIC (new_decl) = DECL_LANG_SPECIFIC (old_decl); - DECL_LANG_SPECIFIC (old_decl) = NULL; - decl = lto_symtab_get_identifier_decl (name); - if (decl == old_decl) - { - lto_symtab_set_identifier_decl (name, new_decl); - return; - } - while ((tree) DECL_LANG_SPECIFIC (decl) != old_decl) - decl = (tree) DECL_LANG_SPECIFIC (decl); - DECL_LANG_SPECIFIC (decl) = (struct lang_decl *) new_decl; - return; + || (old_resolution == new_resolution && !flag_no_common)); + if (old_node) + lto_cgraph_replace_node (old_node, new_node); + /* Choose new_decl, entry2. */ + return entry2; } - if (resolution == LDPR_PREEMPTED_REG - || resolution == LDPR_RESOLVED_EXEC - || resolution == LDPR_RESOLVED_DYN) + if (new_resolution == LDPR_PREEMPTED_REG + || new_resolution == LDPR_RESOLVED_EXEC + || new_resolution == LDPR_RESOLVED_DYN) gcc_assert (old_resolution == LDPR_PREEMPTED_REG || old_resolution == LDPR_RESOLVED_EXEC || old_resolution == LDPR_RESOLVED_DYN); - if (resolution == LDPR_PREEMPTED_IR - || resolution == LDPR_RESOLVED_IR) + if (new_resolution == LDPR_PREEMPTED_IR + || new_resolution == LDPR_RESOLVED_IR) gcc_assert (old_resolution == LDPR_PREVAILING_DEF || old_resolution == LDPR_PREVAILING_DEF_IRONLY || old_resolution == LDPR_PREEMPTED_IR || old_resolution == LDPR_RESOLVED_IR); - return; + if (new_node) + lto_cgraph_replace_node (new_node, old_node); + + /* Choose old_decl, entry1. */ + return entry1; } +/* Resolve the symbol with the candidates in the chain *SLOT and store + their resolutions. */ -/* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous - declaration with the same name. */ +static void +lto_symtab_resolve_symbols (void **slot) +{ + lto_symtab_entry_t e = (lto_symtab_entry_t) *slot; -void -lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution) + /* If the chain is already resolved there is nothing to do. */ + if (e->resolution != LDPR_UNKNOWN) + return; + + /* This is a poor mans resolver. */ + for (; e; e = e->next) + { + gcc_assert (e->resolution == LDPR_UNKNOWN); + if (DECL_EXTERNAL (e->decl) + || (TREE_CODE (e->decl) == FUNCTION_DECL + && !cgraph_get_node (e->decl))) + e->resolution = LDPR_RESOLVED_IR; + else + { + if (TREE_READONLY (e->decl)) + e->resolution = LDPR_PREVAILING_DEF_IRONLY; + else + e->resolution = LDPR_PREVAILING_DEF; + } + } +} + +/* Merge one symbol table chain to a (set of) prevailing decls. */ + +static void +lto_symtab_merge_decls_2 (void **slot) +{ + lto_symtab_entry_t e2, e1; + + /* Nothing to do for a single entry. */ + e1 = (lto_symtab_entry_t) *slot; + if (!e1->next) + return; + + /* Try to merge each entry with each other entry. In case of a + single prevailing decl this is linear. */ +restart: + for (; e1; e1 = e1->next) + for (e2 = e1->next; e2; e2 = e2->next) + { + lto_symtab_entry_t prevailing = lto_symtab_merge (e1, e2); + if (prevailing == e1) + { + lto_symtab_entry_t tmp = prevailing; + while (tmp->next != e2) + tmp = tmp->next; + tmp->next = e2->next; + e2->next = NULL; + e2 = tmp; + } + else if (prevailing == e2) + { + lto_symtab_entry_t tmp = (lto_symtab_entry_t) *slot; + if (tmp == e1) + { + *slot = e1->next; + tmp = e1->next; + } + else + { + while (tmp->next != e1) + tmp = tmp->next; + tmp->next = e1->next; + } + e1->next = NULL; + e1 = tmp; + goto restart; + } + } +} + +/* Fixup the chain of prevailing variable decls *SLOT that are commonized + during link-time. */ + +static void +lto_symtab_fixup_var_decls (void **slot) +{ + lto_symtab_entry_t e = (lto_symtab_entry_t) *slot; + tree size = bitsize_zero_node; + + /* Find the largest prevailing decl and move it to the front of the chain. + This is the decl we will output as representative for the common + section. */ + size = bitsize_zero_node; + if (e->resolution == LDPR_PREVAILING_DEF_IRONLY + || e->resolution == LDPR_PREVAILING_DEF) + size = DECL_SIZE (e->decl); + for (; e->next;) + { + lto_symtab_entry_t next = e->next; + if ((next->resolution == LDPR_PREVAILING_DEF_IRONLY + || next->resolution == LDPR_PREVAILING_DEF) + && tree_int_cst_lt (size, DECL_SIZE (next->decl))) + { + size = DECL_SIZE (next->decl); + e->next = next->next; + next->next = (lto_symtab_entry_t) *slot; + *slot = next; + } + else + e = next; + } + + /* Mark everything apart from the first var as written out. */ + e = (lto_symtab_entry_t) *slot; + for (e = e->next; e; e = e->next) + TREE_ASM_WRITTEN (e->decl) = true; +} + +/* Helper to process the decl chain for the symbol table entry *SLOT. */ + +static int +lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED) { - lto_symtab_merge_decl (new_var, resolution, NULL); + lto_symtab_entry_t e; + + /* Compute the symbol resolutions. */ + lto_symtab_resolve_symbols (slot); + + /* Register and adjust types of the entries. */ + for (e = (lto_symtab_entry_t) *slot; e; e = e->next) + TREE_TYPE (e->decl) = gimple_register_type (TREE_TYPE (e->decl)); + + /* Merge the chain to a (hopefully) single prevailing decl. */ + lto_symtab_merge_decls_2 (slot); + + /* ??? Ideally we should delay all diagnostics until this point to + avoid duplicates. */ + + /* All done for FUNCTION_DECLs. */ + e = (lto_symtab_entry_t) *slot; + if (TREE_CODE (e->decl) == FUNCTION_DECL) + return 1; + + /* Fixup variables in case there are multiple prevailing ones. */ + if (e->next) + lto_symtab_fixup_var_decls (slot); + + /* Insert all variable decls into the global variable decl vector. */ + for (e = (lto_symtab_entry_t) *slot; e; e = e->next) + VEC_safe_push (tree, gc, lto_global_var_decls, e->decl); + + return 1; } -/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous - declaration with the same name. */ +/* Resolve and merge all symbol table chains to a prevailing decl. */ void -lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution, - struct lto_file_decl_data *file_data) +lto_symtab_merge_decls (void) { - lto_symtab_merge_decl (new_fn, resolution, file_data); + lto_symtab_maybe_init_hash_table (); + htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL); } + /* Given the decl DECL, return the prevailing decl with the same name. */ tree lto_symtab_prevailing_decl (tree decl) { - tree ret; - gcc_assert (decl); + lto_symtab_entry_t ret; /* Builtins and local symbols are their own prevailing decl. */ if (!TREE_PUBLIC (decl) || is_builtin_fn (decl)) @@ -709,74 +804,35 @@ lto_symtab_prevailing_decl (tree decl) gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); /* Walk through the list of candidates and return the one we merged to. */ - ret = lto_symtab_get_identifier_decl (DECL_ASSEMBLER_NAME (decl)); - if (!ret - || DECL_LANG_SPECIFIC (ret) == NULL) - return ret; + ret = lto_symtab_get (DECL_ASSEMBLER_NAME (decl)); + if (!ret) + return NULL_TREE; + + /* If there is only one candidate return it. */ + if (ret->next == NULL) + return ret->decl; /* If there are multiple decls to choose from find the one we merged with and return that. */ while (ret) { - if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret))) - return ret; + if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret->decl))) + return ret->decl; - ret = (tree) DECL_LANG_SPECIFIC (ret); + ret = ret->next; } gcc_unreachable (); } -/* Return the hash table entry of DECL. */ - -static struct lto_symtab_decl_def * -lto_symtab_get_symtab_def (tree decl) -{ - struct lto_symtab_decl_def temp, *symtab_decl; - void **slot; - - gcc_assert (decl); - - lto_symtab_maybe_init_hash_tables (); - temp.base.node = decl; - slot = htab_find_slot (lto_symtab_decls, &temp, NO_INSERT); - gcc_assert (slot && *slot); - symtab_decl = (struct lto_symtab_decl_def*) *slot; - return symtab_decl; -} - -/* Return the resolution of DECL. */ - -enum ld_plugin_symbol_resolution -lto_symtab_get_resolution (tree decl) -{ - gcc_assert (decl); - - if (!TREE_PUBLIC (decl) || is_builtin_fn (decl)) - return LDPR_PREVAILING_DEF_IRONLY; - - /* FIXME lto: There should be no DECL_ABSTRACT in the middle end. */ - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl)) - return LDPR_PREVAILING_DEF_IRONLY; - - return lto_symtab_get_symtab_def (decl)->resolution; -} - -/* Return the file of DECL. */ - -struct lto_file_decl_data * -lto_symtab_get_file_data (tree decl) -{ - return lto_symtab_get_symtab_def (decl)->file_data; -} - /* Remove any storage used to store resolution of DECL. */ void lto_symtab_clear_resolution (tree decl) { - struct lto_symtab_decl_def temp; - gcc_assert (decl); + struct lto_symtab_entry_def temp; + lto_symtab_entry_t head; + void **slot; if (!TREE_PUBLIC (decl)) return; @@ -785,9 +841,37 @@ lto_symtab_clear_resolution (tree decl) if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl)) return; - lto_symtab_maybe_init_hash_tables (); - temp.base.node = decl; - htab_remove_elt (lto_symtab_decls, &temp); + gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); + + lto_symtab_maybe_init_hash_table (); + temp.id = DECL_ASSEMBLER_NAME (decl); + slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT); + if (!*slot) + return; + + head = (lto_symtab_entry_t) *slot; + if (head->decl == decl) + { + if (head->next) + { + *slot = head->next; + head->next = NULL; + } + else + htab_remove_elt (lto_symtab_identifiers, &temp); + } + else + { + lto_symtab_entry_t e; + while (head->next && head->next->decl != decl) + head = head->next; + if (head->next) + { + e = head->next; + head->next = e->next; + e->next = NULL; + } + } } #include "gt-lto-symtab.h" diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 3ccce8f..c4ee42a 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,11 @@ +2009-10-05 Richard Guenther <rguenther@suse.de> + + PR lto/41552 + PR lto/41487 + * lto.c (lto_read_decls): Do not register deferred decls. + (read_cgraph_and_symbols): Delay symbol and cgraph merging + until after reading the IPA summaries. + 2009-10-02 Rafael Avila de Espindola <espindola@google.com> * Make-lang.in (lto/lto-lang.o): Don't depend on lto/common.h. diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 056d249..daefa82 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -244,10 +244,6 @@ 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); } @@ -1763,6 +1759,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; @@ -1821,60 +1818,22 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) /* Read the callgraph. */ input_cgraph (); + /* Read the IPA summary data. */ ipa_read_summaries (); - timevar_push (TV_IPA_LTO_DECL_IO); - - lto_fixup_decls (all_file_decl_data); + /* Merge global decls. */ + lto_symtab_merge_decls (); - /* 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)); + /* Mark cgraph nodes needed in the merged cgraph. + ??? Is this really necessary? */ + for (node = cgraph_nodes; node; node = node->next) + if (cgraph_decide_is_function_needed (node, node->decl)) + cgraph_mark_needed_node (node); - /* 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); - } + timevar_push (TV_IPA_LTO_DECL_IO); - /* 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; - } - } + /* Fixup all decls and types. */ + lto_fixup_decls (all_file_decl_data); /* FIXME lto. This loop needs to be changed to use the pass manager to call the ipa passes directly. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ce023aa..67a7428 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,17 @@ 2009-10-05 Richard Guenther <rguenther@suse.de> + PR lto/41552 + PR lto/41487 + * g++.dg/lto/20091002-1_0.C: Adjust flags. + * g++.dg/lto/20091004-1_0.C: New testcase. + * g++.dg/lto/20091004-1_1.C: Likewise. + * g++.dg/lto/20091004-2_0.C: Likewise. + * g++.dg/lto/20091004-2_1.C: Likewise. + * g++.dg/lto/20091004-3_0.C: Likewise. + * g++.dg/lto/20091004-3_1.C: Likewise. + +2009-10-05 Richard Guenther <rguenther@suse.de> + PR tree-optimization/23821 * gcc.dg/torture/pr23821.c: New testcase. diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C index d348e9c..ad1ecf6 100644 --- a/gcc/testsuite/g++.dg/lto/20091002-1_0.C +++ b/gcc/testsuite/g++.dg/lto/20091002-1_0.C @@ -1,5 +1,5 @@ // { dg-lto-do link } -// { dg-lto-options {{-fPIC}} } +// { dg-lto-options {{-fPIC -flto}} } // { dg-extra-ld-options "-fPIC -shared" } namespace std __attribute__ ((__visibility__ ("default"))) diff --git a/gcc/testsuite/g++.dg/lto/20091004-1_0.C b/gcc/testsuite/g++.dg/lto/20091004-1_0.C new file mode 100644 index 0000000..d65cf29 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/20091004-1_0.C @@ -0,0 +1,35 @@ +// { dg-lto-do link } +// { dg-lto-options {{-fPIC -O -flto}} } + +typedef double Real; +class Vector { + int dimen; + Real* val; +public: + Vector& operator=(const Vector& vec); + Vector(int p_dimen, Real *p_val) + : dimen(p_dimen), val(p_val) { } + int dim() const; +}; +class DVector : public Vector { +public: + void reDim(int newdim); + explicit DVector(const Vector& old); + DVector& operator=(const Vector& vec) { + reDim(vec.dim()); + Vector::operator=(vec); + } +}; +Vector& Vector::operator=(const Vector& vec) +{ + dimen = vec.dimen; + val = vec.val; +} +int Vector::dim() const { return dimen; } +DVector::DVector(const Vector& old) : Vector(0, 0) +{ + *this = old; +} +void DVector::reDim(int newdim) {} +int main() {} + diff --git a/gcc/testsuite/g++.dg/lto/20091004-1_1.C b/gcc/testsuite/g++.dg/lto/20091004-1_1.C new file mode 100644 index 0000000..0328aba --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/20091004-1_1.C @@ -0,0 +1,26 @@ +typedef double Real; +class Vector { + int dimen; + Real* val; +public: + Vector& operator=(const Vector& vec); + Vector(int p_dimen, Real *p_val) + : dimen(p_dimen), val(p_val) { } + int dim() const; +}; +class DVector : public Vector { +public: + void reDim(int newdim); + explicit DVector(const Vector& old); + DVector& operator=(const Vector& vec) { + reDim(vec.dim()); + Vector::operator=(vec); + } +}; +class SLUFactor { + DVector vec; + void solveRight (Vector& x, const Vector& b); +}; +void SLUFactor::solveRight (Vector& x, const Vector& b) { + vec = b; +} diff --git a/gcc/testsuite/g++.dg/lto/20091004-2_0.C b/gcc/testsuite/g++.dg/lto/20091004-2_0.C new file mode 100644 index 0000000..321e50b --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/20091004-2_0.C @@ -0,0 +1,29 @@ +// { dg-lto-do link } +// { dg-lto-options {{-fPIC -O -flto}} } + +typedef double Real; +class Vector { + int dimen; + Real* val; +public: + Vector& operator=(const Vector& vec); + Vector(int p_dimen, Real *p_val) + : dimen(p_dimen), val(p_val) { } + int dim() const; +}; +class DVector : public Vector { +public: + void reDim(int newdim); + explicit DVector(const Vector& old); + DVector& operator=(const Vector& vec) { + reDim(vec.dim()); + Vector::operator=(vec); + } +}; +class SLUFactor { + DVector vec; + void solveRight (Vector& x, const Vector& b); +}; +void SLUFactor::solveRight (Vector& x, const Vector& b) { + vec = b; +} diff --git a/gcc/testsuite/g++.dg/lto/20091004-2_1.C b/gcc/testsuite/g++.dg/lto/20091004-2_1.C new file mode 100644 index 0000000..9bbcd51 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/20091004-2_1.C @@ -0,0 +1,32 @@ +typedef double Real; +class Vector { + int dimen; + Real* val; +public: + Vector& operator=(const Vector& vec); + Vector(int p_dimen, Real *p_val) + : dimen(p_dimen), val(p_val) { } + int dim() const; +}; +class DVector : public Vector { +public: + void reDim(int newdim); + explicit DVector(const Vector& old); + DVector& operator=(const Vector& vec) { + reDim(vec.dim()); + Vector::operator=(vec); + } +}; +Vector& Vector::operator=(const Vector& vec) +{ + dimen = vec.dimen; + val = vec.val; +} +int Vector::dim() const { return dimen; } +DVector::DVector(const Vector& old) : Vector(0, 0) +{ + *this = old; +} +void DVector::reDim(int newdim) {} +int main() {} + diff --git a/gcc/testsuite/g++.dg/lto/20091004-3_0.C b/gcc/testsuite/g++.dg/lto/20091004-3_0.C new file mode 100644 index 0000000..124eea5 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/20091004-3_0.C @@ -0,0 +1,18 @@ +// { dg-lto-do assemble } +// { dg-lto-options {{-O -flto}} } + +extern "C" double sqrt (double __x) throw (); +typedef double VECTOR[3]; +enum { X = 0, Y = 1, Z = 2, T = 3 }; +inline void VLength(double& a, const VECTOR b) +{ + a = sqrt(b[X] * b[X] + b[Y] * b[Y] + b[Z] * b[Z]); +} +void +determine_subpatch_flatness(void) +{ + double temp1; + VECTOR TempV; + VLength(temp1, TempV); + VLength(temp1, TempV); +} diff --git a/gcc/testsuite/g++.dg/lto/20091004-3_1.C b/gcc/testsuite/g++.dg/lto/20091004-3_1.C new file mode 100644 index 0000000..641c749 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/20091004-3_1.C @@ -0,0 +1,16 @@ +extern "C" double sqrt (double __x) throw (); +typedef double VECTOR[3]; +enum { X = 0, Y = 1, Z = 2, T = 3 }; +inline void VLength(double& a, const VECTOR b) +{ + a = sqrt(b[X] * b[X] + b[Y] * b[Y] + b[Z] * b[Z]); +} +int +All_Torus_Intersections(void) +{ + double len; + VECTOR D; + VLength(len, D); + VLength(len, D); +} + |