tree-dfa.c (refs_may_alias_p): Exit early if possible.
authorRichard Guenther <rguenther@suse.de>
Thu, 22 May 2008 10:32:55 +0000 (10:32 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 22 May 2008 10:32:55 +0000 (10:32 +0000)
2008-05-22  Richard Guenther  <rguenther@suse.de>

* tree-dfa.c (refs_may_alias_p): Exit early if possible.  Handle
more cases of offset disambiguation that is possible if
strict-aliasing rules apply.
* tree-ssa-loop-im.c (mem_refs_may_alias_p): Use refs_may_alias_p
for basic offset and type-based disambiguation.

* gcc.dg/tree-ssa/alias-18.c: New testcase.

From-SVN: r135754

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/alias-18.c [new file with mode: 0644]
gcc/tree-dfa.c
gcc/tree-ssa-loop-im.c

index 9c02b23b4e3424931f2b016f336b055836431b32..4f2d4c42f81e1bf83aa758749ff75d285abe372e 100644 (file)
@@ -1,3 +1,11 @@
+2008-05-22  Richard Guenther  <rguenther@suse.de>
+
+       * tree-dfa.c (refs_may_alias_p): Exit early if possible.  Handle
+       more cases of offset disambiguation that is possible if
+       strict-aliasing rules apply.
+       * tree-ssa-loop-im.c (mem_refs_may_alias_p): Use refs_may_alias_p
+       for basic offset and type-based disambiguation.
+
 2008-05-21  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/i386.c (ix86_expand_vector_init_one_var): Use
index 71abbb891131684580b36c10a038ad12551c3103..51daefa9b4da7b02aee546ba18c81a28c22cc440 100644 (file)
@@ -1,3 +1,7 @@
+2008-05-22  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/tree-ssa/alias-18.c: New testcase.
+
 2008-05-22  Arnaud Charlet  <charlet@adacore.com>
 
        * gnat.dg/slice5.adb: New test.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-18.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-18.c
new file mode 100644 (file)
index 0000000..9ef3f2a
--- /dev/null
@@ -0,0 +1,90 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-fre-details -fdump-tree-optimized --param max-aliased-vops=0" } */
+
+struct A {
+  int i;
+  int j;
+  float x;
+};
+struct B {
+  struct A a;
+  int k;
+};
+
+int g;
+
+int test0 (struct A *p, struct A *q)
+{
+  p->i = 0;
+  q->j = -1;
+  return p->i;
+}
+
+int test1 (struct A *p, struct B *q)
+{
+  p->i = 1;
+  q->k = -1;
+  return p->i;
+}
+
+int test2 (struct A *p, struct B *q)
+{
+  p->i = 2;
+  q->a.i = -1;
+  return p->i;
+}
+
+int test3 (struct A *p, struct B *q)
+{
+  p->i = 3;
+  q->a.j = -1;
+  return p->i;
+}
+
+int test4 (struct A *p)
+{
+  g = 4;
+  p->i = -1;
+  return g;
+}
+
+int test5 (struct A *p)
+{
+  p->i = 5;
+  g = -1;
+  return p->i;
+}
+
+int test6 (struct A *p, int *q)
+{
+  p->i = 6;
+  *q = -1;
+  return p->i;
+}
+
+int test7 (struct A *p, int *q)
+{
+  p->j = 7;
+  *q = -1;
+  return p->j;
+}
+
+int test8 (struct A *p, int *q)
+{
+  *q = 8;
+  p->x = -1;
+  return *q;
+}
+
+/* { dg-final { scan-tree-dump "with 0" "fre" } } */
+/* { dg-final { scan-tree-dump "with 1" "fre" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump "with 3" "fre" } } */
+/* { dg-final { scan-tree-dump "with 4" "fre" } } */
+/* { dg-final { scan-tree-dump "with 5" "fre" } } */
+/* { dg-final { scan-tree-dump "with 8" "fre" } } */
+/* { dg-final { scan-tree-dump-not "return 2;" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "return 6;" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "return 7;" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "return -1;" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
index 0a8f88de2975304b2345594d612ef0830f2f3253..02d2139d3b3eb151cb17dc68146393089878cc07 100644 (file)
@@ -1041,6 +1041,7 @@ refs_may_alias_p (tree ref1, tree ref2)
   HOST_WIDE_INT offset1 = 0, offset2 = 0;
   HOST_WIDE_INT size1 = -1, size2 = -1;
   HOST_WIDE_INT max_size1 = -1, max_size2 = -1;
+  bool strict_aliasing_applies;
 
   gcc_assert ((SSA_VAR_P (ref1)
               || handled_component_p (ref1)
@@ -1068,19 +1069,78 @@ refs_may_alias_p (tree ref1, tree ref2)
      If both references are based on the same variable, they cannot alias if
      if the accesses do not overlap.  */
   if (SSA_VAR_P (base1)
-      && SSA_VAR_P (base2)
-      && (!operand_equal_p (base1, base2, 0)
-         || !ranges_overlap_p (offset1, max_size1, offset2, max_size2)))
-    return false;
+      && SSA_VAR_P (base2))
+    {
+      if (!operand_equal_p (base1, base2, 0))
+       return false;
+      return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+    }
 
-  /* If both references are through pointers and both pointers are equal
-     then they do not alias if the accesses do not overlap.  */
-  if (TREE_CODE (base1) == INDIRECT_REF
-      && TREE_CODE (base2) == INDIRECT_REF
-      && operand_equal_p (TREE_OPERAND (base1, 0),
-                         TREE_OPERAND (base2, 0), 0)
-      && !ranges_overlap_p (offset1, max_size1, offset2, max_size2))
-    return false;
+  /* If one base is a ref-all pointer weird things are allowed.  */
+  strict_aliasing_applies = (flag_strict_aliasing
+                            && get_alias_set (base1) != 0
+                            && get_alias_set (base2) != 0);
+
+  /* If both references are through the same type, or if strict aliasing
+     doesn't apply they are through two same pointers, they do not alias
+     if the accesses do not overlap.  */
+  if ((strict_aliasing_applies
+       && (TYPE_MAIN_VARIANT (TREE_TYPE (base1))
+          == TYPE_MAIN_VARIANT (TREE_TYPE (base2))))
+      || (TREE_CODE (base1) == INDIRECT_REF
+         && TREE_CODE (base2) == INDIRECT_REF
+         && operand_equal_p (TREE_OPERAND (base1, 0),
+                             TREE_OPERAND (base2, 0), 0)))
+    return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+
+  /* If both are component references through pointers try to find a
+     common base and apply offset based disambiguation.  This handles
+     for example
+       struct A { int i; int j; } *q;
+       struct B { struct A a; int k; } *p;
+     disambiguating q->i and p->a.j.  */
+  if (strict_aliasing_applies
+      && (TREE_CODE (base1) == INDIRECT_REF
+         || TREE_CODE (base2) == INDIRECT_REF)
+      && handled_component_p (ref1)
+      && handled_component_p (ref2))
+    {
+      tree *refp;
+      /* Now search for the type of base1 in the access path of ref2.  This
+        would be a common base for doing offset based disambiguation on.  */
+      refp = &ref2;
+      while (handled_component_p (*refp)
+            /* Note that the following is only conservative if there are
+               never copies of types appearing as sub-structures.  */
+            && (TYPE_MAIN_VARIANT (TREE_TYPE (*refp))
+                != TYPE_MAIN_VARIANT (TREE_TYPE (base1))))
+       refp = &TREE_OPERAND (*refp, 0);
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (*refp))
+         == TYPE_MAIN_VARIANT (TREE_TYPE (base1)))
+       {
+         HOST_WIDE_INT offadj, sztmp, msztmp;
+         get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp);
+         offset2 -= offadj;
+         return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+       }
+      /* The other way around.  */
+      refp = &ref1;
+      while (handled_component_p (*refp)
+            && (TYPE_MAIN_VARIANT (TREE_TYPE (*refp))
+                != TYPE_MAIN_VARIANT (TREE_TYPE (base2))))
+       refp = &TREE_OPERAND (*refp, 0);
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (*refp))
+         == TYPE_MAIN_VARIANT (TREE_TYPE (base2)))
+       {
+         HOST_WIDE_INT offadj, sztmp, msztmp;
+         get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp);
+         offset1 -= offadj;
+         return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+       }
+      /* If we can be sure to catch all equivalent types in the search
+        for the common base then we could return false here.  In that
+        case we would be able to disambiguate q->i and p->k.  */
+    }
 
   return true;
 }
index 8740030397f48bcbb7f01a74c39394827b72439e..2336263b499af42a1bbb406a7a7d64a4b06f719c 100644 (file)
@@ -1617,41 +1617,13 @@ mem_refs_may_alias_p (tree mem1, tree mem2, struct pointer_map_t **ttae_cache)
   /* Perform BASE + OFFSET analysis -- if MEM1 and MEM2 are based on the same
      object and their offset differ in such a way that the locations cannot
      overlap, then they cannot alias.  */
-  aff_tree off1, off2;
   double_int size1, size2;
-  tree base1, base2;
-
-  /* If MEM1 and MEM2 are based on different variables, they cannot alias.  */
-  base1 = get_base_address (mem1);
-  base2 = get_base_address (mem2);
+  aff_tree off1, off2;
 
-  if (base1
-      && !INDIRECT_REF_P (base1)
-      && base2
-      && !INDIRECT_REF_P (base2)
-      && !operand_equal_p (base1, base2, 0))
+  /* Perform basic offset and type-based disambiguation.  */
+  if (!refs_may_alias_p (mem1, mem2))
     return false;
 
-  /* With strict aliasing, it is impossible to access a scalar variable through
-     anything but a pointer dereference or through a union (gcc extension).  */
-  if (flag_strict_aliasing)
-    {
-      if (!INDIRECT_REF_P (mem1)
-         && base1
-         && TREE_CODE (TREE_TYPE (base1)) != UNION_TYPE
-         && SSA_VAR_P (mem2)
-         && !AGGREGATE_TYPE_P (TREE_TYPE (mem2)))
-       return false;
-      if (!INDIRECT_REF_P (mem2)
-         && base2
-         && TREE_CODE (TREE_TYPE (base2)) != UNION_TYPE
-         && SSA_VAR_P (mem1)
-         && !AGGREGATE_TYPE_P (TREE_TYPE (mem1)))
-       return false;
-      if (!alias_sets_conflict_p (get_alias_set (mem1), get_alias_set (mem2)))
-       return false;
-    }
-
   /* The expansion of addresses may be a bit expensive, thus we only do
      the check at -O2 and higher optimization levels.  */
   if (optimize < 2)