diff mbox series

Make aliasing_component_refs_p to work harder when same_type_for_tbaa returns -1

Message ID 20190530152129.c2dooeadirfi6ebr@kam.mff.cuni.cz
State New
Headers show
Series Make aliasing_component_refs_p to work harder when same_type_for_tbaa returns -1 | expand

Commit Message

Jan Hubicka May 30, 2019, 3:21 p.m. UTC
Hi,
this patch makes aliasing_component_refs_p to not give up at the first
-1 returned by types_same_for_tbaa_p and continue searching for pairs of types
we know to be the same.  This affects disambiguations as follows:

With patch:
  refs_may_alias_p: 3013678 disambiguations, 3314059 queries
  ref_maybe_used_by_call_p: 7112 disambiguations, 3039278 queries
  call_may_clobber_ref_p: 817 disambiguations, 817 queries
  aliasing_component_ref_p: 636 disambiguations, 15844 queries
  TBAA oracle: 1417999 disambiguations 2915696 queries
               552182 are in alias set 0
               569795 queries asked about the same object
               0 queries asked about the same alias set
               0 access volatile
               259437 are dependent in the DAG
               116283 are aritificially in conflict with void *

Without:

Alias oracle query stats:
  refs_may_alias_p: 3013194 disambiguations, 3313539 queries
  ref_maybe_used_by_call_p: 7112 disambiguations, 3038794 queries
  call_may_clobber_ref_p: 817 disambiguations, 817 queries
  aliasing_component_ref_p: 152 disambiguations, 14285 queries
  TBAA oracle: 1417999 disambiguations 2914656 queries
               552182 are in alias set 0
               569275 queries asked about the same object
               0 queries asked about the same alias set
               0 access volatile
               258917 are dependent in the DAG
               116283 are aritificially in conflict with void *

Basically all comming from disambiguating
  MEM[(const Element_t[3] &)_116][1];
  usedGuards.upper_m[2];
There are number of similar matches in testsuite.  
More disambiguations would be possible if we did not allow partial
overlaps of arrays.

I had to however plug a problem with alias-2.c testcase (the one about
overlapping arrays):

/* We do not want to treat int[3] as an object that cannot overlap
   itself but treat it as arbitrary sub-array of a larger array object.  */
int ar1(int (*p)[3], int (*q)[3])
{
  (*p)[0] = 1;
  (*q)[1] = 2;
  return (*p)[0];
}
int main()
{
  int a[4];
  if (ar1 ((int (*)[3])&a[1], (int (*)[3])&a[0]) != 2)
    __builtin_abort ();
  return 0;
}

Previously indirect_refs_may_alias_p bypased the offset+range test because
it explicitly tests for array types:

      /* But avoid treating arrays as "objects", instead assume they
         can overlap by an exact multiple of their element size.  */
      && TREE_CODE (TREE_TYPE (ptrtype1)) != ARRAY_TYPE)
    return ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2);

Later the code continues to aliasing_component_refs_p which used to give up
comparing int[3] and int with -1 because of:

  /* ??? In Ada, an lvalue of an unconstrained type can be used to access an
     object of one of its constrained subtypes, e.g. when a function with an
     unconstrained parameter passed by reference is called on an object and
     inlined.  But, even in the case of a fixed size, type and subtypes are
     not equivalent enough as to share the same TYPE_CANONICAL, since this
     would mean that conversions between them are useless, whereas they are
     not (e.g. type and subtypes can have different modes).  So, in the end,
     they are only guaranteed to have the same alias set.  */
  if (get_alias_set (type1) == get_alias_set (type2))
    return -1;

This is more of an accident and there are cases where we do not trip across
this -1 and we disambiguate array accesses that seems unsafe to me.

With my change aliasing_component_refs_p finds the match of the
array types (type_same_for_tbaa_p returns 1 with non-LTO becuase they
have same canonical type) and disambiguates based on disjoint access ranges.

I have thus went ahead and updated all uses of type_same_for_tbaa_p to special
case arrays and reffer to this testcase (which seems odd and is only one in
testsuite): We can still do useful disambiguation if the array is not toplevel
reference or we know that the memory object is not bigger. This is tested by a
testcase I added and is quite frequent in real world code.

I also added check to give up on VLAs since I can not convicne myself that
this is safe: I think early inlining VLAs and streaming them may lead to
same VLA type have two different sizes at a time enabling it to partially
overlap.

	* gcc.dg/lto/alias-access-path-2.0.c: New testcase.

	* tree-ssa-alias.c (aliasing_component_refs_p): Do not give up
	immediately after same_types_for_tbaa_p returns -1 and continue
	looking for possible exact match; if matching types are arrays
	watch for partial overlaps.
	(indirect_ref_may_alias_decl_p): Watch for partial array overlaps.
	(indirect_refs_may_alias_p): Do type based disambiguation first;
	update comment.

Comments

Jan Hubicka May 31, 2019, 9:44 a.m. UTC | #1
> 
> 	* gcc.dg/lto/alias-access-path-2.0.c: New testcase.
> 
> 	* tree-ssa-alias.c (aliasing_component_refs_p): Do not give up
> 	immediately after same_types_for_tbaa_p returns -1 and continue
> 	looking for possible exact match; if matching types are arrays
> 	watch for partial overlaps.
> 	(indirect_ref_may_alias_decl_p): Watch for partial array overlaps.
> 	(indirect_refs_may_alias_p): Do type based disambiguation first;
> 	update comment.
> Index: testsuite/g++.dg/lto/pr88130_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/pr88130_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/pr88130_0.C	(working copy)

Hi,
I have just noticed that I included unrelated testcase by accident,
please ignore it.

Honza
Richard Biener June 6, 2019, 1 p.m. UTC | #2
On Thu, 30 May 2019, Jan Hubicka wrote:

> Hi,
> this patch makes aliasing_component_refs_p to not give up at the first
> -1 returned by types_same_for_tbaa_p and continue searching for pairs of types
> we know to be the same.  This affects disambiguations as follows:
>
> With patch:
>   refs_may_alias_p: 3013678 disambiguations, 3314059 queries
>   ref_maybe_used_by_call_p: 7112 disambiguations, 3039278 queries
>   call_may_clobber_ref_p: 817 disambiguations, 817 queries
>   aliasing_component_ref_p: 636 disambiguations, 15844 queries
>   TBAA oracle: 1417999 disambiguations 2915696 queries
>                552182 are in alias set 0
>                569795 queries asked about the same object
>                0 queries asked about the same alias set
>                0 access volatile
>                259437 are dependent in the DAG
>                116283 are aritificially in conflict with void *
> 
> Without:
> 
> Alias oracle query stats:
>   refs_may_alias_p: 3013194 disambiguations, 3313539 queries
>   ref_maybe_used_by_call_p: 7112 disambiguations, 3038794 queries
>   call_may_clobber_ref_p: 817 disambiguations, 817 queries
>   aliasing_component_ref_p: 152 disambiguations, 14285 queries
>   TBAA oracle: 1417999 disambiguations 2914656 queries
>                552182 are in alias set 0
>                569275 queries asked about the same object
>                0 queries asked about the same alias set
>                0 access volatile
>                258917 are dependent in the DAG
>                116283 are aritificially in conflict with void *
> 
> Basically all comming from disambiguating
>   MEM[(const Element_t[3] &)_116][1];
>   usedGuards.upper_m[2];
> There are number of similar matches in testsuite.  
> More disambiguations would be possible if we did not allow partial
> overlaps of arrays.
> 
> I had to however plug a problem with alias-2.c testcase (the one about
> overlapping arrays):
> 
> /* We do not want to treat int[3] as an object that cannot overlap
>    itself but treat it as arbitrary sub-array of a larger array object.  */
> int ar1(int (*p)[3], int (*q)[3])
> {
>   (*p)[0] = 1;
>   (*q)[1] = 2;
>   return (*p)[0];
> }
> int main()
> {
>   int a[4];
>   if (ar1 ((int (*)[3])&a[1], (int (*)[3])&a[0]) != 2)
>     __builtin_abort ();
>   return 0;
> }
> 
> Previously indirect_refs_may_alias_p bypased the offset+range test because
> it explicitly tests for array types:
> 
>       /* But avoid treating arrays as "objects", instead assume they
>          can overlap by an exact multiple of their element size.  */
>       && TREE_CODE (TREE_TYPE (ptrtype1)) != ARRAY_TYPE)
>     return ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2);
> 
> Later the code continues to aliasing_component_refs_p which used to give up
> comparing int[3] and int with -1 because of:
> 
>   /* ??? In Ada, an lvalue of an unconstrained type can be used to access an
>      object of one of its constrained subtypes, e.g. when a function with an
>      unconstrained parameter passed by reference is called on an object and
>      inlined.  But, even in the case of a fixed size, type and subtypes are
>      not equivalent enough as to share the same TYPE_CANONICAL, since this
>      would mean that conversions between them are useless, whereas they are
>      not (e.g. type and subtypes can have different modes).  So, in the end,
>      they are only guaranteed to have the same alias set.  */
>   if (get_alias_set (type1) == get_alias_set (type2))
>     return -1;
> 
> This is more of an accident and there are cases where we do not trip across
> this -1 and we disambiguate array accesses that seems unsafe to me.
> 
> With my change aliasing_component_refs_p finds the match of the
> array types (type_same_for_tbaa_p returns 1 with non-LTO becuase they
> have same canonical type) and disambiguates based on disjoint access ranges.
> 
> I have thus went ahead and updated all uses of type_same_for_tbaa_p to special
> case arrays and reffer to this testcase (which seems odd and is only one in
> testsuite): We can still do useful disambiguation if the array is not toplevel
> reference or we know that the memory object is not bigger. This is tested by a
> testcase I added and is quite frequent in real world code.
> 
> I also added check to give up on VLAs since I can not convicne myself that
> this is safe: I think early inlining VLAs and streaming them may lead to
> same VLA type have two different sizes at a time enabling it to partially
> overlap.

OK - sorry for the delay.  The array stuff gets a bit ugly so
we eventually want to do sth about that ...

Thanks,
Richard.

> 	* gcc.dg/lto/alias-access-path-2.0.c: New testcase.
> 
> 	* tree-ssa-alias.c (aliasing_component_refs_p): Do not give up
> 	immediately after same_types_for_tbaa_p returns -1 and continue
> 	looking for possible exact match; if matching types are arrays
> 	watch for partial overlaps.
> 	(indirect_ref_may_alias_decl_p): Watch for partial array overlaps.
> 	(indirect_refs_may_alias_p): Do type based disambiguation first;
> 	update comment.
> Index: testsuite/g++.dg/lto/pr88130_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/pr88130_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/pr88130_0.C	(working copy)
> @@ -0,0 +1,28 @@
> +// { dg-lto-do link }
> +// // { dg-lto-options { "-O2 -flto" } }
> +// // { dg-extra-ld-options "-r -nostdlib" }
> +class a {
> +public:
> +  static const long b = 1;
> +};
> +struct c {
> +  enum d { e };
> +};
> +class C;
> +class f {
> +public:
> +  f(c::d);
> +  template <typename g> C operator<=(g);
> +};
> +class C {
> +public:
> +  template <typename h> void operator!=(h &);
> +};
> +void i() {
> +  f j(c::e);
> +  try {
> +    j <= 0 != a::b;
> +  } catch (...) {
> +  }
> +}
> +
> Index: testsuite/gcc.dg/lto/alias-access-path-2_0.c
> ===================================================================
> --- testsuite/gcc.dg/lto/alias-access-path-2_0.c	(nonexistent)
> +++ testsuite/gcc.dg/lto/alias-access-path-2_0.c	(working copy)
> @@ -0,0 +1,38 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */
> +
> +/* In this test the access patch orracle (aliasing_component_refs_p)
> +   can disambiguage array[0] from array[1] by base+offset but it needs to be
> +   able to find the common type and not give up by not being able to compare
> +   types earlier.  */
> +
> +typedef int (*fnptr) ();
> +
> +__attribute__ ((used))
> +struct a
> +{
> +  void *array[2];
> +} a, *aptr = &a;
> +
> +__attribute__ ((used))
> +struct b
> +{
> + struct a a;
> +} *bptr;
> +
> +static void
> +inline_me_late (int argc)
> +{
> +  if (argc == -1)
> +    bptr->a.array[1] = bptr;
> +}
> +
> +int
> +main (int argc)
> +{
> +  aptr->array[0] = 0;
> +  inline_me_late (argc);
> +  if (!__builtin_constant_p (aptr->array[0] == 0))
> +    __builtin_abort ();
> +  return 0;
> +}
> Index: tree-ssa-alias.c
> ===================================================================
> --- tree-ssa-alias.c	(revision 271747)
> +++ tree-ssa-alias.c	(working copy)
> @@ -850,6 +850,7 @@ aliasing_component_refs_p (tree ref1,
>    tree type1, type2;
>    tree *refp;
>    int same_p1 = 0, same_p2 = 0;
> +  bool maybe_match = false;
>  
>    /* Choose bases and base types to search for.  */
>    base1 = ref1;
> @@ -880,8 +881,14 @@ aliasing_component_refs_p (tree ref1,
>  	  if (cmp == 0)
>  	    {
>  	      same_p2 = same_type_for_tbaa (TREE_TYPE (*refp), type1);
> -	      if (same_p2 != 0)
> +	      if (same_p2 == 1)
>  		break;
> +	      /* In case we can't decide whether types are same try to
> +		 continue looking for the exact match.
> +		 Remember however that we possibly saw a match
> +		 to bypass the access path continuations tests we do later.  */
> +	      if (same_p2 == -1)
> +		maybe_match = true;
>  	    }
>  	  if (!handled_component_p (*refp))
>  	    break;
> @@ -891,6 +898,21 @@ aliasing_component_refs_p (tree ref1,
>  	{
>  	  poly_int64 offadj, sztmp, msztmp;
>  	  bool reverse;
> +
> +	  /* We assume that arrays can overlap by multiple of their elements
> +	     size as tested in gcc.dg/torture/alias-2.c.
> +	     This partial overlap happen only when both arrays are bases of
> +	     the access and not contained within another component ref.
> +	     To be safe we also assume partial overlap for VLAs.  */
> +	  if (TREE_CODE (TREE_TYPE (base1)) == ARRAY_TYPE
> +	      && (!TYPE_SIZE (TREE_TYPE (base1))
> +		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) != INTEGER_CST
> +		  || (*refp == base2 && !ref2_is_decl)))
> +	    {
> +	      ++alias_stats.aliasing_component_refs_p_may_alias;
> +	      return true;
> +	    }
> +
>  	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
>  	  offset2 -= offadj;
>  	  get_ref_base_and_extent (base1, &offadj, &sztmp, &msztmp, &reverse);
> @@ -922,8 +944,10 @@ aliasing_component_refs_p (tree ref1,
>  	  if (cmp == 0)
>  	    {
>  	      same_p1 = same_type_for_tbaa (TREE_TYPE (*refp), type2);
> -	      if (same_p1 != 0)
> +	      if (same_p1 == 1)
>  		break;
> +	      if (same_p1 == -1)
> +		maybe_match = true;
>  	    }
>  	  if (!handled_component_p (*refp))
>  	    break;
> @@ -934,6 +958,15 @@ aliasing_component_refs_p (tree ref1,
>  	  poly_int64 offadj, sztmp, msztmp;
>  	  bool reverse;
>  
> +	  if (TREE_CODE (TREE_TYPE (base2)) == ARRAY_TYPE
> +	      && (!TYPE_SIZE (TREE_TYPE (base2))
> +		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base2))) != INTEGER_CST
> +		  || (*refp == base1 && !ref2_is_decl)))
> +	    {
> +	      ++alias_stats.aliasing_component_refs_p_may_alias;
> +	      return true;
> +	    }
> +
>  	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
>  	  offset1 -= offadj;
>  	  get_ref_base_and_extent (base2, &offadj, &sztmp, &msztmp, &reverse);
> @@ -955,7 +988,7 @@ aliasing_component_refs_p (tree ref1,
>       paths do not overlap and thus accesses alias only if one path can be
>       continuation of another.  If we was not able to decide about equivalence,
>       we need to give up.  */
> -  if (same_p1 == -1 || same_p2 == -1)
> +  if (maybe_match)
>      return true;
>
>    /* If we have two type access paths B1.path1 and B2.path2 they may
> @@ -1338,10 +1371,17 @@ indirect_ref_may_alias_decl_p (tree ref1
>       For MEM_REFs we require that the component-ref offset we computed
>       is relative to the start of the type which we ensure by
>       comparing rvalue and access type and disregarding the constant
> -     pointer offset.  */
> +     pointer offset.
> +
> +     But avoid treating variable length arrays as "objects", instead assume they
> +     can overlap by an exact multiple of their element size.
> +     See gcc.dg/torture/alias-2.c.  */
>    if ((TREE_CODE (base1) != TARGET_MEM_REF
>         || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
> -      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1)
> +      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1
> +      && (TREE_CODE (TREE_TYPE (base1)) != ARRAY_TYPE
> +	  || (TYPE_SIZE (TREE_TYPE (base1))
> +	      && TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) == INTEGER_CST)))
>      return ranges_maybe_overlap_p (doffset1, max_size1, doffset2, max_size2);
>  
>    if (ref1 && ref2
> @@ -1434,6 +1474,16 @@ indirect_refs_may_alias_p (tree ref1 ATT
>        || base2_alias_set == 0)
>      return true;
>  
> +  /* Do type-based disambiguation.  */
> +  if (base1_alias_set != base2_alias_set
> +      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
> +    return false;
> +
> +  /* If either reference is view-converted, give up now.  */
> +  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
> +      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
> +    return true;
> +
>    /* If both references are through the same type, they do not alias
>       if the accesses do not overlap.  This does extra disambiguation
>       for mixed/pointer accesses but requires strict aliasing.  */
> @@ -1441,25 +1491,14 @@ indirect_refs_may_alias_p (tree ref1 ATT
>         || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
>        && (TREE_CODE (base2) != TARGET_MEM_REF
>  	  || (!TMR_INDEX (base2) && !TMR_INDEX2 (base2)))
> -      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1
> -      && same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) == 1
>        && same_type_for_tbaa (TREE_TYPE (ptrtype1),
>  			     TREE_TYPE (ptrtype2)) == 1
>        /* But avoid treating arrays as "objects", instead assume they
> -         can overlap by an exact multiple of their element size.  */
> +         can overlap by an exact multiple of their element size.
> +         See gcc.dg/torture/alias-2.c.  */
>        && TREE_CODE (TREE_TYPE (ptrtype1)) != ARRAY_TYPE)
>      return ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2);
>  
> -  /* Do type-based disambiguation.  */
> -  if (base1_alias_set != base2_alias_set
> -      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
> -    return false;
> -
> -  /* If either reference is view-converted, give up now.  */
> -  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
> -      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
> -    return true;
> -
>    if (ref1 && ref2
>        && nonoverlapping_component_refs_p (ref1, ref2))
>      return false;
>
Jan Hubicka June 6, 2019, 1:10 p.m. UTC | #3
> > This is more of an accident and there are cases where we do not trip across
> > this -1 and we disambiguate array accesses that seems unsafe to me.
> > 
> > With my change aliasing_component_refs_p finds the match of the
> > array types (type_same_for_tbaa_p returns 1 with non-LTO becuase they
> > have same canonical type) and disambiguates based on disjoint access ranges.
> > 
> > I have thus went ahead and updated all uses of type_same_for_tbaa_p to special
> > case arrays and reffer to this testcase (which seems odd and is only one in
> > testsuite): We can still do useful disambiguation if the array is not toplevel
> > reference or we know that the memory object is not bigger. This is tested by a
> > testcase I added and is quite frequent in real world code.
> > 
> > I also added check to give up on VLAs since I can not convicne myself that
> > this is safe: I think early inlining VLAs and streaming them may lead to
> > same VLA type have two different sizes at a time enabling it to partially
> > overlap.
> 
> OK - sorry for the delay.  The array stuff gets a bit ugly so
> we eventually want to do sth about that ...

Thanks, no prob with the delay - I apprechiate we could discuss these
things carefully as they are by no means obvious :)

I agree that the way overlapping arrays support is done current is ugly
and seems incomplete.  I hope to clean it up now and craft more
testcases.  It seems bit odd decision to suport the partial overlaps as
done by alias-2.c. I wonder how important it is in practice.

Honza
> 
> Thanks,
> Richard.
> 
> > 	* gcc.dg/lto/alias-access-path-2.0.c: New testcase.
> > 
> > 	* tree-ssa-alias.c (aliasing_component_refs_p): Do not give up
> > 	immediately after same_types_for_tbaa_p returns -1 and continue
> > 	looking for possible exact match; if matching types are arrays
> > 	watch for partial overlaps.
> > 	(indirect_ref_may_alias_decl_p): Watch for partial array overlaps.
> > 	(indirect_refs_may_alias_p): Do type based disambiguation first;
> > 	update comment.
> > Index: testsuite/g++.dg/lto/pr88130_0.C
> > ===================================================================
> > --- testsuite/g++.dg/lto/pr88130_0.C	(nonexistent)
> > +++ testsuite/g++.dg/lto/pr88130_0.C	(working copy)
> > @@ -0,0 +1,28 @@
> > +// { dg-lto-do link }
> > +// // { dg-lto-options { "-O2 -flto" } }
> > +// // { dg-extra-ld-options "-r -nostdlib" }
> > +class a {
> > +public:
> > +  static const long b = 1;
> > +};
> > +struct c {
> > +  enum d { e };
> > +};
> > +class C;
> > +class f {
> > +public:
> > +  f(c::d);
> > +  template <typename g> C operator<=(g);
> > +};
> > +class C {
> > +public:
> > +  template <typename h> void operator!=(h &);
> > +};
> > +void i() {
> > +  f j(c::e);
> > +  try {
> > +    j <= 0 != a::b;
> > +  } catch (...) {
> > +  }
> > +}
> > +
> > Index: testsuite/gcc.dg/lto/alias-access-path-2_0.c
> > ===================================================================
> > --- testsuite/gcc.dg/lto/alias-access-path-2_0.c	(nonexistent)
> > +++ testsuite/gcc.dg/lto/alias-access-path-2_0.c	(working copy)
> > @@ -0,0 +1,38 @@
> > +/* { dg-lto-do run } */
> > +/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */
> > +
> > +/* In this test the access patch orracle (aliasing_component_refs_p)
> > +   can disambiguage array[0] from array[1] by base+offset but it needs to be
> > +   able to find the common type and not give up by not being able to compare
> > +   types earlier.  */
> > +
> > +typedef int (*fnptr) ();
> > +
> > +__attribute__ ((used))
> > +struct a
> > +{
> > +  void *array[2];
> > +} a, *aptr = &a;
> > +
> > +__attribute__ ((used))
> > +struct b
> > +{
> > + struct a a;
> > +} *bptr;
> > +
> > +static void
> > +inline_me_late (int argc)
> > +{
> > +  if (argc == -1)
> > +    bptr->a.array[1] = bptr;
> > +}
> > +
> > +int
> > +main (int argc)
> > +{
> > +  aptr->array[0] = 0;
> > +  inline_me_late (argc);
> > +  if (!__builtin_constant_p (aptr->array[0] == 0))
> > +    __builtin_abort ();
> > +  return 0;
> > +}
> > Index: tree-ssa-alias.c
> > ===================================================================
> > --- tree-ssa-alias.c	(revision 271747)
> > +++ tree-ssa-alias.c	(working copy)
> > @@ -850,6 +850,7 @@ aliasing_component_refs_p (tree ref1,
> >    tree type1, type2;
> >    tree *refp;
> >    int same_p1 = 0, same_p2 = 0;
> > +  bool maybe_match = false;
> >  
> >    /* Choose bases and base types to search for.  */
> >    base1 = ref1;
> > @@ -880,8 +881,14 @@ aliasing_component_refs_p (tree ref1,
> >  	  if (cmp == 0)
> >  	    {
> >  	      same_p2 = same_type_for_tbaa (TREE_TYPE (*refp), type1);
> > -	      if (same_p2 != 0)
> > +	      if (same_p2 == 1)
> >  		break;
> > +	      /* In case we can't decide whether types are same try to
> > +		 continue looking for the exact match.
> > +		 Remember however that we possibly saw a match
> > +		 to bypass the access path continuations tests we do later.  */
> > +	      if (same_p2 == -1)
> > +		maybe_match = true;
> >  	    }
> >  	  if (!handled_component_p (*refp))
> >  	    break;
> > @@ -891,6 +898,21 @@ aliasing_component_refs_p (tree ref1,
> >  	{
> >  	  poly_int64 offadj, sztmp, msztmp;
> >  	  bool reverse;
> > +
> > +	  /* We assume that arrays can overlap by multiple of their elements
> > +	     size as tested in gcc.dg/torture/alias-2.c.
> > +	     This partial overlap happen only when both arrays are bases of
> > +	     the access and not contained within another component ref.
> > +	     To be safe we also assume partial overlap for VLAs.  */
> > +	  if (TREE_CODE (TREE_TYPE (base1)) == ARRAY_TYPE
> > +	      && (!TYPE_SIZE (TREE_TYPE (base1))
> > +		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) != INTEGER_CST
> > +		  || (*refp == base2 && !ref2_is_decl)))
> > +	    {
> > +	      ++alias_stats.aliasing_component_refs_p_may_alias;
> > +	      return true;
> > +	    }
> > +
> >  	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
> >  	  offset2 -= offadj;
> >  	  get_ref_base_and_extent (base1, &offadj, &sztmp, &msztmp, &reverse);
> > @@ -922,8 +944,10 @@ aliasing_component_refs_p (tree ref1,
> >  	  if (cmp == 0)
> >  	    {
> >  	      same_p1 = same_type_for_tbaa (TREE_TYPE (*refp), type2);
> > -	      if (same_p1 != 0)
> > +	      if (same_p1 == 1)
> >  		break;
> > +	      if (same_p1 == -1)
> > +		maybe_match = true;
> >  	    }
> >  	  if (!handled_component_p (*refp))
> >  	    break;
> > @@ -934,6 +958,15 @@ aliasing_component_refs_p (tree ref1,
> >  	  poly_int64 offadj, sztmp, msztmp;
> >  	  bool reverse;
> >  
> > +	  if (TREE_CODE (TREE_TYPE (base2)) == ARRAY_TYPE
> > +	      && (!TYPE_SIZE (TREE_TYPE (base2))
> > +		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base2))) != INTEGER_CST
> > +		  || (*refp == base1 && !ref2_is_decl)))
> > +	    {
> > +	      ++alias_stats.aliasing_component_refs_p_may_alias;
> > +	      return true;
> > +	    }
> > +
> >  	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
> >  	  offset1 -= offadj;
> >  	  get_ref_base_and_extent (base2, &offadj, &sztmp, &msztmp, &reverse);
> > @@ -955,7 +988,7 @@ aliasing_component_refs_p (tree ref1,
> >       paths do not overlap and thus accesses alias only if one path can be
> >       continuation of another.  If we was not able to decide about equivalence,
> >       we need to give up.  */
> > -  if (same_p1 == -1 || same_p2 == -1)
> > +  if (maybe_match)
> >      return true;
> >
> >    /* If we have two type access paths B1.path1 and B2.path2 they may
> > @@ -1338,10 +1371,17 @@ indirect_ref_may_alias_decl_p (tree ref1
> >       For MEM_REFs we require that the component-ref offset we computed
> >       is relative to the start of the type which we ensure by
> >       comparing rvalue and access type and disregarding the constant
> > -     pointer offset.  */
> > +     pointer offset.
> > +
> > +     But avoid treating variable length arrays as "objects", instead assume they
> > +     can overlap by an exact multiple of their element size.
> > +     See gcc.dg/torture/alias-2.c.  */
> >    if ((TREE_CODE (base1) != TARGET_MEM_REF
> >         || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
> > -      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1)
> > +      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1
> > +      && (TREE_CODE (TREE_TYPE (base1)) != ARRAY_TYPE
> > +	  || (TYPE_SIZE (TREE_TYPE (base1))
> > +	      && TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) == INTEGER_CST)))
> >      return ranges_maybe_overlap_p (doffset1, max_size1, doffset2, max_size2);
> >  
> >    if (ref1 && ref2
> > @@ -1434,6 +1474,16 @@ indirect_refs_may_alias_p (tree ref1 ATT
> >        || base2_alias_set == 0)
> >      return true;
> >  
> > +  /* Do type-based disambiguation.  */
> > +  if (base1_alias_set != base2_alias_set
> > +      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
> > +    return false;
> > +
> > +  /* If either reference is view-converted, give up now.  */
> > +  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
> > +      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
> > +    return true;
> > +
> >    /* If both references are through the same type, they do not alias
> >       if the accesses do not overlap.  This does extra disambiguation
> >       for mixed/pointer accesses but requires strict aliasing.  */
> > @@ -1441,25 +1491,14 @@ indirect_refs_may_alias_p (tree ref1 ATT
> >         || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
> >        && (TREE_CODE (base2) != TARGET_MEM_REF
> >  	  || (!TMR_INDEX (base2) && !TMR_INDEX2 (base2)))
> > -      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1
> > -      && same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) == 1
> >        && same_type_for_tbaa (TREE_TYPE (ptrtype1),
> >  			     TREE_TYPE (ptrtype2)) == 1
> >        /* But avoid treating arrays as "objects", instead assume they
> > -         can overlap by an exact multiple of their element size.  */
> > +         can overlap by an exact multiple of their element size.
> > +         See gcc.dg/torture/alias-2.c.  */
> >        && TREE_CODE (TREE_TYPE (ptrtype1)) != ARRAY_TYPE)
> >      return ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2);
> >  
> > -  /* Do type-based disambiguation.  */
> > -  if (base1_alias_set != base2_alias_set
> > -      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
> > -    return false;
> > -
> > -  /* If either reference is view-converted, give up now.  */
> > -  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
> > -      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
> > -    return true;
> > -
> >    if (ref1 && ref2
> >        && nonoverlapping_component_refs_p (ref1, ref2))
> >      return false;
> > 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany;
> GF: Felix Imendörffer, Mary Higgins, Sri Rasiah; HRB 21284 (AG Nürnberg)
Richard Biener June 6, 2019, 1:13 p.m. UTC | #4
On Thu, 6 Jun 2019, Jan Hubicka wrote:

> > > This is more of an accident and there are cases where we do not trip across
> > > this -1 and we disambiguate array accesses that seems unsafe to me.
> > > 
> > > With my change aliasing_component_refs_p finds the match of the
> > > array types (type_same_for_tbaa_p returns 1 with non-LTO becuase they
> > > have same canonical type) and disambiguates based on disjoint access ranges.
> > > 
> > > I have thus went ahead and updated all uses of type_same_for_tbaa_p to special
> > > case arrays and reffer to this testcase (which seems odd and is only one in
> > > testsuite): We can still do useful disambiguation if the array is not toplevel
> > > reference or we know that the memory object is not bigger. This is tested by a
> > > testcase I added and is quite frequent in real world code.
> > > 
> > > I also added check to give up on VLAs since I can not convicne myself that
> > > this is safe: I think early inlining VLAs and streaming them may lead to
> > > same VLA type have two different sizes at a time enabling it to partially
> > > overlap.
> > 
> > OK - sorry for the delay.  The array stuff gets a bit ugly so
> > we eventually want to do sth about that ...
> 
> Thanks, no prob with the delay - I apprechiate we could discuss these
> things carefully as they are by no means obvious :)
> 
> I agree that the way overlapping arrays support is done current is ugly
> and seems incomplete.  I hope to clean it up now and craft more
> testcases.  It seems bit odd decision to suport the partial overlaps as
> done by alias-2.c. I wonder how important it is in practice.

Probably not very, likely appears in the context of VLAs or
multi-dimensional arrays.  IIRC at some point I tried to
understand what the C standard says here but I don't remember
the outcome ;)  Then there's also ARRAY_RANGE_REF ...

Richard.

> Honza
> > 
> > Thanks,
> > Richard.
> > 
> > > 	* gcc.dg/lto/alias-access-path-2.0.c: New testcase.
> > > 
> > > 	* tree-ssa-alias.c (aliasing_component_refs_p): Do not give up
> > > 	immediately after same_types_for_tbaa_p returns -1 and continue
> > > 	looking for possible exact match; if matching types are arrays
> > > 	watch for partial overlaps.
> > > 	(indirect_ref_may_alias_decl_p): Watch for partial array overlaps.
> > > 	(indirect_refs_may_alias_p): Do type based disambiguation first;
> > > 	update comment.
> > > Index: testsuite/g++.dg/lto/pr88130_0.C
> > > ===================================================================
> > > --- testsuite/g++.dg/lto/pr88130_0.C	(nonexistent)
> > > +++ testsuite/g++.dg/lto/pr88130_0.C	(working copy)
> > > @@ -0,0 +1,28 @@
> > > +// { dg-lto-do link }
> > > +// // { dg-lto-options { "-O2 -flto" } }
> > > +// // { dg-extra-ld-options "-r -nostdlib" }
> > > +class a {
> > > +public:
> > > +  static const long b = 1;
> > > +};
> > > +struct c {
> > > +  enum d { e };
> > > +};
> > > +class C;
> > > +class f {
> > > +public:
> > > +  f(c::d);
> > > +  template <typename g> C operator<=(g);
> > > +};
> > > +class C {
> > > +public:
> > > +  template <typename h> void operator!=(h &);
> > > +};
> > > +void i() {
> > > +  f j(c::e);
> > > +  try {
> > > +    j <= 0 != a::b;
> > > +  } catch (...) {
> > > +  }
> > > +}
> > > +
> > > Index: testsuite/gcc.dg/lto/alias-access-path-2_0.c
> > > ===================================================================
> > > --- testsuite/gcc.dg/lto/alias-access-path-2_0.c	(nonexistent)
> > > +++ testsuite/gcc.dg/lto/alias-access-path-2_0.c	(working copy)
> > > @@ -0,0 +1,38 @@
> > > +/* { dg-lto-do run } */
> > > +/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */
> > > +
> > > +/* In this test the access patch orracle (aliasing_component_refs_p)
> > > +   can disambiguage array[0] from array[1] by base+offset but it needs to be
> > > +   able to find the common type and not give up by not being able to compare
> > > +   types earlier.  */
> > > +
> > > +typedef int (*fnptr) ();
> > > +
> > > +__attribute__ ((used))
> > > +struct a
> > > +{
> > > +  void *array[2];
> > > +} a, *aptr = &a;
> > > +
> > > +__attribute__ ((used))
> > > +struct b
> > > +{
> > > + struct a a;
> > > +} *bptr;
> > > +
> > > +static void
> > > +inline_me_late (int argc)
> > > +{
> > > +  if (argc == -1)
> > > +    bptr->a.array[1] = bptr;
> > > +}
> > > +
> > > +int
> > > +main (int argc)
> > > +{
> > > +  aptr->array[0] = 0;
> > > +  inline_me_late (argc);
> > > +  if (!__builtin_constant_p (aptr->array[0] == 0))
> > > +    __builtin_abort ();
> > > +  return 0;
> > > +}
> > > Index: tree-ssa-alias.c
> > > ===================================================================
> > > --- tree-ssa-alias.c	(revision 271747)
> > > +++ tree-ssa-alias.c	(working copy)
> > > @@ -850,6 +850,7 @@ aliasing_component_refs_p (tree ref1,
> > >    tree type1, type2;
> > >    tree *refp;
> > >    int same_p1 = 0, same_p2 = 0;
> > > +  bool maybe_match = false;
> > >  
> > >    /* Choose bases and base types to search for.  */
> > >    base1 = ref1;
> > > @@ -880,8 +881,14 @@ aliasing_component_refs_p (tree ref1,
> > >  	  if (cmp == 0)
> > >  	    {
> > >  	      same_p2 = same_type_for_tbaa (TREE_TYPE (*refp), type1);
> > > -	      if (same_p2 != 0)
> > > +	      if (same_p2 == 1)
> > >  		break;
> > > +	      /* In case we can't decide whether types are same try to
> > > +		 continue looking for the exact match.
> > > +		 Remember however that we possibly saw a match
> > > +		 to bypass the access path continuations tests we do later.  */
> > > +	      if (same_p2 == -1)
> > > +		maybe_match = true;
> > >  	    }
> > >  	  if (!handled_component_p (*refp))
> > >  	    break;
> > > @@ -891,6 +898,21 @@ aliasing_component_refs_p (tree ref1,
> > >  	{
> > >  	  poly_int64 offadj, sztmp, msztmp;
> > >  	  bool reverse;
> > > +
> > > +	  /* We assume that arrays can overlap by multiple of their elements
> > > +	     size as tested in gcc.dg/torture/alias-2.c.
> > > +	     This partial overlap happen only when both arrays are bases of
> > > +	     the access and not contained within another component ref.
> > > +	     To be safe we also assume partial overlap for VLAs.  */
> > > +	  if (TREE_CODE (TREE_TYPE (base1)) == ARRAY_TYPE
> > > +	      && (!TYPE_SIZE (TREE_TYPE (base1))
> > > +		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) != INTEGER_CST
> > > +		  || (*refp == base2 && !ref2_is_decl)))
> > > +	    {
> > > +	      ++alias_stats.aliasing_component_refs_p_may_alias;
> > > +	      return true;
> > > +	    }
> > > +
> > >  	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
> > >  	  offset2 -= offadj;
> > >  	  get_ref_base_and_extent (base1, &offadj, &sztmp, &msztmp, &reverse);
> > > @@ -922,8 +944,10 @@ aliasing_component_refs_p (tree ref1,
> > >  	  if (cmp == 0)
> > >  	    {
> > >  	      same_p1 = same_type_for_tbaa (TREE_TYPE (*refp), type2);
> > > -	      if (same_p1 != 0)
> > > +	      if (same_p1 == 1)
> > >  		break;
> > > +	      if (same_p1 == -1)
> > > +		maybe_match = true;
> > >  	    }
> > >  	  if (!handled_component_p (*refp))
> > >  	    break;
> > > @@ -934,6 +958,15 @@ aliasing_component_refs_p (tree ref1,
> > >  	  poly_int64 offadj, sztmp, msztmp;
> > >  	  bool reverse;
> > >  
> > > +	  if (TREE_CODE (TREE_TYPE (base2)) == ARRAY_TYPE
> > > +	      && (!TYPE_SIZE (TREE_TYPE (base2))
> > > +		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base2))) != INTEGER_CST
> > > +		  || (*refp == base1 && !ref2_is_decl)))
> > > +	    {
> > > +	      ++alias_stats.aliasing_component_refs_p_may_alias;
> > > +	      return true;
> > > +	    }
> > > +
> > >  	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
> > >  	  offset1 -= offadj;
> > >  	  get_ref_base_and_extent (base2, &offadj, &sztmp, &msztmp, &reverse);
> > > @@ -955,7 +988,7 @@ aliasing_component_refs_p (tree ref1,
> > >       paths do not overlap and thus accesses alias only if one path can be
> > >       continuation of another.  If we was not able to decide about equivalence,
> > >       we need to give up.  */
> > > -  if (same_p1 == -1 || same_p2 == -1)
> > > +  if (maybe_match)
> > >      return true;
> > >
> > >    /* If we have two type access paths B1.path1 and B2.path2 they may
> > > @@ -1338,10 +1371,17 @@ indirect_ref_may_alias_decl_p (tree ref1
> > >       For MEM_REFs we require that the component-ref offset we computed
> > >       is relative to the start of the type which we ensure by
> > >       comparing rvalue and access type and disregarding the constant
> > > -     pointer offset.  */
> > > +     pointer offset.
> > > +
> > > +     But avoid treating variable length arrays as "objects", instead assume they
> > > +     can overlap by an exact multiple of their element size.
> > > +     See gcc.dg/torture/alias-2.c.  */
> > >    if ((TREE_CODE (base1) != TARGET_MEM_REF
> > >         || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
> > > -      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1)
> > > +      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1
> > > +      && (TREE_CODE (TREE_TYPE (base1)) != ARRAY_TYPE
> > > +	  || (TYPE_SIZE (TREE_TYPE (base1))
> > > +	      && TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) == INTEGER_CST)))
> > >      return ranges_maybe_overlap_p (doffset1, max_size1, doffset2, max_size2);
> > >  
> > >    if (ref1 && ref2
> > > @@ -1434,6 +1474,16 @@ indirect_refs_may_alias_p (tree ref1 ATT
> > >        || base2_alias_set == 0)
> > >      return true;
> > >  
> > > +  /* Do type-based disambiguation.  */
> > > +  if (base1_alias_set != base2_alias_set
> > > +      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
> > > +    return false;
> > > +
> > > +  /* If either reference is view-converted, give up now.  */
> > > +  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
> > > +      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
> > > +    return true;
> > > +
> > >    /* If both references are through the same type, they do not alias
> > >       if the accesses do not overlap.  This does extra disambiguation
> > >       for mixed/pointer accesses but requires strict aliasing.  */
> > > @@ -1441,25 +1491,14 @@ indirect_refs_may_alias_p (tree ref1 ATT
> > >         || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
> > >        && (TREE_CODE (base2) != TARGET_MEM_REF
> > >  	  || (!TMR_INDEX (base2) && !TMR_INDEX2 (base2)))
> > > -      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1
> > > -      && same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) == 1
> > >        && same_type_for_tbaa (TREE_TYPE (ptrtype1),
> > >  			     TREE_TYPE (ptrtype2)) == 1
> > >        /* But avoid treating arrays as "objects", instead assume they
> > > -         can overlap by an exact multiple of their element size.  */
> > > +         can overlap by an exact multiple of their element size.
> > > +         See gcc.dg/torture/alias-2.c.  */
> > >        && TREE_CODE (TREE_TYPE (ptrtype1)) != ARRAY_TYPE)
> > >      return ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2);
> > >  
> > > -  /* Do type-based disambiguation.  */
> > > -  if (base1_alias_set != base2_alias_set
> > > -      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
> > > -    return false;
> > > -
> > > -  /* If either reference is view-converted, give up now.  */
> > > -  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
> > > -      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
> > > -    return true;
> > > -
> > >    if (ref1 && ref2
> > >        && nonoverlapping_component_refs_p (ref1, ref2))
> > >      return false;
> > > 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany;
> > GF: Felix Imendörffer, Mary Higgins, Sri Rasiah; HRB 21284 (AG Nürnberg)
> 
>
Richard Sandiford June 6, 2019, 5:02 p.m. UTC | #5
Richard Biener <rguenther@suse.de> writes:
> On Thu, 6 Jun 2019, Jan Hubicka wrote:
>
>> > > This is more of an accident and there are cases where we do not trip across
>> > > this -1 and we disambiguate array accesses that seems unsafe to me.
>> > > 
>> > > With my change aliasing_component_refs_p finds the match of the
>> > > array types (type_same_for_tbaa_p returns 1 with non-LTO becuase they
>> > > have same canonical type) and disambiguates based on disjoint access ranges.
>> > > 
>> > > I have thus went ahead and updated all uses of type_same_for_tbaa_p to special
>> > > case arrays and reffer to this testcase (which seems odd and is only one in
>> > > testsuite): We can still do useful disambiguation if the array is not toplevel
>> > > reference or we know that the memory object is not bigger. This is tested by a
>> > > testcase I added and is quite frequent in real world code.
>> > > 
>> > > I also added check to give up on VLAs since I can not convicne myself that
>> > > this is safe: I think early inlining VLAs and streaming them may lead to
>> > > same VLA type have two different sizes at a time enabling it to partially
>> > > overlap.
>> > 
>> > OK - sorry for the delay.  The array stuff gets a bit ugly so
>> > we eventually want to do sth about that ...
>> 
>> Thanks, no prob with the delay - I apprechiate we could discuss these
>> things carefully as they are by no means obvious :)
>> 
>> I agree that the way overlapping arrays support is done current is ugly
>> and seems incomplete.  I hope to clean it up now and craft more
>> testcases.  It seems bit odd decision to suport the partial overlaps as
>> done by alias-2.c. I wonder how important it is in practice.
>
> Probably not very, likely appears in the context of VLAs or
> multi-dimensional arrays.  IIRC at some point I tried to
> understand what the C standard says here but I don't remember
> the outcome ;)  Then there's also ARRAY_RANGE_REF ...

Dropping support for that would also allow cheaper runtime alias checks
in the vectoriser for some cases, via the DDR_COULD_BE_INDEPENDENT_P stuff.

Richard
diff mbox series

Patch

Index: testsuite/g++.dg/lto/pr88130_0.C
===================================================================
--- testsuite/g++.dg/lto/pr88130_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/pr88130_0.C	(working copy)
@@ -0,0 +1,28 @@ 
+// { dg-lto-do link }
+// // { dg-lto-options { "-O2 -flto" } }
+// // { dg-extra-ld-options "-r -nostdlib" }
+class a {
+public:
+  static const long b = 1;
+};
+struct c {
+  enum d { e };
+};
+class C;
+class f {
+public:
+  f(c::d);
+  template <typename g> C operator<=(g);
+};
+class C {
+public:
+  template <typename h> void operator!=(h &);
+};
+void i() {
+  f j(c::e);
+  try {
+    j <= 0 != a::b;
+  } catch (...) {
+  }
+}
+
Index: testsuite/gcc.dg/lto/alias-access-path-2_0.c
===================================================================
--- testsuite/gcc.dg/lto/alias-access-path-2_0.c	(nonexistent)
+++ testsuite/gcc.dg/lto/alias-access-path-2_0.c	(working copy)
@@ -0,0 +1,38 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */
+
+/* In this test the access patch orracle (aliasing_component_refs_p)
+   can disambiguage array[0] from array[1] by base+offset but it needs to be
+   able to find the common type and not give up by not being able to compare
+   types earlier.  */
+
+typedef int (*fnptr) ();
+
+__attribute__ ((used))
+struct a
+{
+  void *array[2];
+} a, *aptr = &a;
+
+__attribute__ ((used))
+struct b
+{
+ struct a a;
+} *bptr;
+
+static void
+inline_me_late (int argc)
+{
+  if (argc == -1)
+    bptr->a.array[1] = bptr;
+}
+
+int
+main (int argc)
+{
+  aptr->array[0] = 0;
+  inline_me_late (argc);
+  if (!__builtin_constant_p (aptr->array[0] == 0))
+    __builtin_abort ();
+  return 0;
+}
Index: tree-ssa-alias.c
===================================================================
--- tree-ssa-alias.c	(revision 271747)
+++ tree-ssa-alias.c	(working copy)
@@ -850,6 +850,7 @@  aliasing_component_refs_p (tree ref1,
   tree type1, type2;
   tree *refp;
   int same_p1 = 0, same_p2 = 0;
+  bool maybe_match = false;
 
   /* Choose bases and base types to search for.  */
   base1 = ref1;
@@ -880,8 +881,14 @@  aliasing_component_refs_p (tree ref1,
 	  if (cmp == 0)
 	    {
 	      same_p2 = same_type_for_tbaa (TREE_TYPE (*refp), type1);
-	      if (same_p2 != 0)
+	      if (same_p2 == 1)
 		break;
+	      /* In case we can't decide whether types are same try to
+		 continue looking for the exact match.
+		 Remember however that we possibly saw a match
+		 to bypass the access path continuations tests we do later.  */
+	      if (same_p2 == -1)
+		maybe_match = true;
 	    }
 	  if (!handled_component_p (*refp))
 	    break;
@@ -891,6 +898,21 @@  aliasing_component_refs_p (tree ref1,
 	{
 	  poly_int64 offadj, sztmp, msztmp;
 	  bool reverse;
+
+	  /* We assume that arrays can overlap by multiple of their elements
+	     size as tested in gcc.dg/torture/alias-2.c.
+	     This partial overlap happen only when both arrays are bases of
+	     the access and not contained within another component ref.
+	     To be safe we also assume partial overlap for VLAs.  */
+	  if (TREE_CODE (TREE_TYPE (base1)) == ARRAY_TYPE
+	      && (!TYPE_SIZE (TREE_TYPE (base1))
+		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) != INTEGER_CST
+		  || (*refp == base2 && !ref2_is_decl)))
+	    {
+	      ++alias_stats.aliasing_component_refs_p_may_alias;
+	      return true;
+	    }
+
 	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
 	  offset2 -= offadj;
 	  get_ref_base_and_extent (base1, &offadj, &sztmp, &msztmp, &reverse);
@@ -922,8 +944,10 @@  aliasing_component_refs_p (tree ref1,
 	  if (cmp == 0)
 	    {
 	      same_p1 = same_type_for_tbaa (TREE_TYPE (*refp), type2);
-	      if (same_p1 != 0)
+	      if (same_p1 == 1)
 		break;
+	      if (same_p1 == -1)
+		maybe_match = true;
 	    }
 	  if (!handled_component_p (*refp))
 	    break;
@@ -934,6 +958,15 @@  aliasing_component_refs_p (tree ref1,
 	  poly_int64 offadj, sztmp, msztmp;
 	  bool reverse;
 
+	  if (TREE_CODE (TREE_TYPE (base2)) == ARRAY_TYPE
+	      && (!TYPE_SIZE (TREE_TYPE (base2))
+		  || TREE_CODE (TYPE_SIZE (TREE_TYPE (base2))) != INTEGER_CST
+		  || (*refp == base1 && !ref2_is_decl)))
+	    {
+	      ++alias_stats.aliasing_component_refs_p_may_alias;
+	      return true;
+	    }
+
 	  get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp, &reverse);
 	  offset1 -= offadj;
 	  get_ref_base_and_extent (base2, &offadj, &sztmp, &msztmp, &reverse);
@@ -955,7 +988,7 @@  aliasing_component_refs_p (tree ref1,
      paths do not overlap and thus accesses alias only if one path can be
      continuation of another.  If we was not able to decide about equivalence,
      we need to give up.  */
-  if (same_p1 == -1 || same_p2 == -1)
+  if (maybe_match)
     return true;
 
   /* If we have two type access paths B1.path1 and B2.path2 they may
@@ -1338,10 +1371,17 @@  indirect_ref_may_alias_decl_p (tree ref1
      For MEM_REFs we require that the component-ref offset we computed
      is relative to the start of the type which we ensure by
      comparing rvalue and access type and disregarding the constant
-     pointer offset.  */
+     pointer offset.
+
+     But avoid treating variable length arrays as "objects", instead assume they
+     can overlap by an exact multiple of their element size.
+     See gcc.dg/torture/alias-2.c.  */
   if ((TREE_CODE (base1) != TARGET_MEM_REF
        || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
-      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1)
+      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (dbase2)) == 1
+      && (TREE_CODE (TREE_TYPE (base1)) != ARRAY_TYPE
+	  || (TYPE_SIZE (TREE_TYPE (base1))
+	      && TREE_CODE (TYPE_SIZE (TREE_TYPE (base1))) == INTEGER_CST)))
     return ranges_maybe_overlap_p (doffset1, max_size1, doffset2, max_size2);
 
   if (ref1 && ref2
@@ -1434,6 +1474,16 @@  indirect_refs_may_alias_p (tree ref1 ATT
       || base2_alias_set == 0)
     return true;
 
+  /* Do type-based disambiguation.  */
+  if (base1_alias_set != base2_alias_set
+      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
+    return false;
+
+  /* If either reference is view-converted, give up now.  */
+  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
+      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
+    return true;
+
   /* If both references are through the same type, they do not alias
      if the accesses do not overlap.  This does extra disambiguation
      for mixed/pointer accesses but requires strict aliasing.  */
@@ -1441,25 +1491,14 @@  indirect_refs_may_alias_p (tree ref1 ATT
        || (!TMR_INDEX (base1) && !TMR_INDEX2 (base1)))
       && (TREE_CODE (base2) != TARGET_MEM_REF
 	  || (!TMR_INDEX (base2) && !TMR_INDEX2 (base2)))
-      && same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) == 1
-      && same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) == 1
       && same_type_for_tbaa (TREE_TYPE (ptrtype1),
 			     TREE_TYPE (ptrtype2)) == 1
       /* But avoid treating arrays as "objects", instead assume they
-         can overlap by an exact multiple of their element size.  */
+         can overlap by an exact multiple of their element size.
+         See gcc.dg/torture/alias-2.c.  */
       && TREE_CODE (TREE_TYPE (ptrtype1)) != ARRAY_TYPE)
     return ranges_maybe_overlap_p (offset1, max_size1, offset2, max_size2);
 
-  /* Do type-based disambiguation.  */
-  if (base1_alias_set != base2_alias_set
-      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
-    return false;
-
-  /* If either reference is view-converted, give up now.  */
-  if (same_type_for_tbaa (TREE_TYPE (base1), TREE_TYPE (ptrtype1)) != 1
-      || same_type_for_tbaa (TREE_TYPE (base2), TREE_TYPE (ptrtype2)) != 1)
-    return true;
-
   if (ref1 && ref2
       && nonoverlapping_component_refs_p (ref1, ref2))
     return false;