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