From 0691d1d4a31ff0a426d2ba07c64acbac5df6b8ae Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Fri, 15 Jul 2005 09:31:39 +0000 Subject: [PATCH] c-common.c (handle_flatten_attribute): New function. 2005-07-15 Richard Guenther * c-common.c (handle_flatten_attribute): New function. Add flatten function attribute. * doc/extend.texi: Document flatten function attribute. * Makefile.in (ipa-inline.o): Depend on hashtab.h. * ipa-inline.c (cgraph_find_cycles, cgraph_flatten_node): New functions. (cgraph_decide_inlining): Handle functions with flatten attribute. * gcc.dg/tree-ssa/flatten-1.c: New testcase. * gcc.dg/tree-ssa/flatten-2.c: Likewise. From-SVN: r102051 --- gcc/ChangeLog | 11 ++++ gcc/Makefile.in | 2 +- gcc/c-common.c | 25 ++++++++ gcc/doc/extend.texi | 10 ++- gcc/ipa-inline.c | 78 +++++++++++++++++++++++ gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c | 57 +++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c | 76 ++++++++++++++++++++++ 8 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 68dec8a96c41..317e2d75f11a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2005-07-15 Richard Guenther + + * c-common.c (handle_flatten_attribute): New function. + Add flatten function attribute. + * doc/extend.texi: Document flatten function attribute. + * Makefile.in (ipa-inline.o): Depend on hashtab.h. + * ipa-inline.c (cgraph_find_cycles, cgraph_flatten_node): + New functions. + (cgraph_decide_inlining): Handle functions with flatten + attribute. + 2005-07-14 David Edelsohn * config/rs6000/rs6000.md (UNSPEC_SYNC, UNSPEC_LWSYNC, diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2bc109238992..3d8b8bc7c253 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2141,7 +2141,7 @@ ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) ipa-inline.o : ipa-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) langhooks.h tree-inline.h $(FLAGS_H) $(CGRAPH_H) intl.h \ $(DIAGNOSTIC_H) $(FIBHEAP_H) $(PARAMS_H) $(TIMEVAR_H) tree-pass.h \ - $(COVERAGE_H) + $(COVERAGE_H) $(HASHTAB_H) coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \ function.h toplev.h $(GGC_H) langhooks.h $(COVERAGE_H) gt-coverage.h \ diff --git a/gcc/c-common.c b/gcc/c-common.c index f3d4a281bdad..f7463e1f5531 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -505,6 +505,7 @@ static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree handle_always_inline_attribute (tree *, tree, tree, int, bool *); +static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); static tree handle_used_attribute (tree *, tree, tree, int, bool *); static tree handle_unused_attribute (tree *, tree, tree, int, bool *); static tree handle_externally_visible_attribute (tree *, tree, tree, int, @@ -571,6 +572,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_noinline_attribute }, { "always_inline", 0, 0, true, false, false, handle_always_inline_attribute }, + { "flatten", 0, 0, true, false, false, + handle_flatten_attribute }, { "used", 0, 0, true, false, false, handle_used_attribute }, { "unused", 0, 0, false, false, false, @@ -4151,6 +4154,28 @@ handle_always_inline_attribute (tree *node, tree name, return NULL_TREE; } +/* Handle a "flatten" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_flatten_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + /* Do nothing else, just set the attribute. We'll get at + it later with lookup_attribute. */ + ; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + + /* Handle a "used" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index cc6ea2de0535..f71c5200a0ae 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -1523,7 +1523,7 @@ attributes when making a declaration. This keyword is followed by an attribute specification inside double parentheses. The following attributes are currently defined for functions on all targets: @code{noreturn}, @code{returns_twice}, @code{noinline}, @code{always_inline}, -@code{pure}, @code{const}, @code{nothrow}, @code{sentinel}, +@code{flatten}, @code{pure}, @code{const}, @code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg}, @code{no_instrument_function}, @code{section}, @code{constructor}, @code{destructor}, @code{used}, @code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, @@ -1566,6 +1566,14 @@ Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level was specified. +@cindex @code{flatten} function attribute +@item flatten +Generally, inlining into a function is limited. For a function marked with +this attribute, every call inside this function will be inlined, if possible. +Whether the function itself is considered for inlining depends on its size and +the current inlining parameters. The @code{flatten} attribute only works +reliably in unit-at-a-time mode. + @item cdecl @cindex functions that do pop the argument stack on the 386 @opindex mrtd diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index cb71047d0aa7..df57ccce0530 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -78,6 +78,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "fibheap.h" #include "intl.h" #include "tree-pass.h" +#include "hashtab.h" #include "coverage.h" #include "ggc.h" @@ -438,6 +439,65 @@ lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where, lookup_recursive_calls (node, e->callee, heap); } +/* Find callgraph nodes closing a circle in the graph. The + resulting hashtab can be used to avoid walking the circles. + Uses the cgraph nodes ->aux field which needs to be zero + before and will be zero after operation. */ + +static void +cgraph_find_cycles (struct cgraph_node *node, htab_t cycles) +{ + struct cgraph_edge *e; + + if (node->aux) + { + void **slot; + slot = htab_find_slot (cycles, node, INSERT); + if (!*slot) + { + if (dump_file) + fprintf (dump_file, "Cycle contains %s\n", cgraph_node_name (node)); + *slot = node; + } + return; + } + + node->aux = node; + for (e = node->callees; e; e = e->next_callee) + cgraph_find_cycles (e->callee, cycles); + node->aux = 0; +} + +/* Leafify the cgraph node. We have to be careful in recursing + as to not run endlessly in circles of the callgraph. + We do so by using a hashtab of cycle entering nodes as generated + by cgraph_find_cycles. */ + +static void +cgraph_flatten_node (struct cgraph_node *node, htab_t cycles) +{ + struct cgraph_edge *e; + + for (e = node->callees; e; e = e->next_callee) + { + /* Inline call, if possible, and recurse. Be sure we are not + entering callgraph circles here. */ + if (e->inline_failed + && e->callee->local.inlinable + && !cgraph_recursive_inlining_p (node, e->callee, + &e->inline_failed) + && !htab_find (cycles, e->callee)) + { + if (dump_file) + fprintf (dump_file, " inlining %s", cgraph_node_name (e->callee)); + cgraph_mark_inline_edge (e); + cgraph_flatten_node (e->callee, cycles); + } + else if (dump_file) + fprintf (dump_file, " !inlining %s", cgraph_node_name (e->callee)); + } +} + /* Decide on recursive inlining: in the case function has recursive calls, inline until body size reaches given argument. */ @@ -769,6 +829,24 @@ cgraph_decide_inlining (void) node = order[i]; + /* Handle nodes to be flattened, but don't update overall unit size. */ + if (lookup_attribute ("flatten", DECL_ATTRIBUTES (node->decl)) != NULL) + { + int old_overall_insns = overall_insns; + htab_t cycles; + if (dump_file) + fprintf (dump_file, + "Leafifying %s\n", cgraph_node_name (node)); + cycles = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL); + cgraph_find_cycles (node, cycles); + cgraph_flatten_node (node, cycles); + htab_delete (cycles); + overall_insns = old_overall_insns; + /* We don't need to consider always_inline functions inside the flattened + function anymore. */ + continue; + } + if (!node->local.disregard_inline_limits) continue; if (dump_file) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2e5eee9ccf40..6bef685f53d5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-07-15 Richard Guenther + + * gcc.dg/tree-ssa/flatten-1.c: New testcase. + * gcc.dg/tree-ssa/flatten-2.c: Likewise. + 2005-07-15 Steven Bosscher PR tree-optimization/22230 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c b/gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c new file mode 100644 index 000000000000..4561f757b8c6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/flatten-1.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ +/* { dg-options -O2 } */ + +/* Basic tests for flatten attribute, check we end up + with only the flattened function bodies. */ + +static int foobar(int i); +static int bar(int i); + +int __attribute__((flatten)) leaf0a(int i) +{ + return bar(i); +} +int __attribute__((flatten)) leaf0b(int i) +{ + return foobar(i); +} +int __attribute__((flatten)) leaf1(int i) +{ + return bar(foobar(i)); +} +int __attribute__((flatten)) leaf2(int i) +{ + int j; + j = foobar(i); + return bar(j); +} + +static int foobar(int i) +{ + return i-1; +} +static int bar(int i) +{ + return i + foobar(i); +} + + +static int g(int i) +{ + return i*5+1; +} +static int f(int i) +{ + return g(i); +} +int __attribute__((flatten)) leaf3(int i) +{ + int j; + j = f(i); + j += f(i); + return j; +} + +/* { dg-final { scan-assembler-not "g:" } } */ +/* { dg-final { scan-assembler-not "f:" } } */ +/* { dg-final { scan-assembler-not "bar:" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c b/gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c new file mode 100644 index 000000000000..56e8083febd4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/flatten-2.c @@ -0,0 +1,76 @@ +/* { dg-do compile } */ +/* { dg-options -O2 } */ + +/* Check that we finish compiling even if instructed to + flatten a cyclic callgraph. Verify we correctly + flatten with another function marked flatten in the + callgraph. */ + +void __attribute__((flatten)) direct(void) +{ + direct(); +} + + +void __attribute__((flatten)) indirect(void); +static void indirect1(void) +{ + indirect(); +} +void __attribute__((flatten)) indirect(void) +{ + indirect1(); +} + + +void __attribute__((flatten)) doubleindirect(void); +static void doubleindirect2(void) +{ + doubleindirect(); +} +static void doubleindirect1(void) +{ + doubleindirect2(); +} +void __attribute__((flatten)) doubleindirect(void) +{ + doubleindirect1(); +} + + +static void subcycle1(void); +static void subcycle2(void) +{ + subcycle1(); +} +static void subcycle1(void) +{ + subcycle2(); +} +void __attribute__((flatten)) subcycle(void) +{ + subcycle1(); +} + + +static void doublesubcycle1(void); +static void doublesubcycle2(void); +static void doublesubcycle3(void) +{ + doublesubcycle1(); +} +static void doublesubcycle2(void) +{ + doublesubcycle3(); +} +static void doublesubcycle1(void) +{ + doublesubcycle2(); +} +void __attribute__((flatten)) doublesubcycle(void) +{ + doublesubcycle1(); +} + +/* { dg-final { scan-assembler "cycle.:" } } */ +/* { dg-final { scan-assembler-not "indirect.:" } } */ -- 2.39.5