inline-3.c: New test.

* gcc.dg/inline-3.c: New test.

	* 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.
	* 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.

From-SVN: r63983
This commit is contained in:
Jan Hubicka 2003-03-08 14:26:37 +01:00 committed by Jan Hubicka
parent 4a07c08a47
commit 18d13f3417
10 changed files with 246 additions and 22 deletions

View File

@ -1,3 +1,26 @@
Sat Mar 8 14:13:35 CET 2003 Jan Hubicka <jh@suse.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.
* 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.
2003-03-08 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* gcse.c (bypass_block, bypass_conditional_jumps): Do not create

View File

@ -6444,7 +6444,7 @@ finish_function (nested, can_defer_p)
predicates depend on cfun and current_function_decl to
function completely. */
timevar_push (TV_INTEGRATION);
uninlinable = ! tree_inlinable_function_p (fndecl);
uninlinable = ! tree_inlinable_function_p (fndecl, 0);
if (! uninlinable && can_defer_p
/* Save function tree for inlining. Should return 0 if the

View File

@ -48,7 +48,7 @@ bool cgraph_global_info_ready = false;
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 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));
@ -95,6 +95,9 @@ cgraph_node (decl)
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;
@ -127,7 +130,7 @@ create_edge (caller, callee)
/* Remove the edge from CALLER to CALLEE in the cgraph. */
static void
remove_edge (caller, callee)
cgraph_remove_edge (caller, callee)
struct cgraph_node *caller, *callee;
{
struct cgraph_edge **edge, **edge2;
@ -146,6 +149,37 @@ remove_edge (caller, callee)
*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 = 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 *
@ -159,7 +193,7 @@ void
cgraph_remove_call (caller, callee)
tree caller, callee;
{
remove_edge (cgraph_node (caller), cgraph_node (callee));
cgraph_remove_edge (cgraph_node (caller), cgraph_node (callee));
}
/* Return true when CALLER_DECL calls CALLEE_DECL. */

View File

@ -30,7 +30,11 @@ struct cgraph_local_info
/* 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
@ -38,8 +42,8 @@ struct cgraph_local_info
struct cgraph_global_info
{
/* Empty for the moment. */
int dummy;
/* Set when the function will be inlined exactly once. */
bool inline_once;
};
/* Information about the function that is propagated by the RTL backend.
@ -60,7 +64,7 @@ struct cgraph_node
tree decl;
struct cgraph_edge *callees;
struct cgraph_edge *callers;
struct cgraph_node *next;
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. */
@ -100,6 +104,7 @@ extern bool cgraph_global_info_ready;
/* In cgraph.c */
void dump_cgraph PARAMS ((FILE *));
void cgraph_remove_call PARAMS ((tree, tree));
void cgraph_remove_node PARAMS ((struct cgraph_node *));
struct cgraph_edge *cgraph_record_call PARAMS ((tree, tree));
struct cgraph_node *cgraph_node PARAMS ((tree decl));
bool cgraph_calls_p PARAMS ((tree, tree));

View File

@ -40,6 +40,8 @@ static void cgraph_mark_functions_to_output PARAMS ((void));
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));
static void cgraph_optimize_function PARAMS ((struct cgraph_node *));
/* Analyze function once it is parsed. Set up the local information
available - create cgraph edges for function calles via BODY. */
@ -53,8 +55,9 @@ cgraph_finalize_function (decl, body)
node->decl = decl;
node->local.can_inline_once = tree_inlinable_function_p (decl, 1);
if (flag_inline_trees)
node->local.inline_many = tree_inlinable_function_p (decl);
node->local.inline_many = tree_inlinable_function_p (decl, 0);
else
node->local.inline_many = 0;
@ -200,7 +203,7 @@ cgraph_finalize_compilation_unit ()
if (!node->reachable && DECL_SAVED_TREE (decl))
{
DECL_SAVED_TREE (decl) = NULL;
cgraph_remove_node (node);
announce_function (decl);
}
}
@ -221,7 +224,8 @@ cgraph_mark_functions_to_output ()
if (DECL_SAVED_TREE (decl)
&& (node->needed
|| (!node->local.inline_many && node->reachable)
|| (!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))
@ -229,6 +233,22 @@ cgraph_mark_functions_to_output ()
}
}
/* Optimize the function before expansion. */
static void
cgraph_optimize_function (node)
struct cgraph_node *node;
{
tree decl = node->decl;
if (flag_inline_trees)
optimize_inline_calls (decl);
if (node->nested)
{
for (node = node->nested; node; node = node->next_nested)
cgraph_optimize_function (node);
}
}
/* Expand function specified by NODE. */
static void
cgraph_expand_function (node)
@ -237,12 +257,18 @@ cgraph_expand_function (node)
tree decl = node->decl;
announce_function (decl);
if (flag_inline_trees)
optimize_inline_calls (decl);
cgraph_optimize_function (node);
/* Avoid RTL inlining from taking place. */
(*lang_hooks.callgraph.expand_function) (decl);
if (DECL_UNINLINABLE (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;
}
@ -354,6 +380,43 @@ cgraph_mark_local_functions ()
}
}
/* 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 || node1->needed)
ok = false;
if (ok)
{
node->global.inline_once = true;
announce_function (node->decl);
}
}
}
}
/* Perform simple optimizations based on callgraph. */
@ -365,6 +428,8 @@ cgraph_optimize ()
cgraph_mark_local_functions ();
cgraph_mark_functions_to_inline_once ();
cgraph_global_info_ready = true;
if (!quiet_flag)
fprintf (stderr, "\n\nAssembling functions:");

View File

@ -4519,6 +4519,16 @@
[(set_attr "type" "sseicvt")
(set_attr "athlon_decode" "double,vector")])
;; Avoid vector decoded form of the instruction.
(define_peephole2
[(match_scratch:SF 2 "x")
(set (match_operand:DI 0 "register_operand" "")
(fix:DI (match_operand:SF 1 "nonimmediate_operand" "")))]
"TARGET_K8 && !optimize_size"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (fix:DI (match_dup 2)))]
"")
(define_insn "fix_truncdfdi_sse"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(fix:DI (match_operand:DF 1 "nonimmediate_operand" "Y,Ym")))]
@ -4527,6 +4537,16 @@
[(set_attr "type" "sseicvt,sseicvt")
(set_attr "athlon_decode" "double,vector")])
;; Avoid vector decoded form of the instruction.
(define_peephole2
[(match_scratch:DF 2 "Y")
(set (match_operand:DI 0 "register_operand" "")
(fix:DI (match_operand:DF 1 "nonimmediate_operand" "")))]
"TARGET_K8 && !optimize_size"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (fix:DI (match_dup 2)))]
"")
;; Signed conversion to SImode.
(define_expand "fix_truncxfsi2"
@ -4630,6 +4650,16 @@
[(set_attr "type" "sseicvt")
(set_attr "athlon_decode" "double,vector")])
;; Avoid vector decoded form of the instruction.
(define_peephole2
[(match_scratch:SF 2 "x")
(set (match_operand:SI 0 "register_operand" "")
(fix:SI (match_operand:SF 1 "nonimmediate_operand" "")))]
"TARGET_K8 && !optimize_size"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (fix:SI (match_dup 2)))]
"")
(define_insn "fix_truncdfsi_sse"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(fix:SI (match_operand:DF 1 "nonimmediate_operand" "Y,Ym")))]
@ -4638,6 +4668,16 @@
[(set_attr "type" "sseicvt")
(set_attr "athlon_decode" "double,vector")])
;; Avoid vector decoded form of the instruction.
(define_peephole2
[(match_scratch:DF 2 "Y")
(set (match_operand:SI 0 "register_operand" "")
(fix:SI (match_operand:DF 1 "nonimmediate_operand" "")))]
"TARGET_K8 && !optimize_size"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (fix:SI (match_dup 2)))]
"")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(fix:SI (match_operand 1 "register_operand" "")))

View File

@ -1,3 +1,7 @@
Sat Mar 8 14:18:15 CET 2003 Jan Hubicka <jh@suse.cz>
* gcc.dg/inline-3.c: New test.
2003-03-08 Mark Mitchell <mark@codesourcery.com>
PR c++/9809
@ -22,6 +26,7 @@
Fri Mar 7 17:41:07 CET 2003 Jan Hubicka <jh@suse.cz>
* gcc.dg/i386-local2.c: Fix problems with certain versions of dejagnu.
* gcc.dg/inline-3.c: New test.
2003-03-06 Mark Mitchell <mark@codesourcery.com>

View File

@ -0,0 +1,47 @@
/* { dg-options "-O2 -funit-at-a-time" } */
/* { 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();
}
static 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());
}

View File

@ -115,7 +115,7 @@ static tree copy_body_r PARAMS ((tree *, int *, void *));
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 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));
@ -872,10 +872,11 @@ declare_return_variable (id, return_slot_addr, var)
/* Returns nonzero if a function can be inlined as a tree. */
int
tree_inlinable_function_p (fn)
tree_inlinable_function_p (fn, nolimit)
tree fn;
int nolimit;
{
return inlinable_function_p (fn, NULL);
return inlinable_function_p (fn, NULL, nolimit);
}
/* If *TP is possibly call to alloca, return nonzero. */
@ -939,9 +940,10 @@ find_builtin_longjmp_call (exp)
can be inlined at all. */
static int
inlinable_function_p (fn, id)
inlinable_function_p (fn, id, nolimit)
tree fn;
inline_data *id;
int nolimit;
{
int inlinable;
int currfn_insns;
@ -973,12 +975,13 @@ inlinable_function_p (fn, id)
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))
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 (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
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.
@ -1009,7 +1012,7 @@ inlinable_function_p (fn, id)
/* 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)
&& inlinable && !nolimit)
{
int sum_insns = (id ? id->inlined_stmts : 0) * INSNS_PER_STMT
+ currfn_insns;
@ -1158,7 +1161,9 @@ expand_call_inline (tp, walk_subtrees, data)
/* Don't try to inline functions that are not well-suited to
inlining. */
if (!inlinable_function_p (fn, id))
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))

View File

@ -25,7 +25,7 @@ Boston, MA 02111-1307, USA. */
/* Function prototypes. */
void optimize_inline_calls PARAMS ((tree));
int tree_inlinable_function_p 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*));