diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2001-10-05 04:20:27 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@gcc.gnu.org> | 2001-10-05 04:20:27 +0000 |
commit | 4838c5ee553f062d75d0a6288a025e98600de97c (patch) | |
tree | 8ce05ef7518fd1359d3ae5d044511179f1ea1c8f /gcc/c-lang.c | |
parent | 8d5463d486fe257414a840e204531a8e4405a9a6 (diff) | |
download | gcc-4838c5ee553f062d75d0a6288a025e98600de97c.zip gcc-4838c5ee553f062d75d0a6288a025e98600de97c.tar.gz gcc-4838c5ee553f062d75d0a6288a025e98600de97c.tar.bz2 |
Makefile.in (c-decl.o): Depend on tree-inline.h.
* Makefile.in (c-decl.o): Depend on tree-inline.h.
(c-lang.o): Likewise, as well as insn-config.h and integrate.h.
* c-decl.c: Include tree-inline.h.
(c_expand_body): Call optimize_inline_calls. Determine whether
a function is inlinable upfront, and only clear
DECL_SAVED_TREE, DECL_INITIAL and DECL_ARGUMENTS if it isn't.
* c-lang.c: Include tree-inline.h, insn-config.h and integrate.h.
(c_disregard_inline_limits): New function.
(inline_forbidden_p, c_cannot_inline_tree_fn): Likewise.
(c_post_options): Enable tree inlining if inlining is enabled.
Don't inline trees when instrumenting functions.
(c_init): Initialize lang_disregard_inline_limits and
lang_cannot_inline_tree_fn.
* tree-inline.c (initialize_inlined_parameters): Handle calls
with fewer arguments than declared parameters, and fewer
parameters than passed arguments. Don't assume value is a
DECL.
(declare_return_variable): Convert return value back to the
original type, if it was promoted.
(tree_inlinable_function_p): New function.
(inlinable_function_p): Don't look at DECL_INLINE if we're
inlining all functions. Make it work with a NULL id.
Re-check DECL_UNINLINABLE after language-specific checks.
(varargs_function_p): Move back to cp/tree.c.
* tree-inline.h (tree_inlinable_function_p): Declare it.
(varargs_function_p): Removed declaration.
* integrate.h (function_attribute_inlinable_p): Declare it.
* integrate.c (function_attribute_inlinable_p): Export it.
(save_for_inline): Don't bother to prepare argvec when not
inlining.
* cse.c (check_for_label_ref): Don't check deleted labels.
From-SVN: r46025
Diffstat (limited to 'gcc/c-lang.c')
-rw-r--r-- | gcc/c-lang.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/gcc/c-lang.c b/gcc/c-lang.c index 36d73d2..7e7ebb7 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -23,6 +23,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "config.h" #include "system.h" #include "tree.h" +#include "tree-inline.h" #include "function.h" #include "input.h" #include "toplev.h" @@ -35,12 +36,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "c-tree.h" #include "c-lex.h" #include "cpplib.h" +#include "insn-config.h" +#include "integrate.h" static int c_tree_printer PARAMS ((output_buffer *)); static int c_missing_noreturn_ok_p PARAMS ((tree)); static void c_init PARAMS ((void)); static void c_init_options PARAMS ((void)); static void c_post_options PARAMS ((void)); +static int c_disregard_inline_limits PARAMS ((tree)); +static int c_cannot_inline_tree_fn PARAMS ((tree *)); /* Each front end provides its own. */ struct lang_hooks lang_hooks = {c_init, @@ -54,6 +59,22 @@ static void c_post_options () { cpp_post_options (parse_in); + + /* Use tree inlining if possible. Function instrumentation is only + done in the RTL level, so we disable tree inlining. */ + if (! flag_instrument_function_entry_exit) + { + if (!flag_no_inline) + { + flag_inline_trees = 1; + flag_no_inline = 1; + } + if (flag_inline_functions) + { + flag_inline_trees = 2; + flag_inline_functions = 0; + } + } } static void @@ -91,6 +112,8 @@ c_init () diagnostic_format_decoder (global_dc) = &c_tree_printer; lang_expand_decl_stmt = &c_expand_decl_stmt; lang_missing_noreturn_ok_p = &c_missing_noreturn_ok_p; + lang_disregard_inline_limits = &c_disregard_inline_limits; + lang_cannot_inline_tree_fn = &c_cannot_inline_tree_fn; c_parse_init (); } @@ -308,3 +331,155 @@ c_missing_noreturn_ok_p (decl) ok for the `main' function in hosted implementations. */ return flag_hosted && MAIN_NAME_P (DECL_ASSEMBLER_NAME (decl)); } + +/* We want to inline `extern inline' functions even if this would + violate inlining limits. Some glibc and linux constructs depend on + such functions always being inlined when optimizing. */ + +static int +c_disregard_inline_limits (fn) + tree fn; +{ + return DECL_INLINE (fn) && DECL_EXTERNAL (fn); +} + +static tree inline_forbidden_p PARAMS ((tree *, int *, void *)); + +static tree +inline_forbidden_p (nodep, walk_subtrees, fn) + tree *nodep; + int *walk_subtrees ATTRIBUTE_UNUSED; + void *fn; +{ + tree node = *nodep; + tree t; + + switch (TREE_CODE (node)) + { + case CALL_EXPR: + t = get_callee_fndecl (node); + + if (! t) + break; + + /* We cannot inline functions that call setjmp. */ + if (setjmp_call_p (t)) + return node; + + switch (DECL_FUNCTION_CODE (t)) + { + /* We cannot inline functions that take a variable number of + arguments. */ + case BUILT_IN_VARARGS_START: + case BUILT_IN_STDARG_START: +#if 0 + /* Functions that need information about the address of the + caller can't (shouldn't?) be inlined. */ + case BUILT_IN_RETURN_ADDRESS: +#endif + return node; + + default: + break; + } + + break; + + case DECL_STMT: + /* We cannot inline functions that contain other functions. */ + if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL + && DECL_INITIAL (TREE_OPERAND (node, 0))) + return node; + break; + + case GOTO_STMT: + case GOTO_EXPR: + t = TREE_OPERAND (node, 0); + + /* We will not inline a function which uses computed goto. The + addresses of its local labels, which may be tucked into + global storage, are of course not constant across + instantiations, which causes unexpected behaviour. */ + if (TREE_CODE (t) != LABEL_DECL) + return node; + + /* We cannot inline a nested function that jumps to a nonlocal + label. */ + if (TREE_CODE (t) == LABEL_DECL + && DECL_CONTEXT (t) && DECL_CONTEXT (t) != fn) + return node; + + break; + + default: + break; + } + + return NULL_TREE; +} + +static int +c_cannot_inline_tree_fn (fnp) + tree *fnp; +{ + tree fn = *fnp; + tree t; + + if (! function_attribute_inlinable_p (fn)) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + + /* If a function has pending sizes, we must not defer its + compilation, and we can't inline it as a tree. */ + if (fn == current_function_decl) + { + t = get_pending_sizes (); + put_pending_sizes (t); + + if (t) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + } + + if (DECL_CONTEXT (fn)) + { + /* If a nested function has pending sizes, we may have already + saved them. */ + if (DECL_LANG_SPECIFIC (fn)->pending_sizes) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + } + else + { + /* We rely on the fact that this function is called upfront, + just before we start expanding a function. If FN is active + (i.e., it's the current_function_decl or a parent thereof), + we have to walk FN's saved tree. Otherwise, we can safely + assume we have done it before and, if we didn't mark it as + uninlinable (in which case we wouldn't have been called), it + is inlinable. Unfortunately, this strategy doesn't work for + nested functions, because they're only expanded as part of + their enclosing functions, so the inlinability test comes in + late. */ + t = current_function_decl; + + while (t && t != fn) + t = DECL_CONTEXT (t); + if (! t) + return 0; + } + + if (walk_tree (&DECL_SAVED_TREE (fn), inline_forbidden_p, fn, NULL)) + { + DECL_UNINLINABLE (fn) = 1; + return 1; + } + + return 0; +} |