> Hi, > > on the 4.7 branch just like on the newer one, I'd like to fix the bug > by simply never propagating through thunks. There even less pre-IPA > devirtualization going on and so this should have minimal impact. > > Bootstrapped and tested on x86_64. OK for the branch?
OK for both branches. Honza > > Thanks, > > Martin > > > 2014-04-01 Martin Jambor <mjam...@suse.cz> > > PR ipa/60640 > * ipa-cp.c (propagate_constants_accross_call): Do not propagate > accross thunks. > > testsuite/ > * g++.dg/ipa/pr60640-1.C: New test. > * g++.dg/ipa/pr60640-2.C: Likewise. > * g++.dg/ipa/pr60640-3.C: Likewise. > > diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c > index 454283a..ddf6605 100644 > --- a/gcc/ipa-cp.c > +++ b/gcc/ipa-cp.c > @@ -1063,21 +1063,21 @@ propagate_constants_accross_call (struct cgraph_edge > *cs) > args_count = ipa_get_cs_argument_count (args); > parms_count = ipa_get_param_count (callee_info); > > - /* If this call goes through a thunk we must not propagate to the first > (0th) > - parameter. However, we might need to uncover a thunk from below a > series > - of aliases first. */ > + /* If this call goes through a thunk we should not propagate because we > + cannot redirect edges to thunks. However, we might need to uncover a > + thunk from below a series of aliases first. */ > alias_or_thunk = cs->callee; > while (alias_or_thunk->alias) > alias_or_thunk = cgraph_alias_aliased_node (alias_or_thunk); > if (alias_or_thunk->thunk.thunk_p) > { > - ret |= set_lattice_contains_variable (ipa_get_lattice (callee_info, > 0)); > - i = 1; > + for (i = 0; i < parms_count; i++) > + ret |= set_lattice_contains_variable (ipa_get_lattice (callee_info, i)); > + > + return ret; > } > - else > - i = 0; > > - for (; (i < args_count) && (i < parms_count); i++) > + for (i = 0; (i < args_count) && (i < parms_count); i++) > { > struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i); > struct ipcp_lattice *dest_lat = ipa_get_lattice (callee_info, i); > diff --git a/gcc/testsuite/g++.dg/ipa/pr60640-1.C > b/gcc/testsuite/g++.dg/ipa/pr60640-1.C > new file mode 100644 > index 0000000..7a0b918 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/ipa/pr60640-1.C > @@ -0,0 +1,50 @@ > +// { dg-do compile } > +// { dg-options "-O3" } > + > +class ASN1Object > +{ > +public: > + virtual ~ASN1Object (); > +}; > +class A > +{ > + virtual unsigned m_fn1 () const; > +}; > +class B > +{ > +public: > + ASN1Object Element; > + virtual unsigned m_fn1 (bool) const; > +}; > +template <class BASE> class C : public BASE > +{ > +}; > + > +class D : ASN1Object, public B > +{ > +}; > +class G : public D > +{ > + unsigned m_fn1 (bool) const {} > +}; > +class F : A > +{ > +public: > + F (A); > + unsigned m_fn1 () const > + { > + int a; > + a = m_fn2 ().m_fn1 (0); > + return a; > + } > + const B &m_fn2 () const { return m_groupParameters; } > + C<G> m_groupParameters; > +}; > +template <class D> void BenchMarkKeyAgreement (int *, int *, int) > +{ > + A f; > + D d (f); > +} > + > +void BenchmarkAll2 () { BenchMarkKeyAgreement<F>(0, 0, 0); } > + > diff --git a/gcc/testsuite/g++.dg/ipa/pr60640-2.C > b/gcc/testsuite/g++.dg/ipa/pr60640-2.C > new file mode 100644 > index 0000000..c6e614c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/ipa/pr60640-2.C > @@ -0,0 +1,15 @@ > +// { dg-do compile } > +// { dg-options "-O3" } > + > +struct B { virtual unsigned f () const; }; > +struct C { virtual void f (); }; > +struct F { virtual unsigned f (bool) const; ~F (); }; > +struct J : C, F {}; > +struct G : J { unsigned f (bool) const { return 0; } }; > +struct H : B > +{ > + H (int); > + unsigned f () const { return ((const F &) h).f (0); } > + G h; > +}; > +H h (0); > diff --git a/gcc/testsuite/g++.dg/ipa/pr60640-3.C > b/gcc/testsuite/g++.dg/ipa/pr60640-3.C > new file mode 100644 > index 0000000..21b1f58 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/ipa/pr60640-3.C > @@ -0,0 +1,81 @@ > +// { dg-do run } > +// { dg-options "-O3" } > + > +struct Distraction > +{ > + char fc[8]; > + virtual Distraction * return_self () > + { return this; } > +}; > + > +namespace { > + > +struct A; > +static A * __attribute__ ((noinline, noclone)) get_an_A (); > + > +static int go; > + > +struct A > +{ > + int fi; > + > + A () : fi(777) {} > + A (int pi) : fi (pi) {} > + virtual A * foo (int p) = 0; > +}; > + > +struct B; > +static B * __attribute__ ((noinline, noclone)) get_a_B (); > + > +struct B : public Distraction, A > +{ > + B () : Distraction(), A() { } > + B (int pi) : Distraction (), A (pi) {} > + virtual B * foo (int p) > + { > + int o = fi; > + for (int i = 0; i < p; i++) > + o += i + i * i; > + go = o; > + > + return get_a_B (); > + } > +}; > + > + > +struct B gb1 (1111), gb2 (2); > +static B * __attribute__ ((noinline, noclone)) > +get_a_B () > +{ > + return &gb1; > +} > + > +static A * __attribute__ ((noinline, noclone)) > +get_an_A () > +{ > + return &gb2; > +} > + > +} > + > +static int __attribute__ ((noinline, noclone)) > +get_a_number () > +{ > + return 5; > +} > + > +extern "C" void abort (void); > + > +int main (int argc, char *argv[]) > +{ > + for (int i = 0; i < get_a_number (); i++) > + { > + struct A *p = get_an_A (); > + struct A *r = p->foo (4); > + if (r->fi != 1111) > + abort (); > + if (go != 22) > + abort (); > + } > + return 0; > +}