Index: c-common.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/c-common.c,v retrieving revision 1.465 diff -u -c -3 -p -r1.465 c-common.c *** c-common.c 20 Oct 2003 22:03:32 -0000 1.465 --- c-common.c 31 Oct 2003 12:42:53 -0000 *************** static tree handle_noreturn_attribute (t *** 762,767 **** --- 762,768 ---- 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 *); *************** const struct attribute_spec c_common_att *** 824,829 **** --- 825,832 ---- 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, *************** handle_always_inline_attribute (tree *no *** 4448,4453 **** --- 4451,4478 ---- 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 -c -3 -p -r1.34 cgraph.c *** cgraph.c 22 Oct 2003 19:18:03 -0000 1.34 --- cgraph.c 31 Oct 2003 12:42:53 -0000 *************** create_edge (struct cgraph_node *caller, *** 157,162 **** --- 157,163 ---- 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. */ *************** create_edge (struct cgraph_node *caller, *** 165,170 **** --- 166,172 ---- 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 -c -3 -p -r1.23 cgraph.h *** cgraph.h 22 Oct 2003 11:58:09 -0000 1.23 --- cgraph.h 31 Oct 2003 12:42:53 -0000 *************** struct cgraph_edge GTY(()) *** 120,125 **** --- 120,126 ---- 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 -c -3 -p -r1.37 cgraphunit.c *** cgraphunit.c 22 Oct 2003 11:58:09 -0000 1.37 --- cgraphunit.c 31 Oct 2003 12:42:53 -0000 *************** static int nfunctions_inlined; *** 57,62 **** --- 57,65 ---- 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 *************** record_call_1 (tree *tp, int *walk_subtr *** 257,265 **** tree decl = get_callee_fndecl (*tp); if (decl && TREE_CODE (decl) == FUNCTION_DECL) { if (DECL_BUILT_IN (decl)) return NULL; ! cgraph_record_call (data, decl); /* When we see a function call, we don't want to look at the function reference in the ADDR_EXPR that is hanging from --- 260,272 ---- tree decl = get_callee_fndecl (*tp); if (decl && TREE_CODE (decl) == FUNCTION_DECL) { + struct cgraph_edge *e; + if (DECL_BUILT_IN (decl)) return NULL; ! 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 *************** cgraph_optimize_function (struct cgraph_ *** 471,477 **** /* optimize_inline_calls avoids inlining of current_function_decl. */ current_function_decl = decl; if (flag_inline_trees) ! optimize_inline_calls (decl); if (node->nested) { for (node = node->nested; node; node = node->next_nested) --- 478,487 ---- /* optimize_inline_calls avoids inlining of current_function_decl. */ current_function_decl = decl; if (flag_inline_trees) ! { ! 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) *************** cgraph_expand_function (struct cgraph_no *** 507,513 **** else { for (e = node->callers; e; e = e->next_caller) ! if (e->inline_call) break; if (!e) DECL_SAVED_TREE (decl) = NULL; --- 517,523 ---- else { for (e = node->callers; e; e = e->next_caller) ! if (e->inline_call || e->maybe_inline_call) break; if (!e) DECL_SAVED_TREE (decl) = NULL; *************** cgraph_decide_inlining_of_small_function *** 1070,1075 **** --- 1080,1106 ---- free (heap_node); } + /* Go down the call tree marking nodes disregarding inlining limits. Called + * for function decls with attribute((leafify)) set. Avoid recursion and + * redundant work by using node->aux field. */ + + static void + cgraph_decide_inlining_leafify(struct cgraph_node *node) + { + struct cgraph_edge *e; + if (node->aux) + return; + node->aux = node; + for (e = node->callees; e; e = e->next_callee) + { + if (e->callee == node) + continue; + e->maybe_inline_call = 1; + e->callee->global.inlined = 1; + cgraph_decide_inlining_leafify(e->callee); + } + } + /* Decide on the inlining. We do so in the topological order to avoid expenses on updating datastructures. */ *************** cgraph_decide_inlining (void) *** 1216,1221 **** --- 1247,1274 ---- } } + /* 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, " *************** cgraph_inline_p (tree caller_decl, tree *** 1291,1297 **** for (e = caller->callees; e; e = e->next_callee) if (e->callee == callee) ! return e->inline_call; /* 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. */ --- 1344,1350 ---- for (e = caller->callees; e; e = e->next_callee) if (e->callee == callee) ! 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 -c -3 -p -r1.169 extend.texi *** doc/extend.texi 26 Oct 2003 19:03:42 -0000 1.169 --- doc/extend.texi 31 Oct 2003 12:42:57 -0000 *************** The keyword @code{__attribute__} allows *** 1976,1982 **** 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{pure}, @code{const}, @code{nothrow}, @code{format}, @code{format_arg}, @code{no_instrument_function}, @code{section}, @code{constructor}, @code{destructor}, @code{used}, --- 1976,1982 ---- 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{leafify}, @code{pure}, @code{const}, @code{nothrow}, @code{format}, @code{format_arg}, @code{no_instrument_function}, @code{section}, @code{constructor}, @code{destructor}, @code{used}, *************** inlining. *** 2052,2057 **** --- 2052,2066 ---- 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