diff options
author | Richard Guenther <rguenther@suse.de> | 2009-08-13 15:44:01 +0000 |
---|---|---|
committer | Richard Guenther <rguenther@suse.de> | 2009-08-13 15:44:01 +0000 |
commit | 7c02b343e59d54c6ebadba7f366970fa2639821d (patch) | |
tree | 737825de91722d8c814370649fe168ea50ea0217 | |
parent | f1f6d5b60f0d4fe7e620a5f03d89610be254f163 (diff) |
2009-08-13 Richard Guenther <rguenther@suse.de>
PR lto/41032
* tree.c (free_lang_data): NULL the types_compatible_p langhook.
* gimple.c (gtc_visited): Global type compatibility hashtable.
(compare_field_offset): New helper function.
(gimple_compare_types): Fold into ...
(gimple_types_compatible_p): ... here. Types with differing
hash values are not compatible. Adjust function now that it
is no longer used as types_compatible_p langhook. Complete
incomplete pointer targets.
(iterative_hash_type_name): New helper function.
(iterative_hash_gimple_type): Do not hash type sizes. Do not
recurse into aggregate pointer targets. Properly hash
complex and vector types. Hash the name of record types.
(print_gimple_types_stats): Print stats of gtc_visited.
* lto-symtab.c (lto_merge_qualifiers): Remove.
(lto_merge_types): Likewise.
(merge_incomplete_and_complete_type): New helper function.
(maybe_merge_incomplete_and_complete_type): Likewise.
(lto_symtab_compatible): Remove do_warn arg. Complete types
during decl merging. Forcefully merge more types than
elsewhere. Do not compare DECL_MODE.
(lto_symtab_prevailing_decl): Use gimple_types_compatible_p, not
lto_symtab_compatible for finding the decl we merged with.
lto/
* lto-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Define to NULL.
* gcc.dg/lto/20090812_0.c: New testcase.
* gcc.dg/lto/20090812_1.c: Likewise.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/lto@150719 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog.lto | 26 | ||||
-rw-r--r-- | gcc/gimple.c | 235 | ||||
-rw-r--r-- | gcc/lto-symtab.c | 224 | ||||
-rw-r--r-- | gcc/lto/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/lto/lto-lang.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog.lto | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/lto/20090812_0.c | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/lto/20090812_1.c | 26 | ||||
-rw-r--r-- | gcc/tree.c | 2 |
9 files changed, 345 insertions, 192 deletions
diff --git a/gcc/ChangeLog.lto b/gcc/ChangeLog.lto index 6ca439146bb..cd23144aa6b 100644 --- a/gcc/ChangeLog.lto +++ b/gcc/ChangeLog.lto @@ -1,3 +1,29 @@ +2009-08-13 Richard Guenther <rguenther@suse.de> + + PR lto/41032 + * tree.c (free_lang_data): NULL the types_compatible_p langhook. + * gimple.c (gtc_visited): Global type compatibility hashtable. + (compare_field_offset): New helper function. + (gimple_compare_types): Fold into ... + (gimple_types_compatible_p): ... here. Types with differing + hash values are not compatible. Adjust function now that it + is no longer used as types_compatible_p langhook. Complete + incomplete pointer targets. + (iterative_hash_type_name): New helper function. + (iterative_hash_gimple_type): Do not hash type sizes. Do not + recurse into aggregate pointer targets. Properly hash + complex and vector types. Hash the name of record types. + (print_gimple_types_stats): Print stats of gtc_visited. + * lto-symtab.c (lto_merge_qualifiers): Remove. + (lto_merge_types): Likewise. + (merge_incomplete_and_complete_type): New helper function. + (maybe_merge_incomplete_and_complete_type): Likewise. + (lto_symtab_compatible): Remove do_warn arg. Complete types + during decl merging. Forcefully merge more types than + elsewhere. Do not compare DECL_MODE. + (lto_symtab_prevailing_decl): Use gimple_types_compatible_p, not + lto_symtab_compatible for finding the decl we merged with. + 2009-08-12 Richard Guenther <rguenther@suse.de> Mainline merge @150705. diff --git a/gcc/gimple.c b/gcc/gimple.c index 4113ea6ce9e..e242134da07 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -43,6 +43,9 @@ along with GCC; see the file COPYING3. If not see static htab_t gimple_types; static struct pointer_map_t *type_hash_cache; +/* Global type comparison cache. */ +static htab_t gtc_visited; + #define DEFGSCODE(SYM, NAME, STRUCT) NAME, const char *const gimple_code_name[] = { #include "gimple.def" @@ -3081,7 +3084,7 @@ gimple_call_copy_skip_args (gimple stmt, bitmap args_to_skip) /* Structure used to maintain a cache of some type pairs compared by - gimple_compare_types when comparing aggregate types. There are + gimple_types_compatible_p when comparing aggregate types. There are four possible values for SAME_P: -2: The pair (T1, T2) has just been inserted in the table. @@ -3199,14 +3202,46 @@ compare_type_names_p (tree t1, tree t2) return false; } -/* Recursive helper for gimple_types_compatible_p. Return 1 iff T1 - and T2 are structurally identical. Otherwise, return 0. - VISITED_P points to a hash table of type pairs that have been - visited while comparing aggregate types. This prevents infinite - recursion when comparing aggregates with self-referential fields. */ +/* Return true if the field decls F1 and F2 are at the same offset. */ -static int -gimple_compare_types (tree t1, tree t2, htab_t *visited_p) +static bool +compare_field_offset (tree f1, tree f2) +{ + if (DECL_OFFSET_ALIGN (f1) == DECL_OFFSET_ALIGN (f2)) + return (operand_equal_p (DECL_FIELD_OFFSET (f1), + DECL_FIELD_OFFSET (f2), 0) + && tree_int_cst_equal (DECL_FIELD_BIT_OFFSET (f1), + DECL_FIELD_BIT_OFFSET (f2))); + + /* Fortran and C do not always agree on what DECL_OFFSET_ALIGN + should be, so handle differing ones specially by decomposing + the offset into a byte and bit offset manually. */ + if (host_integerp (DECL_FIELD_OFFSET (f1), 0) + && host_integerp (DECL_FIELD_OFFSET (f2), 0)) + { + unsigned HOST_WIDE_INT byte_offset1, byte_offset2; + unsigned HOST_WIDE_INT bit_offset1, bit_offset2; + bit_offset1 = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (f1)); + byte_offset1 = (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (f1)) + + bit_offset1 / BITS_PER_UNIT); + bit_offset2 = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (f2)); + byte_offset2 = (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (f2)) + + bit_offset2 / BITS_PER_UNIT); + if (byte_offset1 != byte_offset2) + return false; + return bit_offset1 % BITS_PER_UNIT == bit_offset2 % BITS_PER_UNIT; + } + + return false; +} + +static hashval_t gimple_type_hash (const void *); + +/* Return 1 iff T1 and T2 are structurally identical. + Otherwise, return 0. */ + +int +gimple_types_compatible_p (tree t1, tree t2) { type_pair_t p = NULL; @@ -3230,9 +3265,15 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) goto different_types; + /* If the hash values of t1 and t2 are different the types can't + possibly be the same. This helps keeping the type-pair hashtable + small, only tracking comparisons for hash collisions. */ + if (gimple_type_hash (t1) != gimple_type_hash (t2)) + return 0; + /* If we've visited this type pair before (in the case of aggregates - with self-referntial types), and we made a decision, return it. */ - p = lookup_type_pair (t1, t2, visited_p); + with self-referential types), and we made a decision, return it. */ + p = lookup_type_pair (t1, t2, >c_visited); if (p->same_p == 0 || p->same_p == 1) { /* We have already decided whether T1 and T2 are the @@ -3248,13 +3289,13 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) gcc_assert (p->same_p == -2); + /* Mark the (T1, T2) comparison in progress. */ + p->same_p = -1; + /* If their attributes are not the same they can't be the same type. */ if (!attribute_list_equal (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2))) goto different_types; - if (!targetm.comp_type_attributes (t1, t2)) - goto different_types; - /* For numerical types, the bounds must coincide. */ if (INTEGRAL_TYPE_P (t1) || SCALAR_FLOAT_TYPE_P (t1) @@ -3326,7 +3367,7 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) case ARRAY_TYPE: /* Array types are the same if the element types are the same and the number of elements are the same. */ - if (!gimple_compare_types (TREE_TYPE (t1), TREE_TYPE (t2), visited_p) + if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)) || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)) goto different_types; else @@ -3340,37 +3381,25 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) goto same_types; else if (i1 == NULL_TREE || i2 == NULL_TREE) goto different_types; + /* If for a complete array type the possibly gimplified sizes + are different the types are different. */ + else if (((TYPE_SIZE (i1) != NULL) ^ (TYPE_SIZE (i2) != NULL)) + || (TYPE_SIZE (i1) + && TYPE_SIZE (i2) + && !operand_equal_p (TYPE_SIZE (i1), TYPE_SIZE (i2), 0))) + goto different_types; else { tree min1 = TYPE_MIN_VALUE (i1); tree min2 = TYPE_MIN_VALUE (i2); tree max1 = TYPE_MAX_VALUE (i1); tree max2 = TYPE_MAX_VALUE (i2); - bool min_equal_p = false; - bool max_equal_p = false; - - /* For variable-sized arrays, use the same notion as in the C - front end. If either domain is variable, consider the types - compatible. */ - if (min1 == NULL_TREE && min2 == NULL_TREE) - min_equal_p = true; - else if (min1 && TREE_CODE (min1) != INTEGER_CST) - min_equal_p = true; - else if (min2 && TREE_CODE (min2) != INTEGER_CST) - min_equal_p = true; - else if (min1 && min2 && operand_equal_p (min1, min2, 0)) - min_equal_p = true; - - if (max1 == NULL_TREE && max2 == NULL_TREE) - max_equal_p = true; - else if (max1 && TREE_CODE (max1) != INTEGER_CST) - max_equal_p = true; - else if (max2 && TREE_CODE (max2) != INTEGER_CST) - max_equal_p = true; - else if (max1 && max2 && operand_equal_p (max1, max2, 0)) - max_equal_p = true; - - if (min_equal_p && max_equal_p) + + /* The minimum/maximum values have to be the same. */ + if ((min1 == min2 + || (min1 && min2 && operand_equal_p (min1, min2, 0))) + && (max1 == max2 + || (max1 && max2 && operand_equal_p (max1, max2, 0)))) goto same_types; else goto different_types; @@ -3379,9 +3408,8 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) case METHOD_TYPE: /* Method types should belong to the same class. */ - if (!gimple_compare_types (TYPE_METHOD_BASETYPE (t1), - TYPE_METHOD_BASETYPE (t2), - visited_p)) + if (!gimple_types_compatible_p (TYPE_METHOD_BASETYPE (t1), + TYPE_METHOD_BASETYPE (t2))) goto different_types; /* Fallthru */ @@ -3389,10 +3417,13 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) case FUNCTION_TYPE: /* Function types are the same if the return type and arguments types are the same. */ - if (!gimple_compare_types (TREE_TYPE (t1), TREE_TYPE (t2), visited_p)) + if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) goto different_types; else { + if (!targetm.comp_type_attributes (t1, t2)) + goto different_types; + if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)) goto same_types; else @@ -3403,9 +3434,8 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) parms1 && parms2; parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2)) { - if (!gimple_compare_types (TREE_VALUE (parms1), - TREE_VALUE (parms2), - visited_p)) + if (!gimple_types_compatible_p (TREE_VALUE (parms1), + TREE_VALUE (parms2))) goto different_types; } @@ -3424,9 +3454,24 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) if (TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)) goto different_types; + /* If one pointer points to an incomplete type variant of + the other pointed-to type they are the same. */ + if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)) + && (!COMPLETE_TYPE_P (TREE_TYPE (t1)) + || !COMPLETE_TYPE_P (TREE_TYPE (t2))) + && compare_type_names_p (TREE_TYPE (t1), TREE_TYPE (t2))) + { + /* If t2 is complete we want to choose it instead of t1. + There's no other way than copying t2 to t1 in this case. + Yuck. We'll just call this "completing" t1. */ + if (COMPLETE_TYPE_P (TREE_TYPE (t2))) + memcpy (t1, t2, tree_size (t1)); + goto same_types; + } + /* Otherwise, pointer and reference types are the same if the pointed-to types are the same. */ - if (gimple_compare_types (TREE_TYPE (t1), TREE_TYPE (t2), visited_p)) + if (gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) goto same_types; goto different_types; @@ -3472,27 +3517,16 @@ gimple_compare_types (tree t1, tree t2, htab_t *visited_p) /* For aggregate types, all the fields must be the same. */ tree f1, f2; - /* Mark the (T1, T2) comparison in progress. */ - p->same_p = -1; - - /* If either structure is empty, they should at least have - the same name. */ - if ((!TYPE_SIZE (t1) || !TYPE_SIZE (t2)) - && compare_type_names_p (t1, t2)) - goto same_types; - - /* Otherwise, compare every field. */ + /* Compare every field. */ for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2); f1 && f2; f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2)) { /* The fields must have the same name, offset and type. */ if (DECL_NAME (f1) != DECL_NAME (f2) - || !tree_int_cst_equal (DECL_FIELD_OFFSET (f1), - DECL_FIELD_OFFSET (f2)) - || !gimple_compare_types (TREE_TYPE (f1), - TREE_TYPE (f2), - visited_p)) + || !compare_field_offset (f1, f2) + || !gimple_types_compatible_p (TREE_TYPE (f1), + TREE_TYPE (f2))) goto different_types; } @@ -3522,22 +3556,6 @@ same_types: } -/* Return 1 iff T1 and T2 are structurally identical. Otherwise, - return 0. */ - -int -gimple_types_compatible_p (tree t1, tree t2) -{ - int same_p; - htab_t visited = NULL; - - same_p = gimple_compare_types (t1, t2, &visited); - - if (visited) - htab_delete (visited); - - return same_p; -} /* Per pointer state for the SCC finding. The on_sccstack flag @@ -3627,6 +3645,22 @@ visit (tree t, struct sccs *state, hashval_t v, return v; } +/* Hash the name of TYPE with the previous hash value V and return it. */ + +static hashval_t +iterative_hash_type_name (tree type, hashval_t v) +{ + tree name = TYPE_NAME (TYPE_MAIN_VARIANT (type)); + if (!name) + return v; + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + if (!name) + return v; + gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + return iterative_hash_object (IDENTIFIER_HASH_VALUE (name), v); +} + /* Returning a hash value for gimple type TYPE combined with VAL. SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. @@ -3668,10 +3702,11 @@ iterative_hash_gimple_type (tree type, hashval_t val, checked. */ v = iterative_hash_hashval_t (TREE_CODE (type), 0); v = iterative_hash_hashval_t (TYPE_QUALS (type), v); - v = iterative_hash_expr (TYPE_SIZE (type), v); - v = iterative_hash_expr (TYPE_SIZE_UNIT (type), v); v = iterative_hash_hashval_t (TREE_ADDRESSABLE (type), v); + /* Do not hash the types size as this will cause differences in + hash values for the complete vs. the incomplete type variant. */ + /* Incorporate common features of numerical types. */ if (INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type) @@ -3682,6 +3717,28 @@ iterative_hash_gimple_type (tree type, hashval_t val, v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); } + /* For pointer and reference types, fold in information about the type + pointed to but do not recurse into possibly incomplete types to + avoid hash differences for complete vs. incomplete types. */ + if (POINTER_TYPE_P (type)) + { + if (AGGREGATE_TYPE_P (TREE_TYPE (type))) + { + v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); + v = iterative_hash_type_name (type, v); + } + else + v = visit (TREE_TYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + } + + /* Recurse for aggregates with a single element. */ + if (TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == COMPLEX_TYPE + || TREE_CODE (type) == VECTOR_TYPE) + v = visit (TREE_TYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + /* Incorporate function return and argument types. */ if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) { @@ -3706,12 +3763,6 @@ iterative_hash_gimple_type (tree type, hashval_t val, v = iterative_hash_hashval_t (na, v); } - /* For pointer and reference types, fold in information about the type - pointed to. */ - if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) - v = visit (TREE_TYPE (type), state, v, - sccstack, sccstate, sccstate_obstack); - if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == QUAL_UNION_TYPE) @@ -3719,6 +3770,8 @@ iterative_hash_gimple_type (tree type, hashval_t val, unsigned nf; tree f; + v = iterative_hash_type_name (type, v); + for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f)) { v = visit (TREE_TYPE (f), state, v, @@ -3866,6 +3919,16 @@ print_gimple_types_stats (void) htab_collisions (gimple_types)); else fprintf (stderr, "GIMPLE type table is empty\n"); + if (gtc_visited) + fprintf (stderr, "GIMPLE type comparison table: size %ld, %ld elements, " + "%ld searches, %ld collisions (ratio: %f)\n", + (long) htab_size (gtc_visited), + (long) htab_elements (gtc_visited), + (long) gtc_visited->searches, + (long) gtc_visited->collisions, + htab_collisions (gtc_visited)); + else + fprintf (stderr, "GIMPLE type comparison table is empty\n"); } diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c index 7a41a90021e..5d254a3fd5e 100644 --- a/gcc/lto-symtab.c +++ b/gcc/lto-symtab.c @@ -143,60 +143,6 @@ lto_symtab_maybe_init_hash_tables (void) } } -/* Transfer qualifiers between TYPE_1 and TYPE_2 so that qualifiers - for both types are conservatively correct with respect to - optimization done before the merge. */ - -static void -lto_merge_qualifiers (tree type_1, tree type_2) -{ - /* If one is volatile, the other should also be. */ - if (TYPE_VOLATILE (type_2)) - TYPE_VOLATILE (type_1) = 1; - else if (TYPE_VOLATILE (type_1)) - TYPE_VOLATILE (type_2) = 1; - - /* If one type is writable, the other should also be. */ - if (!TYPE_READONLY (type_2)) - TYPE_READONLY (type_1) = 0; - else if (!TYPE_READONLY (type_1)) - TYPE_READONLY (type_2) = 0; - - /* If one type does not have the restrict qualifier, the other - should not have it either. */ - if (!TYPE_RESTRICT (type_2)) - TYPE_RESTRICT (type_1) = 0; - else if (!TYPE_RESTRICT (type_1)) - TYPE_RESTRICT (type_2) = 0; -} - -/* If TYPE_1 and TYPE_2 can be merged to form a common type, do it. - Specifically, if they are both array types that have the same element - type and one of them is a complete array type and the other isn't, - return the complete array type. Otherwise return NULL_TREE. */ - -static tree -lto_merge_types (tree type_1, tree type_2) -{ - if (TREE_CODE (type_1) == ARRAY_TYPE - && TREE_CODE (type_2) == ARRAY_TYPE - && !TYPE_ATTRIBUTES (type_1) - && !TYPE_ATTRIBUTES (type_2) - && gimple_types_compatible_p (TREE_TYPE (type_1), TREE_TYPE (type_2))) - { - lto_merge_qualifiers (type_1, type_2); - - if (COMPLETE_TYPE_P (type_1) && !COMPLETE_TYPE_P (type_2)) - return type_1; - else if (COMPLETE_TYPE_P (type_2) && !COMPLETE_TYPE_P (type_1)) - return type_2; - else - return type_1; - } - - return NULL_TREE; -} - /* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be applied to DECL. */ static bool @@ -226,13 +172,63 @@ external_aggregate_decl_p (tree decl) && AGGREGATE_TYPE_P (TREE_TYPE (decl))); } +static bool maybe_merge_incomplete_and_complete_type (tree, tree); + +/* Try to merge an incomplete type INCOMPLETE with a complete type + COMPLETE of same kinds. + Return true if they were merged, false otherwise. */ + +static bool +merge_incomplete_and_complete_type (tree incomplete, tree complete) +{ + /* For merging array types do some extra sanity checking. */ + if (TREE_CODE (incomplete) == ARRAY_TYPE + && !maybe_merge_incomplete_and_complete_type (TREE_TYPE (incomplete), + TREE_TYPE (complete)) + && !gimple_types_compatible_p (TREE_TYPE (incomplete), + TREE_TYPE (complete))) + return false; + + /* ??? Ideally we would do this by means of a common canonical type, but + that's difficult as we do not have links from the canonical type + back to all its children. */ + memcpy (incomplete, complete, tree_size (incomplete)); + + return true; +} + +/* Try to merge a maybe complete / incomplete type pair TYPE1 and TYPE2. + Return true if they were merged, false otherwise. */ + +static bool +maybe_merge_incomplete_and_complete_type (tree type1, tree type2) +{ + bool res = false; + + if (TREE_CODE (type1) != TREE_CODE (type2)) + return false; + + if (!COMPLETE_TYPE_P (type1) && COMPLETE_TYPE_P (type2)) + res = merge_incomplete_and_complete_type (type1, type2); + else if (COMPLETE_TYPE_P (type1) && !COMPLETE_TYPE_P (type2)) + res = merge_incomplete_and_complete_type (type2, type1); + + /* Recurse on pointer targets. */ + if (!res + && POINTER_TYPE_P (type1) + && POINTER_TYPE_P (type2)) + res = maybe_merge_incomplete_and_complete_type (TREE_TYPE (type1), + TREE_TYPE (type2)); + + return res; +} + /* Check if OLD_DECL and NEW_DECL are compatible. */ static bool -lto_symtab_compatible (tree old_decl, tree new_decl, bool do_warn) +lto_symtab_compatible (tree old_decl, tree new_decl) { tree merged_type = NULL_TREE; - tree merged_result = NULL_TREE; if (TREE_CODE (old_decl) != TREE_CODE (new_decl)) { @@ -259,16 +255,68 @@ lto_symtab_compatible (tree old_decl, tree new_decl, bool do_warn) } } + /* Handle external declarations with incomplete type or pointed-to + incomplete types by forcefully merging the types. + ??? In principle all types involved in the two decls should + be merged forcefully, for example without considering type or + field names. */ + if (TREE_CODE (old_decl) == VAR_DECL) + { + tree old_type = TREE_TYPE (old_decl); + tree new_type = TREE_TYPE (new_decl); + + if (DECL_EXTERNAL (old_decl) || DECL_EXTERNAL (new_decl)) + maybe_merge_incomplete_and_complete_type (old_type, new_type); + else if (POINTER_TYPE_P (old_type) + && POINTER_TYPE_P (new_type)) + maybe_merge_incomplete_and_complete_type (TREE_TYPE (old_type), + TREE_TYPE (new_type)); + + /* For array types we have to accept external declarations with + different sizes than the actual definition (164.gzip). + ??? We could emit a warning here. */ + if (TREE_CODE (old_type) == TREE_CODE (new_type) + && TREE_CODE (old_type) == ARRAY_TYPE + && COMPLETE_TYPE_P (old_type) + && COMPLETE_TYPE_P (new_type) + && tree_int_cst_compare (TYPE_SIZE (old_type), + TYPE_SIZE (new_type)) != 0 + && gimple_types_compatible_p (TREE_TYPE (old_type), + TREE_TYPE (new_type))) + { + /* If only one is external use the type of the non-external decl. + Else use the larger one and also adjust the decl size. + ??? Directional merging would allow us to simply pick the + larger one instead of rewriting it. */ + if (DECL_EXTERNAL (old_decl) ^ DECL_EXTERNAL (new_decl)) + { + if (DECL_EXTERNAL (old_decl)) + TREE_TYPE (old_decl) = new_type; + else if (DECL_EXTERNAL (new_decl)) + TREE_TYPE (new_decl) = old_type; + } + else + { + if (tree_int_cst_compare (TYPE_SIZE (old_type), + TYPE_SIZE (new_type)) < 0) + { + TREE_TYPE (old_type) = new_type; + DECL_SIZE (old_decl) = DECL_SIZE (new_decl); + DECL_SIZE_UNIT (old_decl) = DECL_SIZE_UNIT (new_decl); + } + else + { + TREE_TYPE (new_type) = old_type; + DECL_SIZE (new_decl) = DECL_SIZE (old_decl); + DECL_SIZE_UNIT (new_decl) = DECL_SIZE_UNIT (old_decl); + } + } + } + } + if (!gimple_types_compatible_p (TREE_TYPE (old_decl), TREE_TYPE (new_decl))) { - /* Allow an array type with unspecified bounds to - be merged with an array type whose bounds are specified, so - as to allow "extern int i[];" in one file to be combined with - "int i[3];" in another. */ - if (TREE_CODE (new_decl) == VAR_DECL) - merged_type = lto_merge_types (TREE_TYPE (old_decl), - TREE_TYPE (new_decl)); - else if (TREE_CODE (new_decl) == FUNCTION_DECL) + if (TREE_CODE (new_decl) == FUNCTION_DECL) { if (!merged_type /* We want either of the types to have argument types, @@ -289,12 +337,10 @@ lto_symtab_compatible (tree old_decl, tree new_decl, bool do_warn) if (TYPE_ARG_TYPES (TREE_TYPE (old_decl))) { merged_type = TREE_TYPE (old_decl); - merged_result = DECL_RESULT (old_decl); } else { merged_type = TREE_TYPE (new_decl); - merged_result = DECL_RESULT (new_decl); } } @@ -309,26 +355,21 @@ lto_symtab_compatible (tree old_decl, tree new_decl, bool do_warn) if (!DECL_EXTERNAL (new_decl)) { merged_type = TREE_TYPE (new_decl); - merged_result = DECL_RESULT (new_decl); } else { merged_type = TREE_TYPE (old_decl); - merged_result = DECL_RESULT (old_decl); } } } if (!merged_type) { - if (do_warn) - { - warning_at (DECL_SOURCE_LOCATION (new_decl), 0, + if (warning_at (DECL_SOURCE_LOCATION (new_decl), 0, "type of %qD does not match original declaration", - new_decl); - inform (DECL_SOURCE_LOCATION (old_decl), - "previously declared here"); - } + new_decl)) + inform (DECL_SOURCE_LOCATION (old_decl), + "previously declared here"); return false; } } @@ -390,33 +431,8 @@ lto_symtab_compatible (tree old_decl, tree new_decl, bool do_warn) return false; } - if (DECL_MODE (old_decl) != DECL_MODE (new_decl)) - { - /* We can arrive here when we are merging 'extern char foo[]' and - 'char foo[SMALLNUM]'; the former is probably BLKmode and the - latter is not. In such a case, we should have merged the types - already; detect it and don't complain. We also need to handle - external aggregate declaration specially. */ - if ((TREE_CODE (TREE_TYPE (old_decl)) - == TREE_CODE (TREE_TYPE (new_decl))) - && (((TREE_CODE (TREE_TYPE (old_decl)) != ARRAY_TYPE) - && ((external_aggregate_decl_p (old_decl) - && DECL_MODE (old_decl) == VOIDmode) - || (external_aggregate_decl_p (new_decl) - && DECL_MODE (new_decl) == VOIDmode))) - || ((TREE_CODE (TREE_TYPE (old_decl)) == ARRAY_TYPE) - && merged_type))) - ; - else - { - error_at (DECL_SOURCE_LOCATION (new_decl), - "machine mode of %qD does not match original declaration", - new_decl); - inform (DECL_SOURCE_LOCATION (old_decl), - "previously declared here"); - return false; - } - } + /* Do not compare the modes of the decls. The type compatibility + checks or the completing of types has properly dealt with all issues. */ if (!lto_compatible_attributes_p (old_decl, DECL_ATTRIBUTES (old_decl), @@ -594,7 +610,7 @@ lto_symtab_merge_decl (tree new_decl, Find a decl we can merge with or chain it in the list of decls for that symbol. */ while (old_decl - && !lto_symtab_compatible (old_decl, new_decl, true)) + && !lto_symtab_compatible (old_decl, new_decl)) old_decl = TREE_CHAIN (old_decl); if (!old_decl) { @@ -702,7 +718,7 @@ lto_symtab_prevailing_decl (tree decl) with and return that. */ while (ret) { - if (lto_symtab_compatible (decl, ret, false)) + if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret))) return ret; ret = TREE_CHAIN (ret); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 9c5cc4aa73d..a523d581935 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,8 @@ +2009-08-13 Richard Guenther <rguenther@suse.de> + + PR lto/41032 + * lto-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Define to NULL. + 2009-07-30 Richard Guenther <rguenther@suse.de> PR lto/40903 diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 7c01c4bde44..671bace8478 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -1209,7 +1209,7 @@ static void lto_init_ts (void) #undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS #define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true #undef LANG_HOOKS_TYPES_COMPATIBLE_P -#define LANG_HOOKS_TYPES_COMPATIBLE_P gimple_types_compatible_p +#define LANG_HOOKS_TYPES_COMPATIBLE_P NULL /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE diff --git a/gcc/testsuite/ChangeLog.lto b/gcc/testsuite/ChangeLog.lto index 54c2df89d18..76ac00d63ed 100644 --- a/gcc/testsuite/ChangeLog.lto +++ b/gcc/testsuite/ChangeLog.lto @@ -1,3 +1,9 @@ +2009-08-13 Richard Guenther <rguenther@suse.de> + + PR lto/41032 + * gcc.dg/lto/20090812_0.c: New testcase. + * gcc.dg/lto/20090812_1.c: Likewise. + 2009-07-30 Richard Guenther <rguenther@suse.de> PR lto/40903 diff --git a/gcc/testsuite/gcc.dg/lto/20090812_0.c b/gcc/testsuite/gcc.dg/lto/20090812_0.c new file mode 100644 index 00000000000..baf20f520a2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/20090812_0.c @@ -0,0 +1,11 @@ +struct X; +struct Y +{ + struct X *p; + int i; +}; + +void foo (struct Y *p) +{ + p->i = 1; +} diff --git a/gcc/testsuite/gcc.dg/lto/20090812_1.c b/gcc/testsuite/gcc.dg/lto/20090812_1.c new file mode 100644 index 00000000000..e91424492a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/20090812_1.c @@ -0,0 +1,26 @@ +/* struct X is complete in this TU, this causes us to not merge Y and + thus assign different alias-sets to them. */ +struct X +{ + int i; +}; +struct Y +{ + struct X *p; + int i; +}; +extern void abort (void); +extern void foo(struct Y *); +int __attribute__((noinline)) bar(struct Y *p) +{ + p->i = 0; + foo (p); + return p->i; +} +int main() +{ + struct Y y; + if (bar (&y) != 1) + abort (); + return 0; +} diff --git a/gcc/tree.c b/gcc/tree.c index a679b93cc20..1690f73e5f2 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4796,7 +4796,7 @@ free_lang_data (void) /* Reset some langhooks. */ lang_hooks.callgraph.analyze_expr = NULL; - lang_hooks.types_compatible_p = gimple_types_compatible_p; + lang_hooks.types_compatible_p = NULL; /* FIXME lto: We have to compute these names early. */ lang_hooks.dwarf_name = lhd_dwarf_name; |