On Mon, 23 Nov 2015, Jan Hubicka wrote:

> Hi,
> here is updated patch which I finally comitted today.  It addresses all the 
> comments
> and also fixes one nasty bug that really cost me a lot of time to understand. 
> 
> +       /* 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.  */
> 
> This problem manifested itself only as a lto-bootstrap miscompare on 32bit
> build and I spent a lot of time localizing the wrong code since it reproduces
> only in quite large programs where we get conficts in canonical type merging
> like this.
> 
> The patch thus updates record_component_aliases to substitute 
> void_ptr_type for all pointer types. I re-did the stats.  Now the 
> improvement on dealII is 14% that is quite a bit lower than earlier, but 
> still substantial.  Since we have voidptr globing counter, I know that 
> the number of disambiguations would go at least 19% up if we did not do 
> it.

Please in future leave patches for review again if you do such
big changes before committing...

I don't understand why we need this (testcase?) because get_alias_set ()
is supposed to do the alias-set of pointer globbing for us.

Thanks,
Richard.

> THere is a lot of low hanging fruit in that area now, but the real 
> solution is to track types that needs to be merge by fortran rules and 
> don't do all this fancy globing for C/C++ types.  I will open branch for 
> IPA work and try to prepare this for next stage 1.
> 
> bootstrapped/regtested x86_64-linux and ppc64-linux, earlier version tested 
> on i386-linux
> and also on some bigger apps, committed
> 
> Note that we still have bootstrap miscompare with LTO build and 
> --disable-checking,
> I am looking for that now.  Additoinally after fixing the ICEs preventing us 
> to build
> the gnat1 binary, gnat1 aborts. Both these are independent of the patch.
> 
> Honza
>       * 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.
> Index: tree.c
> ===================================================================
> --- tree.c    (revision 230714)
> +++ tree.c    (working copy)
> @@ -7919,7 +7919,8 @@ build_pointer_type_for_mode (tree to_typ
>    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_t
>    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 (cons
>     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 (con
>             || (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));
> Index: lto/lto.c
> ===================================================================
> --- lto/lto.c (revision 230714)
> +++ lto/lto.c (working copy)
> @@ -388,8 +388,13 @@ iterative_hash_canonical_type (tree type
>  
>    /* 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
>  {
>    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
>  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: alias.c
> ===================================================================
> --- alias.c   (revision 230714)
> +++ alias.c   (working copy)
> @@ -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:
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to