re PR tree-optimization/15262 ([tree-ssa] Alias analyzer cannot handle addressable...
authorDiego Novillo <dnovillo@redhat.com>
Tue, 14 Sep 2004 22:45:54 +0000 (22:45 +0000)
committerDiego Novillo <dnovillo@gcc.gnu.org>
Tue, 14 Sep 2004 22:45:54 +0000 (18:45 -0400)
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

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr15262-1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/pr15262-2.c [new file with mode: 0644]
gcc/tree-dfa.c
gcc/tree-ssa-alias.c

index 9a6ba5fcd37cf082f5863e5a8aae4fdd7f3f077e..eb5533dbddcd08863f603b8caa14e81a4a3b8d4f 100644 (file)
@@ -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
index 2a7f9d41d2d91b573142610ac9f8d552b012cab4..6ac93c8b42f8a980e59246d3c5c2d72944e9c0a2 100644 (file)
@@ -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.
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr15262-1.c b/gcc/testsuite/gcc.c-torture/execute/pr15262-1.c
new file mode 100644 (file)
index 0000000..f6a6fe4
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr15262-2.c b/gcc/testsuite/gcc.c-torture/execute/pr15262-2.c
new file mode 100644 (file)
index 0000000..82e8aab
--- /dev/null
@@ -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;
+}
index 7f552ca928f45118b7049af1a17d856d0ea1ce4e..533b98884e66f17654a83641bf58056b23124dfc 100644 (file)
@@ -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: ");
index 47f8d96bc966cf0f66406bca0bdf35259bb37e7e..65b0d7bc776e75f89c9883934ebf8cd236318c59 100644 (file)
@@ -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++;