[PR,85447] Check that clones of edges exist during IPA-CP

Message ID ri6po2u70ax.fsf@suse.cz
State New
Headers show
Series
  • [PR,85447] Check that clones of edges exist during IPA-CP
Related show

Commit Message

Martin Jambor April 20, 2018, 8:24 a.m.
Hi,

the details of what leads to this bug are in Bugzilla (comment 3), the
basic problem is that when IPA-CP is looking for a clone of an edge it
is not there because speculation resolution removed it.

After conversation with Honza, he preferred this smaller local fix
rather than incorporating the clone-of-callee redirection into the
cgraph cloning infrastructure.  He has pre-approved the patch below in
person, and since it has passed bootstrap, LTO bootstrap and testing on
x86_64-linux (and a lot of further testing together with the patch for
PR 85449 which I am going to post in a minute), I will commit it to
trunk in a few moments.

Thanks,

Martin


2018-04-19  Martin Jambor  <mjambor@suse.cz>

	ipa/85447
	* ipa-cp.c (create_specialized_node): Check that clones of
	self-recursive edges exist during IPA-CP.

testsuite/
	* g++.dg/ipa/pr85447.C: New file.
	* gcc.dg/ipa/ipcp-self-recursion-1.c: Likewise.
---
 gcc/ipa-cp.c                                     | 14 ++++++--
 gcc/testsuite/g++.dg/ipa/pr85447.C               | 23 ++++++++++++
 gcc/testsuite/gcc.dg/ipa/ipcp-self-recursion-1.c | 46 ++++++++++++++++++++++++
 3 files changed, 80 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ipa/pr85447.C
 create mode 100644 gcc/testsuite/gcc.dg/ipa/ipcp-self-recursion-1.c

-- 
2.16.3

Patch

diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 4e0e20af409..9388482bbea 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -3867,9 +3867,17 @@  create_specialized_node (struct cgraph_node *node,
   for (unsigned j = 0; j < self_recursive_calls.length (); j++)
     {
       cgraph_edge *cs = next_edge_clone[self_recursive_calls[j]->uid];
-      gcc_checking_assert (cs);
-      gcc_assert (cs->caller == new_node);
-      cs->redirect_callee_duplicating_thunks (new_node);
+      /* Cloned edges can disappear during cloning as speculation can be
+	 resolved, check that we have one and that it comes from the last
+	 cloning.  */
+      if (cs && cs->caller == new_node)
+	cs->redirect_callee_duplicating_thunks (new_node);
+      /* Any future code that would make more than one clone of an outgoing
+	 edge would confuse this mechanism, so let's check that does not
+	 happen.  */
+      gcc_checking_assert (!cs
+			   || !next_edge_clone[cs->uid]
+			   || next_edge_clone[cs->uid]->caller != new_node);
     }
   if (have_self_recursive_calls)
     new_node->expand_all_artificial_thunks ();
diff --git a/gcc/testsuite/g++.dg/ipa/pr85447.C b/gcc/testsuite/g++.dg/ipa/pr85447.C
new file mode 100644
index 00000000000..d7a7716af2e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr85447.C
@@ -0,0 +1,23 @@ 
+// { dg-do compile }
+// { dg-options "-O3 -std=gnu++11" }
+
+typedef int a;
+enum b : a;
+class c {
+public:
+  enum { d };
+  virtual b e(int *, int, const int *) = 0;
+};
+class f : c {
+  b e(int *, int, const int *);
+  b g();
+};
+b f::e(int *h, int i, const int *j) {
+  if (i == d)
+    return g();
+  for (;;)
+    e(h, i, j);
+}
+int k;
+c *l;
+void m() { l->e(&k, c::d, nullptr); }
diff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-self-recursion-1.c b/gcc/testsuite/gcc.dg/ipa/ipcp-self-recursion-1.c
new file mode 100644
index 00000000000..7ecbf79de61
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipcp-self-recursion-1.c
@@ -0,0 +1,46 @@ 
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-early-inlining"  } */
+
+int array[128];
+
+volatile int v = 0;
+volatile int blah = 0;
+volatile int counter = 0;
+
+int __attribute__((noipa))
+obscured_one ()
+{
+  return 1;
+}
+
+static void
+f (int c, int l)
+{
+  int i;
+  for (i = 0; i < c; i++)
+    array[i] = 455;
+
+  counter++;
+  if (counter > 6)
+    __builtin_abort ();
+
+  v = l;
+  if (l > 0)
+    f (c, l - 1);
+  blah = l;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+  for (i = 0; i < 100; i++)
+    {
+      counter = 0;
+      f (0, 5);
+      if (obscured_one ())
+	break;
+    }
+
+  return 0;
+}