re PR c/18851 (IMA is slow and could be sped up)

2005-10-02  Andrew Pinski  <pinskia@physics.uc.edu>

        PR c/18851
        * c-typeck.c (tagged_tu_seen): Rename to ...
        (tagged_tu_seen_cache): this and add val field.
        (comptypes): Move functional to comptypes_internal
        and free tagged_tu_seen.
        (comptypes_internal): New function and call comptypes_internal
        instead of comptypes. Speed up by sibcalling
        tagged_types_tu_compatible_p.
        (alloc_tagged_tu_seen): New function
        (free_all_tagged_tu_seen_up_to): New function.
        (tagged_types_tu_compatible_p): Return the val of the seen two
        types.
        Add that the two types are the same to tagged_tu_seen_base
        if they are and call comptypes_internal instead of comptypes.
        <case UNION_TYPE>: Speed up common type where the fields are
        in the same order.
        (function_types_compatible_p): Call comptypes_internal instead of
        comptypes.
        (type_lists_compatible_p): Likewise.
        (all functions): s/tagged_tu_seen/tagged_tu_seen_cache/.

From-SVN: r104873
This commit is contained in:
Andrew Pinski 2005-10-02 19:15:58 +00:00 committed by Andrew Pinski
parent aa58883c23
commit f13c9b2c76
2 changed files with 186 additions and 53 deletions

View File

@ -1,3 +1,26 @@
2005-10-02 Andrew Pinski <pinskia@physics.uc.edu>
PR c/18851
* c-typeck.c (tagged_tu_seen): Rename to ...
(tagged_tu_seen_cache): this and add val field.
(comptypes): Move functional to comptypes_internal
and free tagged_tu_seen.
(comptypes_internal): New function and call comptypes_internal
instead of comptypes. Speed up by sibcalling
tagged_types_tu_compatible_p.
(alloc_tagged_tu_seen): New function
(free_all_tagged_tu_seen_up_to): New function.
(tagged_types_tu_compatible_p): Return the val of the seen two
types.
Add that the two types are the same to tagged_tu_seen_base
if they are and call comptypes_internal instead of comptypes.
<case UNION_TYPE>: Speed up common type where the fields are
in the same order.
(function_types_compatible_p): Call comptypes_internal instead of
comptypes.
(type_lists_compatible_p): Likewise.
(all functions): s/tagged_tu_seen/tagged_tu_seen_cache/.
2005-10-02 Matthias Klose <doko@debian.org>
* doc/invoke.texi: Fix typo and speling error.

View File

@ -105,7 +105,21 @@ static void readonly_error (tree, enum lvalue_use);
static int lvalue_or_else (tree, enum lvalue_use);
static int lvalue_p (tree);
static void record_maybe_used_decl (tree);
static int comptypes_internal (tree, tree);
/* This is a cache to hold if two types are compatible or not. */
struct tagged_tu_seen_cache {
const struct tagged_tu_seen_cache * next;
tree t1;
tree t2;
/* The return value of tagged_types_tu_compatible_p if we had seen
these two types already. */
int val;
};
static const struct tagged_tu_seen_cache * tagged_tu_seen_base;
static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *);
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
@ -663,13 +677,29 @@ common_type (tree t1, tree t2)
return c_common_type (t1, t2);
}
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
but a warning may be needed if you use them together. */
int
comptypes (tree type1, tree type2)
{
const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
int val;
val = comptypes_internal (type1, type2);
free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
return val;
}
/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations. Return 2 if they are compatible
but a warning may be needed if you use them together. This
differs from comptypes, in that we don't free the seen types. */
static int
comptypes_internal (tree type1, tree type2)
{
tree t1 = type1;
tree t2 = type2;
@ -737,7 +767,7 @@ comptypes (tree type1, tree type2)
|| TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2))
break;
val = (TREE_TYPE (t1) == TREE_TYPE (t2)
? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2)));
break;
case FUNCTION_TYPE:
@ -754,7 +784,7 @@ comptypes (tree type1, tree type2)
/* Target types must match incl. qualifiers. */
if (TREE_TYPE (t1) != TREE_TYPE (t2)
&& 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2))))
&& 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2))))
return 0;
/* Sizes must match unless one is missing or variable. */
@ -787,12 +817,16 @@ comptypes (tree type1, tree type2)
case RECORD_TYPE:
case UNION_TYPE:
if (val != 1 && !same_translation_unit_p (t1, t2))
val = tagged_types_tu_compatible_p (t1, t2);
{
if (attrval != 2)
return tagged_types_tu_compatible_p (t1, t2);
val = tagged_types_tu_compatible_p (t1, t2);
}
break;
case VECTOR_TYPE:
val = TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
&& comptypes (TREE_TYPE (t1), TREE_TYPE (t2));
&& comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2));
break;
default:
@ -861,21 +895,48 @@ same_translation_unit_p (tree t1, tree t2)
return t1 == t2;
}
/* The C standard says that two structures in different translation
units are compatible with each other only if the types of their
fields are compatible (among other things). So, consider two copies
of this structure: */
/* Allocate the seen two types, assuming that they are compatible. */
struct tagged_tu_seen {
const struct tagged_tu_seen * next;
tree t1;
tree t2;
};
static struct tagged_tu_seen_cache *
alloc_tagged_tu_seen_cache (tree t1, tree t2)
{
struct tagged_tu_seen_cache *tu = xmalloc (sizeof (struct tagged_tu_seen_cache));
tu->next = tagged_tu_seen_base;
tu->t1 = t1;
tu->t2 = t2;
tagged_tu_seen_base = tu;
/* The C standard says that two structures in different translation
units are compatible with each other only if the types of their
fields are compatible (among other things). We assume that they
are compatible until proven otherwise when building the cache.
An example where this can occur is:
struct a
{
struct a *next;
};
If we are comparing this against a similar struct in another TU,
and did not assume they were compatiable, we end up with an infinite
loop. */
tu->val = 1;
return tu;
}
/* Can they be compatible with each other? We choose to break the
recursion by allowing those types to be compatible. */
/* Free the seen types until we get to TU_TIL. */
static const struct tagged_tu_seen * tagged_tu_seen_base;
static void
free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til)
{
const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base;
while (tu != tu_til)
{
struct tagged_tu_seen_cache *tu1 = (struct tagged_tu_seen_cache*)tu;
tu = tu1->next;
free (tu1);
}
tagged_tu_seen_base = tu_til;
}
/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are
compatible. If the two types are not the same (which has been
@ -917,73 +978,123 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
return 1;
{
const struct tagged_tu_seen * tts_i;
const struct tagged_tu_seen_cache * tts_i;
for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next)
if (tts_i->t1 == t1 && tts_i->t2 == t2)
return 1;
return tts_i->val;
}
switch (TREE_CODE (t1))
{
case ENUMERAL_TYPE:
{
struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
/* Speed up the case where the type values are in the same order. */
tree tv1 = TYPE_VALUES (t1);
tree tv2 = TYPE_VALUES (t2);
if (tv1 == tv2)
return 1;
{
return 1;
}
for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2))
{
if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2))
break;
if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1)
return 0;
{
tu->val = 0;
return 0;
}
}
if (tv1 == NULL_TREE && tv2 == NULL_TREE)
return 1;
{
return 1;
}
if (tv1 == NULL_TREE || tv2 == NULL_TREE)
return 0;
{
tu->val = 0;
return 0;
}
if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2)))
return 0;
{
tu->val = 0;
return 0;
}
for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1))
{
s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2));
if (s2 == NULL
|| simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1)
return 0;
{
tu->val = 0;
return 0;
}
}
return 1;
}
case UNION_TYPE:
{
struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
return 0;
{
tu->val = 0;
return 0;
}
/* Speed up the common case where the fields are in the same order. */
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2;
s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
{
int result;
if (DECL_NAME (s1) == NULL
|| DECL_NAME (s1) != DECL_NAME (s2))
break;
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
if (result == 0)
{
tu->val = 0;
return 0;
}
if (result == 2)
needs_warning = true;
if (TREE_CODE (s1) == FIELD_DECL
&& simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
DECL_FIELD_BIT_OFFSET (s2)) != 1)
{
tu->val = 0;
return 0;
}
}
if (!s1 && !s2)
{
tu->val = needs_warning ? 2 : 1;
return tu->val;
}
for (s1 = TYPE_FIELDS (t1); s1; s1 = TREE_CHAIN (s1))
{
bool ok = false;
struct tagged_tu_seen tts;
tts.next = tagged_tu_seen_base;
tts.t1 = t1;
tts.t2 = t2;
tagged_tu_seen_base = &tts;
if (DECL_NAME (s1) != NULL)
for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
if (DECL_NAME (s1) == DECL_NAME (s2))
{
int result;
result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2));
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
if (result == 0)
break;
{
tu->val = 0;
return 0;
}
if (result == 2)
needs_warning = true;
@ -995,21 +1106,19 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
ok = true;
break;
}
tagged_tu_seen_base = tts.next;
if (!ok)
return 0;
{
tu->val = 0;
return 0;
}
}
return needs_warning ? 2 : 1;
tu->val = needs_warning ? 2 : 10;
return tu->val;
}
case RECORD_TYPE:
{
struct tagged_tu_seen tts;
tts.next = tagged_tu_seen_base;
tts.t1 = t1;
tts.t2 = t2;
tagged_tu_seen_base = &tts;
struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
s1 && s2;
@ -1019,7 +1128,7 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
if (TREE_CODE (s1) != TREE_CODE (s2)
|| DECL_NAME (s1) != DECL_NAME (s2))
break;
result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2));
result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2));
if (result == 0)
break;
if (result == 2)
@ -1030,10 +1139,11 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
DECL_FIELD_BIT_OFFSET (s2)) != 1)
break;
}
tagged_tu_seen_base = tts.next;
if (s1 && s2)
return 0;
return needs_warning ? 2 : 1;
tu->val = 0;
else
tu->val = needs_warning ? 2 : 1;
return tu->val;
}
default:
@ -1070,7 +1180,7 @@ function_types_compatible_p (tree f1, tree f2)
if (TYPE_VOLATILE (ret2))
ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
val = comptypes (ret1, ret2);
val = comptypes_internal (ret1, ret2);
if (val == 0)
return 0;
@ -1151,7 +1261,7 @@ type_lists_compatible_p (tree args1, tree args2)
else if (TREE_CODE (a1) == ERROR_MARK
|| TREE_CODE (a2) == ERROR_MARK)
;
else if (!(newval = comptypes (mv1, mv2)))
else if (!(newval = comptypes_internal (mv1, mv2)))
{
/* Allow wait (union {union wait *u; int *i} *)
and wait (union wait *) to be compatible. */
@ -1170,7 +1280,7 @@ type_lists_compatible_p (tree args1, tree args2)
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
if (comptypes (mv3, mv2))
if (comptypes_internal (mv3, mv2))
break;
}
if (memb == 0)
@ -1191,7 +1301,7 @@ type_lists_compatible_p (tree args1, tree args2)
if (mv3 && mv3 != error_mark_node
&& TREE_CODE (mv3) != ARRAY_TYPE)
mv3 = TYPE_MAIN_VARIANT (mv3);
if (comptypes (mv3, mv1))
if (comptypes_internal (mv3, mv1))
break;
}
if (memb == 0)