From 1a735925e30877491ac12ca78612e4de29c4bf0f Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Mon, 5 Oct 2009 14:05:54 +0000 Subject: [PATCH] re PR lto/41552 (Undefined references with -flto, dependent on object file ordering) 2009-10-05 Richard Guenther 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 --- gcc/ChangeLog | 60 +++ gcc/lto-cgraph.c | 49 +- gcc/lto-streamer-in.c | 102 +--- gcc/lto-streamer.h | 8 +- gcc/lto-symtab.c | 682 +++++++++++++----------- gcc/lto/ChangeLog | 8 + gcc/lto/lto.c | 65 +-- gcc/testsuite/ChangeLog | 12 + gcc/testsuite/g++.dg/lto/20091002-1_0.C | 2 +- gcc/testsuite/g++.dg/lto/20091004-1_0.C | 35 ++ gcc/testsuite/g++.dg/lto/20091004-1_1.C | 26 + gcc/testsuite/g++.dg/lto/20091004-2_0.C | 29 + gcc/testsuite/g++.dg/lto/20091004-2_1.C | 32 ++ gcc/testsuite/g++.dg/lto/20091004-3_0.C | 18 + gcc/testsuite/g++.dg/lto/20091004-3_1.C | 16 + 15 files changed, 656 insertions(+), 488 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lto/20091004-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-2_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-3_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-3_1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a5460f302f9..5da6b90eb87 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,63 @@ +2009-10-05 Richard Guenther + + 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 PR tree-optimization/23821 diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index b11483c9c81..47ccccd51f4 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 a8d237959c3..175a1e771e7 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 b156ff42455..c4d66b7a65a 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 90a200fc735..85e3c6c9f93 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); + /* Keep this only if the decl or the chain is marked. */ + return (ggc_marked_p (base->decl) + || (base->next && ggc_marked_p (base->next))); } -/* 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); -} - -#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; - 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); - *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. */ - -static lto_symtab_identifier_t -lto_symtab_get_identifier (tree id, bool insert_p) -{ - struct lto_symtab_identifier_def temp; - lto_symtab_identifier_t symtab_id; - 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; -} - -/* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE - if there is none. */ - -static tree -lto_symtab_get_identifier_decl (tree id) -{ - lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false); - return symtab_id ? symtab_id->decl : NULL_TREE; -} - -/* SET the associated DECL of an IDENTIFIER ID to be 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; -} - -/* 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. */ - -static void -lto_symtab_merge_decl (tree new_decl, - enum ld_plugin_symbol_resolution resolution, - struct lto_file_decl_data *file_data) -{ - 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))); + 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)); - /* Remember the resolution of this symbol. */ - lto_symtab_set_resolution_and_file_data (new_decl, resolution, file_data); + 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_table (); + slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT); + new_entry->next = (lto_symtab_entry_t) *slot; + *slot = new_entry; +} - /* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */ - gcc_assert (DECL_ASSEMBLER_NAME_SET_P (new_decl)); +/* Get the lto_symtab_entry_def struct associated with ID + if there is one. */ - /* Retrieve the previous declaration. */ - name = DECL_ASSEMBLER_NAME (new_decl); - old_decl = lto_symtab_get_identifier_decl (name); +static lto_symtab_entry_t +lto_symtab_get (tree id) +{ + struct lto_symtab_entry_def temp; + void **slot; - /* If there was no previous declaration, then there is nothing to - merge. */ - if (!old_decl) + 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; +} + +/* Get the linker resolution for DECL. */ + +enum ld_plugin_symbol_resolution +lto_symtab_get_resolution (tree decl) +{ + lto_symtab_entry_t e; + + gcc_assert (DECL_ASSEMBLER_NAME_SET_P (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; +} + +/* Replace the cgraph node OLD_NODE with NEW_NODE in the cgraph, merging + all edges and removing the old node. */ + +static void +lto_cgraph_replace_node (struct cgraph_node *old_node, + struct cgraph_node *new_node) +{ + 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) { - lto_symtab_set_identifier_decl (name, new_decl); - VEC_safe_push (tree, gc, lto_global_var_decls, new_decl); - return; + next = e->next_caller; + cgraph_redirect_edge_callee (e, new_node); } + /* 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); + } + + /* Finally remove the replaced node. */ + cgraph_remove_node (old_node); +} + +/* Merge two variable or function symbol table entries ENTRY1 and ENTRY2. + Return the prevailing one or NULL if a merge is not possible. */ + +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; + + /* 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_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; +} + +/* Resolve and merge all symbol table chains to a prevailing decl. */ void -lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution) +lto_symtab_merge_decls (void) { - lto_symtab_merge_decl (new_var, resolution, NULL); + lto_symtab_maybe_init_hash_table (); + htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL); } -/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous - declaration with the same name. */ - -void -lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution, - struct lto_file_decl_data *file_data) -{ - lto_symtab_merge_decl (new_fn, resolution, file_data); -} /* 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 3ccce8fb5cf..c4ee42ae6a2 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,11 @@ +2009-10-05 Richard Guenther + + 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 * 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 056d249a161..daefa823db3 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,61 +1818,23 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) /* Read the callgraph. */ input_cgraph (); + /* Read the IPA summary data. */ ipa_read_summaries (); + /* Merge global decls. */ + lto_symtab_merge_decls (); + + /* 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); + timevar_push (TV_IPA_LTO_DECL_IO); + /* Fixup all decls and types. */ lto_fixup_decls (all_file_decl_data); - /* 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)); - - /* 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); - } - - /* 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; - } - } - /* FIXME lto. This loop needs to be changed to use the pass manager to call the ipa passes directly. */ if (!errorcount) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ce023aa6c97..67a74284b64 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2009-10-05 Richard Guenther + + 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 PR tree-optimization/23821 diff --git a/gcc/testsuite/g++.dg/lto/20091002-1_0.C b/gcc/testsuite/g++.dg/lto/20091002-1_0.C index d348e9c1a7d..ad1ecf673f5 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 00000000000..d65cf29fff1 --- /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 00000000000..0328abaae27 --- /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 00000000000..321e50bc28d --- /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 00000000000..9bbcd51f754 --- /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 00000000000..124eea5e4eb --- /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 00000000000..641c7495b4f --- /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); +} +