diff options
author | Jan Hubicka <jh@suse.cz> | 2003-03-08 14:26:37 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2003-03-08 13:26:37 +0000 |
commit | 18d13f34175f157bc3152afdf48da798452afc1b (patch) | |
tree | 8a4f34953d22192851b98b6fb46d7a44532ecfc0 /gcc | |
parent | 4a07c08a47f2a4fbce5634b93834ed824ebafc79 (diff) | |
download | gcc-18d13f34175f157bc3152afdf48da798452afc1b.zip gcc-18d13f34175f157bc3152afdf48da798452afc1b.tar.gz gcc-18d13f34175f157bc3152afdf48da798452afc1b.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/c-decl.c | 2 | ||||
-rw-r--r-- | gcc/cgraph.c | 40 | ||||
-rw-r--r-- | gcc/cgraph.h | 11 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 77 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 40 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/inline-3.c | 47 | ||||
-rw-r--r-- | gcc/tree-inline.c | 21 | ||||
-rw-r--r-- | gcc/tree-inline.h | 2 |
10 files changed, 246 insertions, 22 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e3919a9..383f9e6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 4779406..f7996f1 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -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 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 1a078f6..bb035b2 100644 --- a/gcc/cgraph.c +++ b/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. */ diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 6c8c8af..b785e17 100644 --- a/gcc/cgraph.h +++ b/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)); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 81a8b2e..c01bba6 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -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:"); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index d5bc360..3152299 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -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" ""))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e85ff23..d44271e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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> diff --git a/gcc/testsuite/gcc.dg/inline-3.c b/gcc/testsuite/gcc.dg/inline-3.c new file mode 100644 index 0000000..a3de193 --- /dev/null +++ b/gcc/testsuite/gcc.dg/inline-3.c @@ -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()); +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index e1fab06..a49dca9 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -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)) diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h index 9c11436..0b9fc89 100644 --- a/gcc/tree-inline.h +++ b/gcc/tree-inline.h @@ -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*)); |