Message ID | 20140404153149.GC11790@virgil.suse |
---|---|
State | New |
Headers | show |
> 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 <mjambor@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; > +}
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; +}