On Wed, 7 Oct 2015, Jan Hubicka wrote:

> > > I also disabled type matching done by operand_equal_p and cleaned up the
> > > conditional of MEM_REF into multiple ones - for example it was passing
> > > OEP_ADDRESS_OF when comparing TYPE_SIZE which is quite a nonsense.
> > > 
> > > I wonder what to do about OPE_CONSTANT_ADDRESS_OF.  This flag does not 
> > > seem
> > > to be used at all in current tree nor documented somehow.
> > 
> > It is used and (un-)documented as OEP_ADDRESS_OF, see the ADDR_EXPR case:
> > 
> >      case ADDR_EXPR:
> >  return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
> >                     TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)
> >                     ? OEP_CONSTANT_ADDRESS_OF | OEP_ADDRESS_OF : 0);
> > 
> > So it's OEP_ADDRESS_OF but for constant addresses.
> 
> Yep, I noticed it, but just after reading the sources for few times. The
> use is well hidden :)
> 
> Here is updated patch adding Richard's feedback and also making most of
> OEP_ADDRESS_OF special cases to also handle OEP_CONSTANT_ADDRESS_OF.
> OEP_CONSTANT_ADDRESS_OF means we care about address and we know the whole
> expr is constant, so it is stronger than OEP_ADDRESS_OF.

Yeah, we always set OEP_ADDRESS_OF when we set OEP_CONSTANT_ADDRESS_OF
though ...

> I also added documentation and cleaned up handling of ADDR_EXPR.  There are 
> two
> cases handing ADDR_EXPR.
> One handles TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1) and the other the
> rest of cases, so we do not need the conditional in the code quoted above.
> This will hopefully make it more obvious when the OEP_CONSTANT_ADDRESS_OF
> is set and used.
> 
> I also added sanity check that OEP_ADDRESSOF|OEP_CONSTANT_ADDRESS_OF is not
> used for INTEGER_CST and NOP_EXPR.  There are many other cases where we can't
> take address, but this seems strong enough to catch the wrong recursion which
> forgets to clear the flag and forced me to fix the OEP_CONSTANT_ADDRESS_OF
> handling.
> 
> I wonder if the INDIRECT_REF also needs the TBAA check that we do for MEM_REF?
> While we lower that early, I think we can still unify the code like in case
> of
>   cond ? ref_alias_set_1 : ref_alias_set_2

I believe that INDIRECT_REFs have to be "type safe", that is,
TREE_TYPE (ref) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ref, 0))) and
thus in theory type checks should catch mismatches.  OTOH we only
have

  /* If both types don't have the same precision, then it is not safe
     to strip NOPs.  */
  if (element_precision (TREE_TYPE (arg0))
      != element_precision (TREE_TYPE (arg1)))
    return 0;

and thus even miss basic TYPE_SIZE checks here...  Thus

struct S { int i[3]; };
struct R { int i[7]; };

 cond ? *(struct S *)p : *(struct R *)p;

will probably unify (well, hopefully the FE will complain about
the size mismatch, but the INDIRECT_REFs will be operand_equal_p).

Then we also do STRIP_NOPS on the pointer types which will strip

typedef int myint __attribute__((may_alias));
int *p;

 cond ? *(myint *)p : *p;

So yeah, the INDIRECT_REF case looks very suspicious.

> Bootstrapped/regtested x86_64-linux, OK?

Few comments below

> Honza
> 
>       * fold-const.c (operand_equal_p): Document OEP_ADDRESS_OF
>       and OEP_CONSTANT_ADDRESS_OF; make most of OEP_ADDRESS_OF
>       special cases to also handle OEP_CONSTANT_ADDRESS_OF; skip
>       type checking for OPE_*ADDRESS_OF.
> Index: fold-const.c
> ===================================================================
> --- fold-const.c      (revision 228131)
> +++ fold-const.c      (working copy)
> @@ -2691,7 +2691,12 @@ combine_comparisons (location_t loc,
>  
>     If OEP_PURE_SAME is set, then pure functions with identical arguments
>     are considered the same.  It is used when the caller has other ways
> -   to ensure that global memory is unchanged in between.  */
> +   to ensure that global memory is unchanged in between.
> +
> +   If OEP_ADDRESS_OF/OEP_CONSTANT_ADDRESS_OF is set, we are actually 
> comparing
> +   addresses of objects, not values of expressions.  OEP_CONSTANT_ADDRESS_OF
> +   is used for ADDR_EXPR with TREE_CONSTANT flag set and we further ignore
> +   any side effects on SAVE_EXPRs then.  */
>  
>  int
>  operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
> @@ -2710,31 +2715,48 @@ operand_equal_p (const_tree arg0, const_
>    /* Check equality of integer constants before bailing out due to
>       precision differences.  */
>    if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
> -    return tree_int_cst_equal (arg0, arg1);
> +    {
> +      /* Address of INTEGER_CST is not defined; check that we did not forget
> +      to drop the OEP_ADDRESS_OF/OEP_CONSTANT_ADDRESS_OF flags.  */
> +      gcc_checking_assert (!(flags
> +                          & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF)));
> +      return tree_int_cst_equal (arg0, arg1);
> +    }
>  
> -  /* If both types don't have the same signedness, then we can't consider
> -     them equal.  We must check this before the STRIP_NOPS calls
> -     because they may change the signedness of the arguments.  As pointers
> -     strictly don't have a signedness, require either two pointers or
> -     two non-pointers as well.  */
> -  if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))
> -      || POINTER_TYPE_P (TREE_TYPE (arg0)) != POINTER_TYPE_P (TREE_TYPE 
> (arg1)))
> -    return 0;
> +  if (!(flags & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF)))
> +    {
> +      /* If both types don't have the same signedness, then we can't consider
> +      them equal.  We must check this before the STRIP_NOPS calls
> +      because they may change the signedness of the arguments.  As pointers
> +      strictly don't have a signedness, require either two pointers or
> +      two non-pointers as well.  */
> +      if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE 
> (arg1))
> +       || POINTER_TYPE_P (TREE_TYPE (arg0))
> +                          != POINTER_TYPE_P (TREE_TYPE (arg1)))
> +     return 0;
>  
> -  /* We cannot consider pointers to different address space equal.  */
> -  if (POINTER_TYPE_P (TREE_TYPE (arg0)) && POINTER_TYPE_P (TREE_TYPE (arg1))
> -      && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
> -       != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))
> -    return 0;
> +      /* We cannot consider pointers to different address space equal.  */
> +      if (POINTER_TYPE_P (TREE_TYPE (arg0))
> +                       && POINTER_TYPE_P (TREE_TYPE (arg1))
> +       && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0)))
> +           != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1)))))
> +     return 0;
>  
> -  /* If both types don't have the same precision, then it is not safe
> -     to strip NOPs.  */
> -  if (element_precision (TREE_TYPE (arg0))
> -      != element_precision (TREE_TYPE (arg1)))
> -    return 0;
> +      /* If both types don't have the same precision, then it is not safe
> +      to strip NOPs.  */
> +      if (element_precision (TREE_TYPE (arg0))
> +       != element_precision (TREE_TYPE (arg1)))
> +     return 0;
>  
> -  STRIP_NOPS (arg0);
> -  STRIP_NOPS (arg1);
> +      STRIP_NOPS (arg0);
> +      STRIP_NOPS (arg1);
> +    }
> +  else
> +    /* Addresses of NOP_EXPR (and many other things) are not well defined. 
> +       Check that we did not forget to drop the
> +       OEP_ADDRESS_OF/OEP_CONSTANT_ADDRESS_OF flags.  */
> +    gcc_checking_assert (TREE_CODE (arg0) != NOP_EXPR
> +                      && TREE_CODE (arg1) != NOP_EXPR);

Use ! CONVERT_EXPR_P (arg0) && ! CONVERT_EXPR_P (arg1)
 
>    /* In case both args are comparisons but with different comparison
>       code, try to swap the comparison operands of one arg to produce
> @@ -2757,7 +2779,7 @@ operand_equal_p (const_tree arg0, const_
>        /* NOP_EXPR and CONVERT_EXPR are considered equal.  */
>        if (CONVERT_EXPR_P (arg0) && CONVERT_EXPR_P (arg1))
>       ;
> -      else if (flags & OEP_ADDRESS_OF)
> +      else if (flags & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF))
>       {
>         /* If we are interested in comparing addresses ignore
>            MEM_REF wrappings of the base that can appear just for
> @@ -2858,9 +2880,10 @@ operand_equal_p (const_tree arg0, const_
>                             TREE_STRING_LENGTH (arg0)));
>  
>        case ADDR_EXPR:
> +     /* Be sure we pass right ADDRESS_OF flag.  */
> +     gcc_checking_assert (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1));

Well, it's guarded with if (TREE_CONSTANT (arg0) && ... so the
assert is quite pointless.

>       return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
> -                             TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)
> -                             ? OEP_CONSTANT_ADDRESS_OF | OEP_ADDRESS_OF : 0);
> +                             OEP_CONSTANT_ADDRESS_OF);
>        default:
>       break;
>        }
> @@ -2922,7 +2945,7 @@ operand_equal_p (const_tree arg0, const_
>        switch (TREE_CODE (arg0))
>       {
>       case INDIRECT_REF:
> -       if (!(flags & OEP_ADDRESS_OF)
> +       if (!(flags & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF))
>             && (TYPE_ALIGN (TREE_TYPE (arg0))
>                 != TYPE_ALIGN (TREE_TYPE (arg1))))
>           return 0;
> @@ -2935,27 +2958,34 @@ operand_equal_p (const_tree arg0, const_
>  
>       case TARGET_MEM_REF:
>       case MEM_REF:
> -       /* Require equal access sizes, and similar pointer types.
> -          We can have incomplete types for array references of
> -          variable-sized arrays from the Fortran frontend
> -          though.  Also verify the types are compatible.  */
> -       if (!((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))
> -               && ((flags & OEP_ADDRESS_OF)
> -                   || (alias_ptr_types_compatible_p
> -                         (TREE_TYPE (TREE_OPERAND (arg0, 1)),
> -                          TREE_TYPE (TREE_OPERAND (arg1, 1)))
> -                       && (MR_DEPENDENCE_CLIQUE (arg0)
> -                           == MR_DEPENDENCE_CLIQUE (arg1))
> -                       && (MR_DEPENDENCE_BASE (arg0)
> -                           == MR_DEPENDENCE_BASE (arg1))
> -                       && (TYPE_ALIGN (TREE_TYPE (arg0))
> -                         == TYPE_ALIGN (TREE_TYPE (arg1)))))))
> -         return 0;
> +       if (!(flags & (OEP_ADDRESS_OF | OEP_CONSTANT_ADDRESS_OF)))
> +         {
> +           /* Require equal access sizes */
> +           if (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)))
> +             return 0;
> +           /* Verify that access happens in similar types.  */
> +           if (!types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1)))
> +             return 0;
> +           /* Verify that accesses are TBAA compatible.  */
> +           if (flag_strict_aliasing
> +               && (!alias_ptr_types_compatible_p
> +                     (TREE_TYPE (TREE_OPERAND (arg0, 1)),
> +                      TREE_TYPE (TREE_OPERAND (arg1, 1)))
> +                   || (MR_DEPENDENCE_CLIQUE (arg0)
> +                       != MR_DEPENDENCE_CLIQUE (arg1))
> +                   || (MR_DEPENDENCE_BASE (arg0)
> +                       != MR_DEPENDENCE_BASE (arg1))))
> +             return 0;
> +          /* Verify that alignment is compatible.  */
> +          if (TYPE_ALIGN (TREE_TYPE (arg0))
> +              != TYPE_ALIGN (TREE_TYPE (arg1)))
> +             return 0;
> +         }
>         flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
>         return (OP_SAME (0) && OP_SAME (1)
>                 /* TARGET_MEM_REF require equal extra operands.  */
> @@ -3001,6 +3031,8 @@ operand_equal_p (const_tree arg0, const_
>        switch (TREE_CODE (arg0))
>       {
>       case ADDR_EXPR:
> +       /* Be sure we pass right ADDRESS_OF flag.  */
> +       gcc_checking_assert (!(TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)));

Likewise.

Otherwise the patch looks ok.

Thanks,
Richard.

>         return operand_equal_p (TREE_OPERAND (arg0, 0),
>                                 TREE_OPERAND (arg1, 0),
>                                 flags | OEP_ADDRESS_OF);
> 
> 

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

Reply via email to