From: Yury Gribov Date: Fri, 21 Jul 2017 19:48:51 +0000 (+0000) Subject: re PR middle-end/56727 (Recursive call goes through the PLT unnecessarily) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=325fe81618c822b8cac4fd31c1ec57066ef338cf;p=gcc.git re PR middle-end/56727 (Recursive call goes through the PLT unnecessarily) 2017-07-21 Yury Gribov PR middle-end/56727 * ipa-visibility (function_and_variable_visibility): Convert recursive PLT call to direct call if appropriate. * gcc.dg/pr56727-1.c: New test. * gcc.dg/pr56727-2.c: New test. From-SVN: r250442 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2033b33789f..55937a8a344 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2017-07-21 Yury Gribov + + PR middle-end/56727 + * ipa-visibility (function_and_variable_visibility): Convert + recursive PLT call to direct call if appropriate. + 2017-07-21 Andrew Pinski * tree-ssa-sccvn.c (vn_nary_op_eq): Check BIT_INSERT_EXPR's diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c index 17186e9d2e6..21321703dbb 100644 --- a/gcc/ipa-visibility.c +++ b/gcc/ipa-visibility.c @@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "calls.h" #include "varasm.h" +#include "ipa-utils.h" /* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ @@ -617,6 +618,36 @@ function_and_variable_visibility (bool whole_program) /* All aliases should be procssed at this point. */ gcc_checking_assert (!alias_pairs || !alias_pairs->length ()); + FOR_EACH_DEFINED_FUNCTION (node) + { + if (node->get_availability () != AVAIL_INTERPOSABLE + || DECL_EXTERNAL (node->decl) + || node->has_aliases_p ()) + continue; + + cgraph_node *alias = 0; + for (cgraph_edge *e = node->callees; e; e = e->next_callee) + { + /* Recursive function calls usually can't be interposed. */ + + if (!e->recursive_p ()) + continue; + + if (!alias) + { + alias = dyn_cast (node->noninterposable_alias ()); + gcc_assert (alias && alias != node); + } + + e->redirect_callee (alias); + if (gimple_has_body_p (e->caller->decl)) + { + push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl)); + e->redirect_call_stmt_to_callee (); + pop_cfun (); + } + } + } FOR_EACH_FUNCTION (node) { int flags = flags_from_decl_or_type (node->decl); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 530a4abc1a7..6ee65b15e97 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2017-07-21 Yury Gribov + + PR middle-end/56727 + * gcc.dg/pr56727-1.c: New test. + * gcc.dg/pr56727-2.c: New test. + 2017-07-21 Steven Munroe * gcc.target/powerpc/mmx-check.h: New file. diff --git a/gcc/testsuite/gcc.dg/pr56727-1.c b/gcc/testsuite/gcc.dg/pr56727-1.c new file mode 100644 index 00000000000..ffc133545e7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr56727-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target fpic } } */ +/* { dg-options "-O2 -fPIC" } */ +/* { dg-final { scan-assembler-not "@(PLT|plt)" { target i?86-*-* x86_64-*-* powerpc*-*-* } } } */ + +#define define_func(type) \ + void f_ ## type (type b) { f_ ## type (0); } \ + void __attribute__((noinline, noclone)) f_noinline_ ## type (type b) \ + { f_noinline_ ## type (0); } + +define_func(char) +define_func(short) +define_func(int) +define_func(long) + +int foo(int n) +{ + return (n == 1 || n == 2) ? 1 : foo(n-1) * foo(n-2); +} + +int __attribute__((noinline, noclone)) foo_noinline(int n) +{ + return (n == 1 || n == 2) ? 1 : foo_noinline(n-1) * foo_noinline(n-2); +} diff --git a/gcc/testsuite/gcc.dg/pr56727-2.c b/gcc/testsuite/gcc.dg/pr56727-2.c new file mode 100644 index 00000000000..a285d5760eb --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr56727-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target fpic } } */ +/* { dg-options "-O2 -fPIC" } */ +/* { dg-final { scan-assembler "@(PLT|plt)" { target i?86-*-* x86_64-*-* powerpc*-*-* } } } */ + +__attribute__((noinline, noclone)) +void f (short b) +{ + f (0); +} + +static void g (short) __attribute__ ((alias ("f"))); + +void h () +{ + g (0); +}