This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: better wpa [1/n]: merge types during read-in
Hi,
On Wed, 20 Apr 2011, Michael Matz wrote:
> > It would have been nice to have the top-level tree merging as a
> > separate patch, as I am not convinced it is correct, but see below ...
>
> I'll split it out.
Like so (also including the other remarks).
Regstrapping on x86_64-linux in progress.
Ciao,
Michael.
* 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).
Index: lto-streamer.c
===================================================================
*** lto-streamer.c (revision 172769)
--- lto-streamer.c (working copy)
*************** lto_streamer_cache_insert_1 (struct lto_
*** 383,401 ****
{
/* If the caller wants to insert T at a specific slot
location, and ENTRY->TO does not match *IX_P, add T to
! the requested location slot. This situation arises when
! 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;
-
lto_streamer_cache_add_to_node_array (cache, ix, t);
}
--- 383,390 ----
{
/* If the caller wants to insert T at a specific slot
location, and ENTRY->TO does not match *IX_P, add T to
! the requested location slot. */
ix = *ix_p;
lto_streamer_cache_add_to_node_array (cache, ix, t);
}
*************** lto_record_common_node (tree *nodep, VEC
*** 513,518 ****
--- 502,509 ----
TYPE_CANONICAL (node) = NULL_TREE;
node = gimple_register_type (node);
TYPE_CANONICAL (node) = gimple_register_canonical_type (node);
+ if (in_lto_p)
+ TYPE_CANONICAL (*nodep) = TYPE_CANONICAL (node);
*nodep = node;
}
Index: lto/lto.c
===================================================================
*** lto/lto.c (revision 172769)
--- lto/lto.c (working copy)
*************** along with GCC; see the file COPYING3.
*** 24,29 ****
--- 24,30 ----
#include "opts.h"
#include "toplev.h"
#include "tree.h"
+ #include "tree-flow.h"
#include "diagnostic-core.h"
#include "tm.h"
#include "cgraph.h"
*************** lto_read_in_decl_state (struct data_in *
*** 215,228 ****
tree *decls = ggc_alloc_vec_tree (size);
for (j = 0; j < size; j++)
! {
! decls[j] = lto_streamer_cache_get (data_in->reader_cache, data[j]);
!
! /* Register every type in the global type table. If the
! type existed already, use the existing type. */
! if (TYPE_P (decls[j]))
! decls[j] = gimple_register_type (decls[j]);
! }
state->streams[i].size = size;
state->streams[i].trees = decls;
--- 216,222 ----
tree *decls = ggc_alloc_vec_tree (size);
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;
*************** lto_read_in_decl_state (struct data_in *
*** 232,237 ****
--- 226,666 ----
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
+ {
+ 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);
+ }
+ }
+
+ /* If we found a tree that is equal to oldt replace it in the
+ cache, so that further users (in the various LTO sections)
+ make use of it. */
+ lto_streamer_cache_insert_at (cache, t, i);
+ }
+ }
+ }
/* 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
*************** lto_read_decls (struct lto_file_decl_dat
*** 260,267 ****
/* Read the global declarations and types. */
while (ib_main.p < ib_main.len)
{
! tree t = lto_input_tree (&ib_main, data_in);
gcc_assert (t && ib_main.p <= ib_main.len);
}
/* Read in lto_in_decl_state objects. */
--- 689,699 ----
/* Read the global declarations and types. */
while (ib_main.p < ib_main.len)
{
! 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);
+ uniquify_nodes (data_in, from);
}
/* Read in lto_in_decl_state objects. */
*************** lto_wpa_write_files (void)
*** 1514,1520 ****
fprintf (stderr, " %s (%s %i insns)", temp_filename, part->name, part->insns);
if (cgraph_dump_file)
{
! fprintf (cgraph_dump_file, "Writting partition %s to file %s, %i insns\n",
part->name, temp_filename, part->insns);
fprintf (cgraph_dump_file, "cgraph nodes:");
dump_cgraph_node_set (cgraph_dump_file, set);
--- 1946,1952 ----
fprintf (stderr, " %s (%s %i insns)", temp_filename, part->name, part->insns);
if (cgraph_dump_file)
{
! fprintf (cgraph_dump_file, "Writing partition %s to file %s, %i insns\n",
part->name, temp_filename, part->insns);
fprintf (cgraph_dump_file, "cgraph nodes:");
dump_cgraph_node_set (cgraph_dump_file, set);
*************** lto_wpa_write_files (void)
*** 1548,1963 ****
}
! typedef struct {
! struct pointer_set_t *seen;
! } lto_fixup_data_t;
!
! #define LTO_FIXUP_SUBTREE(t) \
! do \
! walk_tree (&(t), lto_fixup_tree, data, NULL); \
! 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. */
!
! static void
! lto_fixup_common (tree t, void *data)
! {
! /* 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
! {
! 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_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);
! TYPE_NEXT_VARIANT (tem) = NULL_TREE;
! tem = tem2;
! }
! }
!
! /* 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_FIXUP_SUBTREE (ce->value);
! }
! }
!
! /* A walk_tree callback used by lto_fixup_state. TP is the pointer to the
! current tree. WALK_SUBTREES indicates if the subtrees will be walked.
! DATA is a pointer set to record visited nodes. */
!
! static tree
! 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)
! {
! prevailing = lto_symtab_prevailing_decl (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))
{
! /* Replace t with the prevailing type. We don't want to insert the
! other type in the seen set as we want to replace all instances of it. */
! t = gimple_register_type (t);
! *tp = t;
}
!
! 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:
! 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. */
! lto_fixup_common (t, data);
! LTO_FIXUP_SUBTREE (t->exp.block);
! *walk_subtrees = 1;
! }
! else
{
! /* Let walk_tree handle sub-trees. */
! *walk_subtrees = 1;
}
}
-
- return NULL;
}
/* 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
! 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
! lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data)
{
unsigned i, si;
struct lto_tree_ref_table *table;
--- 1980,2085 ----
}
! /* If TT is a variable or function decl replace it with its
! prevailing variant. */
! #define LTO_SET_PREVAIL(tt) \
! do {\
! if ((tt) && VAR_OR_FUNCTION_DECL_P (tt)) \
! tt = lto_symtab_prevailing_decl (tt); \
! } while (0)
!
! /* 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
! lto_fixup_prevailing_decls (tree t)
! {
! enum tree_code code = TREE_CODE (t);
! LTO_NO_PREVAIL (TREE_TYPE (t));
! LTO_NO_PREVAIL (TREE_CHAIN (t));
! if (DECL_P (t))
! {
! LTO_NO_PREVAIL (DECL_NAME (t));
! LTO_SET_PREVAIL (DECL_CONTEXT (t));
! if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
! {
! LTO_SET_PREVAIL (DECL_SIZE (t));
! LTO_SET_PREVAIL (DECL_SIZE_UNIT (t));
! LTO_SET_PREVAIL (DECL_INITIAL (t));
! LTO_NO_PREVAIL (DECL_ATTRIBUTES (t));
! LTO_SET_PREVAIL (DECL_ABSTRACT_ORIGIN (t));
! }
! if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
! {
! LTO_NO_PREVAIL (t->decl_with_vis.assembler_name);
! LTO_NO_PREVAIL (DECL_SECTION_NAME (t));
! }
! if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
! {
! LTO_NO_PREVAIL (DECL_ARGUMENT_FLD (t));
! LTO_NO_PREVAIL (DECL_RESULT_FLD (t));
! 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))
{
! LTO_NO_PREVAIL (TYPE_CACHED_VALUES (t));
! 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));
!
! LTO_SET_PREVAIL (t->type.minval);
! LTO_SET_PREVAIL (t->type.maxval);
! LTO_SET_PREVAIL (t->type.binfo);
!
! LTO_SET_PREVAIL (TYPE_CONTEXT (t));
!
! LTO_NO_PREVAIL (TYPE_CANONICAL (t));
! LTO_NO_PREVAIL (TYPE_MAIN_VARIANT (t));
! LTO_NO_PREVAIL (TYPE_NEXT_VARIANT (t));
! }
! else if (EXPR_P (t))
! {
! int i;
! LTO_NO_PREVAIL (t->exp.block);
! for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
! LTO_SET_PREVAIL (TREE_OPERAND (t, i));
}
! else
{
! switch (code)
{
! case TREE_LIST:
! LTO_SET_PREVAIL (TREE_VALUE (t));
! LTO_SET_PREVAIL (TREE_PURPOSE (t));
! break;
! default:
! gcc_unreachable ();
}
}
}
+ #undef LTO_SET_PREVAIL
+ #undef LTO_NO_PREVAIL
/* Helper function of lto_fixup_decls. Walks the var and fn streams in STATE,
! replaces var and function decls with the corresponding prevailing def. */
static void
! lto_fixup_state (struct lto_in_decl_state *state)
{
unsigned i, si;
struct lto_tree_ref_table *table;
*************** lto_fixup_state (struct lto_in_decl_stat
*** 1969,1986 ****
{
table = &state->streams[si];
for (i = 0; i < table->size; i++)
! walk_tree (table->trees + i, lto_fixup_tree, data, NULL);
}
}
! /* A callback of htab_traverse. Just extract a state from SLOT and the
! lto_fixup_data_t object from AUX and calls lto_fixup_state. */
static int
! lto_fixup_state_aux (void **slot, void *aux)
{
struct lto_in_decl_state *state = (struct lto_in_decl_state *) *slot;
! lto_fixup_state (state, (lto_fixup_data_t *) aux);
return 1;
}
--- 2091,2112 ----
{
table = &state->streams[si];
for (i = 0; i < table->size; i++)
! {
! tree *tp = table->trees + i;
! if (VAR_OR_FUNCTION_DECL_P (*tp))
! *tp = lto_symtab_prevailing_decl (*tp);
! }
}
}
! /* A callback of htab_traverse. Just extracts a state from SLOT
! and calls lto_fixup_state. */
static int
! lto_fixup_state_aux (void **slot, void *aux ATTRIBUTE_UNUSED)
{
struct lto_in_decl_state *state = (struct lto_in_decl_state *) *slot;
! lto_fixup_state (state);
return 1;
}
*************** static void
*** 1991,2019 ****
lto_fixup_decls (struct lto_file_decl_data **files)
{
unsigned int i;
! tree decl;
! struct pointer_set_t *seen = pointer_set_create ();
! lto_fixup_data_t data;
- data.seen = seen;
for (i = 0; files[i]; i++)
{
struct lto_file_decl_data *file = files[i];
struct lto_in_decl_state *state = file->global_decl_state;
! lto_fixup_state (state, &data);
!
! htab_traverse (file->function_decl_states, lto_fixup_state_aux, &data);
! }
! FOR_EACH_VEC_ELT (tree, lto_global_var_decls, i, decl)
! {
! 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
--- 2117,2136 ----
lto_fixup_decls (struct lto_file_decl_data **files)
{
unsigned int i;
! htab_iterator hi;
! tree t;
!
! FOR_EACH_HTAB_ELEMENT (tree_with_vars, t, tree, hi)
! lto_fixup_prevailing_decls (t);
for (i = 0; files[i]; i++)
{
struct lto_file_decl_data *file = files[i];
struct lto_in_decl_state *state = file->global_decl_state;
! lto_fixup_state (state);
! htab_traverse (file->function_decl_states, lto_fixup_state_aux, NULL);
}
}
/* Read the options saved from each file in the command line. Called
*************** read_cgraph_and_symbols (unsigned nfiles
*** 2144,2149 ****
--- 2261,2269 ----
gcc_assert (num_objects == nfiles);
}
+ tree_with_vars = htab_create_ggc (101, htab_hash_pointer, htab_eq_pointer,
+ NULL);
+
if (!quiet_flag)
fprintf (stderr, "Reading object files:");
*************** read_cgraph_and_symbols (unsigned nfiles
*** 2211,2216 ****
--- 2331,2338 ----
/* Fixup all decls and types and free the type hash tables. */
lto_fixup_decls (all_file_decl_data);
+ htab_delete (tree_with_vars);
+ tree_with_vars = NULL;
free_gimple_type_tables ();
ggc_collect ();
Index: lto/Make-lang.in
===================================================================
*** lto/Make-lang.in (revision 172769)
--- lto/Make-lang.in (working copy)
*************** lto/lto-lang.o: lto/lto-lang.c $(CONFIG_
*** 81,87 ****
$(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \
$(EXPR_H) $(LTO_STREAMER_H)
lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
! toplev.h $(TREE_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \
$(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_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) \
--- 81,87 ----
$(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \
$(EXPR_H) $(LTO_STREAMER_H)
lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
! toplev.h $(TREE_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(TM_H) \
$(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_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) \