Index: c-common.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-common.c,v retrieving revision 1.465 diff -u -u -r1.465 c-common.c --- c-common.c 20 Oct 2003 22:03:32 -0000 1.465 +++ c-common.c 31 Oct 2003 10:30:20 -0000 @@ -762,6 +762,7 @@ static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree handle_always_inline_attribute (tree *, tree, tree, int, bool *); +static tree handle_leafify_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_const_attribute (tree *, tree, tree, int, bool *); @@ -824,6 +825,8 @@ handle_noinline_attribute }, { "always_inline", 0, 0, true, false, false, handle_always_inline_attribute }, + { "leafify", 0, 0, true, false, false, + handle_leafify_attribute }, { "used", 0, 0, true, false, false, handle_used_attribute }, { "unused", 0, 0, false, false, false, @@ -4448,6 +4451,28 @@ 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 ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "leafify" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_leafify_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) { Index: cgraph.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v retrieving revision 1.34 diff -u -u -r1.34 cgraph.c --- cgraph.c 22 Oct 2003 19:18:03 -0000 1.34 +++ cgraph.c 31 Oct 2003 10:30:20 -0000 @@ -157,6 +157,7 @@ struct cgraph_edge *edge2; edge->inline_call = false; + edge->maybe_inline_call = false; /* At the moment we don't associate calls with specific CALL_EXPRs as we probably ought to, so we must preserve inline_call flags to be the same in all copies of the same edge. */ @@ -165,6 +166,7 @@ if (edge2->callee == callee) { edge->inline_call = edge2->inline_call; + edge->maybe_inline_call = edge2->maybe_inline_call; break; } Index: cgraph.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v retrieving revision 1.23 diff -u -u -r1.23 cgraph.h --- cgraph.h 22 Oct 2003 11:58:09 -0000 1.23 +++ cgraph.h 31 Oct 2003 10:30:20 -0000 @@ -120,6 +120,7 @@ struct cgraph_edge *next_caller; struct cgraph_edge *next_callee; bool inline_call; + bool maybe_inline_call; }; /* The cgraph_varpool data strutcture. Index: cgraphunit.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v retrieving revision 1.37 diff -u -u -r1.37 cgraphunit.c --- cgraphunit.c 22 Oct 2003 11:58:09 -0000 1.37 +++ cgraphunit.c 31 Oct 2003 10:30:20 -0000 @@ -57,6 +57,9 @@ static int initial_insns; static int overall_insns; +/* Flag if we expand a leafify function. */ +static int leafify; + /* Records tree nodes seen in cgraph_create_edges. Simply using walk_tree_without_duplicates doesn't guarantee each node is visited once because it gets a new htab upon each recursive call from @@ -257,9 +260,13 @@ tree decl = get_callee_fndecl (*tp); if (decl && TREE_CODE (decl) == FUNCTION_DECL) { + struct cgraph_edge *e; + if (DECL_BUILT_IN (decl)) return NULL; - cgraph_record_call (data, decl); + e = cgraph_record_call (data, decl); + if (leafify) + e->maybe_inline_call = 1; /* When we see a function call, we don't want to look at the function reference in the ADDR_EXPR that is hanging from @@ -471,7 +478,10 @@ /* optimize_inline_calls avoids inlining of current_function_decl. */ current_function_decl = decl; if (flag_inline_trees) - optimize_inline_calls (decl); + { + leafify = (lookup_attribute ("leafify", DECL_ATTRIBUTES (node->decl)) != NULL); + optimize_inline_calls (decl); + } if (node->nested) { for (node = node->nested; node; node = node->next_nested) @@ -507,7 +517,7 @@ else { for (e = node->callers; e; e = e->next_caller) - if (e->inline_call) + if (e->inline_call || e->maybe_inline_call) break; if (!e) DECL_SAVED_TREE (decl) = NULL; @@ -1070,6 +1080,23 @@ free (heap_node); } +/* Go down the call tree marking nodes disregarding inlining limits. Called + * for function decls with attribute((leafify)) set. */ + +static void +cgraph_decide_inlining_leafify(struct cgraph_node *node) +{ + struct cgraph_edge *e; + if (node->aux) + return; + for (e = node->callees; e; e = e->next_callee) + { + e->maybe_inline_call = 1; + cgraph_decide_inlining_leafify(e->callee); + } + node->aux = node; +} + /* Decide on the inlining. We do so in the topological order to avoid expenses on updating datastructures. */ @@ -1216,6 +1243,28 @@ } } + /* For all nodes with their function decl having attribute((leafify)) set + * remove inline mark and set maybe_inline_call downward all callees. + * Use node->aux to avoid duplicate walking of callees. */ + + for (node = cgraph_nodes; node; node = node->next) + node->aux = 0; + + for (i = nnodes - 1; i >= 0; i--) + { + struct cgraph_edge *e; + + node = order[i]; + + if (lookup_attribute ("leafify", DECL_ATTRIBUTES (node->decl)) == NULL) + continue; + + for (e = node->callers; e; e = e->next_caller) + e->inline_call = 0; + + cgraph_decide_inlining_leafify(node); + } + if (cgraph_dump_file) fprintf (cgraph_dump_file, "\nInlined %i calls, eliminated %i functions, " @@ -1291,7 +1340,8 @@ for (e = caller->callees; e; e = e->next_callee) if (e->callee == callee) - return e->inline_call; + return e->inline_call + || (e->maybe_inline_call && leafify); /* We do not record builtins in the callgraph. Perhaps it would make more sense to do so and then prune out those not overwritten by explicit function body. */ Index: doc/extend.texi =================================================================== RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v retrieving revision 1.169 diff -u -u -r1.169 extend.texi --- doc/extend.texi 26 Oct 2003 19:03:42 -0000 1.169 +++ doc/extend.texi 31 Oct 2003 10:30:21 -0000 @@ -1976,7 +1976,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{noinline}, @code{always_inline}, +@code{noreturn}, @code{noinline}, @code{always_inline}, @code{leafify}, @code{pure}, @code{const}, @code{nothrow}, @code{format}, @code{format_arg}, @code{no_instrument_function}, @code{section}, @code{constructor}, @code{destructor}, @code{used}, @@ -2052,6 +2052,15 @@ 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{leafify} function attribute +@item leafify +Generally, inlining into a function is limited. For a function marked with +this attribute, every call inside this function will be inlined, if possible. +This attribute implies that the function itself is not considered for automatic +inlining, but into functions marked @code{leafify}. You need to mark the function +@code{noinline} if you want to prevent the latter. The @code{leafify} attribute +only works in unit-at-a-time mode. @cindex @code{pure} function attribute @item pure