Nice fix! I noticed that this patch is already combined to the trunk.

Thank you very much, Richard!



Cong

On Tue, Sep 24, 2013 at 1:49 AM, Richard Biener <rguent...@suse.de> wrote:
> On Tue, 24 Sep 2013, Richard Biener wrote:
>
>> On Tue, 24 Sep 2013, Jakub Jelinek wrote:
>>
>> > Hi!
>> >
>> > On Mon, Sep 23, 2013 at 05:26:13PM -0700, Cong Hou wrote:
>> >
>> > Missing ChangeLog entry.
>> >
>> > > --- gcc/testsuite/gcc.dg/alias-14.c (revision 0)
>> > > +++ gcc/testsuite/gcc.dg/alias-14.c (revision 0)
>> >
>> > Vectorizer tests should go into gcc.dg/vect/ instead, or, if they are
>> > for a single target (but there is no reason why this should be a single
>> > target), into gcc.target/<target>/.
>> >
>> > > --- gcc/fold-const.c (revision 202662)
>> > > +++ gcc/fold-const.c (working copy)
>> > > @@ -2693,8 +2693,9 @@ operand_equal_p (const_tree arg0, const_
>> > >         && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
>> > >     TYPE_SIZE (TREE_TYPE (arg1)), flags)))
>> > >    && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
>> > > -  && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1)))
>> > > -      == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 1))))
>> > > +  && types_compatible_p (
>> > > +       TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1))),
>> > > +       TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 1))))
>> > >    && OP_SAME (0) && OP_SAME (1));
>> >
>> > This looks wrong.  types_compatible_p will happily return true say
>> > for unsigned long and unsigned long long types on x86_64, because
>> > they are both integral types with the same precision, but the second
>> > argument of MEM_REF contains aliasing information, where the distinction
>> > between the two is important.
>> > So, while == comparison of main variant is too strict, types_compatible_p
>> > is too weak, so I guess you need to write a new predicate that will either
>> > handle the == and a few special cases that are safe to be handled, or
>> > look for what exactly we use the type of the second MEM_REF argument
>> > and check those properties.  We certainly need that
>> > get_deref_alias_set_1 and get_deref_alias_set return the same values
>> > for both the types, but whether that is the only information we are using,
>> > not sure, CCing Richard.
>>
>> Using TYPE_MAIN_VARIANT is exactly correct - this is the best we
>> can do that will work with all frontends.  TYPE_MAIN_VARIANT
>> guarantees that the alias-sets stay the same:
>>
>>       /* If the innermost reference is a MEM_REF that has a
>>          conversion embedded treat it like a VIEW_CONVERT_EXPR above,
>>          using the memory access type for determining the alias-set.  */
>>      if (TREE_CODE (inner) == MEM_REF
>>          && TYPE_MAIN_VARIANT (TREE_TYPE (inner))
>>             != TYPE_MAIN_VARIANT
>>                (TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1)))))
>>        return get_deref_alias_set (TREE_OPERAND (inner, 1));
>>
>> so we cannot change the compatibility checks without touching the
>> alias-set deriving code.  For the testcase in question we have
>> MEM[(const int &)_7] vs. MEM[(int *)_7] and unfortunately pointer
>> and reference types are not variant types.
>>
>> We also cannot easily resort to pointed-to types as our all-beloved
>> ref-all qualification is on the pointer type rather than on the
>> pointed-to type.
>>
>> But yes, we could implement a more complicated predicate
>>
>> bool
>> alias_ptr_types_compatible_p (const_tree t1, const_tree t2)
>> {
>>   t1 = TYPE_MAIN_VARIANT (t1);
>>   t2 = TYPE_MAIN_VARIANT (t2);
>>   if (t1 == t2)
>>     return true;
>>
>>   if (TYPE_REF_CAN_ALIAS_ALL (t1)
>>       || TYPE_REF_CAN_ALIAS_ALL (t2))
>>     return false;
>>
>>   return (TYPE_MAIN_VARIANT (TREE_TYPE (t1))
>>           == TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
>> }
>>
>> Note that the fold-const code in question is
>>
>>           return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE
>> (arg1))
>>                    || (TYPE_SIZE (TREE_TYPE (arg0))
>>                        && TYPE_SIZE (TREE_TYPE (arg1))
>>                        && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
>>                                            TYPE_SIZE (TREE_TYPE (arg1)),
>> flags)))
>>                   && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE
>> (arg1))
>>                   && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0,
>> 1)))
>>                       == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1,
>> 1))))
>>                   && OP_SAME (0) && OP_SAME (1));
>>
>> which you may notice uses types_compatible_p on the reference type
>> which is at least suspicious as that can let through reference trees
>> that will end up using different alias sets due to the stricter
>> check in get_alias_set.
>>
>> So in addition to alias_ptr_types_compatible_p we may want to have
>>
>> bool
>> reference_alias_ptr_types_compatible_p (const_tree t1, const_tree t2)
>> {
>> ...
>> }
>>
>> abstracting this away for the actual reference trees (also noting
>> that reference_alias_ptr_type isn't 1:1 following what get_alias_set
>> does either).
>>
>> I will give this a try.
>
> The following is an untested (well, the testcase from PR58513 is now
> vectorized) patch doing that refactoring.
>
> Richard.
>
> Index: gcc/tree.c
> ===================================================================
> *** gcc/tree.c  (revision 202859)
> --- gcc/tree.c  (working copy)
> *************** mem_ref_offset (const_tree t)
> *** 4263,4286 ****
>     return tree_to_double_int (toff).sext (TYPE_PRECISION (TREE_TYPE (toff)));
>   }
>
> - /* Return the pointer-type relevant for TBAA purposes from the
> -    gimple memory reference tree T.  This is the type to be used for
> -    the offset operand of MEM_REF or TARGET_MEM_REF replacements of T.  */
> -
> - tree
> - reference_alias_ptr_type (const_tree t)
> - {
> -   const_tree base = t;
> -   while (handled_component_p (base))
> -     base = TREE_OPERAND (base, 0);
> -   if (TREE_CODE (base) == MEM_REF)
> -     return TREE_TYPE (TREE_OPERAND (base, 1));
> -   else if (TREE_CODE (base) == TARGET_MEM_REF)
> -     return TREE_TYPE (TMR_OFFSET (base));
> -   else
> -     return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (base)));
> - }
> -
>   /* Return an invariant ADDR_EXPR of type TYPE taking the address of BASE
>      offsetted by OFFSET units.  */
>
> --- 4263,4268 ----
> Index: gcc/tree.h
> ===================================================================
> *** gcc/tree.h  (revision 202859)
> --- gcc/tree.h  (working copy)
> *************** extern tree build_simple_mem_ref_loc (lo
> *** 4345,4351 ****
>   #define build_simple_mem_ref(T)\
>         build_simple_mem_ref_loc (UNKNOWN_LOCATION, T)
>   extern double_int mem_ref_offset (const_tree);
> - extern tree reference_alias_ptr_type (const_tree);
>   extern tree build_invariant_address (tree, tree, HOST_WIDE_INT);
>   extern tree constant_boolean_node (bool, tree);
>   extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree);
> --- 4345,4350 ----
> Index: gcc/alias.c
> ===================================================================
> *** gcc/alias.c (revision 202859)
> --- gcc/alias.c (working copy)
> *************** component_uses_parent_alias_set (const_t
> *** 547,552 ****
> --- 547,564 ----
>       }
>   }
>
> +
> + /* Return whether the pointer-type T effective for aliasing may
> +    access everything and thus the reference has to be assigned
> +    alias-set zero.  */
> +
> + static bool
> + ref_all_alias_ptr_type_p (const_tree t)
> + {
> +   return (TREE_CODE (TREE_TYPE (t)) == VOID_TYPE
> +         || TYPE_REF_CAN_ALIAS_ALL (t));
> + }
> +
>   /* Return the alias set for the memory pointed to by T, which may be
>      either a type or an expression.  Return -1 if there is nothing
>      special about dereferencing T.  */
> *************** component_uses_parent_alias_set (const_t
> *** 554,564 ****
>   static alias_set_type
>   get_deref_alias_set_1 (tree t)
>   {
> -   /* If we're not doing any alias analysis, just assume everything
> -      aliases everything else.  */
> -   if (!flag_strict_aliasing)
> -     return 0;
> -
>     /* All we care about is the type.  */
>     if (! TYPE_P (t))
>       t = TREE_TYPE (t);
> --- 566,571 ----
> *************** get_deref_alias_set_1 (tree t)
> *** 566,573 ****
>     /* If we have an INDIRECT_REF via a void pointer, we don't
>        know anything about what that might alias.  Likewise if the
>        pointer is marked that way.  */
> !   if (TREE_CODE (TREE_TYPE (t)) == VOID_TYPE
> !       || TYPE_REF_CAN_ALIAS_ALL (t))
>       return 0;
>
>     return -1;
> --- 573,579 ----
>     /* If we have an INDIRECT_REF via a void pointer, we don't
>        know anything about what that might alias.  Likewise if the
>        pointer is marked that way.  */
> !   if (ref_all_alias_ptr_type_p (t))
>       return 0;
>
>     return -1;
> *************** get_deref_alias_set_1 (tree t)
> *** 579,584 ****
> --- 585,595 ----
>   alias_set_type
>   get_deref_alias_set (tree t)
>   {
> +   /* If we're not doing any alias analysis, just assume everything
> +      aliases everything else.  */
> +   if (!flag_strict_aliasing)
> +     return 0;
> +
>     alias_set_type set = get_deref_alias_set_1 (t);
>
>     /* Fall back to the alias-set of the pointed-to type.  */
> *************** get_deref_alias_set (tree t)
> *** 592,597 ****
> --- 603,698 ----
>     return set;
>   }
>
> + static tree
> + reference_alias_ptr_type_1 (tree *t)
> + {
> +   tree inner;
> +
> +   /* Get the base object of the reference.  */
> +   inner = *t;
> +   while (handled_component_p (inner))
> +     {
> +       /* If there is a VIEW_CONVERT_EXPR in the chain we cannot use
> +        the type of any component references that wrap it to
> +        determine the alias-set.  */
> +       if (TREE_CODE (inner) == VIEW_CONVERT_EXPR)
> +       *t = TREE_OPERAND (inner, 0);
> +       inner = TREE_OPERAND (inner, 0);
> +     }
> +
> +   /* Handle pointer dereferences here, they can override the
> +      alias-set.  */
> +   if (INDIRECT_REF_P (inner)
> +       && ref_all_alias_ptr_type_p (TREE_TYPE (TREE_OPERAND (inner, 0))))
> +     return TREE_TYPE (TREE_OPERAND (inner, 0));
> +   else if (TREE_CODE (inner) == TARGET_MEM_REF)
> +     return TREE_TYPE (TMR_OFFSET (inner));
> +   else if (TREE_CODE (inner) == MEM_REF
> +          && ref_all_alias_ptr_type_p (TREE_TYPE (TREE_OPERAND (inner, 1))))
> +     return TREE_TYPE (TREE_OPERAND (inner, 1));
> +
> +   /* If the innermost reference is a MEM_REF that has a
> +      conversion embedded treat it like a VIEW_CONVERT_EXPR above,
> +      using the memory access type for determining the alias-set.  */
> +   if (TREE_CODE (inner) == MEM_REF
> +       && (TYPE_MAIN_VARIANT (TREE_TYPE (inner))
> +         != TYPE_MAIN_VARIANT
> +              (TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1))))))
> +     return TREE_TYPE (TREE_OPERAND (inner, 1));
> +
> +   /* Otherwise, pick up the outermost object that we could have a pointer
> +      to, processing conversions as above.  */
> +   /* ???  Ick, this is worse than quadratic!  */
> +   while (component_uses_parent_alias_set (*t))
> +     {
> +       *t = TREE_OPERAND (*t, 0);
> +       STRIP_NOPS (*t);
> +     }
> +
> +   return NULL_TREE;
> + }
> +
> + /* Return the pointer-type relevant for TBAA purposes from the
> +    gimple memory reference tree T.  This is the type to be used for
> +    the offset operand of MEM_REF or TARGET_MEM_REF replacements of T
> +    and guarantees that get_alias_set will return the same alias
> +    set for T and the replacement.  */
> +
> + tree
> + reference_alias_ptr_type (tree t)
> + {
> +   tree ptype = reference_alias_ptr_type_1 (&t);
> +   /* If there is a given pointer type for aliasing purposes, return it.  */
> +   if (ptype != NULL_TREE)
> +     return ptype;
> +
> +   /* Otherwise build one from the outermost component reference we
> +      may use.  */
> +   if (TREE_CODE (t) == MEM_REF
> +       || TREE_CODE (t) == TARGET_MEM_REF)
> +     return TREE_TYPE (TREE_OPERAND (t, 1));
> +   else
> +     return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (t)));
> + }
> +
> + /* Return whether the pointer-types T1 and T2 used to determine
> +    two alias sets of two references will yield the same answer
> +    from get_deref_alias_set.  */
> +
> + bool
> + alias_ptr_types_compatible_p (tree t1, tree t2)
> + {
> +   if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
> +     return true;
> +
> +   if (ref_all_alias_ptr_type_p (t1)
> +       || ref_all_alias_ptr_type_p (t2))
> +     return false;
> +
> +   return (TYPE_MAIN_VARIANT (TREE_TYPE (t1))
> +         == TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
> + }
> +
>   /* Return the alias set for T, which may be either a type or an
>      expression.  Call language-specific routine for help, if needed.  */
>
> *************** get_alias_set (tree t)
> *** 615,622 ****
>        aren't types.  */
>     if (! TYPE_P (t))
>       {
> -       tree inner;
> -
>         /* Give the language a chance to do something with this tree
>          before we look at it.  */
>         STRIP_NOPS (t);
> --- 716,721 ----
> *************** get_alias_set (tree t)
> *** 624,674 ****
>         if (set != -1)
>         return set;
>
> !       /* Get the base object of the reference.  */
> !       inner = t;
> !       while (handled_component_p (inner))
> !       {
> !         /* If there is a VIEW_CONVERT_EXPR in the chain we cannot use
> !            the type of any component references that wrap it to
> !            determine the alias-set.  */
> !         if (TREE_CODE (inner) == VIEW_CONVERT_EXPR)
> !           t = TREE_OPERAND (inner, 0);
> !         inner = TREE_OPERAND (inner, 0);
> !       }
> !
> !       /* Handle pointer dereferences here, they can override the
> !        alias-set.  */
> !       if (INDIRECT_REF_P (inner))
> !       {
> !         set = get_deref_alias_set_1 (TREE_OPERAND (inner, 0));
> !         if (set != -1)
> !           return set;
> !       }
> !       else if (TREE_CODE (inner) == TARGET_MEM_REF)
> !       return get_deref_alias_set (TMR_OFFSET (inner));
> !       else if (TREE_CODE (inner) == MEM_REF)
> !       {
> !         set = get_deref_alias_set_1 (TREE_OPERAND (inner, 1));
> !         if (set != -1)
> !           return set;
> !       }
> !
> !       /* If the innermost reference is a MEM_REF that has a
> !        conversion embedded treat it like a VIEW_CONVERT_EXPR above,
> !        using the memory access type for determining the alias-set.  */
> !      if (TREE_CODE (inner) == MEM_REF
> !        && TYPE_MAIN_VARIANT (TREE_TYPE (inner))
> !           != TYPE_MAIN_VARIANT
> !              (TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1)))))
> !        return get_deref_alias_set (TREE_OPERAND (inner, 1));
> !
> !       /* Otherwise, pick up the outermost object that we could have a 
> pointer
> !        to, processing conversions as above.  */
> !       while (component_uses_parent_alias_set (t))
> !       {
> !         t = TREE_OPERAND (t, 0);
> !         STRIP_NOPS (t);
> !       }
>
>         /* If we've already determined the alias set for a decl, just return
>          it.  This is necessary for C++ anonymous unions, whose component
> --- 723,733 ----
>         if (set != -1)
>         return set;
>
> !       /* Get the alias pointer-type to use or the outermost object
> !          that we could have a pointer to.  */
> !       tree ptype = reference_alias_ptr_type_1 (&t);
> !       if (ptype != NULL)
> !       return get_deref_alias_set (ptype);
>
>         /* If we've already determined the alias set for a decl, just return
>          it.  This is necessary for C++ anonymous unions, whose component
> Index: gcc/alias.h
> ===================================================================
> *** gcc/alias.h (revision 202859)
> --- gcc/alias.h (working copy)
> *************** extern int alias_sets_conflict_p (alias_
> *** 41,46 ****
> --- 41,48 ----
>   extern int alias_sets_must_conflict_p (alias_set_type, alias_set_type);
>   extern int objects_must_conflict_p (tree, tree);
>   extern int nonoverlapping_memrefs_p (const_rtx, const_rtx, bool);
> + tree reference_alias_ptr_type (tree);
> + bool alias_ptr_types_compatible_p (tree, tree);
>
>   /* This alias set can be used to force a memory to conflict with all
>      other memories, creating a barrier across which no memory reference
> Index: gcc/fold-const.c
> ===================================================================
> *** gcc/fold-const.c    (revision 202859)
> --- gcc/fold-const.c    (working copy)
> *************** operand_equal_p (const_tree arg0, const_
> *** 2693,2700 ****
>                        && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
>                                            TYPE_SIZE (TREE_TYPE (arg1)), 
> flags)))
>                   && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
> !                 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1)))
> !                     == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 
> 1))))
>                   && OP_SAME (0) && OP_SAME (1));
>
>         case ARRAY_REF:
> --- 2693,2701 ----
>                        && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
>                                            TYPE_SIZE (TREE_TYPE (arg1)), 
> flags)))
>                   && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
> !                 && alias_ptr_types_compatible_p
> !                      (TREE_TYPE (TREE_OPERAND (arg0, 1)),
> !                       TREE_TYPE (TREE_OPERAND (arg1, 1)))
>                   && OP_SAME (0) && OP_SAME (1));
>
>         case ARRAY_REF:

Reply via email to