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

Reply via email to