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:
Richard Guenther 2009-10-05 14:05:54 +00:00 committed by Richard Biener
parent e9d85fa6a7
commit 1a735925e3
15 changed files with 656 additions and 488 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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"

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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")))

View 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() {}

View 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;
}

View 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;
}

View 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() {}

View 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);
}

View 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);
}