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: Tue, 26 May 2015 13:15:39 +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> <alpine dot LSU dot 2 dot 11 dot 1505221518250 dot 30088 at zhemvz dot fhfr dot qr> <20150522135025 dot GE75713 at kam dot mff dot cuni dot cz>
On Fri, 22 May 2015, Jan Hubicka wrote:
> > > + 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 explicitly says what is the type of class whose virtual
> method is called. It is GIMPLE operand expression like other, so I think
> we need to handle it.
>
> Actually I think I can just drop the flag_devirtualize check because with
> !flag_devirtualize we should simply avoid having OBJ_TYPE_REF around. That
> would make it looking less devirt specific. We can also test types for
> equivalence of main variant, but that would just introduce false positives when
> LTO did not merged two identical ODR types. It would be correct though.
Ok, please split it out without the devritualize bits.
> >
> > > + /* 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?
>
> FIELD_DECL has TREE_TYPE and TREE_TYPE may not get merged by LTO. So if
> the two expressions originate from two different units, we may have two
> semantically equivalent FIELD_DECLs (of compatible types and same
> offsets) that occupy different memory locations because their merging
> was prevented by something upstream (like complete wrt incmplete pointer
> in the type)
Still, operand_equal_p isn't about LTO, it's about GENERIC as created by
FEs...
> > > + /* 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.
>
> many false negatives is better than all false negatices :)
>
> You are right, either I should punt on non-empty constructors or compare
> the indexes, will do the second.
Thanks - please split it out to a separate patch.
> > > + 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.
>
> Will do if we agree on having this.
>
> I know you would like ipa-icf to keep original bodies and use them for
> inlining declaring alias sets to be function local. This is wrong plan.
> Consder:
>
> void t(int *ptr)
> {
> *ptr=1;
> }
>
> int a(int *ptr1, int *ptr2)
> {
> int a = *ptr1;
> t(ptr2)
> return a+*ptr1;
> }
>
> long b(long *ptr1, int *ptr2)
> {
> int a = *ptr1;
> t(ptr2)
> return a+*ptr1;
> }
>
> here aliasing leads to the two options to be optimizer differently:
> a:
> .LFB1:
> .cfi_startproc
> movl 4(%esp), %edx
> movl 8(%esp), %ecx
> movl (%edx), %eax
> movl $1, (%ecx)
> addl (%edx), %eax
> ret
> .cfi_endproc
> b:
> .LFB2:
> .cfi_startproc
> movl 4(%esp), %eax
> movl 8(%esp), %edx
> movl (%eax), %eax
> movl $1, (%edx)
> addl %eax, %eax
> ret
> .cfi_endproc
>
> however with -fno-early-inlining the functions look identical (modulo alias
> sets) at ipa-icf time. If we merged a/b, we could get wrong code for a
> even though no inlining of a or b happens.
First of all the return types don't agree so the testcase is bogus.
> So either we match the alias sets or we need to verify that the alias sets
> permit precisely the same set of optimizations with taking possible inlining
> into account.
Hmm, but then what makes ICF of a and b _with_ early inlining fail with
-fno-tree-fre1? The casts from *ptr1 to int in the 'long' case.
So I think I need to see a real testcase and then I'll show you
even with no inlining after ICF you get wrong-code thus it is a bug
in ICF ;)
> I also do not believe that TBAA should be function local. I believe it is
> useful to propagate stuff interprocedurally, like ipa-prop could be able to
> propagate this:
>
> long *ptr1;
> int *ptr2;
> t(int *ptr)
> {
> return *ptr;
> }
> wrap(int *ptr)
> {
> *ptr1=1;
> }
> call()
> {
> return wrap (*ptr2);
> }
>
> and we could have ipa-reference style pass that collect alias sets
> read/written by a function and uses it during local optimization to
> figure out if there is a true dependence between function call and
> memory store.
Sure, but after ICF there is no IPA propagation...
Richard.
--
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)