===================================================================
@@ -877,22 +877,62 @@ aliasing_component_refs_p (tree ref1,
tree *refp;
int same_p1 = 0, same_p2 = 0;
bool maybe_match = false;
+ tree end_struct_ref1 = NULL, end_struct_ref2 = NULL;
/* Choose bases and base types to search for. */
base1 = ref1;
while (handled_component_p (base1))
- base1 = TREE_OPERAND (base1, 0);
+ {
+ /* Generally access paths are monotous in the size of object. The
+ exception are trailing arrays of structures. I.e.
+ struct a {int array[0];};
+ or
+ struct a {int array1[0]; int array[];};
+ Such struct has size 0 but accesses to a.array may have non-zero size.
+ In this case the size of TREE_TYPE (base1) is smaller than
+ size of TREE_TYPE (TREE_OPERNAD (base1, 0)).
+
+ Because we compare sizes of arrays just by sizes of their elements,
+ we only need to care about zero sized array fields here. */
+ if (TREE_CODE (base1) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (base1, 1))) == ARRAY_TYPE
+ && (!TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base1, 1)))
+ || integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base1, 1)))))
+ && array_at_struct_end_p (base1))
+ {
+ gcc_checking_assert (!end_struct_ref1);
+ end_struct_ref1 = base1;
+ }
+ base1 = TREE_OPERAND (base1, 0);
+ }
type1 = TREE_TYPE (base1);
base2 = ref2;
while (handled_component_p (base2))
- base2 = TREE_OPERAND (base2, 0);
+ {
+ if (TREE_CODE (base2) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (base2, 1))) == ARRAY_TYPE
+ && (!TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base2, 1)))
+ || integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (base2, 1)))))
+ && array_at_struct_end_p (base2))
+ {
+ gcc_checking_assert (!end_struct_ref2);
+ end_struct_ref2 = base2;
+ }
+ base2 = TREE_OPERAND (base2, 0);
+ }
type2 = TREE_TYPE (base2);
/* Now search for the type1 in the access path of ref2. This
would be a common base for doing offset based disambiguation on.
This however only makes sense if type2 is big enough to hold type1. */
int cmp_outer = compare_type_sizes (type2, type1);
- if (cmp_outer >= 0)
+
+ /* If type2 is big enough to contain type1 walk its access path.
+ We also need to care of arrays at the end of structs that may extend
+ beyond the end of structure. */
+ if (cmp_outer >= 0
+ || (end_struct_ref2
+ && compare_type_sizes (TREE_TYPE (end_struct_ref2), type1) >= 0))
{
refp = &ref2;
while (true)
@@ -900,7 +940,11 @@ aliasing_component_refs_p (tree ref1,
/* We walk from inner type to the outer types. If type we see is
already too large to be part of type1, terminate the search. */
int cmp = compare_type_sizes (type1, TREE_TYPE (*refp));
- if (cmp < 0)
+
+ if (cmp < 0
+ && (!end_struct_ref1
+ || compare_type_sizes (TREE_TYPE (end_struct_ref1),
+ TREE_TYPE (*refp)) < 0))
break;
/* If types may be of same size, see if we can decide about their
equality. */
@@ -957,13 +1001,18 @@ aliasing_component_refs_p (tree ref1,
}
/* If we didn't find a common base, try the other way around. */
- if (cmp_outer <= 0)
+ if (cmp_outer <= 0
+ || (end_struct_ref1
+ && compare_type_sizes (TREE_TYPE (end_struct_ref1), type1) <= 0))
{
refp = &ref1;
while (true)
{
int cmp = compare_type_sizes (type2, TREE_TYPE (*refp));
- if (cmp < 0)
+ if (cmp < 0
+ && (!end_struct_ref2
+ || compare_type_sizes (TREE_TYPE (end_struct_ref2),
+ TREE_TYPE (*refp)) < 0))
break;
/* If types may be of same size, see if we can decide about their
equality. */
@@ -1022,8 +1071,14 @@ aliasing_component_refs_p (tree ref1,
But we can still have a path that goes B1.path1...B2.path2 with
a part that we do not see. So we can only disambiguate now
if there is no B2 in the tail of path1 and no B1 on the
tail of path2. */
if (compare_type_sizes (TREE_TYPE (ref2), type1) >= 0
+ && (!end_struct_ref1
+ || compare_type_sizes (TREE_TYPE (ref2),
+ TREE_TYPE (end_struct_ref1)) >= 0)
&& type_has_components_p (TREE_TYPE (ref2))
&& (base1_alias_set == ref2_alias_set
|| alias_set_subset_of (base1_alias_set, ref2_alias_set)))
@@ -1034,6 +1089,9 @@ aliasing_component_refs_p (tree ref1,
/* If this is ptr vs. decl then we know there is no ptr ... decl path. */
if (!ref2_is_decl
&& compare_type_sizes (TREE_TYPE (ref1), type2) >= 0
+ && (!end_struct_ref2
+ || compare_type_sizes (TREE_TYPE (ref1),
+ TREE_TYPE (end_struct_ref2)) >= 0)
&& type_has_components_p (TREE_TYPE (ref1))
&& (base2_alias_set == ref1_alias_set
|| alias_set_subset_of (base2_alias_set, ref1_alias_set)))
===================================================================
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+struct a {int v1;
+ int v2;};
+struct b {struct a a[0];};
+union c {struct b b;};
+
+int
+test (struct b *bptr1, union c *cptr, int i, int j)
+{
+ bptr1->a[i].v1=123;
+ cptr->b.a[j].v2=1;
+ return bptr1->a[i].v1;
+}
+int
+test2 (struct b *bptr1, union c *cptr, int i, int j)
+{
+ bptr1->a[i].v1=124;
+ cptr->b.a[j].v1=1;
+ return bptr1->a[i].v1;
+}
+/* { dg-final { scan-tree-dump-times "return 123" 1 "optimized"} } */
+/* { dg-final { scan-tree-dump-not "return 124" "optimized"} } */
===================================================================
@@ -0,0 +1,25 @@
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+struct a {int v1;
+ int v2;};
+struct b {int array[0]; struct a a[];};
+union c {struct b b;};
+
+int
+test (struct b *bptr1, union c *cptr, int i, int j)
+{
+ bptr1->a[i].v1=123;
+ cptr->b.a[j].v2=1;
+ return bptr1->a[i].v1;
+}
+int
+test2 (struct b *bptr1, union c *cptr, int i, int j)
+{
+ bptr1->a[i].v1=124;
+ cptr->b.a[j].v1=1;
+ return bptr1->a[i].v1;
+}
+/* { dg-final { scan-tree-dump-times "return 123" 1 "optimized"} } */
+/* { dg-final { scan-tree-dump-not "return 124" "optimized"} } */