Commit b823cdfe by Michael Matz Committed by Michael Matz

lto-streamer.c (lto_streamer_cache_insert_1): Accept to override other trees that just builtins.

	* lto-streamer.c (lto_streamer_cache_insert_1): Accept to override
	other trees that just builtins.
	(lto_record_common_node): Don't leave NULL TYPE_CANONICAL.

lto/
	* lto.c (toplevel): Include tree-flow.h.
	(lto_read_in_decl_state): Don't merge types here.
	(tree_with_vars): New static hash table.
	(remember_with_vars): New static functions.
	(LTO_FIXUP_TYPE): New macro.
	(lto_ft_common, lto_ft_decl_minimal, lto_ft_decl_common,
	lto_ft_decl_with_vis, lto_ft_decl_non_common, lto_ft_function,
	lto_ft_field_decl, lto_ft_type, lto_ft_binfo, lto_ft_constructor,
	lto_ft_expr, lto_fixup_types, uniquify_nodes): New static functions.
	(lto_read_decls): Uniquify while reading in trees.
	(lto_fixup_data_t, LTO_FIXUP_SUBTREE,
	LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE, no_fixup_p, lto_fixup_common,
	lto_fixup_decl_minimal, lto_fixup_decl_common, lto_fixup_decl_with_vis,
	lto_fixup_decl_non_common, lto_fixup_function, lto_fixup_field_decl,
	lto_fixup_type, lto_fixup_binfo, lto_fixup_constructor,
	lto_fixup_tree): Remove.
	(lto_fixup_state): Remove data argument.  Use
	lto_symtab_prevailing_decl.
	(LTO_SET_PREVAIL, LTO_NO_PREVAIL): New macros.
	(lto_fixup_prevailing_decls): New function.
	(lto_fixup_state_aux): Argument aux is unused.
	(lto_fixup_decls): Don't allocate pointer sets, don't use
	lto_fixup_tree, use lto_fixup_prevailing_decls.
	(read_cgraph_and_symbols): Allocate and remove tree_with_vars.
	* Make-lang.in (lto/lto.o): Depend on $(TREE_FLOW_H).

From-SVN: r173155
parent fa5e5a76
2011-04-29 Michael Matz <matz@suse.de>
* lto-streamer.c (lto_streamer_cache_insert_1): Accept to override
other trees that just builtins.
(lto_record_common_node): Don't leave NULL TYPE_CANONICAL.
2011-04-29 Richard Guenther <rguenther@suse.de> 2011-04-29 Richard Guenther <rguenther@suse.de>
* tree-nested.c (get_trampoline_type): Use size_int. * tree-nested.c (get_trampoline_type): Use size_int.
......
...@@ -383,19 +383,8 @@ lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache, ...@@ -383,19 +383,8 @@ lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
{ {
/* If the caller wants to insert T at a specific slot /* If the caller wants to insert T at a specific slot
location, and ENTRY->TO does not match *IX_P, add T to location, and ENTRY->TO does not match *IX_P, add T to
the requested location slot. This situation arises when the requested location slot. */
streaming builtin functions.
For instance, on the writer side we could have two
FUNCTION_DECLS T1 and T2 that are represented by the same
builtin function. The reader will only instantiate the
canonical builtin, but since T1 and T2 had been
originally stored in different cache slots (S1 and S2),
the reader must be able to find the canonical builtin
function at slots S1 and S2. */
gcc_assert (lto_stream_as_builtin_p (t));
ix = *ix_p; ix = *ix_p;
lto_streamer_cache_add_to_node_array (cache, ix, t); lto_streamer_cache_add_to_node_array (cache, ix, t);
} }
...@@ -513,6 +502,8 @@ lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes, ...@@ -513,6 +502,8 @@ lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes,
TYPE_CANONICAL (node) = NULL_TREE; TYPE_CANONICAL (node) = NULL_TREE;
node = gimple_register_type (node); node = gimple_register_type (node);
TYPE_CANONICAL (node) = gimple_register_canonical_type (node); TYPE_CANONICAL (node) = gimple_register_canonical_type (node);
if (in_lto_p)
TYPE_CANONICAL (*nodep) = TYPE_CANONICAL (node);
*nodep = node; *nodep = node;
} }
......
2011-04-29 Michael Matz <matz@suse.de>
* lto.c (toplevel): Include tree-flow.h.
(lto_read_in_decl_state): Don't merge types here.
(tree_with_vars): New static hash table.
(remember_with_vars): New static functions.
(LTO_FIXUP_TYPE): New macro.
(lto_ft_common, lto_ft_decl_minimal, lto_ft_decl_common,
lto_ft_decl_with_vis, lto_ft_decl_non_common, lto_ft_function,
lto_ft_field_decl, lto_ft_type, lto_ft_binfo, lto_ft_constructor,
lto_ft_expr, lto_fixup_types, uniquify_nodes): New static functions.
(lto_read_decls): Uniquify while reading in trees.
(lto_fixup_data_t, LTO_FIXUP_SUBTREE,
LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE, no_fixup_p, lto_fixup_common,
lto_fixup_decl_minimal, lto_fixup_decl_common, lto_fixup_decl_with_vis,
lto_fixup_decl_non_common, lto_fixup_function, lto_fixup_field_decl,
lto_fixup_type, lto_fixup_binfo, lto_fixup_constructor,
lto_fixup_tree): Remove.
(lto_fixup_state): Remove data argument. Use
lto_symtab_prevailing_decl.
(LTO_SET_PREVAIL, LTO_NO_PREVAIL): New macros.
(lto_fixup_prevailing_decls): New function.
(lto_fixup_state_aux): Argument aux is unused.
(lto_fixup_decls): Don't allocate pointer sets, don't use
lto_fixup_tree, use lto_fixup_prevailing_decls.
(read_cgraph_and_symbols): Allocate and remove tree_with_vars.
* Make-lang.in (lto/lto.o): Depend on $(TREE_FLOW_H).
2011-04-16 Eric Botcazou <ebotcazou@adacore.com> 2011-04-16 Eric Botcazou <ebotcazou@adacore.com>
* lto.c (lto_balanced_map): Fix typos in head comment. * lto.c (lto_balanced_map): Fix typos in head comment.
......
...@@ -81,7 +81,7 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \ ...@@ -81,7 +81,7 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
$(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \ $(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \
$(EXPR_H) $(LTO_STREAMER_H) $(EXPR_H) $(LTO_STREAMER_H)
lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \ lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \ toplev.h $(TREE_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \
$(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \ $(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \
langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \ langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
$(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \ $(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
......
...@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "opts.h" #include "opts.h"
#include "toplev.h" #include "toplev.h"
#include "tree.h" #include "tree.h"
#include "tree-flow.h"
#include "diagnostic-core.h" #include "diagnostic-core.h"
#include "tm.h" #include "tm.h"
#include "cgraph.h" #include "cgraph.h"
...@@ -215,24 +216,452 @@ lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data, ...@@ -215,24 +216,452 @@ lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data,
tree *decls = ggc_alloc_vec_tree (size); tree *decls = ggc_alloc_vec_tree (size);
for (j = 0; j < size; j++) for (j = 0; j < size; j++)
decls[j] = lto_streamer_cache_get (data_in->reader_cache, data[j]);
state->streams[i].size = size;
state->streams[i].trees = decls;
data += size;
}
return data;
}
/* A hashtable of trees that potentially refer to variables or functions
that must be replaced with their prevailing variant. */
static GTY((if_marked ("ggc_marked_p"), param_is (union tree_node))) htab_t
tree_with_vars;
/* Remember that T is a tree that (potentially) refers to a variable
or function decl that may be replaced with its prevailing variant. */
static void
remember_with_vars (tree t)
{
*(tree *) htab_find_slot (tree_with_vars, t, INSERT) = t;
}
#define LTO_FIXUP_TREE(tt) \
do \
{ \
if (tt) \
{ \
if (TYPE_P (tt)) \
(tt) = gimple_register_type (tt); \
if (VAR_OR_FUNCTION_DECL_P (tt) && TREE_PUBLIC (tt)) \
remember_with_vars (t); \
} \
} while (0)
static void lto_fixup_types (tree);
/* Fix up fields of a tree_common T. */
static void
lto_ft_common (tree t)
{
/* The following re-creates the TYPE_REFERENCE_TO and TYPE_POINTER_TO
lists. We do not stream TYPE_REFERENCE_TO, TYPE_POINTER_TO or
TYPE_NEXT_PTR_TO and TYPE_NEXT_REF_TO.
First remove us from any pointer list we are on. */
if (TREE_CODE (t) == POINTER_TYPE)
{
if (TYPE_POINTER_TO (TREE_TYPE (t)) == t)
TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t);
else
{ {
decls[j] = lto_streamer_cache_get (data_in->reader_cache, data[j]); tree tem = TYPE_POINTER_TO (TREE_TYPE (t));
while (tem && TYPE_NEXT_PTR_TO (tem) != t)
tem = TYPE_NEXT_PTR_TO (tem);
if (tem)
TYPE_NEXT_PTR_TO (tem) = TYPE_NEXT_PTR_TO (t);
}
TYPE_NEXT_PTR_TO (t) = NULL_TREE;
}
else if (TREE_CODE (t) == REFERENCE_TYPE)
{
if (TYPE_REFERENCE_TO (TREE_TYPE (t)) == t)
TYPE_REFERENCE_TO (TREE_TYPE (t)) = TYPE_NEXT_REF_TO (t);
else
{
tree tem = TYPE_REFERENCE_TO (TREE_TYPE (t));
while (tem && TYPE_NEXT_REF_TO (tem) != t)
tem = TYPE_NEXT_REF_TO (tem);
if (tem)
TYPE_NEXT_REF_TO (tem) = TYPE_NEXT_REF_TO (t);
}
TYPE_NEXT_REF_TO (t) = NULL_TREE;
}
/* Fixup our type. */
LTO_FIXUP_TREE (TREE_TYPE (t));
/* Second put us on the list of pointers of the new pointed-to type
if we are a main variant. This is done in lto_ft_type after
fixing up our main variant. */
LTO_FIXUP_TREE (TREE_CHAIN (t));
}
/* Fix up fields of a decl_minimal T. */
static void
lto_ft_decl_minimal (tree t)
{
lto_ft_common (t);
LTO_FIXUP_TREE (DECL_NAME (t));
LTO_FIXUP_TREE (DECL_CONTEXT (t));
}
/* Fix up fields of a decl_common T. */
static void
lto_ft_decl_common (tree t)
{
lto_ft_decl_minimal (t);
LTO_FIXUP_TREE (DECL_SIZE (t));
LTO_FIXUP_TREE (DECL_SIZE_UNIT (t));
LTO_FIXUP_TREE (DECL_INITIAL (t));
LTO_FIXUP_TREE (DECL_ATTRIBUTES (t));
LTO_FIXUP_TREE (DECL_ABSTRACT_ORIGIN (t));
}
/* Fix up fields of a decl_with_vis T. */
static void
lto_ft_decl_with_vis (tree t)
{
lto_ft_decl_common (t);
/* Accessor macro has side-effects, use field-name here. */
LTO_FIXUP_TREE (t->decl_with_vis.assembler_name);
LTO_FIXUP_TREE (DECL_SECTION_NAME (t));
}
/* Fix up fields of a decl_non_common T. */
static void
lto_ft_decl_non_common (tree t)
{
lto_ft_decl_with_vis (t);
LTO_FIXUP_TREE (DECL_ARGUMENT_FLD (t));
LTO_FIXUP_TREE (DECL_RESULT_FLD (t));
LTO_FIXUP_TREE (DECL_VINDEX (t));
}
/* Fix up fields of a decl_non_common T. */
static void
lto_ft_function (tree t)
{
lto_ft_decl_non_common (t);
LTO_FIXUP_TREE (DECL_FUNCTION_PERSONALITY (t));
}
/* Fix up fields of a field_decl T. */
static void
lto_ft_field_decl (tree t)
{
lto_ft_decl_common (t);
LTO_FIXUP_TREE (DECL_FIELD_OFFSET (t));
LTO_FIXUP_TREE (DECL_BIT_FIELD_TYPE (t));
LTO_FIXUP_TREE (DECL_QUALIFIER (t));
LTO_FIXUP_TREE (DECL_FIELD_BIT_OFFSET (t));
LTO_FIXUP_TREE (DECL_FCONTEXT (t));
}
/* Fix up fields of a type T. */
static void
lto_ft_type (tree t)
{
tree tem, mv;
lto_ft_common (t);
LTO_FIXUP_TREE (TYPE_CACHED_VALUES (t));
LTO_FIXUP_TREE (TYPE_SIZE (t));
LTO_FIXUP_TREE (TYPE_SIZE_UNIT (t));
LTO_FIXUP_TREE (TYPE_ATTRIBUTES (t));
LTO_FIXUP_TREE (TYPE_NAME (t));
/* Accessors are for derived node types only. */
if (!POINTER_TYPE_P (t))
LTO_FIXUP_TREE (t->type.minval);
LTO_FIXUP_TREE (t->type.maxval);
/* Accessor is for derived node types only. */
LTO_FIXUP_TREE (t->type.binfo);
LTO_FIXUP_TREE (TYPE_CONTEXT (t));
/* Compute the canonical type of t and fix that up. From this point
there are no longer any types with TYPE_STRUCTURAL_EQUALITY_P
and its type-based alias problems. */
if (!TYPE_CANONICAL (t))
{
TYPE_CANONICAL (t) = gimple_register_canonical_type (t);
LTO_FIXUP_TREE (TYPE_CANONICAL (t));
}
/* The following re-creates proper variant lists while fixing up
the variant leaders. We do not stream TYPE_NEXT_VARIANT so the
variant list state before fixup is broken. */
/* Remove us from our main variant list if we are not the variant leader. */
if (TYPE_MAIN_VARIANT (t) != t)
{
tem = TYPE_MAIN_VARIANT (t);
while (tem && TYPE_NEXT_VARIANT (tem) != t)
tem = TYPE_NEXT_VARIANT (tem);
if (tem)
TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t);
TYPE_NEXT_VARIANT (t) = NULL_TREE;
}
/* Query our new main variant. */
mv = gimple_register_type (TYPE_MAIN_VARIANT (t));
/* If we were the variant leader and we get replaced ourselves drop
all variants from our list. */
if (TYPE_MAIN_VARIANT (t) == t
&& mv != t)
{
tem = t;
while (tem)
{
tree tem2 = TYPE_NEXT_VARIANT (tem);
TYPE_NEXT_VARIANT (tem) = NULL_TREE;
tem = tem2;
}
}
/* Finally adjust our main variant and fix it up. */
TYPE_MAIN_VARIANT (t) = mv;
LTO_FIXUP_TREE (TYPE_MAIN_VARIANT (t));
/* As the second step of reconstructing the pointer chains put us
on the list of pointers of the new pointed-to type
if we are a main variant. See lto_ft_common for the first step. */
if (TREE_CODE (t) == POINTER_TYPE
&& TYPE_MAIN_VARIANT (t) == t)
{
TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (TREE_TYPE (t));
TYPE_POINTER_TO (TREE_TYPE (t)) = t;
}
else if (TREE_CODE (t) == REFERENCE_TYPE
&& TYPE_MAIN_VARIANT (t) == t)
{
TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (TREE_TYPE (t));
TYPE_REFERENCE_TO (TREE_TYPE (t)) = t;
}
}
/* Fix up fields of a BINFO T. */
static void
lto_ft_binfo (tree t)
{
unsigned HOST_WIDE_INT i, n;
tree base, saved_base;
lto_ft_common (t);
LTO_FIXUP_TREE (BINFO_VTABLE (t));
LTO_FIXUP_TREE (BINFO_OFFSET (t));
LTO_FIXUP_TREE (BINFO_VIRTUALS (t));
LTO_FIXUP_TREE (BINFO_VPTR_FIELD (t));
n = VEC_length (tree, BINFO_BASE_ACCESSES (t));
for (i = 0; i < n; i++)
{
saved_base = base = BINFO_BASE_ACCESS (t, i);
LTO_FIXUP_TREE (base);
if (base != saved_base)
VEC_replace (tree, BINFO_BASE_ACCESSES (t), i, base);
}
LTO_FIXUP_TREE (BINFO_INHERITANCE_CHAIN (t));
LTO_FIXUP_TREE (BINFO_SUBVTT_INDEX (t));
LTO_FIXUP_TREE (BINFO_VPTR_INDEX (t));
n = BINFO_N_BASE_BINFOS (t);
for (i = 0; i < n; i++)
{
saved_base = base = BINFO_BASE_BINFO (t, i);
LTO_FIXUP_TREE (base);
if (base != saved_base)
VEC_replace (tree, BINFO_BASE_BINFOS (t), i, base);
}
}
/* Fix up fields of a CONSTRUCTOR T. */
static void
lto_ft_constructor (tree t)
{
unsigned HOST_WIDE_INT idx;
constructor_elt *ce;
LTO_FIXUP_TREE (TREE_TYPE (t));
for (idx = 0;
VEC_iterate(constructor_elt, CONSTRUCTOR_ELTS (t), idx, ce);
idx++)
{
LTO_FIXUP_TREE (ce->index);
LTO_FIXUP_TREE (ce->value);
}
}
/* Fix up fields of an expression tree T. */
static void
lto_ft_expr (tree t)
{
int i;
lto_ft_common (t);
for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
LTO_FIXUP_TREE (TREE_OPERAND (t, i));
}
/* Given a tree T fixup fields of T by replacing types with their merged
variant and other entities by an equal entity from an earlier compilation
unit, or an entity being canonical in a different way. This includes
for instance integer or string constants. */
static void
lto_fixup_types (tree t)
{
switch (TREE_CODE (t))
{
case IDENTIFIER_NODE:
break;
case TREE_LIST:
LTO_FIXUP_TREE (TREE_VALUE (t));
LTO_FIXUP_TREE (TREE_PURPOSE (t));
LTO_FIXUP_TREE (TREE_CHAIN (t));
break;
case FIELD_DECL:
lto_ft_field_decl (t);
break;
case LABEL_DECL:
case CONST_DECL:
case PARM_DECL:
case RESULT_DECL:
case IMPORTED_DECL:
lto_ft_decl_common (t);
break;
case VAR_DECL:
lto_ft_decl_with_vis (t);
break;
case TYPE_DECL:
lto_ft_decl_non_common (t);
break;
case FUNCTION_DECL:
lto_ft_function (t);
break;
case TREE_BINFO:
lto_ft_binfo (t);
break;
case PLACEHOLDER_EXPR:
lto_ft_common (t);
break;
case BLOCK:
case TRANSLATION_UNIT_DECL:
case OPTIMIZATION_NODE:
case TARGET_OPTION_NODE:
break;
default:
if (TYPE_P (t))
lto_ft_type (t);
else if (TREE_CODE (t) == CONSTRUCTOR)
lto_ft_constructor (t);
else if (CONSTANT_CLASS_P (t))
LTO_FIXUP_TREE (TREE_TYPE (t));
else if (EXPR_P (t))
{
lto_ft_expr (t);
}
else
{
remember_with_vars (t);
}
}
}
/* Given a streamer cache structure DATA_IN (holding a sequence of trees
for one compilation unit) go over all trees starting at index FROM until the
end of the sequence and replace fields of those trees, and the trees
themself with their canonical variants as per gimple_register_type. */
static void
uniquify_nodes (struct data_in *data_in, unsigned from)
{
struct lto_streamer_cache_d *cache = data_in->reader_cache;
unsigned len = VEC_length (tree, cache->nodes);
unsigned i;
/* Go backwards because childs streamed for the first time come
as part of their parents, and hence are created after them. */
for (i = len; i-- > from;)
{
tree t = VEC_index (tree, cache->nodes, i);
tree oldt = t;
if (!t)
continue;
/* First fixup the fields of T. */
lto_fixup_types (t);
/* Now try to find a canonical variant of T itself. */
if (TYPE_P (t))
{
t = gimple_register_type (t);
if (t == oldt
&& TYPE_MAIN_VARIANT (t) != t)
{
/* If this is its own type, link it into the variant chain. */
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (t));
TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (t)) = t;
}
}
if (t != oldt)
{
if (RECORD_OR_UNION_TYPE_P (t))
{
tree f1, f2;
if (TYPE_FIELDS (t) != TYPE_FIELDS (oldt))
for (f1 = TYPE_FIELDS (t), f2 = TYPE_FIELDS (oldt);
f1 && f2; f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
{
unsigned ix;
gcc_assert (f1 != f2 && DECL_NAME (f1) == DECL_NAME (f2));
if (!lto_streamer_cache_lookup (cache, f2, &ix))
gcc_unreachable ();
/* If we're going to replace an element which we'd
still visit in the next iterations, we wouldn't
handle it, so do it here. We do have to handle it
even though the field_decl itself will be removed,
as it could refer to e.g. integer_cst which we
wouldn't reach via any other way, hence they
(and their type) would stay uncollected. */
if (ix < i)
lto_fixup_types (f2);
lto_streamer_cache_insert_at (cache, f1, ix);
}
}
/* Register every type in the global type table. If the /* If we found a tree that is equal to oldt replace it in the
type existed already, use the existing type. */ cache, so that further users (in the various LTO sections)
if (TYPE_P (decls[j])) make use of it. */
decls[j] = gimple_register_type (decls[j]); lto_streamer_cache_insert_at (cache, t, i);
} }
state->streams[i].size = size;
state->streams[i].trees = decls;
data += size;
} }
return data;
} }
/* Read all the symbols from buffer DATA, using descriptors in DECL_DATA. /* Read all the symbols from buffer DATA, using descriptors in DECL_DATA.
RESOLUTIONS is the set of symbols picked by the linker (read from the RESOLUTIONS is the set of symbols picked by the linker (read from the
resolution file when the linker plugin is being used). */ resolution file when the linker plugin is being used). */
...@@ -260,8 +689,11 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data, ...@@ -260,8 +689,11 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
/* Read the global declarations and types. */ /* Read the global declarations and types. */
while (ib_main.p < ib_main.len) while (ib_main.p < ib_main.len)
{ {
tree t = lto_input_tree (&ib_main, data_in); tree t;
unsigned from = VEC_length (tree, data_in->reader_cache->nodes);
t = lto_input_tree (&ib_main, data_in);
gcc_assert (t && ib_main.p <= ib_main.len); gcc_assert (t && ib_main.p <= ib_main.len);
uniquify_nodes (data_in, from);
} }
/* Read in lto_in_decl_state objects. */ /* Read in lto_in_decl_state objects. */
...@@ -1514,7 +1946,7 @@ lto_wpa_write_files (void) ...@@ -1514,7 +1946,7 @@ lto_wpa_write_files (void)
fprintf (stderr, " %s (%s %i insns)", temp_filename, part->name, part->insns); fprintf (stderr, " %s (%s %i insns)", temp_filename, part->name, part->insns);
if (cgraph_dump_file) if (cgraph_dump_file)
{ {
fprintf (cgraph_dump_file, "Writting partition %s to file %s, %i insns\n", fprintf (cgraph_dump_file, "Writing partition %s to file %s, %i insns\n",
part->name, temp_filename, part->insns); part->name, temp_filename, part->insns);
fprintf (cgraph_dump_file, "cgraph nodes:"); fprintf (cgraph_dump_file, "cgraph nodes:");
dump_cgraph_node_set (cgraph_dump_file, set); dump_cgraph_node_set (cgraph_dump_file, set);
...@@ -1548,416 +1980,106 @@ lto_wpa_write_files (void) ...@@ -1548,416 +1980,106 @@ lto_wpa_write_files (void)
} }
typedef struct { /* If TT is a variable or function decl replace it with its
struct pointer_set_t *seen; prevailing variant. */
} lto_fixup_data_t; #define LTO_SET_PREVAIL(tt) \
do {\
#define LTO_FIXUP_SUBTREE(t) \ if ((tt) && VAR_OR_FUNCTION_DECL_P (tt)) \
do \ tt = lto_symtab_prevailing_decl (tt); \
walk_tree (&(t), lto_fixup_tree, data, NULL); \ } while (0)
while (0)
#define LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE(t) \
do \
{ \
if (t) \
(t) = gimple_register_type (t); \
walk_tree (&(t), lto_fixup_tree, data, NULL); \
} \
while (0)
static tree lto_fixup_tree (tree *, int *, void *);
/* Return true if T does not need to be fixed up recursively. */
static inline bool
no_fixup_p (tree t)
{
return (t == NULL
|| CONSTANT_CLASS_P (t)
|| TREE_CODE (t) == IDENTIFIER_NODE);
}
/* Fix up fields of a tree_common T. DATA points to fix-up states. */ /* Ensure that TT isn't a replacable var of function decl. */
#define LTO_NO_PREVAIL(tt) \
gcc_assert (!(tt) || !VAR_OR_FUNCTION_DECL_P (tt))
/* Given a tree T replace all fields referring to variables or functions
with their prevailing variant. */
static void static void
lto_fixup_common (tree t, void *data) lto_fixup_prevailing_decls (tree t)
{ {
/* The following re-creates the TYPE_REFERENCE_TO and TYPE_POINTER_TO enum tree_code code = TREE_CODE (t);
lists. We do not stream TYPE_REFERENCE_TO, TYPE_POINTER_TO or LTO_NO_PREVAIL (TREE_TYPE (t));
TYPE_NEXT_PTR_TO and TYPE_NEXT_REF_TO. LTO_NO_PREVAIL (TREE_CHAIN (t));
First remove us from any pointer list we are on. */ if (DECL_P (t))
if (TREE_CODE (t) == POINTER_TYPE)
{ {
if (TYPE_POINTER_TO (TREE_TYPE (t)) == t) LTO_NO_PREVAIL (DECL_NAME (t));
TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t); LTO_SET_PREVAIL (DECL_CONTEXT (t));
else if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
{ {
tree tem = TYPE_POINTER_TO (TREE_TYPE (t)); LTO_SET_PREVAIL (DECL_SIZE (t));
while (tem && TYPE_NEXT_PTR_TO (tem) != t) LTO_SET_PREVAIL (DECL_SIZE_UNIT (t));
tem = TYPE_NEXT_PTR_TO (tem); LTO_SET_PREVAIL (DECL_INITIAL (t));
if (tem) LTO_NO_PREVAIL (DECL_ATTRIBUTES (t));
TYPE_NEXT_PTR_TO (tem) = TYPE_NEXT_PTR_TO (t); LTO_SET_PREVAIL (DECL_ABSTRACT_ORIGIN (t));
} }
TYPE_NEXT_PTR_TO (t) = NULL_TREE; if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
}
else if (TREE_CODE (t) == REFERENCE_TYPE)
{
if (TYPE_REFERENCE_TO (TREE_TYPE (t)) == t)
TYPE_REFERENCE_TO (TREE_TYPE (t)) = TYPE_NEXT_REF_TO (t);
else
{ {
tree tem = TYPE_REFERENCE_TO (TREE_TYPE (t)); LTO_NO_PREVAIL (t->decl_with_vis.assembler_name);
while (tem && TYPE_NEXT_REF_TO (tem) != t) LTO_NO_PREVAIL (DECL_SECTION_NAME (t));
tem = TYPE_NEXT_REF_TO (tem);
if (tem)
TYPE_NEXT_REF_TO (tem) = TYPE_NEXT_REF_TO (t);
} }
TYPE_NEXT_REF_TO (t) = NULL_TREE; if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
}
/* Fixup our type. */
LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
/* Second put us on the list of pointers of the new pointed-to type
if we are a main variant. This is done in lto_fixup_type after
fixing up our main variant. */
/* This is not very efficient because we cannot do tail-recursion with
a long chain of trees. */
if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON))
LTO_FIXUP_SUBTREE (TREE_CHAIN (t));
}
/* Fix up fields of a decl_minimal T. DATA points to fix-up states. */
static void
lto_fixup_decl_minimal (tree t, void *data)
{
lto_fixup_common (t, data);
LTO_FIXUP_SUBTREE (DECL_NAME (t));
LTO_FIXUP_SUBTREE (DECL_CONTEXT (t));
}
/* Fix up fields of a decl_common T. DATA points to fix-up states. */
static void
lto_fixup_decl_common (tree t, void *data)
{
lto_fixup_decl_minimal (t, data);
LTO_FIXUP_SUBTREE (DECL_SIZE (t));
LTO_FIXUP_SUBTREE (DECL_SIZE_UNIT (t));
LTO_FIXUP_SUBTREE (DECL_INITIAL (t));
LTO_FIXUP_SUBTREE (DECL_ATTRIBUTES (t));
LTO_FIXUP_SUBTREE (DECL_ABSTRACT_ORIGIN (t));
}
/* Fix up fields of a decl_with_vis T. DATA points to fix-up states. */
static void
lto_fixup_decl_with_vis (tree t, void *data)
{
lto_fixup_decl_common (t, data);
/* Accessor macro has side-effects, use field-name here. */
LTO_FIXUP_SUBTREE (t->decl_with_vis.assembler_name);
gcc_assert (no_fixup_p (DECL_SECTION_NAME (t)));
}
/* Fix up fields of a decl_non_common T. DATA points to fix-up states. */
static void
lto_fixup_decl_non_common (tree t, void *data)
{
lto_fixup_decl_with_vis (t, data);
LTO_FIXUP_SUBTREE (DECL_ARGUMENT_FLD (t));
LTO_FIXUP_SUBTREE (DECL_RESULT_FLD (t));
LTO_FIXUP_SUBTREE (DECL_VINDEX (t));
/* SAVED_TREE should not cleared by now. Also no accessor for base type. */
gcc_assert (no_fixup_p (t->decl_non_common.saved_tree));
}
/* Fix up fields of a decl_non_common T. DATA points to fix-up states. */
static void
lto_fixup_function (tree t, void *data)
{
lto_fixup_decl_non_common (t, data);
LTO_FIXUP_SUBTREE (DECL_FUNCTION_PERSONALITY (t));
}
/* Fix up fields of a field_decl T. DATA points to fix-up states. */
static void
lto_fixup_field_decl (tree t, void *data)
{
lto_fixup_decl_common (t, data);
LTO_FIXUP_SUBTREE (DECL_FIELD_OFFSET (t));
LTO_FIXUP_SUBTREE (DECL_BIT_FIELD_TYPE (t));
LTO_FIXUP_SUBTREE (DECL_QUALIFIER (t));
gcc_assert (no_fixup_p (DECL_FIELD_BIT_OFFSET (t)));
LTO_FIXUP_SUBTREE (DECL_FCONTEXT (t));
}
/* Fix up fields of a type T. DATA points to fix-up states. */
static void
lto_fixup_type (tree t, void *data)
{
tree tem, mv;
lto_fixup_common (t, data);
LTO_FIXUP_SUBTREE (TYPE_CACHED_VALUES (t));
LTO_FIXUP_SUBTREE (TYPE_SIZE (t));
LTO_FIXUP_SUBTREE (TYPE_SIZE_UNIT (t));
LTO_FIXUP_SUBTREE (TYPE_ATTRIBUTES (t));
LTO_FIXUP_SUBTREE (TYPE_NAME (t));
/* Accessors are for derived node types only. */
if (!POINTER_TYPE_P (t))
LTO_FIXUP_SUBTREE (t->type.minval);
LTO_FIXUP_SUBTREE (t->type.maxval);
/* Accessor is for derived node types only. */
LTO_FIXUP_SUBTREE (t->type.binfo);
if (TYPE_CONTEXT (t))
{
if (TYPE_P (TYPE_CONTEXT (t)))
LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CONTEXT (t));
else
LTO_FIXUP_SUBTREE (TYPE_CONTEXT (t));
}
/* Compute the canonical type of t and fix that up. From this point
there are no longer any types with TYPE_STRUCTURAL_EQUALITY_P
and its type-based alias problems. */
if (!TYPE_CANONICAL (t))
{
TYPE_CANONICAL (t) = gimple_register_canonical_type (t);
LTO_FIXUP_SUBTREE (TYPE_CANONICAL (t));
}
/* The following re-creates proper variant lists while fixing up
the variant leaders. We do not stream TYPE_NEXT_VARIANT so the
variant list state before fixup is broken. */
/* Remove us from our main variant list if we are not the variant leader. */
if (TYPE_MAIN_VARIANT (t) != t)
{
tem = TYPE_MAIN_VARIANT (t);
while (tem && TYPE_NEXT_VARIANT (tem) != t)
tem = TYPE_NEXT_VARIANT (tem);
if (tem)
TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t);
TYPE_NEXT_VARIANT (t) = NULL_TREE;
}
/* Query our new main variant. */
mv = gimple_register_type (TYPE_MAIN_VARIANT (t));
/* If we were the variant leader and we get replaced ourselves drop
all variants from our list. */
if (TYPE_MAIN_VARIANT (t) == t
&& mv != t)
{
tem = t;
while (tem)
{ {
tree tem2 = TYPE_NEXT_VARIANT (tem); LTO_NO_PREVAIL (DECL_ARGUMENT_FLD (t));
TYPE_NEXT_VARIANT (tem) = NULL_TREE; LTO_NO_PREVAIL (DECL_RESULT_FLD (t));
tem = tem2; LTO_NO_PREVAIL (DECL_VINDEX (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
LTO_SET_PREVAIL (DECL_FUNCTION_PERSONALITY (t));
if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
{
LTO_NO_PREVAIL (DECL_FIELD_OFFSET (t));
LTO_NO_PREVAIL (DECL_BIT_FIELD_TYPE (t));
LTO_NO_PREVAIL (DECL_QUALIFIER (t));
LTO_NO_PREVAIL (DECL_FIELD_BIT_OFFSET (t));
LTO_NO_PREVAIL (DECL_FCONTEXT (t));
} }
} }
else if (TYPE_P (t))
/* If we are not our own variant leader link us into our new leaders
variant list. */
if (mv != t)
{
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (mv);
TYPE_NEXT_VARIANT (mv) = t;
}
/* Finally adjust our main variant and fix it up. */
TYPE_MAIN_VARIANT (t) = mv;
LTO_FIXUP_SUBTREE (TYPE_MAIN_VARIANT (t));
/* As the second step of reconstructing the pointer chains put us
on the list of pointers of the new pointed-to type
if we are a main variant. See lto_fixup_common for the first step. */
if (TREE_CODE (t) == POINTER_TYPE
&& TYPE_MAIN_VARIANT (t) == t)
{
TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (TREE_TYPE (t));
TYPE_POINTER_TO (TREE_TYPE (t)) = t;
}
else if (TREE_CODE (t) == REFERENCE_TYPE
&& TYPE_MAIN_VARIANT (t) == t)
{
TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (TREE_TYPE (t));
TYPE_REFERENCE_TO (TREE_TYPE (t)) = t;
}
}
/* Fix up fields of a BINFO T. DATA points to fix-up states. */
static void
lto_fixup_binfo (tree t, void *data)
{
unsigned HOST_WIDE_INT i, n;
tree base, saved_base;
lto_fixup_common (t, data);
gcc_assert (no_fixup_p (BINFO_OFFSET (t)));
LTO_FIXUP_SUBTREE (BINFO_VTABLE (t));
LTO_FIXUP_SUBTREE (BINFO_VIRTUALS (t));
LTO_FIXUP_SUBTREE (BINFO_VPTR_FIELD (t));
n = VEC_length (tree, BINFO_BASE_ACCESSES (t));
for (i = 0; i < n; i++)
{
saved_base = base = BINFO_BASE_ACCESS (t, i);
LTO_FIXUP_SUBTREE (base);
if (base != saved_base)
VEC_replace (tree, BINFO_BASE_ACCESSES (t), i, base);
}
LTO_FIXUP_SUBTREE (BINFO_INHERITANCE_CHAIN (t));
LTO_FIXUP_SUBTREE (BINFO_SUBVTT_INDEX (t));
LTO_FIXUP_SUBTREE (BINFO_VPTR_INDEX (t));
n = BINFO_N_BASE_BINFOS (t);
for (i = 0; i < n; i++)
{
saved_base = base = BINFO_BASE_BINFO (t, i);
LTO_FIXUP_SUBTREE (base);
if (base != saved_base)
VEC_replace (tree, BINFO_BASE_BINFOS (t), i, base);
}
}
/* Fix up fields of a CONSTRUCTOR T. DATA points to fix-up states. */
static void
lto_fixup_constructor (tree t, void *data)
{
unsigned HOST_WIDE_INT idx;
constructor_elt *ce;
LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
for (idx = 0;
VEC_iterate(constructor_elt, CONSTRUCTOR_ELTS (t), idx, ce);
idx++)
{ {
LTO_FIXUP_SUBTREE (ce->index); LTO_NO_PREVAIL (TYPE_CACHED_VALUES (t));
LTO_FIXUP_SUBTREE (ce->value); LTO_SET_PREVAIL (TYPE_SIZE (t));
} LTO_SET_PREVAIL (TYPE_SIZE_UNIT (t));
} LTO_NO_PREVAIL (TYPE_ATTRIBUTES (t));
LTO_NO_PREVAIL (TYPE_NAME (t));
/* A walk_tree callback used by lto_fixup_state. TP is the pointer to the LTO_SET_PREVAIL (t->type.minval);
current tree. WALK_SUBTREES indicates if the subtrees will be walked. LTO_SET_PREVAIL (t->type.maxval);
DATA is a pointer set to record visited nodes. */ LTO_SET_PREVAIL (t->type.binfo);
static tree LTO_SET_PREVAIL (TYPE_CONTEXT (t));
lto_fixup_tree (tree *tp, int *walk_subtrees, void *data)
{
tree t;
lto_fixup_data_t *fixup_data = (lto_fixup_data_t *) data;
tree prevailing;
t = *tp;
*walk_subtrees = 0;
if (!t || pointer_set_contains (fixup_data->seen, t))
return NULL;
if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL) LTO_NO_PREVAIL (TYPE_CANONICAL (t));
{ LTO_NO_PREVAIL (TYPE_MAIN_VARIANT (t));
prevailing = lto_symtab_prevailing_decl (t); LTO_NO_PREVAIL (TYPE_NEXT_VARIANT (t));
if (t != prevailing)
{
/* Also replace t with prevailing defintion. We don't want to
insert the other defintion in the seen set as we want to
replace all instances of it. */
*tp = prevailing;
t = prevailing;
}
} }
else if (TYPE_P (t)) else if (EXPR_P (t))
{ {
/* Replace t with the prevailing type. We don't want to insert the int i;
other type in the seen set as we want to replace all instances of it. */ LTO_NO_PREVAIL (t->exp.block);
t = gimple_register_type (t); for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
*tp = t; LTO_SET_PREVAIL (TREE_OPERAND (t, i));
} }
else
if (pointer_set_insert (fixup_data->seen, t))
return NULL;
/* walk_tree does not visit all reachable nodes that need to be fixed up.
Hence we do special processing here for those kind of nodes. */
switch (TREE_CODE (t))
{ {
case FIELD_DECL: switch (code)
lto_fixup_field_decl (t, data);
break;
case LABEL_DECL:
case CONST_DECL:
case PARM_DECL:
case RESULT_DECL:
case IMPORTED_DECL:
lto_fixup_decl_common (t, data);
break;
case VAR_DECL:
lto_fixup_decl_with_vis (t, data);
break;
case TYPE_DECL:
lto_fixup_decl_non_common (t, data);
break;
case FUNCTION_DECL:
lto_fixup_function (t, data);
break;
case TREE_BINFO:
lto_fixup_binfo (t, data);
break;
default:
if (TYPE_P (t))
lto_fixup_type (t, data);
else if (TREE_CODE (t) == CONSTRUCTOR)
lto_fixup_constructor (t, data);
else if (CONSTANT_CLASS_P (t))
LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
else if (EXPR_P (t))
{ {
/* walk_tree only handles TREE_OPERANDs. Do the rest here. */ case TREE_LIST:
lto_fixup_common (t, data); LTO_SET_PREVAIL (TREE_VALUE (t));
LTO_FIXUP_SUBTREE (t->exp.block); LTO_SET_PREVAIL (TREE_PURPOSE (t));
*walk_subtrees = 1; break;
} default:
else gcc_unreachable ();
{
/* Let walk_tree handle sub-trees. */
*walk_subtrees = 1;
} }
} }
return NULL;
} }
#undef LTO_SET_PREVAIL
#undef LTO_NO_PREVAIL
/* Helper function of lto_fixup_decls. Walks the var and fn streams in STATE, /* Helper function of lto_fixup_decls. Walks the var and fn streams in STATE,
replaces var and function decls with the corresponding prevailing def and replaces var and function decls with the corresponding prevailing def. */
records the old decl in the free-list in DATA. We also record visted nodes
in the seen-set in DATA to avoid multiple visit for nodes that need not
to be replaced. */
static void static void
lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data) lto_fixup_state (struct lto_in_decl_state *state)
{ {
unsigned i, si; unsigned i, si;
struct lto_tree_ref_table *table; struct lto_tree_ref_table *table;
...@@ -1969,18 +2091,22 @@ lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data) ...@@ -1969,18 +2091,22 @@ lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data)
{ {
table = &state->streams[si]; table = &state->streams[si];
for (i = 0; i < table->size; i++) for (i = 0; i < table->size; i++)
walk_tree (table->trees + i, lto_fixup_tree, data, NULL); {
tree *tp = table->trees + i;
if (VAR_OR_FUNCTION_DECL_P (*tp))
*tp = lto_symtab_prevailing_decl (*tp);
}
} }
} }
/* A callback of htab_traverse. Just extract a state from SLOT and the /* A callback of htab_traverse. Just extracts a state from SLOT
lto_fixup_data_t object from AUX and calls lto_fixup_state. */ and calls lto_fixup_state. */
static int static int
lto_fixup_state_aux (void **slot, void *aux) lto_fixup_state_aux (void **slot, void *aux ATTRIBUTE_UNUSED)
{ {
struct lto_in_decl_state *state = (struct lto_in_decl_state *) *slot; struct lto_in_decl_state *state = (struct lto_in_decl_state *) *slot;
lto_fixup_state (state, (lto_fixup_data_t *) aux); lto_fixup_state (state);
return 1; return 1;
} }
...@@ -1991,29 +2117,20 @@ static void ...@@ -1991,29 +2117,20 @@ static void
lto_fixup_decls (struct lto_file_decl_data **files) lto_fixup_decls (struct lto_file_decl_data **files)
{ {
unsigned int i; unsigned int i;
tree decl; htab_iterator hi;
struct pointer_set_t *seen = pointer_set_create (); tree t;
lto_fixup_data_t data;
FOR_EACH_HTAB_ELEMENT (tree_with_vars, t, tree, hi)
lto_fixup_prevailing_decls (t);
data.seen = seen;
for (i = 0; files[i]; i++) for (i = 0; files[i]; i++)
{ {
struct lto_file_decl_data *file = files[i]; struct lto_file_decl_data *file = files[i];
struct lto_in_decl_state *state = file->global_decl_state; struct lto_in_decl_state *state = file->global_decl_state;
lto_fixup_state (state, &data); lto_fixup_state (state);
htab_traverse (file->function_decl_states, lto_fixup_state_aux, &data);
}
FOR_EACH_VEC_ELT (tree, lto_global_var_decls, i, decl) htab_traverse (file->function_decl_states, lto_fixup_state_aux, NULL);
{
tree saved_decl = decl;
walk_tree (&decl, lto_fixup_tree, &data, NULL);
if (decl != saved_decl)
VEC_replace (tree, lto_global_var_decls, i, decl);
} }
pointer_set_destroy (seen);
} }
/* Read the options saved from each file in the command line. Called /* Read the options saved from each file in the command line. Called
...@@ -2144,6 +2261,9 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) ...@@ -2144,6 +2261,9 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
gcc_assert (num_objects == nfiles); gcc_assert (num_objects == nfiles);
} }
tree_with_vars = htab_create_ggc (101, htab_hash_pointer, htab_eq_pointer,
NULL);
if (!quiet_flag) if (!quiet_flag)
fprintf (stderr, "Reading object files:"); fprintf (stderr, "Reading object files:");
...@@ -2211,6 +2331,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) ...@@ -2211,6 +2331,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
/* Fixup all decls and types and free the type hash tables. */ /* Fixup all decls and types and free the type hash tables. */
lto_fixup_decls (all_file_decl_data); lto_fixup_decls (all_file_decl_data);
htab_delete (tree_with_vars);
tree_with_vars = NULL;
free_gimple_type_tables (); free_gimple_type_tables ();
ggc_collect (); ggc_collect ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment