This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Inline functions called once III
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org, rth at cygnus dot com
- Date: Wed, 5 Mar 2003 16:23:23 +0100
- Subject: Inline functions called once III
Hi,
This is update of the patch to inline functions called once to the current
unit-at-a-time infrastructure.
Regtested and bootstrapped i386 with -O3 (so the code is excersised)
Honza
/* { dg-options "-O2 -finline-functions-called-once" } */
/* { dg-final { scan-assembler-not "big_function_2" } } */
static void
big_function_2(void);
void
big_function_1()
{
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
big_function_2();
}
void
big_function_2()
{
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
while (t());
}
Tue Feb 18 13:52:22 CET 2003 Jan Hubicka <jh at suse dot cz>
* c-decl.c: (finish_function): Update call of tree_inlinable_function_p.
* cgraph.h: (cgraph_local_info): Add can_inline_once
(cgraph_global_info): Add inline_once.
(cgraph_node): Add previous.
(cgraph_remove_node): New.
* cgraphunit.c (cgraph_mark_functions_to_inline_once): New static
function.
(cgraph_optimize): Call it.
(cgraph_finalize_function): Set inlinable flags.
(cgraph_finalize_compilation_unit): Actually remove the reclaimed nodes.
(cgraph_mark_functions_to_output): Use new inlining heuristics flags.
(cgraph_expand_function): Likewise.
* cgraph.c
(cgraph_node): Put nodes into doubly linked chain.
(cgraph_remove_node): New function.
* flags.h (flag_inline_functions_called_once): Declare.
* toplev.c (flag_inline_functions_called_once): New global variable.
(lang_independent-options): Add inline-functions-called-once.
(parse_options_and_default_flags): Set flag_inline_functions_called_once
for -O3 and -Os.
(process_options): Imply flag_unit_at_a_time when needed.
* tree-inline.c: Include cgraph.h
(inlinable_functions_p): Add extra argument to bypass limits.
(expand_call_inline): Obey cgraph flag.
* tree-inline.h (tree_inlinable_function_p): Update prototype.
* doc/invoke.texi (-finline-functions-called-once): Document.
Index: gcc/c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.367
diff -c -3 -p -r1.367 c-decl.c
*** gcc/c-decl.c 2 Mar 2003 21:18:09 -0000 1.367
--- gcc/c-decl.c 5 Mar 2003 15:16:56 -0000
*************** finish_function (nested, can_defer_p)
*** 6444,6450 ****
predicates depend on cfun and current_function_decl to
function completely. */
timevar_push (TV_INTEGRATION);
! uninlinable = ! tree_inlinable_function_p (fndecl);
if (! uninlinable && can_defer_p
/* Save function tree for inlining. Should return 0 if the
--- 6444,6450 ----
predicates depend on cfun and current_function_decl to
function completely. */
timevar_push (TV_INTEGRATION);
! uninlinable = ! tree_inlinable_function_p (fndecl, 0);
if (! uninlinable && can_defer_p
/* Save function tree for inlining. Should return 0 if the
Index: gcc/cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.5
diff -c -3 -p -r1.5 cgraph.c
*** gcc/cgraph.c 5 Mar 2003 01:33:25 -0000 1.5
--- gcc/cgraph.c 5 Mar 2003 15:16:56 -0000
*************** bool cgraph_global_info_ready = false;
*** 48,54 ****
static struct cgraph_edge *create_edge PARAMS ((struct cgraph_node *,
struct cgraph_node *));
! static void remove_edge PARAMS ((struct cgraph_node *, struct cgraph_node *));
static hashval_t hash_node PARAMS ((const PTR));
static int eq_node PARAMS ((const PTR, const PTR));
--- 48,54 ----
static struct cgraph_edge *create_edge PARAMS ((struct cgraph_node *,
struct cgraph_node *));
! static void cgraph_remove_edge PARAMS ((struct cgraph_node *, struct cgraph_node *));
static hashval_t hash_node PARAMS ((const PTR));
static int eq_node PARAMS ((const PTR, const PTR));
*************** cgraph_node (decl)
*** 95,100 ****
--- 95,103 ----
node = xcalloc (sizeof (*node), 1);
node->decl = decl;
node->next = cgraph_nodes;
+ if (cgraph_nodes)
+ cgraph_nodes->previous = node;
+ node->previous = NULL;
cgraph_nodes = node;
cgraph_n_nodes++;
*slot = node;
*************** create_edge (caller, callee)
*** 127,133 ****
/* Remove the edge from CALLER to CALLEE in the cgraph. */
static void
! remove_edge (caller, callee)
struct cgraph_node *caller, *callee;
{
struct cgraph_edge **edge, **edge2;
--- 130,136 ----
/* Remove the edge from CALLER to CALLEE in the cgraph. */
static void
! cgraph_remove_edge (caller, callee)
struct cgraph_node *caller, *callee;
{
struct cgraph_edge **edge, **edge2;
*************** remove_edge (caller, callee)
*** 146,151 ****
--- 149,185 ----
*edge2 = (*edge2)->next_callee;
}
+ /* Remove the node from cgraph. */
+
+ void
+ cgraph_remove_node (node)
+ struct cgraph_node *node;
+ {
+ while (node->callers)
+ cgraph_remove_edge (node->callers->caller, node);
+ while (node->callees)
+ cgraph_remove_edge (node, node->callees->callee);
+ while (node->nested)
+ cgraph_remove_node (node->nested);
+ if (node->origin)
+ {
+ struct cgraph_node **node2 = &node->origin->nested;
+
+ while (*node2 != node)
+ node2 = &(*node2)->next_nested;
+ (*node2)->next_nested = node->next_nested;
+ }
+ if (node->previous)
+ node->previous->next = node->next;
+ else
+ cgraph_nodes = node;
+ if (node->next)
+ node->next->previous = node->previous;
+ DECL_SAVED_TREE (node->decl) = NULL;
+ /* Do not free the structure itself so the walk over chain can continue. */
+ }
+
+
/* Record call from CALLER to CALLEE */
struct cgraph_edge *
*************** void
*** 159,165 ****
cgraph_remove_call (caller, callee)
tree caller, callee;
{
! remove_edge (cgraph_node (caller), cgraph_node (callee));
}
/* Return true when CALLER_DECL calls CALLEE_DECL. */
--- 193,199 ----
cgraph_remove_call (caller, callee)
tree caller, callee;
{
! cgraph_remove_edge (cgraph_node (caller), cgraph_node (callee));
}
/* Return true when CALLER_DECL calls CALLEE_DECL. */
Index: gcc/cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.2
diff -c -3 -p -r1.2 cgraph.h
*** gcc/cgraph.h 5 Mar 2003 01:33:25 -0000 1.2
--- gcc/cgraph.h 5 Mar 2003 15:16:56 -0000
*************** struct cgraph_local_info
*** 30,36 ****
--- 30,40 ----
/* Set when function function is visiable in current compilation unit only
and it's address is never taken. */
bool local;
+ /* Set when function is small enought to be inlinable many times. */
bool inline_many;
+ /* Set when function can be inlined once (false only for functions calling
+ alloca, using varargs and so on). */
+ bool can_inline_once;
};
/* Information about the function that needs to be computed globally
*************** struct cgraph_local_info
*** 38,45 ****
struct cgraph_global_info
{
! /* Empty for the moment. */
! int dummy;
};
--- 42,49 ----
struct cgraph_global_info
{
! /* Set when the function will be inlined exactly once. */
! bool inline_once;
};
*************** struct cgraph_node
*** 51,57 ****
tree decl;
struct cgraph_edge *callees;
struct cgraph_edge *callers;
! struct cgraph_node *next;
/* For nested functions points to function the node is nested in. */
struct cgraph_node *origin;
/* Points to first nested function, if any. */
--- 55,61 ----
tree decl;
struct cgraph_edge *callees;
struct cgraph_edge *callers;
! struct cgraph_node *next, *previous;
/* For nested functions points to function the node is nested in. */
struct cgraph_node *origin;
/* Points to first nested function, if any. */
*************** struct cgraph_node *cgraph_node PARAMS
*** 95,100 ****
--- 99,105 ----
bool cgraph_calls_p PARAMS ((tree, tree));
struct cgraph_local_info *cgraph_local_info PARAMS ((tree));
struct cgraph_global_info *cgraph_global_info PARAMS ((tree));
+ void cgraph_remove_node PARAMS ((struct cgraph_node *));
/* In cgraphunit.c */
void cgraph_finalize_function PARAMS ((tree, tree));
Index: gcc/cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 cgraphunit.c
*** gcc/cgraphunit.c 5 Mar 2003 01:33:25 -0000 1.2
--- gcc/cgraphunit.c 5 Mar 2003 15:16:56 -0000
*************** static void cgraph_mark_functions_to_out
*** 40,45 ****
--- 40,46 ----
static void cgraph_expand_function PARAMS ((struct cgraph_node *));
static tree record_call_1 PARAMS ((tree *, int *, void *));
static void cgraph_mark_local_functions PARAMS ((void));
+ static void cgraph_mark_functions_to_inline_once PARAMS ((void));
/* Analyze function once it is parsed. Set up the local information
available - create cgraph edges for function calles via BODY. */
*************** cgraph_finalize_function (decl, body)
*** 53,60 ****
node->decl = decl;
if (flag_inline_trees)
! node->local.inline_many = tree_inlinable_function_p (decl);
else
node->local.inline_many = 0;
--- 54,65 ----
node->decl = decl;
+ if (flag_inline_functions_called_once)
+ node->local.can_inline_once = tree_inlinable_function_p (decl, 1);
+ else
+ node->local.can_inline_once = 0;
if (flag_inline_trees)
! node->local.inline_many = tree_inlinable_function_p (decl, 0);
else
node->local.inline_many = 0;
*************** cgraph_finalize_compilation_unit ()
*** 200,206 ****
if (!node->reachable && DECL_SAVED_TREE (decl))
{
! DECL_SAVED_TREE (decl) = NULL;
announce_function (decl);
}
}
--- 205,211 ----
if (!node->reachable && DECL_SAVED_TREE (decl))
{
! cgraph_remove_node (node);
announce_function (decl);
}
}
*************** cgraph_mark_functions_to_output ()
*** 221,227 ****
if (DECL_SAVED_TREE (decl)
&& (node->needed
! || (!node->local.inline_many && node->reachable)
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
&& !TREE_ASM_WRITTEN (decl) && !node->origin
&& !DECL_EXTERNAL (decl))
--- 226,233 ----
if (DECL_SAVED_TREE (decl)
&& (node->needed
! || (!node->local.inline_many && !node->global.inline_once
! && node->reachable)
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
&& !TREE_ASM_WRITTEN (decl) && !node->origin
&& !DECL_EXTERNAL (decl))
*************** cgraph_expand_function (node)
*** 242,248 ****
/* Avoid RTL inlining from taking place. */
(*lang_hooks.callgraph.expand_function) (decl);
! if (DECL_UNINLINABLE (decl))
DECL_SAVED_TREE (decl) = NULL;
current_function_decl = NULL;
}
--- 248,260 ----
/* Avoid RTL inlining from taking place. */
(*lang_hooks.callgraph.expand_function) (decl);
!
! /* When we decided to inline the function once, we never ever should need to
! output it separately. */
! if (node->global.inline_once)
! abort ();
! if (!node->local.inline_many
! || !node->callers)
DECL_SAVED_TREE (decl) = NULL;
current_function_decl = NULL;
}
*************** cgraph_mark_local_functions ()
*** 354,359 ****
--- 366,406 ----
}
}
+ /* Decide what function should be inlined because they are invoked once
+ (so inlining won't result in duplication of the code). */
+
+ static void
+ cgraph_mark_functions_to_inline_once ()
+ {
+ struct cgraph_node *node, *node1;
+
+ if (!quiet_flag)
+ fprintf (stderr, "\n\nMarking functions to inline once:");
+
+ /* Now look for function called only once and mark them to inline. From this
+ point number of calls to given function won't grow. */
+ for (node = cgraph_nodes; node; node = node->next)
+ {
+ if (node->callers && !node->callers->next_caller && !node->needed
+ && node->local.can_inline_once)
+ {
+ bool ok = true;
+
+ /* Verify that we won't duplicate the caller. */
+ for (node1 = node->callers->caller;
+ node1->local.inline_many && node1->callers && ok;
+ node1 = node1->callers->caller)
+ if (node1->callers->next_caller)
+ ok = false;
+ if (ok)
+ {
+ node->global.inline_once = true;
+ announce_function (node->decl);
+ }
+ }
+ }
+ }
+
/* Perform simple optimizations based on callgraph. */
*************** cgraph_optimize ()
*** 364,369 ****
--- 411,419 ----
bool changed = true;
cgraph_mark_local_functions ();
+
+ if (flag_inline_functions_called_once)
+ cgraph_mark_functions_to_inline_once ();
cgraph_global_info_ready = true;
if (!quiet_flag)
Index: gcc/flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.101
diff -c -3 -p -r1.101 flags.h
*** gcc/flags.h 28 Feb 2003 23:57:49 -0000 1.101
--- gcc/flags.h 5 Mar 2003 15:16:56 -0000
*************** extern int flag_rerun_loop_opt;
*** 378,383 ****
--- 378,388 ----
extern int flag_inline_functions;
+ /* Nonzero means to inline functions that are known to be called only
+ once independently on their size. */
+
+ extern int flag_inline_functions_called_once;
+
/* Nonzero for -fkeep-inline-functions: even if we make a function
go inline everywhere, keep its definition around for debugging
purposes. */
Index: gcc/toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.730
diff -c -3 -p -r1.730 toplev.c
*** gcc/toplev.c 5 Mar 2003 01:33:25 -0000 1.730
--- gcc/toplev.c 5 Mar 2003 15:16:57 -0000
*************** int flag_rerun_loop_opt;
*** 681,686 ****
--- 681,691 ----
int flag_inline_functions;
+ /* Nonzero for -finline-functions-called-once: ok to inline functions
+ that are known to be called just once independently on their size. */
+
+ int flag_inline_functions_called_once;
+
/* Nonzero for -fkeep-inline-functions: even if we make a function
go inline everywhere, keep its definition around for debugging
purposes. */
*************** static const lang_independent_options f_
*** 1057,1062 ****
--- 1062,1069 ----
N_("Allow function addresses to be held in registers") },
{"inline-functions", &flag_inline_functions, 1,
N_("Integrate simple functions into their callers") },
+ {"inline-functions-called-once", &flag_inline_functions_called_once, 1,
+ N_("Integrate functions into their callers when they are known to be called just once") },
{"keep-inline-functions", &flag_keep_inline_functions, 1,
N_("Generate code for funcs even if they are fully inlined") },
{"inline", &flag_no_inline, 0,
*************** parse_options_and_default_flags (argc, a
*** 5019,5024 ****
--- 5026,5037 ----
flag_rename_registers = 1;
flag_unswitch_loops = 1;
flag_unit_at_a_time = 1;
+ flag_inline_functions_called_once = 1;
+ }
+
+ if (optimize_size)
+ {
+ flag_inline_functions_called_once = 1;
}
if (optimize < 2 || optimize_size)
*************** process_options ()
*** 5223,5228 ****
--- 5236,5246 ----
flag_asynchronous_unwind_tables = 1;
if (flag_asynchronous_unwind_tables)
flag_unwind_tables = 1;
+
+ /* Unrolling all loops implies that standard loop unrolling must also
+ be done. */
+ if (flag_inline_functions_called_once)
+ flag_unit_at_a_time = 1;
/* Disable unit-at-a-time mode for frontends not supporting callgraph
interface. */
Index: gcc/tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.47
diff -c -3 -p -r1.47 tree-inline.c
*** gcc/tree-inline.c 3 Mar 2003 21:28:21 -0000 1.47
--- gcc/tree-inline.c 5 Mar 2003 15:16:57 -0000
*************** static tree copy_body_r PARAMS ((tree *,
*** 115,121 ****
static tree copy_body PARAMS ((inline_data *));
static tree expand_call_inline PARAMS ((tree *, int *, void *));
static void expand_calls_inline PARAMS ((tree *, inline_data *));
! static int inlinable_function_p PARAMS ((tree, inline_data *));
static tree remap_decl PARAMS ((tree, inline_data *));
#ifndef INLINER_FOR_JAVA
static tree initialize_inlined_parameters PARAMS ((inline_data *, tree, tree));
--- 115,121 ----
static tree copy_body PARAMS ((inline_data *));
static tree expand_call_inline PARAMS ((tree *, int *, void *));
static void expand_calls_inline PARAMS ((tree *, inline_data *));
! static int inlinable_function_p PARAMS ((tree, inline_data *, int));
static tree remap_decl PARAMS ((tree, inline_data *));
#ifndef INLINER_FOR_JAVA
static tree initialize_inlined_parameters PARAMS ((inline_data *, tree, tree));
*************** declare_return_variable (id, return_slot
*** 872,881 ****
/* Returns nonzero if a function can be inlined as a tree. */
int
! tree_inlinable_function_p (fn)
tree fn;
{
! return inlinable_function_p (fn, NULL);
}
/* If *TP is possibly call to alloca, return nonzero. */
--- 872,882 ----
/* Returns nonzero if a function can be inlined as a tree. */
int
! tree_inlinable_function_p (fn, nolimit)
tree fn;
+ int nolimit;
{
! return inlinable_function_p (fn, NULL, nolimit);
}
/* If *TP is possibly call to alloca, return nonzero. */
*************** find_builtin_longjmp_call (exp)
*** 939,947 ****
can be inlined at all. */
static int
! inlinable_function_p (fn, id)
tree fn;
inline_data *id;
{
int inlinable;
int currfn_insns;
--- 940,949 ----
can be inlined at all. */
static int
! inlinable_function_p (fn, id, nolimit)
tree fn;
inline_data *id;
+ int nolimit;
{
int inlinable;
int currfn_insns;
*************** inlinable_function_p (fn, id)
*** 978,989 ****
front-end that must set DECL_INLINE in this case, because
dwarf2out loses if a function is inlined that doesn't have
DECL_INLINE set. */
! else if (! DECL_INLINE (fn))
;
/* We can't inline functions that are too big. Only allow a single
function to be of MAX_INLINE_INSNS_SINGLE size. Make special
allowance for extern inline functions, though. */
! else if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
&& currfn_insns > max_inline_insns_single)
;
/* We can't inline functions that call __builtin_longjmp at all.
--- 980,992 ----
front-end that must set DECL_INLINE in this case, because
dwarf2out loses if a function is inlined that doesn't have
DECL_INLINE set. */
! else if (! DECL_INLINE (fn) && !nolimit)
;
/* We can't inline functions that are too big. Only allow a single
function to be of MAX_INLINE_INSNS_SINGLE size. Make special
allowance for extern inline functions, though. */
! else if (!nolimit
! && ! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
&& currfn_insns > max_inline_insns_single)
;
/* We can't inline functions that call __builtin_longjmp at all.
*************** inlinable_function_p (fn, id)
*** 1014,1020 ****
/* In case we don't disregard the inlining limits and we basically
can inline this function, investigate further. */
if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
! && inlinable)
{
int sum_insns = (id ? id->inlined_stmts : 0) * INSNS_PER_STMT
+ currfn_insns;
--- 1017,1023 ----
/* In case we don't disregard the inlining limits and we basically
can inline this function, investigate further. */
if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
! && inlinable && !nolimit)
{
int sum_insns = (id ? id->inlined_stmts : 0) * INSNS_PER_STMT
+ currfn_insns;
*************** expand_call_inline (tp, walk_subtrees, d
*** 1160,1166 ****
/* Don't try to inline functions that are not well-suited to
inlining. */
! if (!inlinable_function_p (fn, id))
return NULL_TREE;
if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
--- 1163,1171 ----
/* Don't try to inline functions that are not well-suited to
inlining. */
! if ((!flag_unit_at_a_time || !DECL_SAVED_TREE (fn)
! || !cgraph_global_info (fn)->inline_once)
! && !inlinable_function_p (fn, id, 0))
return NULL_TREE;
if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
Index: gcc/tree-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.h,v
retrieving revision 1.4
diff -c -3 -p -r1.4 tree-inline.h
*** gcc/tree-inline.h 31 May 2002 22:15:38 -0000 1.4
--- gcc/tree-inline.h 5 Mar 2003 15:16:57 -0000
*************** Boston, MA 02111-1307, USA. */
*** 25,31 ****
/* Function prototypes. */
void optimize_inline_calls PARAMS ((tree));
! int tree_inlinable_function_p PARAMS ((tree));
tree walk_tree PARAMS ((tree*, walk_tree_fn, void*, void*));
tree walk_tree_without_duplicates PARAMS ((tree*, walk_tree_fn, void*));
tree copy_tree_r PARAMS ((tree*, int*, void*));
--- 25,31 ----
/* Function prototypes. */
void optimize_inline_calls PARAMS ((tree));
! int tree_inlinable_function_p PARAMS ((tree, int));
tree walk_tree PARAMS ((tree*, walk_tree_fn, void*, void*));
tree walk_tree_without_duplicates PARAMS ((tree*, walk_tree_fn, void*));
tree copy_tree_r PARAMS ((tree*, int*, void*));
Index: gcc/doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.253
diff -c -3 -p -r1.253 invoke.texi
*** gcc/doc/invoke.texi 5 Mar 2003 01:33:26 -0000 1.253
--- gcc/doc/invoke.texi 5 Mar 2003 15:16:59 -0000
*************** in the following sections.
*** 272,279 ****
-fexpensive-optimizations -ffast-math -ffloat-store @gol
-fforce-addr -fforce-mem -ffunction-sections @gol
-fgcse -fgcse-lm -fgcse-sm -floop-optimize -fcrossjumping @gol
! -fif-conversion -fif-conversion2 @gol
! -finline-functions -finline-limit= at var{n} -fkeep-inline-functions @gol
-fkeep-static-consts -fmerge-constants -fmerge-all-constants @gol
-fmove-all-movables -fnew-ra -fno-branch-count-reg @gol
-fno-default-inline -fno-defer-pop @gol
--- 272,279 ----
-fexpensive-optimizations -ffast-math -ffloat-store @gol
-fforce-addr -fforce-mem -ffunction-sections @gol
-fgcse -fgcse-lm -fgcse-sm -floop-optimize -fcrossjumping @gol
! -fif-conversion -fif-conversion2 -finline-functions @gol
! -finline-functions-called-once -finline-limit= at var{n} -fkeep-inline-functions @gol
-fkeep-static-consts -fmerge-constants -fmerge-all-constants @gol
-fmove-all-movables -fnew-ra -fno-branch-count-reg @gol
-fno-default-inline -fno-defer-pop @gol
*************** declared @code{static}, then the functio
*** 3628,3633 ****
--- 3628,3643 ----
assembler code in its own right.
Enabled at level @option{-O3}.
+
+ @item -finline-functions-called-once
+ @opindex finline-functions-called-once
+ Integrate all functions that are known to be called once and whose address is
+ not taken, so the out of line copy of function won't be needed anymore.
+ This should result in both smaller and faster programs in most cases.
+
+ Enabled at level @option{-O3} and @option{-Os}. The function implies
+ @option{-funit-at-a-time} and has effect only for language frontends supporting
+ this mode.
@item -finline-limit= at var{n}
@opindex finline-limit