re PR tree-optimization/15262 ([tree-ssa] Alias analyzer cannot handle addressable fields)
PR tree-optimization/15262 * tree-dfa.c (dump_variable): Also print the type of the variable. * tree-ssa-alias.c (compute_flow_insensitive_aliasing): If two memory tags are of conflicting alias sets but have no aliased symbols in common, add one tag to the alias set of the other. (setup_pointers_and_addressables): Remove hack to deal with programs with no aliased symbols. (may_alias_p): Don't special case aggregate types. testsuite/ChangeLog PR tree-optimization/15262 * gcc.c-torture/execute/pr15262-1.c: New test. * gcc.c-torture/execute/pr15262-2.c: New test. From-SVN: r87515
This commit is contained in:
parent
0e6d31fb86
commit
1810f6edaa
|
@ -1,3 +1,15 @@
|
|||
2004-09-14 Diego Novillo <dnovillo@redhat.com>
|
||||
|
||||
PR tree-optimization/15262
|
||||
* tree-dfa.c (dump_variable): Also print the type of the
|
||||
variable.
|
||||
* tree-ssa-alias.c (compute_flow_insensitive_aliasing): If two
|
||||
memory tags are of conflicting alias sets but have no aliased
|
||||
symbols in common, add one tag to the alias set of the other.
|
||||
(setup_pointers_and_addressables): Remove hack to deal with
|
||||
programs with no aliased symbols.
|
||||
(may_alias_p): Don't special case aggregate types.
|
||||
|
||||
2004-09-14 Joseph S. Myers <jsm@polyomino.org.uk>
|
||||
|
||||
PR c/15498
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2004-09-14 Diego Novillo <dnovillo@redhat.com>
|
||||
|
||||
PR tree-optimization/15262
|
||||
* gcc.c-torture/execute/pr15262-1.c: New test.
|
||||
* gcc.c-torture/execute/pr15262-2.c: New test.
|
||||
|
||||
2004-09-14 Joseph S. Myers <jsm@polyomino.org.uk>
|
||||
|
||||
* gcc.dg/declspec-12.c: New test.
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* PR 15262.
|
||||
The alias analyzer only considers relations between pointers and
|
||||
symbols. If two pointers P and Q point to the same symbol S, then
|
||||
their respective memory tags will either be the same or they will
|
||||
have S in their alias set.
|
||||
|
||||
However, if there are no common symbols between P and Q, TBAA will
|
||||
currently miss their alias relationship altogether. */
|
||||
struct A
|
||||
{
|
||||
int t;
|
||||
int i;
|
||||
};
|
||||
|
||||
int foo () { return 3; }
|
||||
|
||||
main ()
|
||||
{
|
||||
struct A loc, *locp;
|
||||
float f, g, *p;
|
||||
int T355, *T356;
|
||||
|
||||
/* Avoid the partial hack in TBAA that would consider memory tags if
|
||||
the program had no addressable symbols. */
|
||||
f = 3;
|
||||
g = 2;
|
||||
p = foo () ? &g : &f;
|
||||
if (*p > 0.0)
|
||||
g = 1;
|
||||
|
||||
/* Store into *locp and cache its current value. */
|
||||
locp = malloc (sizeof (*locp));
|
||||
locp->i = 10;
|
||||
T355 = locp->i;
|
||||
|
||||
/* Take the address of one of locp's fields and write to it. */
|
||||
T356 = &locp->i;
|
||||
*T356 = 1;
|
||||
|
||||
/* Read the recently stored value. If TBAA fails, this will appear
|
||||
as a redundant load that will be replaced with '10'. */
|
||||
T355 = locp->i;
|
||||
if (T355 != 1)
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* PR 15262. Similar to pr15262-1.c but with no obvious addresses
|
||||
being taken in function foo(). Without IPA, by only looking inside
|
||||
foo() we cannot tell for certain whether 'q' and 'b' alias each
|
||||
other. */
|
||||
struct A
|
||||
{
|
||||
int t;
|
||||
int i;
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
int *p;
|
||||
float b;
|
||||
};
|
||||
|
||||
float X;
|
||||
|
||||
foo (struct B b, struct A *q, float *h)
|
||||
{
|
||||
X += *h;
|
||||
*(b.p) = 3;
|
||||
q->t = 2;
|
||||
return *(b.p);
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
struct A a;
|
||||
struct B b;
|
||||
|
||||
b.p = &a.t;
|
||||
if (foo (b, &a, &X) == 3)
|
||||
abort ();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -528,6 +528,9 @@ dump_variable (FILE *file, tree var)
|
|||
|
||||
fprintf (file, ", UID %u", (unsigned) ann->uid);
|
||||
|
||||
fprintf (file, ", ");
|
||||
print_generic_expr (file, TREE_TYPE (var), dump_flags);
|
||||
|
||||
if (ann->type_mem_tag)
|
||||
{
|
||||
fprintf (file, ", type memory tag: ");
|
||||
|
|
|
@ -875,6 +875,7 @@ static void
|
|||
compute_flow_insensitive_aliasing (struct alias_info *ai)
|
||||
{
|
||||
size_t i;
|
||||
sbitmap res;
|
||||
|
||||
/* Initialize counter for the total number of virtual operands that
|
||||
aliasing will introduce. When AI->TOTAL_ALIAS_VOPS goes beyond the
|
||||
|
@ -943,6 +944,75 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
|
|||
}
|
||||
}
|
||||
|
||||
/* Since this analysis is based exclusively on symbols, it fails to
|
||||
handle cases where two pointers P and Q have different memory
|
||||
tags with conflicting alias set numbers but no aliased symbols in
|
||||
common.
|
||||
|
||||
For example, suppose that we have two memory tags TMT.1 and TMT.2
|
||||
such that
|
||||
|
||||
may-aliases (TMT.1) = { a }
|
||||
may-aliases (TMT.2) = { b }
|
||||
|
||||
and the alias set number of TMT.1 conflicts with that of TMT.2.
|
||||
Since they don't have symbols in common, loads and stores from
|
||||
TMT.1 and TMT.2 will seem independent of each other, which will
|
||||
lead to the optimizers making invalid transformations (see
|
||||
testsuite/gcc.c-torture/execute/pr15262-[12].c).
|
||||
|
||||
To avoid this problem, we do a final traversal of AI->POINTERS
|
||||
looking for pairs of pointers that have no aliased symbols in
|
||||
common and yet have conflicting alias set numbers. */
|
||||
res = sbitmap_alloc (num_referenced_vars);
|
||||
|
||||
for (i = 0; i < ai->num_pointers; i++)
|
||||
{
|
||||
size_t j;
|
||||
struct alias_map_d *p_map1 = ai->pointers[i];
|
||||
tree tag1 = var_ann (p_map1->var)->type_mem_tag;
|
||||
sbitmap may_aliases1 = p_map1->may_aliases;
|
||||
|
||||
for (j = i + 1; j < ai->num_pointers; j++)
|
||||
{
|
||||
struct alias_map_d *p_map2 = ai->pointers[j];
|
||||
tree tag2 = var_ann (p_map2->var)->type_mem_tag;
|
||||
var_ann_t tag2_ann = var_ann (tag2);
|
||||
sbitmap may_aliases2 = p_map2->may_aliases;
|
||||
|
||||
/* If the pointers may not point to each other, do nothing. */
|
||||
if (!may_alias_p (p_map1->var, p_map1->set, p_map2->var, p_map2->set))
|
||||
continue;
|
||||
|
||||
/* The two pointers may alias each other. If they already have
|
||||
symbols in common, do nothing. */
|
||||
sbitmap_a_and_b (res, may_aliases1, may_aliases2);
|
||||
if (sbitmap_first_set_bit (res) >= 0)
|
||||
continue;
|
||||
|
||||
if (sbitmap_first_set_bit (may_aliases2) >= 0)
|
||||
{
|
||||
size_t k;
|
||||
|
||||
/* Add all the aliases for TAG2 into TAG1's alias set.
|
||||
FIXME, update grouping heuristic counters. */
|
||||
EXECUTE_IF_SET_IN_SBITMAP (may_aliases2, 0, k,
|
||||
add_may_alias (tag1, referenced_var (k)));
|
||||
sbitmap_a_or_b (may_aliases1, may_aliases1, may_aliases2);
|
||||
sbitmap_zero (may_aliases2);
|
||||
tag2_ann->may_aliases = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since TAG2 does not have any aliases of its own, add
|
||||
TAG2 itself to the alias set of TAG1. */
|
||||
add_may_alias (tag1, tag2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sbitmap_free (res);
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "%s: Total number of aliased vops: %ld\n",
|
||||
get_name (current_function_decl),
|
||||
|
@ -1262,8 +1332,9 @@ setup_pointers_and_addressables (struct alias_info *ai)
|
|||
|
||||
/* Name memory tags already have flow-sensitive aliasing
|
||||
information, so they need not be processed by
|
||||
compute_may_aliases. Similarly, type memory tags are already
|
||||
accounted for when we process their associated pointer. */
|
||||
compute_flow_insensitive_aliasing. Similarly, type memory
|
||||
tags are already accounted for when we process their
|
||||
associated pointer. */
|
||||
if (v_ann->mem_tag_kind != NOT_A_TAG)
|
||||
continue;
|
||||
|
||||
|
@ -1367,41 +1438,6 @@ setup_pointers_and_addressables (struct alias_info *ai)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we found no addressable variables, but we have more than one
|
||||
pointer, we will need to check for conflicts between the
|
||||
pointers. Otherwise, we would miss alias relations as in
|
||||
testsuite/gcc.dg/tree-ssa/20040319-1.c:
|
||||
|
||||
struct bar { int count; int *arr;};
|
||||
|
||||
void foo (struct bar *b)
|
||||
{
|
||||
b->count = 0;
|
||||
*(b->arr) = 2;
|
||||
if (b->count == 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
b->count and *(b->arr) could be aliased if b->arr == &b->count.
|
||||
To do this, we add all the memory tags for the pointers in
|
||||
AI->POINTERS to AI->ADDRESSABLE_VARS, so that
|
||||
compute_flow_insensitive_aliasing will naturally compare every
|
||||
pointer to every type tag. */
|
||||
if (ai->num_addressable_vars == 0
|
||||
&& ai->num_pointers > 1)
|
||||
{
|
||||
free (ai->addressable_vars);
|
||||
ai->addressable_vars = xcalloc (ai->num_pointers,
|
||||
sizeof (struct alias_map_d *));
|
||||
ai->num_addressable_vars = 0;
|
||||
for (i = 0; i < ai->num_pointers; i++)
|
||||
{
|
||||
struct alias_map_d *p = ai->pointers[i];
|
||||
tree tag = var_ann (p->var)->type_mem_tag;
|
||||
create_alias_map_for (tag, ai);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1536,58 +1572,9 @@ may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
|
|||
/* If the alias sets don't conflict then MEM cannot alias VAR. */
|
||||
if (!alias_sets_conflict_p (mem_alias_set, var_alias_set))
|
||||
{
|
||||
/* Handle aliases to structure fields. If either VAR or MEM are
|
||||
aggregate types, they may not have conflicting types, but one of
|
||||
the structures could contain a pointer to the other one.
|
||||
|
||||
For instance, given
|
||||
|
||||
MEM -> struct P *p;
|
||||
VAR -> struct Q *q;
|
||||
|
||||
It may happen that '*p' and '*q' can't alias because 'struct P'
|
||||
and 'struct Q' have non-conflicting alias sets. However, it could
|
||||
happen that one of the fields in 'struct P' is a 'struct Q *' or
|
||||
vice-versa.
|
||||
|
||||
Therefore, we also need to check if 'struct P' aliases 'struct Q *'
|
||||
or 'struct Q' aliases 'struct P *'. Notice, that since GIMPLE
|
||||
does not have more than one-level pointers, we don't need to
|
||||
recurse into the structures. */
|
||||
if (AGGREGATE_TYPE_P (TREE_TYPE (mem))
|
||||
|| AGGREGATE_TYPE_P (TREE_TYPE (var)))
|
||||
{
|
||||
tree ptr_to_var;
|
||||
|
||||
if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
|
||||
ptr_to_var = TYPE_POINTER_TO (TREE_TYPE (TREE_TYPE (var)));
|
||||
else
|
||||
ptr_to_var = TYPE_POINTER_TO (TREE_TYPE (var));
|
||||
|
||||
/* If no pointer-to VAR exists, then MEM can't alias VAR. */
|
||||
if (ptr_to_var == NULL_TREE)
|
||||
{
|
||||
alias_stats.alias_noalias++;
|
||||
alias_stats.tbaa_resolved++;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If MEM doesn't alias a pointer to VAR and VAR doesn't alias
|
||||
PTR, then PTR can't alias VAR. */
|
||||
if (!alias_sets_conflict_p (mem_alias_set, get_alias_set (ptr_to_var))
|
||||
&& !alias_sets_conflict_p (var_alias_set, get_alias_set (ptr)))
|
||||
{
|
||||
alias_stats.alias_noalias++;
|
||||
alias_stats.tbaa_resolved++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
alias_stats.alias_noalias++;
|
||||
alias_stats.tbaa_resolved++;
|
||||
return false;
|
||||
}
|
||||
alias_stats.alias_noalias++;
|
||||
alias_stats.tbaa_resolved++;
|
||||
return false;
|
||||
}
|
||||
|
||||
alias_stats.alias_mayalias++;
|
||||
|
|
Loading…
Reference in New Issue