From: Michael Matz Date: Fri, 29 Apr 2011 12:27:26 +0000 (+0000) Subject: lto-streamer.c (lto_streamer_cache_insert_1): Accept to override other trees that... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b823cdfe763c9784a8e9f7b86b8e91614c29de6c;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 13f36591d26..6f7430c1483 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2011-04-29 Michael Matz + + * 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 * tree-nested.c (get_trampoline_type): Use size_int. diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c index 74034b07485..80927927dcc 100644 --- a/gcc/lto-streamer.c +++ b/gcc/lto-streamer.c @@ -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 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)); + the requested location slot. */ ix = *ix_p; - 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, 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; } diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 507e9b22fd7..be3a873736a 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,31 @@ +2011-04-29 Michael Matz + + * 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 * lto.c (lto_balanced_map): Fix typos in head comment. diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in index 5287c127088..6b6930f25d9 100644 --- a/gcc/lto/Make-lang.in +++ b/gcc/lto/Make-lang.in @@ -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 \ $(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) \ + 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) \ diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 8215c02ca5b..d8e69c57e80 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "opts.h" #include "toplev.h" #include "tree.h" +#include "tree-flow.h" #include "diagnostic-core.h" #include "tm.h" #include "cgraph.h" @@ -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); 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). */ @@ -260,8 +689,11 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data, /* 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. */ @@ -1514,7 +1946,7 @@ lto_wpa_write_files (void) 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); @@ -1548,416 +1980,106 @@ lto_wpa_write_files (void) } -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; @@ -1969,18 +2091,22 @@ lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data) { 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; } @@ -1991,29 +2117,20 @@ static void 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 @@ -2144,6 +2261,9 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) 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:"); @@ -2211,6 +2331,8 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) /* 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 ();