ipa: Make call redirection detect already adjusted calls (PR 93621)
authorMartin Jambor <mjambor@suse.cz>
Thu, 16 Apr 2020 17:21:02 +0000 (19:21 +0200)
committerMartin Jambor <mjambor@suse.cz>
Thu, 16 Apr 2020 17:21:02 +0000 (19:21 +0200)
PR 93621 testcase makes redirect_call_stmt_to_callee wrongly assume
that a call statement needs redirecting but then rightly fails an
assert ensuring the call statement parameters have not already been
adjusted because they were already created adjusted as part of thunk
expansion.

The test fails because the decl in the call call statement is
different than the decl of the callee, because the latter was created
in save_inline_function_body.  This patch adds a way to link these two
and detect the situation in redirect_call_stmt_to_callee.

2020-04-16  Martin Jambor  <mjambor@suse.cz>

PR ipa/93621
* ipa-inline.h (ipa_saved_clone_sources): Declare.
* ipa-inline-transform.c (ipa_saved_clone_sources): New variable.
(save_inline_function_body): Link the new body holder with the
previous one.
* cgraph.c: Include ipa-inline.h.
(cgraph_edge::redirect_call_stmt_to_callee): Try to find the decl from
the statement in ipa_saved_clone_sources.
* cgraphunit.c: Include ipa-inline.h.
(expand_all_functions): Free ipa_saved_clone_sources.

testsuite/
* g++.dg/ipa/pr93621.C: New test.

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraphunit.c
gcc/ipa-inline-transform.c
gcc/ipa-inline.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/pr93621.C [new file with mode: 0644]

index 0c7dad08637516890f3338b7496334da39d46aea..5fd869a92393ed6ba6328fb3ff71eb1350025691 100644 (file)
@@ -1,3 +1,16 @@
+2020-04-16  Martin Jambor  <mjambor@suse.cz>
+
+       PR ipa/93621
+       * ipa-inline.h (ipa_saved_clone_sources): Declare.
+       * ipa-inline-transform.c (ipa_saved_clone_sources): New variable.
+       (save_inline_function_body): Link the new body holder with the
+       previous one.
+       * cgraph.c: Include ipa-inline.h.
+       (cgraph_edge::redirect_call_stmt_to_callee): Try to find the decl from
+       the statement in ipa_saved_clone_sources.
+       * cgraphunit.c: Include ipa-inline.h.
+       (expand_all_functions): Free ipa_saved_clone_sources.
+
 2020-04-16  Richard Sandiford  <richard.sandiford@arm.com>
 
        PR target/94606
index ecb234d032f6ec53bbf8df78fd719656a66701d5..72d7cb54301981c3dd8f66921e7a5bee24cacd54 100644 (file)
@@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "selftest.h"
 #include "tree-into-ssa.h"
+#include "ipa-inline.h"
 
 /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  */
 #include "tree-pass.h"
@@ -1470,6 +1471,16 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e)
       || decl == e->callee->decl)
     return e->call_stmt;
 
+  if (decl && ipa_saved_clone_sources)
+    {
+      tree *p = ipa_saved_clone_sources->get (e->callee);
+      if (p && decl == *p)
+       {
+         gimple_call_set_fndecl (e->call_stmt, e->callee->decl);
+         return e->call_stmt;
+       }
+    }
+
   if (flag_checking && decl)
     {
       cgraph_node *node = cgraph_node::get (decl);
index 0e255f25b7d00808992b0dec26e95f45e0edcb0e..a1ace95879a34bbe4ad842746088dbb8e3caf0cd 100644 (file)
@@ -205,6 +205,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-section-names.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include "ipa-inline.h"
 
 /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
    secondary queue used during optimization to accommodate passes that
@@ -2481,7 +2482,8 @@ expand_all_functions (void)
 
   symtab->process_new_functions ();
   free_gimplify_stack ();
-
+  delete ipa_saved_clone_sources;
+  ipa_saved_clone_sources = NULL;
   free (order);
 }
 
index eed992d314da1312560fa9966d9dc6d87b41a875..be60bbccb5cca5e28cfee63961e87e9be832f04f 100644 (file)
@@ -531,6 +531,11 @@ inline_call (struct cgraph_edge *e, bool update_original,
   return new_edges_found;
 }
 
+/* For each node that was made the holder of function body by
+   save_inline_function_body, this summary contains pointer to the previous
+   holder of the body.  */
+
+function_summary <tree *> *ipa_saved_clone_sources;
 
 /* Copy function body of NODE and redirect all inline clones to it.
    This is done before inline plan is applied to NODE when there are
@@ -588,6 +593,20 @@ save_inline_function_body (struct cgraph_node *node)
       first_clone->next_sibling_clone = NULL;
       gcc_assert (!first_clone->prev_sibling_clone);
     }
+
+  tree prev_body_holder = node->decl;
+  if (!ipa_saved_clone_sources)
+    ipa_saved_clone_sources = new function_summary <tree *> (symtab);
+  else
+    {
+      tree *p = ipa_saved_clone_sources->get (node);
+      if (p)
+       {
+         prev_body_holder = *p;
+         gcc_assert (prev_body_holder);
+       }
+    }
+  *ipa_saved_clone_sources->get_create (first_clone) = prev_body_holder;
   first_clone->clone_of = NULL;
 
   /* Now node in question has no clones.  */
index 5025b6045fcf0bd304ed91035cfc1203feb7f002..74c08685e4984023e3ce9178d848f5edd4508936 100644 (file)
@@ -65,6 +65,7 @@ void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *);
 
 extern int ncalls_inlined;
 extern int nfunctions_inlined;
+extern function_summary <tree *> *ipa_saved_clone_sources;
 
 /* Return estimated size of the inline sequence of EDGE.  */
 
index 72bed4064e561ef8e96c70c7e49dff955364c245..ad4b7e29ec7a88dfc030138e494308306483d882 100644 (file)
@@ -1,3 +1,8 @@
+2020-04-16  Martin Jambor  <mjambor@suse.cz>
+
+       PR ipa/93621
+       * g++.dg/ipa/pr93621.C: New test.
+
 2020-04-16  Richard Sandiford  <richard.sandiford@arm.com>
 
        PR target/94606
diff --git a/gcc/testsuite/g++.dg/ipa/pr93621.C b/gcc/testsuite/g++.dg/ipa/pr93621.C
new file mode 100644 (file)
index 0000000..ffe6bbd
--- /dev/null
@@ -0,0 +1,29 @@
+// PR ipa/93621
+// { dg-do compile }
+// { dg-options "-O3 --param ipa-cp-eval-threshold=100 --param large-function-growth=60 --param large-function-insns=10 --param uninlined-thunk-insns=1000" }
+
+typedef enum { X } E;
+struct A {
+  virtual void bar ();
+};
+struct B {
+  virtual E fn (const char *, int, int *) = 0;
+};
+struct C : A, B {
+  E fn (const char *, int, int *);
+  void fn2 ();
+  B *foo;
+};
+void C::fn2 () {
+  if (!foo)
+    return;
+  foo->fn (0, 0, 0);
+}
+E
+C::fn (const char *, int, int *)
+{
+  fn2 ();
+  foo = 0;
+  fn (0, 0, 0);
+  return X;
+}