aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2009-08-13 15:44:01 +0000
committerRichard Guenther <rguenther@suse.de>2009-08-13 15:44:01 +0000
commit7c02b343e59d54c6ebadba7f366970fa2639821d (patch)
tree737825de91722d8c814370649fe168ea50ea0217
parentf1f6d5b60f0d4fe7e620a5f03d89610be254f163 (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.lto26
-rw-r--r--gcc/gimple.c235
-rw-r--r--gcc/lto-symtab.c224
-rw-r--r--gcc/lto/ChangeLog5
-rw-r--r--gcc/lto/lto-lang.c2
-rw-r--r--gcc/testsuite/ChangeLog.lto6
-rw-r--r--gcc/testsuite/gcc.dg/lto/20090812_0.c11
-rw-r--r--gcc/testsuite/gcc.dg/lto/20090812_1.c26
-rw-r--r--gcc/tree.c2
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, &gtc_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;