#include "opts.h"
#include "toplev.h"
#include "tree.h"
+#include "tree-flow.h"
#include "diagnostic-core.h"
#include "tm.h"
#include "cgraph.h"
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;
+ 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
- type existed already, use the existing type. */
- if (TYPE_P (decls[j]))
- decls[j] = gimple_register_type (decls[j]);
+ /* 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);
}
-
- 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.
RESOLUTIONS is the set of symbols picked by the linker (read from the
resolution file when the linker plugin is being used). */
/* Read the global declarations and types. */
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);
+ uniquify_nodes (data_in, from);
}
/* Read in lto_in_decl_state objects. */
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",
+ 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);
}
-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);
-}
+/* 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)
-/* 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
-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
- 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)
+ enum tree_code code = TREE_CODE (t);
+ LTO_NO_PREVAIL (TREE_TYPE (t));
+ LTO_NO_PREVAIL (TREE_CHAIN (t));
+ if (DECL_P (t))
{
- if (TYPE_POINTER_TO (TREE_TYPE (t)) == t)
- TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t);
- else
+ LTO_NO_PREVAIL (DECL_NAME (t));
+ LTO_SET_PREVAIL (DECL_CONTEXT (t));
+ if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
{
- 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);
+ 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));
}
- 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
+ if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
{
- 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);
+ LTO_NO_PREVAIL (t->decl_with_vis.assembler_name);
+ LTO_NO_PREVAIL (DECL_SECTION_NAME (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)
+ if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
{
- tree tem2 = TYPE_NEXT_VARIANT (tem);
- TYPE_NEXT_VARIANT (tem) = NULL_TREE;
- tem = tem2;
+ 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));
}
}
-
- /* 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++)
+ else if (TYPE_P (t))
{
- LTO_FIXUP_SUBTREE (ce->index);
- LTO_FIXUP_SUBTREE (ce->value);
- }
-}
+ 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));
-/* 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. */
+ LTO_SET_PREVAIL (t->type.minval);
+ LTO_SET_PREVAIL (t->type.maxval);
+ LTO_SET_PREVAIL (t->type.binfo);
-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;
+ LTO_SET_PREVAIL (TYPE_CONTEXT (t));
- 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;
- }
+ LTO_NO_PREVAIL (TYPE_CANONICAL (t));
+ LTO_NO_PREVAIL (TYPE_MAIN_VARIANT (t));
+ LTO_NO_PREVAIL (TYPE_NEXT_VARIANT (t));
}
- else if (TYPE_P (t))
+ else if (EXPR_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;
+ 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));
}
-
- 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))
+ else
{
- 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))
+ switch (code)
{
- /* 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;
+ case TREE_LIST:
+ LTO_SET_PREVAIL (TREE_VALUE (t));
+ LTO_SET_PREVAIL (TREE_PURPOSE (t));
+ break;
+ default:
+ gcc_unreachable ();
}
}
-
- return NULL;
}
+#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 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. */
+ replaces var and function decls with the corresponding prevailing def. */
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;
struct lto_tree_ref_table *table;
{
table = &state->streams[si];
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
- lto_fixup_data_t object from AUX and calls lto_fixup_state. */
+/* 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)
+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, (lto_fixup_data_t *) aux);
+ lto_fixup_state (state);
return 1;
}
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;
+ htab_iterator hi;
+ tree t;
+
+ FOR_EACH_HTAB_ELEMENT (tree_with_vars, t, tree, hi)
+ lto_fixup_prevailing_decls (t);
- 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);
- }
+ lto_fixup_state (state);
- 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);
+ htab_traverse (file->function_decl_states, lto_fixup_state_aux, NULL);
}
-
- pointer_set_destroy (seen);
}
/* Read the options saved from each file in the command line. Called
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:");
/* 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 ();