lto.c (iterative_hash_canonical_type): Always recurse for pointers.
authorJan Hubicka <hubicka@ucw.cz>
Sat, 21 Nov 2015 23:59:49 +0000 (00:59 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 21 Nov 2015 23:59:49 +0000 (23:59 +0000)
* lto.c (iterative_hash_canonical_type): Always recurse for pointers.
(gimple_register_canonical_type_1): Check that pointers do not get
canonical types.
(gimple_register_canonical_type): Do not register pointers.

* tree.c (build_pointer_type_for_mode,build_reference_type_for_mode):
In LTO we do not compute TYPE_CANONICAL of pointers.
(gimple_canonical_types_compatible_p): Improve coments; sanity check
that pointers do not have canonical type that would make us believe
they are different.
* alias.c (get_alias_set): Do structural type equality on pointers;
enable pointer path for LTO; also glob pointer to vector with pointer
to vector element; glob pointers and references for LTO; do more strict
sanity checking about build_pointer_type returning the canonical type
which is also the main variant.
(record_component_aliases): When component type is pointer and we
do LTO; record void_type_node alias set.

From-SVN: r230715

gcc/ChangeLog
gcc/alias.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/tree.c

index ee27e99..00db0ba 100644 (file)
@@ -1,3 +1,18 @@
+2015-11-21  Jan Hubicka  <hubicka@ucw.cz>
+
+       * tree.c (build_pointer_type_for_mode,build_reference_type_for_mode):
+       In LTO we do not compute TYPE_CANONICAL of pointers.
+       (gimple_canonical_types_compatible_p): Improve coments; sanity check
+       that pointers do not have canonical type that would make us believe
+       they are different.
+       * alias.c (get_alias_set): Do structural type equality on pointers;
+       enable pointer path for LTO; also glob pointer to vector with pointer
+       to vector element; glob pointers and references for LTO; do more strict
+       sanity checking about build_pointer_type returning the canonical type
+       which is also the main variant.
+       (record_component_aliases): When component type is pointer and we
+       do LTO; record void_type_node alias set.
+
 2015-11-21  Nathan Sidwell  <nathan@acm.org>
 
        * config/nvptx/nvptx.md (clz<mode>2): Use operand 1 for type.
index 42605c2..f3f7986 100644 (file)
@@ -869,13 +869,23 @@ get_alias_set (tree t)
       set = lang_hooks.get_alias_set (t);
       if (set != -1)
        return set;
-      return 0;
+      /* Handle structure type equality for pointer types.  This is easy
+        to do, because the code bellow ignore canonical types on these anyway.
+        This is important for LTO, where TYPE_CANONICAL for pointers can not
+        be meaningfuly computed by the frotnend.  */
+      if (!POINTER_TYPE_P (t))
+       {
+         /* In LTO we set canonical types for all types where it makes
+            sense to do so.  Double check we did not miss some type.  */
+         gcc_checking_assert (!in_lto_p || !type_with_alias_set_p (t));
+          return 0;
+       }
+    }
+  else
+    {
+      t = TYPE_CANONICAL (t);
+      gcc_checking_assert (!TYPE_STRUCTURAL_EQUALITY_P (t));
     }
-
-  t = TYPE_CANONICAL (t);
-
-  /* The canonical type should not require structural equality checks.  */
-  gcc_checking_assert (!TYPE_STRUCTURAL_EQUALITY_P (t));
 
   /* If this is a type with a known alias set, return it.  */
   if (TYPE_ALIAS_SET_KNOWN_P (t))
@@ -952,20 +962,23 @@ get_alias_set (tree t)
      ptr_type_node but that is a bad idea, because it prevents disabiguations
      in between pointers.  For Firefox this accounts about 20% of all
      disambiguations in the program.  */
-  else if (POINTER_TYPE_P (t) && t != ptr_type_node && !in_lto_p)
+  else if (POINTER_TYPE_P (t) && t != ptr_type_node)
     {
       tree p;
       auto_vec <bool, 8> reference;
 
       /* Unnest all pointers and references.
-         We also want to make pointer to array equivalent to pointer to its
-         element. So skip all array types, too.  */
+        We also want to make pointer to array/vector equivalent to pointer to
+        its element (see the reasoning above). Skip all those types, too.  */
       for (p = t; POINTER_TYPE_P (p)
-          || (TREE_CODE (p) == ARRAY_TYPE && !TYPE_NONALIASED_COMPONENT (p));
+          || (TREE_CODE (p) == ARRAY_TYPE && !TYPE_NONALIASED_COMPONENT (p))
+          || TREE_CODE (p) == VECTOR_TYPE;
           p = TREE_TYPE (p))
        {
          if (TREE_CODE (p) == REFERENCE_TYPE)
-           reference.safe_push (true);
+           /* In LTO we want languages that use references to be compatible
+              with languages that use pointers.  */
+           reference.safe_push (true && !in_lto_p);
          if (TREE_CODE (p) == POINTER_TYPE)
            reference.safe_push (false);
        }
@@ -981,7 +994,7 @@ get_alias_set (tree t)
        set = get_alias_set (ptr_type_node);
       else
        {
-         /* Rebuild pointer type from starting from canonical types using
+         /* Rebuild pointer type starting from canonical types using
             unqualified pointers and references only.  This way all such
             pointers will have the same alias set and will conflict with
             each other.
@@ -998,9 +1011,15 @@ get_alias_set (tree t)
                p = build_reference_type (p);
              else
                p = build_pointer_type (p);
-             p = TYPE_CANONICAL (TYPE_MAIN_VARIANT (p));
+             gcc_checking_assert (p == TYPE_MAIN_VARIANT (p));
+             /* build_pointer_type should always return the canonical type.
+                For LTO TYPE_CANOINCAL may be NULL, because we do not compute
+                them.  Be sure that frontends do not glob canonical types of
+                pointers in unexpected way and that p == TYPE_CANONICAL (p)
+                in all other cases.  */
+             gcc_checking_assert (!TYPE_CANONICAL (p)
+                                  || p == TYPE_CANONICAL (p));
            }
-          gcc_checking_assert (TYPE_CANONICAL (p) == p);
 
          /* Assign the alias set to both p and t.
             We can not call get_alias_set (p) here as that would trigger
@@ -1015,11 +1034,12 @@ get_alias_set (tree t)
            }
        }
     }
-  /* In LTO the rules above needs to be part of canonical type machinery.
-     For now just punt.  */
-  else if (POINTER_TYPE_P (t)
-          && t != TYPE_CANONICAL (ptr_type_node) && in_lto_p)
-    set = get_alias_set (TYPE_CANONICAL (ptr_type_node));
+  /* Alias set of ptr_type_node is special and serve as universal pointer which
+     is TBAA compatible with every other pointer type.  Be sure we have the
+     alias set built even for LTO which otherwise keeps all TYPE_CANONICAL
+     of pointer types NULL.  */
+  else if (t == ptr_type_node)
+    set = new_alias_set ();
 
   /* Otherwise make a new alias set for this type.  */
   else
@@ -1155,7 +1175,42 @@ record_component_aliases (tree 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))
-         record_alias_subset (superset, get_alias_set (TREE_TYPE (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 ((TREE_CODE (t) == ARRAY_TYPE
+                       && (!COMPLETE_TYPE_P (t)
+                           || TYPE_NONALIASED_COMPONENT (t)))
+                      || TREE_CODE (t) == VECTOR_TYPE)
+                 t = TREE_TYPE (t);
+               if (POINTER_TYPE_P (t))
+                 t = ptr_type_node;
+             }
+          
+           record_alias_subset (superset, get_alias_set (t));
+         }
       break;
 
     case COMPLEX_TYPE:
index 49adea6..4105337 100644 (file)
@@ -1,4 +1,11 @@
-2015-11-11  Jan Hubicka  <hubicka@ucw.cz>
+2015-11-21  Jan Hubicka  <hubicka@ucw.cz>
+
+       * lto.c (iterative_hash_canonical_type): Always recurse for pointers.
+       (gimple_register_canonical_type_1): Check that pointers do not get
+       canonical types.
+       (gimple_register_canonical_type): Do not register pointers.
+
+2015-11-21  Jan Hubicka  <hubicka@ucw.cz>
 
        * lto-symtab.c (warn_type_compatibility_p): Do not set ODR mismatch
        flag for types that are not ODR; fix loop walking parameters.
index 36138e8..2661491 100644 (file)
@@ -388,8 +388,13 @@ iterative_hash_canonical_type (tree type, inchash::hash &hstate)
 
   /* All type variants have same TYPE_CANONICAL.  */
   type = TYPE_MAIN_VARIANT (type);
+
+  /* We do not compute TYPE_CANONICAl of POINTER_TYPE because the aliasing
+     code never use it anyway.  */
+  if (POINTER_TYPE_P (type))
+    v = hash_canonical_type (type);
   /* An already processed type.  */
-  if (TYPE_CANONICAL (type))
+  else if (TYPE_CANONICAL (type))
     {
       type = TYPE_CANONICAL (type);
       v = gimple_canonical_type_hash (type);
@@ -437,7 +442,9 @@ gimple_register_canonical_type_1 (tree t, hashval_t hash)
 {
   void **slot;
 
-  gcc_checking_assert (TYPE_P (t) && !TYPE_CANONICAL (t));
+  gcc_checking_assert (TYPE_P (t) && !TYPE_CANONICAL (t)
+                      && type_with_alias_set_p (t)
+                      && !POINTER_TYPE_P (t));
 
   slot = htab_find_slot_with_hash (gimple_canonical_types, t, hash, INSERT);
   if (*slot)
@@ -470,7 +477,7 @@ gimple_register_canonical_type_1 (tree t, hashval_t hash)
 static void
 gimple_register_canonical_type (tree t)
 {
-  if (TYPE_CANONICAL (t) || !type_with_alias_set_p (t))
+  if (TYPE_CANONICAL (t) || !type_with_alias_set_p (t) || POINTER_TYPE_P (t))
     return;
 
   /* Canonical types are same among all complete variants.  */
index d5a71a3..779fe93 100644 (file)
@@ -7919,7 +7919,8 @@ build_pointer_type_for_mode (tree to_type, machine_mode mode,
   TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type);
   TYPE_POINTER_TO (to_type) = t;
 
-  if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
+  /* During LTO we do not set TYPE_CANONICAL of pointers and references.  */
+  if (TYPE_STRUCTURAL_EQUALITY_P (to_type) || in_lto_p)
     SET_TYPE_STRUCTURAL_EQUALITY (t);
   else if (TYPE_CANONICAL (to_type) != to_type || could_alias)
     TYPE_CANONICAL (t)
@@ -7987,7 +7988,8 @@ build_reference_type_for_mode (tree to_type, machine_mode mode,
   TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
   TYPE_REFERENCE_TO (to_type) = t;
 
-  if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
+  /* During LTO we do not set TYPE_CANONICAL of pointers and references.  */
+  if (TYPE_STRUCTURAL_EQUALITY_P (to_type) || in_lto_p)
     SET_TYPE_STRUCTURAL_EQUALITY (t);
   else if (TYPE_CANONICAL (to_type) != to_type || could_alias)
     TYPE_CANONICAL (t)
@@ -13224,7 +13226,9 @@ type_with_interoperable_signedness (const_tree type)
    TBAA is concerned.  
    This function is used both by lto.c canonical type merging and by the
    verifier.  If TRUST_TYPE_CANONICAL we do not look into structure of types
-   that have TYPE_CANONICAL defined and assume them equivalent.  */
+   that have TYPE_CANONICAL defined and assume them equivalent.  This is useful
+   only for LTO because only in these cases TYPE_CANONICAL equivalence
+   correspond to one defined by gimple_canonical_types_compatible_p.  */
 
 bool
 gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
@@ -13265,9 +13269,19 @@ gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
              || (type_with_alias_set_p (t1) && type_with_alias_set_p (t2)));
   /* If the types have been previously registered and found equal
      they still are.  */
+
   if (TYPE_CANONICAL (t1) && TYPE_CANONICAL (t2)
       && trust_type_canonical)
-    return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+    {
+      /* Do not use TYPE_CANONICAL of pointer types.  For LTO streamed types
+        they are always NULL, but they are set to non-NULL for types
+        constructed by build_pointer_type and variants.  In this case the
+        TYPE_CANONICAL is more fine grained than the equivalnce we test (where
+        all pointers are considered equal.  Be sure to not return false
+        negatives.  */
+      gcc_checking_assert (!POINTER_TYPE_P (t1) && !POINTER_TYPE_P (t2));
+      return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+    }
 
   /* Can't be the same type if the types don't have the same code.  */
   enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));