mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-03 16:54:27 +08:00
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:
parent
4a07c08a47
commit
18d13f3417
@ -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
|
||||
|
@ -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
|
||||
|
40
gcc/cgraph.c
40
gcc/cgraph.c
@ -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. */
|
||||
|
11
gcc/cgraph.h
11
gcc/cgraph.h
@ -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));
|
||||
|
@ -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:");
|
||||
|
@ -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" "")))
|
||||
|
@ -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>
|
||||
|
||||
|
47
gcc/testsuite/gcc.dg/inline-3.c
Normal file
47
gcc/testsuite/gcc.dg/inline-3.c
Normal 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());
|
||||
}
|
@ -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))
|
||||
|
@ -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*));
|
||||
|
Loading…
Reference in New Issue
Block a user