diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/alias-18.c | 90 | ||||
-rw-r--r-- | gcc/tree-dfa.c | 84 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-im.c | 34 |
5 files changed, 177 insertions, 43 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9c02b23..4f2d4c4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 71abbb8..51daefa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 0000000..9ef3f2a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-18.c @@ -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" } } */ diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index 0a8f88d..02d2139 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -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; } diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index 8740030..2336263 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -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) |