tree-dfa.c (refs_may_alias_p): Exit early if possible.

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
This commit is contained in:
Richard Guenther 2008-05-22 10:32:55 +00:00 committed by Richard Biener
parent 3f9f247417
commit 1842e4d44e
5 changed files with 177 additions and 43 deletions

View 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

View 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.

View file

@ -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" } } */

View 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;
}

View 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;
aff_tree off1, off2;
/* If MEM1 and MEM2 are based on different variables, they cannot alias. */
base1 = get_base_address (mem1);
base2 = get_base_address (mem2);
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)