--- /dev/null
+/* { 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" } } */
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)
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;
}
/* 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)