diff mbox

[4.7,PR,60640] Disable IPA-CP through thunks

Message ID 20140404153149.GC11790@virgil.suse
State New
Headers show

Commit Message

Martin Jambor April 4, 2014, 3:31 p.m. UTC
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  <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.

Comments

Jan Hubicka April 4, 2014, 5:12 p.m. UTC | #1
> 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 mbox

Patch

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