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
This commit is contained in:
parent
e9d85fa6a7
commit
1a735925e3
@ -1,3 +1,63 @@
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
682
gcc/lto-symtab.c
682
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"
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -1,3 +1,15 @@
|
||||
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
|
||||
|
@ -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")))
|
||||
|
35
gcc/testsuite/g++.dg/lto/20091004-1_0.C
Normal file
35
gcc/testsuite/g++.dg/lto/20091004-1_0.C
Normal file
@ -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() {}
|
||||
|
26
gcc/testsuite/g++.dg/lto/20091004-1_1.C
Normal file
26
gcc/testsuite/g++.dg/lto/20091004-1_1.C
Normal file
@ -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;
|
||||
}
|
29
gcc/testsuite/g++.dg/lto/20091004-2_0.C
Normal file
29
gcc/testsuite/g++.dg/lto/20091004-2_0.C
Normal file
@ -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;
|
||||
}
|
32
gcc/testsuite/g++.dg/lto/20091004-2_1.C
Normal file
32
gcc/testsuite/g++.dg/lto/20091004-2_1.C
Normal file
@ -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() {}
|
||||
|
18
gcc/testsuite/g++.dg/lto/20091004-3_0.C
Normal file
18
gcc/testsuite/g++.dg/lto/20091004-3_0.C
Normal file
@ -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);
|
||||
}
|
16
gcc/testsuite/g++.dg/lto/20091004-3_1.C
Normal file
16
gcc/testsuite/g++.dg/lto/20091004-3_1.C
Normal file
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user