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? 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; +}