On Thu, 12 Nov 2020, Jan Hubicka wrote:

> Hi,
> with ipa-icf we often run into problem that operand_equal_p does not
> match ADDR_EXPR that take address of fields from two different instances
> of same class (at ideantical offsets).  Similar problem can also happen
> for record types with LTO if they did not get tree merged.
> This patch makes fold-const to compare offsets rather then pinter
> equality of FIELD_DECLs. This is done in OEP_ADDRESS_OF mode only sinc
> it is not TBAA safe and the TBAA side should be correctly solved by my
> ICF patch.
> 
> Bootstrapped/regtested x86_64-linux, OK?
> 
> Honza
> 
>       * fold-const.c (operand_compare::operand_equal_p): When comparing 
> addresses
>       look info field offsets for COMPONENT_REFs.
>       (operand_compare::hash_operand): Likewise.
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index c47557daeba..a4e8cccb1b7 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -3312,9 +3312,41 @@ operand_compare::operand_equal_p (const_tree arg0, 
> const_tree arg1,
>       case COMPONENT_REF:
>         /* Handle operand 2 the same as for ARRAY_REF.  Operand 0
>            may be NULL when we're called to compare MEM_EXPRs.  */
> -       if (!OP_SAME_WITH_NULL (0)
> -           || !OP_SAME (1))
> +       if (!OP_SAME_WITH_NULL (0))
>           return false;
> +       /* Most of time we only need to compare FIELD_DECLs for equality.
> +          However when determining address look into actual offsets.
> +          These may match for unions and unshared record types.  */
> +       if (!OP_SAME (1))
> +         {
> +           if (flags & OEP_ADDRESS_OF)
> +             {

actually if OP2 is not NULL for both you can just compare that (and that's
more correct then).

> +               tree field0 = TREE_OPERAND (arg0, 1);
> +               tree field1 = TREE_OPERAND (arg1, 1);
> +               tree type0 = DECL_CONTEXT (field0);
> +               tree type1 = DECL_CONTEXT (field1);
> +
> +               if (TREE_CODE (type0) == RECORD_TYPE
> +                   && DECL_BIT_FIELD_REPRESENTATIVE (field0))
> +                 field0 = DECL_BIT_FIELD_REPRESENTATIVE (field0);
> +               if (TREE_CODE (type1) == RECORD_TYPE
> +                   && DECL_BIT_FIELD_REPRESENTATIVE (field1))
> +                 field1 = DECL_BIT_FIELD_REPRESENTATIVE (field1);

Why does the representative matter?  For a 32bit bitfield if you'd
have two addresses at 8bit boundary but different you'd make them
equal this way.  Soo ...

> +               /* Assume that different FIELD_DECLs never overlap within a
> +                  RECORD_TYPE.  */
> +               if (type0 == type1 && TREE_CODE (type0) == RECORD_TYPE)
> +                 return false;

this isn't really about "overlap", OEP_ADDRESS_OF is just about
the address (not it's extent).

> +               if (!operand_equal_p (DECL_FIELD_OFFSET (field0),
> +                                     DECL_FIELD_OFFSET (field1),
> +                                     flags & ~OEP_ADDRESS_OF)
> +                   || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0),
> +                                        DECL_FIELD_BIT_OFFSET (field1),
> +                                        flags & ~OEP_ADDRESS_OF))
> +                 return false;

So this should suffice (on the original fields).

> +             }
> +           else
> +             return false;
> +         }
>         flags &= ~OEP_ADDRESS_OF;
>         return OP_SAME_WITH_NULL (2);
>  
> @@ -3787,9 +3819,28 @@ operand_compare::hash_operand (const_tree t, 
> inchash::hash &hstate,
>             sflags = flags;
>             break;
>  
> +         case COMPONENT_REF:
> +           if (flags & OEP_ADDRESS_OF)
> +             {
> +               tree field = TREE_OPERAND (t, 1);
> +               tree type = DECL_CONTEXT (field);
> +
> +               if (TREE_CODE (type) == RECORD_TYPE
> +                   && DECL_BIT_FIELD_REPRESENTATIVE (field))
> +                 field = DECL_BIT_FIELD_REPRESENTATIVE (field);

see above.

> +               hash_operand (TREE_OPERAND (t, 0), hstate, flags);
> +               hash_operand (DECL_FIELD_OFFSET (field),
> +                             hstate, flags & ~OEP_ADDRESS_OF);
> +               hash_operand (DECL_FIELD_BIT_OFFSET (field),
> +                             hstate, flags & ~OEP_ADDRESS_OF);
> +               hash_operand (TREE_OPERAND (t, 2), hstate,
> +                             flags & ~OEP_ADDRESS_OF);

otherwise this looks ok.

> +               return;
> +             }
> +           break;
>           case ARRAY_REF:
>           case ARRAY_RANGE_REF:
> -         case COMPONENT_REF:
>           case BIT_FIELD_REF:
>             sflags &= ~OEP_ADDRESS_OF;
>             break;
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imend

Reply via email to