Make alias sets of ODR types more precise

Message ID 20190716085643.wnqot6j7dkcp2mva@kam.mff.cuni.cz
State New
Headers show
Series
  • Make alias sets of ODR types more precise
Related show

Commit Message

Jan Hubicka July 16, 2019, 8:56 a.m.
Hi,
this is the hunk we omitted from the original patch enabling TBAA for
ODR types.  Currently record_component_aliases record all pointers as
void *.  This is because canonical type merging handles them this way
and thus it may merge for example

strut a { int *ptr;};

and 

struct b { short *ptr;};

into one canonical type.  The alias set of that canonical type then must
conflict with both int * and short * which we do by globing it to void *
which conflict with everything.

For ODR types where we do canonical types based on their name we however
assign differnt TYPE_CANONICAL to each of them.  Thanks to this we can
make alias set to contain int * or short * respectively.


Bootstrapped/regtested x86_64-linux, OK?

Honza
	* alias.c (record_component_aliases): Do not simplify pointed-to
	types of ODR types 
	* testsuite/g++.dg/lto/alias-4_0.C

Comments

Richard Biener July 17, 2019, 10:39 a.m. | #1
On Tue, 16 Jul 2019, Jan Hubicka wrote:

> Hi,

> this is the hunk we omitted from the original patch enabling TBAA for

> ODR types.  Currently record_component_aliases record all pointers as

> void *.  This is because canonical type merging handles them this way

> and thus it may merge for example

> 

> strut a { int *ptr;};

> 

> and 

> 

> struct b { short *ptr;};

> 

> into one canonical type.  The alias set of that canonical type then must

> conflict with both int * and short * which we do by globing it to void *

> which conflict with everything.

> 

> For ODR types where we do canonical types based on their name we however

> assign differnt TYPE_CANONICAL to each of them.  Thanks to this we can

> make alias set to contain int * or short * respectively.

> 

> 

> Bootstrapped/regtested x86_64-linux, OK?


OK.

Richard.

> Honza

> 	* alias.c (record_component_aliases): Do not simplify pointed-to

> 	types of ODR types 

> 	* testsuite/g++.dg/lto/alias-4_0.C

> Index: alias.c

> ===================================================================

> --- alias.c	(revision 273478)

> +++ alias.c	(working copy)

> @@ -1202,47 +1202,52 @@ record_component_aliases (tree type)

>      case RECORD_TYPE:

>      case UNION_TYPE:

>      case QUAL_UNION_TYPE:

> -      for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field))

> -	if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field))

> -	  {

> -	    /* LTO type merging does not make any difference between 

> -	       component pointer types.  We may have

> -

> -	       struct foo {int *a;};

> -

> -	       as TYPE_CANONICAL of 

> -

> -	       struct bar {float *a;};

> -

> -	       Because accesses to int * and float * do not alias, we would get

> -	       false negative when accessing the same memory location by

> -	       float ** and bar *. We thus record the canonical type as:

> -

> -	       struct {void *a;};

> -

> -	       void * is special cased and works as a universal pointer type.

> -	       Accesses to it conflicts with accesses to any other pointer

> -	       type.  */

> -	    tree t = TREE_TYPE (field);

> -	    if (in_lto_p)

> -	      {

> -		/* VECTOR_TYPE and ARRAY_TYPE share the alias set with their

> -		   element type and that type has to be normalized to void *,

> -		   too, in the case it is a pointer. */

> -		while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t))

> -		  {

> -		    gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t));

> -		    t = TREE_TYPE (t);

> -		  }

> -		if (POINTER_TYPE_P (t))

> -		  t = ptr_type_node;

> -		else if (flag_checking)

> -		  gcc_checking_assert (get_alias_set (t)

> -				       == get_alias_set (TREE_TYPE (field)));

> -	      }

> -

> -	    record_alias_subset (superset, get_alias_set (t));

> -	  }

> +      {

> +	/* LTO non-ODR type merging does not make any difference between 

> +	   component pointer types.  We may have

> +

> +	   struct foo {int *a;};

> +

> +	   as TYPE_CANONICAL of 

> +

> +	   struct bar {float *a;};

> +

> +	   Because accesses to int * and float * do not alias, we would get

> +	   false negative when accessing the same memory location by

> +	   float ** and bar *. We thus record the canonical type as:

> +

> +	   struct {void *a;};

> +

> +	   void * is special cased and works as a universal pointer type.

> +	   Accesses to it conflicts with accesses to any other pointer

> +	   type.  */

> +	bool void_pointers = in_lto_p

> +			     && (!odr_type_p (type)

> +				 || !odr_based_tbaa_p (type));

> +	for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field))

> +	  if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field))

> +	    {

> +	      tree t = TREE_TYPE (field);

> +	      if (void_pointers)

> +		{

> +		  /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their

> +		     element type and that type has to be normalized to void *,

> +		     too, in the case it is a pointer. */

> +		  while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t))

> +		    {

> +		      gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t));

> +		      t = TREE_TYPE (t);

> +		    }

> +		  if (POINTER_TYPE_P (t))

> +		    t = ptr_type_node;

> +		  else if (flag_checking)

> +		    gcc_checking_assert (get_alias_set (t)

> +					 == get_alias_set (TREE_TYPE (field)));

> +		}

> +

> +	      record_alias_subset (superset, get_alias_set (t));

> +	    }

> +      }

>        break;

>  

>      case COMPLEX_TYPE:

> 

> Index: testsuite/g++.dg/lto/alias-4_0.C

> ===================================================================

> --- testsuite/g++.dg/lto/alias-4_0.C	(nonexistent)

> +++ testsuite/g++.dg/lto/alias-4_0.C	(working copy)

> @@ -0,0 +1,31 @@

> +/* { dg-lto-do run } */

> +/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */

> +__attribute__ ((used))

> +short *ptr_init, **ptr=&ptr_init;

> +

> +__attribute__ ((used))

> +struct a {

> +  int *aptr;

> +} a, *aptr=&a;

> +

> +void

> +write_ptr ()

> +{

> +  *aptr = a;

> +}

> +

> +__attribute__ ((used))

> +void

> +test ()

> +{

> +  *ptr = (short int *)0;

> +  write_ptr ();

> +  if (!__builtin_constant_p (*ptr == (void *)0))

> +    __builtin_abort ();

> +}

> +int

> +main()

> +{

> +  test ();

> +  return 0;

> +}

> 


-- 
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)

Patch

Index: alias.c
===================================================================
--- alias.c	(revision 273478)
+++ alias.c	(working copy)
@@ -1202,47 +1202,52 @@  record_component_aliases (tree type)
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field))
-	if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field))
-	  {
-	    /* LTO type merging does not make any difference between 
-	       component pointer types.  We may have
-
-	       struct foo {int *a;};
-
-	       as TYPE_CANONICAL of 
-
-	       struct bar {float *a;};
-
-	       Because accesses to int * and float * do not alias, we would get
-	       false negative when accessing the same memory location by
-	       float ** and bar *. We thus record the canonical type as:
-
-	       struct {void *a;};
-
-	       void * is special cased and works as a universal pointer type.
-	       Accesses to it conflicts with accesses to any other pointer
-	       type.  */
-	    tree t = TREE_TYPE (field);
-	    if (in_lto_p)
-	      {
-		/* VECTOR_TYPE and ARRAY_TYPE share the alias set with their
-		   element type and that type has to be normalized to void *,
-		   too, in the case it is a pointer. */
-		while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t))
-		  {
-		    gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t));
-		    t = TREE_TYPE (t);
-		  }
-		if (POINTER_TYPE_P (t))
-		  t = ptr_type_node;
-		else if (flag_checking)
-		  gcc_checking_assert (get_alias_set (t)
-				       == get_alias_set (TREE_TYPE (field)));
-	      }
-
-	    record_alias_subset (superset, get_alias_set (t));
-	  }
+      {
+	/* LTO non-ODR type merging does not make any difference between 
+	   component pointer types.  We may have
+
+	   struct foo {int *a;};
+
+	   as TYPE_CANONICAL of 
+
+	   struct bar {float *a;};
+
+	   Because accesses to int * and float * do not alias, we would get
+	   false negative when accessing the same memory location by
+	   float ** and bar *. We thus record the canonical type as:
+
+	   struct {void *a;};
+
+	   void * is special cased and works as a universal pointer type.
+	   Accesses to it conflicts with accesses to any other pointer
+	   type.  */
+	bool void_pointers = in_lto_p
+			     && (!odr_type_p (type)
+				 || !odr_based_tbaa_p (type));
+	for (field = TYPE_FIELDS (type); field != 0; field = DECL_CHAIN (field))
+	  if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field))
+	    {
+	      tree t = TREE_TYPE (field);
+	      if (void_pointers)
+		{
+		  /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their
+		     element type and that type has to be normalized to void *,
+		     too, in the case it is a pointer. */
+		  while (!canonical_type_used_p (t) && !POINTER_TYPE_P (t))
+		    {
+		      gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t));
+		      t = TREE_TYPE (t);
+		    }
+		  if (POINTER_TYPE_P (t))
+		    t = ptr_type_node;
+		  else if (flag_checking)
+		    gcc_checking_assert (get_alias_set (t)
+					 == get_alias_set (TREE_TYPE (field)));
+		}
+
+	      record_alias_subset (superset, get_alias_set (t));
+	    }
+      }
       break;
 
     case COMPLEX_TYPE:

Index: testsuite/g++.dg/lto/alias-4_0.C
===================================================================
--- testsuite/g++.dg/lto/alias-4_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/alias-4_0.C	(working copy)
@@ -0,0 +1,31 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { { -O3 -flto -fno-early-inlining } } } */
+__attribute__ ((used))
+short *ptr_init, **ptr=&ptr_init;
+
+__attribute__ ((used))
+struct a {
+  int *aptr;
+} a, *aptr=&a;
+
+void
+write_ptr ()
+{
+  *aptr = a;
+}
+
+__attribute__ ((used))
+void
+test ()
+{
+  *ptr = (short int *)0;
+  write_ptr ();
+  if (!__builtin_constant_p (*ptr == (void *)0))
+    __builtin_abort ();
+}
+int
+main()
+{
+  test ();
+  return 0;
+}