This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Add few cases to operand_equal_p
- From: Richard Biener <rguenther at suse dot de>
- To: Jan Hubicka <hubicka at ucw dot cz>
- Cc: gcc-patches at gcc dot gnu dot org, mliska at suse dot cz
- Date: Fri, 22 May 2015 15:27:35 +0200 (CEST)
- Subject: Re: Add few cases to operand_equal_p
- Authentication-results: sourceware.org; auth=none
- References: <20150522123341 dot GD91616 at kam dot mff dot cuni dot cz>
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 <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)