On Fri, 22 May 2015, Jan Hubicka wrote:

> Hi,
> I am working on patch that makes operand_equal_p replace logic from
> ipa-icf-gimple's compare_op via a valueizer hook.  Currently the patch however
> cuts number of merges on firefox to half (apparently becuase it gives up on
> some tree codes too early)
> The patch bellow merges code from ipa-icf-gimple.c that is missing in
> fold-const and is needed. 
> 
> Bootstrapped/regtested x86_64-linux, OK?

No, I don't like this.

> Honza
> 
>       * fold-const.c (operand_equal_p): Handle OBJ_TYPE_REF, CONSTRUCTOR
>       and be more tolerant about FIELD_DECL.
>       * tree.c (add_expr): Handle FIELD_DECL.
>       (prototype_p, virtual_method_call_p, obj_type_ref_class): Constify.
>       * tree.h (prototype_p, virtual_method_call_p, obj_type_ref_class):
>       Constify.
> Index: fold-const.c
> ===================================================================
> --- fold-const.c      (revision 223500)
> @@ -3037,6 +3058,40 @@ operand_equal_p (const_tree arg0, const_
>       case DOT_PROD_EXPR:
>         return OP_SAME (0) && OP_SAME (1) && OP_SAME (2);
>  
> +     /* OBJ_TYPE_REF really is just a transparent wrapper around expression,
> +        but it holds additional type information for devirtualization that
> +        needs to be matched.  We may want to intoruce OEP flag if we want
> +        to compare the actual value only, or if we also care about effects
> +        of potentially merging the code.  This flag can bypass this check
> +        as well as the alias set matching in MEM_REF.  */
> +     case OBJ_TYPE_REF:
> +       {
> +         if (!operand_equal_p (OBJ_TYPE_REF_EXPR (arg0),
> +                               OBJ_TYPE_REF_EXPR (arg1), flags))
> +           return false;
> +         if (flag_devirtualize && virtual_method_call_p (arg0))
> +           {
> +             if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg0))
> +                 != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (arg1)))
> +               return false;
> +             if (!types_same_for_odr (obj_type_ref_class (arg0),
> +                                      obj_type_ref_class (arg1)))
> +               return false;

devirt machinery in operand_equal_p?  please not.  not more places!

> +             /* OBJ_TYPE_REF_OBJECT is used to track the instance of
> +                object THIS pointer points to.  Checking that both
> +                addresses equal is safe approximation of the fact
> +                that dynamic types are equal.
> +                Do not care about the other flags, because this expression
> +                does not attribute to actual value of OBJ_TYPE_REF  */
> +             if (!operand_equal_p (OBJ_TYPE_REF_OBJECT (arg0),
> +                                   OBJ_TYPE_REF_OBJECT (arg1),
> +                                   OEP_ADDRESS_OF))
> +               return false;
> +           }
> +
> +         return true;
> +       }
> +
>       default:
>         return 0;
>       }
> @@ -3097,6 +3152,21 @@ operand_equal_p (const_tree arg0, const_
>       }
>  
>      case tcc_declaration:
> +      /* At LTO time the FIELD_DECL may exist in multiple copies.
> +      We only care about offsets and bit offsets for operands.  */

Err?  Even at LTO time FIELD_DECLs should only appear once.
So - testcase?

IMHO most of this boils down to ICF being too strict about aliasing
because it inlines merged bodies instead of original ones.

> +      if (TREE_CODE (arg0) == FIELD_DECL)
> +     {
> +       tree offset1 = DECL_FIELD_OFFSET (arg0);
> +       tree offset2 = DECL_FIELD_OFFSET (arg1);
> +
> +       tree bit_offset1 = DECL_FIELD_BIT_OFFSET (arg0);
> +       tree bit_offset2 = DECL_FIELD_BIT_OFFSET (arg1);
> +
> +       flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
> +
> +       return operand_equal_p (offset1, offset2, flags)
> +              && operand_equal_p (bit_offset1, bit_offset2, flags);
> +     }
>        /* Consider __builtin_sqrt equal to sqrt.  */
>        return (TREE_CODE (arg0) == FUNCTION_DECL
>             && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1)
> @@ -3104,12 +3174,50 @@ operand_equal_p (const_tree arg0, const_
>             && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1));
>  
>      default:

case tcc_exceptional:

> +      /* In GIMPLE empty constructors are allowed in initializers of
> +      vector types.  */

Why this comment about GIMPLE?  This is about comparing GENERIC
trees which of course can have CONSTRUCTORs of various sorts.

> +      if (TREE_CODE (arg0) == CONSTRUCTOR)
> +     {
> +       unsigned length1 = vec_safe_length (CONSTRUCTOR_ELTS (arg0));
> +       unsigned length2 = vec_safe_length (CONSTRUCTOR_ELTS (arg1));
> +
> +       if (length1 != length2)
> +         return false;
> +
> +       flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF);
> +
> +       for (unsigned i = 0; i < length1; i++)
> +         if (!operand_equal_p (CONSTRUCTOR_ELT (arg0, i)->value,
> +                               CONSTRUCTOR_ELT (arg1, i)->value, flags))

You need to compare ->index as well here.  I'm not sure constructor
values are sorted always so you might get very many false negatives.

> +           return false;
> +
> +       return true;
> +     }
>        return 0;
>      }
>  
>  #undef OP_SAME
>  #undef OP_SAME_WITH_NULL
>  }
> Index: tree.c
> ===================================================================
> --- tree.c    (revision 223500)
> +++ tree.c    (working copy)
> @@ -7647,6 +7647,12 @@ add_expr (const_tree t, inchash::hash &h
>         }
>       return;
>        }
> +    case FIELD_DECL:
> +      /* At LTO time the FIELD_DECL may exist in multiple copies.
> +      We only care about offsets and bit offsets for operands.  */

So explain that this is the reason we don't want to hash by
DECL_UID.  I still think this is bogus.

> +      inchash::add_expr (DECL_FIELD_OFFSET (t), hstate);
> +      inchash::add_expr (DECL_FIELD_BIT_OFFSET (t), hstate);
> +      return;
>      case FUNCTION_DECL:
>        /* When referring to a built-in FUNCTION_DECL, use the __builtin__ 
> form.
>        Otherwise nodes that compare equal according to operand_equal_p might
> @@ -11579,7 +11585,7 @@ stdarg_p (const_tree fntype)
>  /* Return true if TYPE has a prototype.  */
>  
>  bool
> -prototype_p (tree fntype)
> +prototype_p (const_tree fntype)

This and the following look like independent (and obvious) changes.

>  {
>    tree t;
>  
> @@ -12005,7 +12011,7 @@ lhd_gcc_personality (void)
>     can't apply.) */
>  
>  bool
> -virtual_method_call_p (tree target)
> +virtual_method_call_p (const_tree target)
>  {
>    if (TREE_CODE (target) != OBJ_TYPE_REF)
>      return false;
> @@ -12026,7 +12032,7 @@ virtual_method_call_p (tree target)
>  /* REF is OBJ_TYPE_REF, return the class the ref corresponds to.  */
>  
>  tree
> -obj_type_ref_class (tree ref)
> +obj_type_ref_class (const_tree ref)
>  {
>    gcc_checking_assert (TREE_CODE (ref) == OBJ_TYPE_REF);
>    ref = TREE_TYPE (ref);
> Index: tree.h
> ===================================================================
> --- tree.h    (revision 223500)
> +++ tree.h    (working copy)
> @@ -4375,7 +4375,7 @@ extern int operand_equal_for_phi_arg_p (
>  extern tree create_artificial_label (location_t);
>  extern const char *get_name (tree);
>  extern bool stdarg_p (const_tree);
> -extern bool prototype_p (tree);
> +extern bool prototype_p (const_tree);
>  extern bool is_typedef_decl (tree x);
>  extern bool typedef_variant_p (tree);
>  extern bool auto_var_in_fn_p (const_tree, const_tree);
> @@ -4544,8 +4544,8 @@ extern location_t *block_nonartificial_l
>  extern location_t tree_nonartificial_location (tree);
>  extern tree block_ultimate_origin (const_tree);
>  extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree);
> -extern bool virtual_method_call_p (tree);
> -extern tree obj_type_ref_class (tree ref);
> +extern bool virtual_method_call_p (const_tree);
> +extern tree obj_type_ref_class (const_tree ref);
>  extern bool types_same_for_odr (const_tree type1, const_tree type2,
>                               bool strict=false);
>  extern bool contains_bitfld_component_ref_p (const_tree);
> 
> 

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

Reply via email to