From 4985cde3ef44391a43fd95c0972bf72c86e127cb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 29 Aug 2003 16:21:13 -0700 Subject: [PATCH] tree-optimize.c: New file. gcc/ * tree-optimize.c: New file. * Makefile.in (OBJS-archive): Add tree-optimize.o. (tree-optimize.o): New. * c-decl.c (store_parm_decls): Use allocate_struct_function. (finish_function): Don't free_after_parsing or free_after_compilation. (set_save_expr_context): Move to tree-optimize.c. (c_expand_body_1): Use tree_rest_of_compilation. * c-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New. * objc/objc-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New. * c-objc-common.c (expand_deferred_fns): Don't emit unused inlines; iterate until closure. * langhooks-def.h (LANG_HOOKS_RTL_EXPAND_START, LANG_HOOKS_RTL_EXPAND_STMT, LANG_HOOKS_RTL_EXPAND_END): New. (LANG_HOOKS_RTL_EXPAND_INITIALIZER): New. * langhooks.h (struct lang_hooks_for_rtl_expansion): New. * toplev.h (tree_rest_of_compilation): Declare it. gcc/cp/ * cp-lang.c (LANG_HOOKS_RTL_EXPAND_START): New. (LANG_HOOKS_RTL_EXPAND_STMT): New. * cp-tree.h (cxx_expand_function_start): Declare. * decl.c (start_function): Use allocate_struct_function. Move stmts_are_full_exprs_p assertion from expand_body. Do not free_after_parsing or free_after_compilation. (cxx_push_function_context): Move code to set struct function data from genrtl_start_function. * optimize.c (optimize_function): Don't inc/dec function_depth. * semantics.c (expand_body): Use tree_rest_of_compilation. (cxx_expand_function_start): Rename from genrtl_start_function, omit bits done by tree_rest_of_compilation. (genrtl_finish_function): Remove. (clear_decl_rtl): Move to ../tree-optimize.c. Co-Authored-By: Jason Merrill From-SVN: r70933 --- gcc/ChangeLog | 19 ++++ gcc/Makefile.in | 13 ++- gcc/c-decl.c | 139 +----------------------- gcc/c-lang.c | 3 + gcc/c-objc-common.c | 39 +++++-- gcc/cp/ChangeLog | 18 ++++ gcc/cp/cp-lang.c | 5 + gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 40 +++++-- gcc/cp/optimize.c | 14 --- gcc/cp/semantics.c | 250 ++++--------------------------------------- gcc/langhooks-def.h | 13 ++- gcc/langhooks.h | 15 +++ gcc/objc/objc-lang.c | 3 + gcc/toplev.h | 1 + gcc/tree-optimize.c | 250 +++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 422 insertions(+), 401 deletions(-) create mode 100644 gcc/tree-optimize.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d573615b6e3..fdabb62d39d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2003-08-29 Richard Henderson + + * tree-optimize.c: New file. + * Makefile.in (OBJS-archive): Add tree-optimize.o. + (tree-optimize.o): New. + * c-decl.c (store_parm_decls): Use allocate_struct_function. + (finish_function): Don't free_after_parsing or free_after_compilation. + (set_save_expr_context): Move to tree-optimize.c. + (c_expand_body_1): Use tree_rest_of_compilation. + * c-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New. + * objc/objc-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New. + * c-objc-common.c (expand_deferred_fns): Don't emit unused inlines; + iterate until closure. + * langhooks-def.h (LANG_HOOKS_RTL_EXPAND_START, + LANG_HOOKS_RTL_EXPAND_STMT, LANG_HOOKS_RTL_EXPAND_END): New. + (LANG_HOOKS_RTL_EXPAND_INITIALIZER): New. + * langhooks.h (struct lang_hooks_for_rtl_expansion): New. + * toplev.h (tree_rest_of_compilation): Declare it. + 2003-08-29 Richard Henderson * function.h (struct function): Add rtl_inline_init, saved_for_inline. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 94569eb237a..3ea2c569d74 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -845,7 +845,7 @@ OBJS-common = \ OBJS-md = $(out_object_file) OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \ - cgraph.o cgraphunit.o + tree-optimize.o cgraph.o cgraphunit.o OBJS = $(OBJS-common) $(out_object_file) $(OBJS-archive) @@ -1466,10 +1466,13 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h fu tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) flags.h langhooks.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ $(EXPR_H) $(SPLAY_TREE_H) tree-dump.h -tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h $(INTEGRATE_H) \ - $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h langhooks.h \ - $(C_COMMON_H) tree-inline.h cgraph.h +tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h \ + $(INTEGRATE_H) $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \ + langhooks.h $(C_COMMON_H) tree-inline.h cgraph.h +tree-optimize.o : tree-optimize.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) toplev.h langhooks.h cgraph.h $(TIMEVAR_H) function.h $(GGC_H) + print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(GGC_H) langhooks.h real.h stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 51491d283e5..eef6e6df7b5 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -6032,7 +6032,7 @@ store_parm_decls (void) gen_aux_info_record (fndecl, 1, 0, prototype); /* Initialize the RTL code for the function. */ - init_function_start (fndecl); + allocate_struct_function (fndecl); /* Begin the statement tree for this function. */ begin_stmt_tree (&DECL_SAVED_TREE (fndecl)); @@ -6142,11 +6142,8 @@ finish_function (int nested, int can_defer_p) && DECL_INLINE (fndecl)) warning ("no return statement in function returning non-void"); - /* Clear out memory we no longer need. */ - free_after_parsing (cfun); - /* Since we never call rest_of_compilation, we never clear - CFUN. Do so explicitly. */ - free_after_compilation (cfun); + /* We're leaving the context of this function, so zap cfun. It's still in + DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation. */ cfun = NULL; if (flag_unit_at_a_time && can_defer_p) @@ -6239,25 +6236,6 @@ c_expand_deferred_function (tree fndecl) } } -/* Called to move the SAVE_EXPRs for parameter declarations in a - nested function into the nested function. DATA is really the - nested FUNCTION_DECL. */ - -static tree -set_save_expr_context (tree *tp, - int *walk_subtrees, - void *data) -{ - if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp)) - SAVE_EXPR_CONTEXT (*tp) = (tree) data; - /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause - circularity. */ - else if (DECL_P (*tp)) - *walk_subtrees = 0; - - return NULL_TREE; -} - /* Generate the RTL for the body of FNDECL. If NESTED_P is nonzero, then we are already in the process of generating RTL for another function. If can_defer_p is zero, we won't attempt to defer the @@ -6266,78 +6244,14 @@ set_save_expr_context (tree *tp, static void c_expand_body_1 (tree fndecl, int nested_p) { - timevar_push (TV_EXPAND); - if (nested_p) { /* Make sure that we will evaluate variable-sized types involved in our function's type. */ expand_pending_sizes (DECL_LANG_SPECIFIC (fndecl)->pending_sizes); - /* Squirrel away our current state. */ - push_function_context (); } - /* Initialize the RTL code for the function. */ - current_function_decl = fndecl; - input_location = DECL_SOURCE_LOCATION (fndecl); - init_function_start (fndecl); - - /* This function is being processed in whole-function mode. */ - cfun->x_whole_function_mode_p = 1; - - /* Even though we're inside a function body, we still don't want to - call expand_expr to calculate the size of a variable-sized array. - We haven't necessarily assigned RTL to all variables yet, so it's - not safe to try to expand expressions involving them. */ - immediate_size_expand = 0; - cfun->x_dont_save_pending_sizes_p = 1; - - /* Set up parameters and prepare for return, for the function. */ - expand_function_start (fndecl, 0); - - /* If the function has a variably modified type, there may be - SAVE_EXPRs in the parameter types. Their context must be set to - refer to this function; they cannot be expanded in the containing - function. */ - if (decl_function_context (fndecl) - && variably_modified_type_p (TREE_TYPE (fndecl))) - walk_tree (&TREE_TYPE (fndecl), set_save_expr_context, fndecl, - NULL); - - /* If this function is `main', emit a call to `__main' - to run global initializers, etc. */ - if (DECL_NAME (fndecl) - && MAIN_NAME_P (DECL_NAME (fndecl)) - && DECL_FILE_SCOPE_P (fndecl)) - expand_main_function (); - - /* Generate the RTL for this function. */ - expand_stmt (DECL_SAVED_TREE (fndecl)); - - /* We hard-wired immediate_size_expand to zero above. - expand_function_end will decrement this variable. So, we set the - variable to one here, so that after the decrement it will remain - zero. */ - immediate_size_expand = 1; - - /* Allow language dialects to perform special processing. */ - if (lang_expand_function_end) - (*lang_expand_function_end) (); - - /* Generate rtl for function exit. */ - expand_function_end (); - - /* If this is a nested function, protect the local variables in the stack - above us from being collected while we're compiling this function. */ - if (nested_p) - ggc_push_context (); - - /* Run the optimizers and output the assembler code for this function. */ - rest_of_compilation (fndecl); - - /* Undo the GC context switch. */ - if (nested_p) - ggc_pop_context (); + tree_rest_of_compilation (fndecl); /* With just -Wextra, complain only if function returns both with and without a value. */ @@ -6346,46 +6260,6 @@ c_expand_body_1 (tree fndecl, int nested_p) && current_function_returns_null) warning ("this function may return with or without a value"); - /* If requested, warn about function definitions where the function will - return a value (usually of some struct or union type) which itself will - take up a lot of stack space. */ - - if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl)) - { - tree ret_type = TREE_TYPE (TREE_TYPE (fndecl)); - - if (ret_type && TYPE_SIZE_UNIT (ret_type) - && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST - && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type), - larger_than_size)) - { - const location_t *locus = &DECL_SOURCE_LOCATION (fndecl); - unsigned int size_as_int - = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type)); - - if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0) - warning ("%Hsize of return value of '%D' is %u bytes", - locus, fndecl, size_as_int); - else - warning ("%Hsize of return value of '%D' is larger than %wd bytes", - locus, fndecl, larger_than_size); - } - } - - if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested_p - && ! flag_inline_trees) - { - /* Stop pointing to the local nodes about to be freed. - But DECL_INITIAL must remain nonzero so we know this - was an actual function definition. - For a nested function, this is done in c_pop_function_context. - If rest_of_compilation set this to 0, leave it 0. */ - if (DECL_INITIAL (fndecl) != 0) - DECL_INITIAL (fndecl) = error_mark_node; - - DECL_ARGUMENTS (fndecl) = 0; - } - if (DECL_STATIC_CONSTRUCTOR (fndecl)) { if (targetm.have_ctors_dtors) @@ -6403,11 +6277,6 @@ c_expand_body_1 (tree fndecl, int nested_p) else static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors); } - - if (nested_p) - /* Return to the enclosing function. */ - pop_function_context (); - timevar_pop (TV_EXPAND); } /* Like c_expand_body_1 but only for unnested functions. */ diff --git a/gcc/c-lang.c b/gcc/c-lang.c index 93437a3733d..fb1741dea13 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -90,6 +90,9 @@ enum c_language_kind c_language = clk_c; #undef LANG_HOOKS_DECL_UNINIT #define LANG_HOOKS_DECL_UNINIT c_decl_uninit +#undef LANG_HOOKS_RTL_EXPAND_STMT +#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt + /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index b5f263fe35c..16e0cffec32 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -289,20 +289,43 @@ static void expand_deferred_fns (void) { unsigned int i; + bool reconsider; - for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++) + do { - tree decl = VARRAY_TREE (deferred_fns, i); - - if (! TREE_ASM_WRITTEN (decl)) + reconsider = false; + for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++) { - /* For static inline functions, delay the decision whether to - emit them or not until wrapup_global_declarations. */ - if (! TREE_PUBLIC (decl)) - DECL_DEFER_OUTPUT (decl) = 1; + tree decl = VARRAY_TREE (deferred_fns, i); + + if (TREE_ASM_WRITTEN (decl)) + continue; + + /* "extern inline" says the symbol exists externally, + which means we should *never* expand it locally + unless we're actually inlining it. */ + /* ??? Why did we queue these in the first place? */ + if (DECL_DECLARED_INLINE_P (decl) && DECL_EXTERNAL (decl)) + continue; + + /* With flag_keep_inline_functions, we're emitting everything, + so we never need to reconsider. */ + if (flag_keep_inline_functions) + ; + /* Must emit all public functions. C doesn't have COMDAT + functions, so we don't need to check that, like C++. */ + else if (TREE_PUBLIC (decl)) + reconsider = true; + /* Must emit if the symbol is referenced. */ + else if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + reconsider = true; + else + continue; + c_expand_deferred_function (decl); } } + while (reconsider); deferred_fns = 0; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 60c81ab4fad..503a3b86e5b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2003-08-29 Richard Henderson + Jason Merrill + + * cp-lang.c (LANG_HOOKS_RTL_EXPAND_START): New. + (LANG_HOOKS_RTL_EXPAND_STMT): New. + * cp-tree.h (cxx_expand_function_start): Declare. + * decl.c (start_function): Use allocate_struct_function. + Move stmts_are_full_exprs_p assertion from expand_body. + Do not free_after_parsing or free_after_compilation. + (cxx_push_function_context): Move code to set struct function + data from genrtl_start_function. + * optimize.c (optimize_function): Don't inc/dec function_depth. + * semantics.c (expand_body): Use tree_rest_of_compilation. + (cxx_expand_function_start): Rename from genrtl_start_function, + omit bits done by tree_rest_of_compilation. + (genrtl_finish_function): Remove. + (clear_decl_rtl): Move to ../tree-optimize.c. + 2003-08-29 Gabriel Dos Reis PR c++/11811 diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index 8ca93610dab..4d5ed27b3c7 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -115,6 +115,11 @@ static void cxx_initialize_diagnostics (diagnostic_context *); #undef LANG_HOOKS_FUNCTION_FINAL #define LANG_HOOKS_FUNCTION_FINAL cxx_pop_function_context +#undef LANG_HOOKS_RTL_EXPAND_START +#define LANG_HOOKS_RTL_EXPAND_START cxx_expand_function_start +#undef LANG_HOOKS_RTL_EXPAND_STMT +#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt + /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e1ad9df35e7..1a2f06e1ad2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4137,6 +4137,7 @@ extern tree finish_alignof (tree); extern void finish_decl_cleanup (tree, tree); extern void finish_eh_cleanup (tree); extern void expand_body (tree); +extern void cxx_expand_function_start (void); extern tree nullify_returns_r (tree *, int *, void *); extern void do_pushlevel (scope_kind); extern tree do_poplevel (void); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0f6d09061b8..b4eb0192eb8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13539,7 +13539,7 @@ start_function (tree declspecs, tree declarator, tree attrs, int flags) CFUN set up, and our per-function variables initialized. FIXME factor out the non-RTL stuff. */ bl = current_binding_level; - init_function_start (decl1); + allocate_struct_function (decl1); current_binding_level = bl; /* Even though we're inside a function body, we still don't want to @@ -14084,6 +14084,10 @@ finish_function (int flags) } poplevel (1, 0, 1); + /* Statements should always be full-expressions at the outermost set + of curly braces for a function. */ + my_friendly_assert (stmts_are_full_exprs_p (), 19990831); + /* Set up the named return value optimization, if we can. Here, we eliminate the copy from the nrv into the RESULT_DECL and any cleanup for the nrv. genrtl_start_function and declare_return_variable @@ -14154,12 +14158,9 @@ finish_function (int flags) inline function, as we might never be compiled separately. */ && (DECL_INLINE (fndecl) || processing_template_decl)) warning ("no return statement in function returning non-void"); - - /* Clear out memory we no longer need. */ - free_after_parsing (cfun); - /* Since we never call rest_of_compilation, we never clear - CFUN. Do so explicitly. */ - free_after_compilation (cfun); + + /* We're leaving the context of this function, so zap cfun. It's still in + DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation. */ cfun = NULL; /* If this is an in-class inline definition, we may have to pop the @@ -14479,6 +14480,31 @@ cxx_push_function_context (struct function * f) /* Whenever we start a new function, we destroy temporaries in the usual way. */ current_stmt_tree ()->stmts_are_full_exprs_p = 1; + + if (f->decl) + { + tree fn = f->decl; + + current_function_is_thunk = DECL_THUNK_P (fn); + + if (DECL_SAVED_FUNCTION_DATA (fn)) + { + /* If we already parsed this function, and we're just expanding it + now, restore saved state. */ + *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn); + + /* If we decided that we didn't want to inline this function, + make sure the back-end knows that. */ + if (!current_function_cannot_inline) + current_function_cannot_inline = cp_function_chain->cannot_inline; + + /* We don't need the saved data anymore. Unless this is an inline + function; we need the named return value info for + cp_copy_res_decl_for_inlining. */ + if (! DECL_INLINE (fn)) + DECL_SAVED_FUNCTION_DATA (fn) = NULL; + } + } } /* Free the language-specific parts of F, now that we've finished diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 4cb5c695f34..8c604e3bf8b 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -49,17 +49,6 @@ optimize_function (tree fn) { dump_function (TDI_original, fn); - /* While in this function, we may choose to go off and compile - another function. For example, we might instantiate a function - in the hopes of inlining it. Normally, that wouldn't trigger any - actual RTL code-generation -- but it will if the template is - actually needed. (For example, if it's address is taken, or if - some other function already refers to the template.) If - code-generation occurs, then garbage collection will occur, so we - must protect ourselves, just as we do while building up the body - of the function. */ - ++function_depth; - if (flag_inline_trees /* We do not inline thunks, as (a) the backend tries to optimize the call to the thunkee, (b) tree based inlining breaks that @@ -72,9 +61,6 @@ optimize_function (tree fn) dump_function (TDI_inlined, fn); } - /* Undo the call to ggc_push_context above. */ - --function_depth; - dump_function (TDI_optimized, fn); } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c38bdd3681a..c9f3675d307 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -59,9 +59,7 @@ static void genrtl_try_block (tree); static void genrtl_eh_spec_block (tree); static void genrtl_handler (tree); static void cp_expand_stmt (tree); -static void genrtl_start_function (tree); -static void genrtl_finish_function (tree); -static tree clear_decl_rtl (tree *, int *, void *); + /* Finish processing the COND, the SUBSTMT condition for STMT. */ @@ -2863,9 +2861,6 @@ expand_body (tree fn) location_t saved_loc; tree saved_function; - if (flag_unit_at_a_time && !cgraph_global_info_ready) - abort (); - /* Compute the appropriate object-file linkage for inline functions. */ if (DECL_DECLARED_INLINE_P (fn)) @@ -2879,61 +2874,35 @@ expand_body (tree fn) if (DECL_EXTERNAL (fn)) return; - /* Save the current file name and line number. When we expand the - body of the function, we'll set INPUT_LOCATION so that - error-messages come out in the right places. */ + /* ??? When is this needed? */ saved_loc = input_location; saved_function = current_function_decl; - input_location = DECL_SOURCE_LOCATION (fn); - current_function_decl = fn; timevar_push (TV_INTEGRATION); - - /* Optimize the body of the function before expanding it. */ optimize_function (fn); - timevar_pop (TV_INTEGRATION); - timevar_push (TV_EXPAND); - genrtl_start_function (fn); - current_function_is_thunk = DECL_THUNK_P (fn); + tree_rest_of_compilation (fn); - /* Expand the body. */ - expand_stmt (DECL_SAVED_TREE (fn)); - - /* Statements should always be full-expressions at the outermost set - of curly braces for a function. */ - my_friendly_assert (stmts_are_full_exprs_p (), 19990831); - - /* The outermost statement for a function contains the line number - recorded when we finished processing the function. */ - input_line = STMT_LINENO (DECL_SAVED_TREE (fn)); - - /* Generate code for the function. */ - genrtl_finish_function (fn); - - /* If possible, obliterate the body of the function so that it can - be garbage collected. */ - if (dump_enabled_p (TDI_all)) - /* Keep the body; we're going to dump it. */ - ; - else if (DECL_INLINE (fn) && flag_inline_trees) - /* We might need the body of this function so that we can expand - it inline somewhere else. */ - ; - else - /* We don't need the body; blow it away. */ - DECL_SAVED_TREE (fn) = NULL_TREE; - - /* And restore the current source position. */ current_function_decl = saved_function; input_location = saved_loc; - extract_interface_info (); - timevar_pop (TV_EXPAND); + extract_interface_info (); /* Emit any thunks that should be emitted at the same time as FN. */ emit_associated_thunks (fn); + + /* If this function is marked with the constructor attribute, add it + to the list of functions to be called along with constructors + from static duration objects. */ + if (DECL_STATIC_CONSTRUCTOR (fn)) + static_ctors = tree_cons (NULL_TREE, fn, static_ctors); + + /* If this function is marked with the destructor attribute, add it + to the list of functions to be called along with destructors from + static duration objects. */ + if (DECL_STATIC_DESTRUCTOR (fn)) + static_dtors = tree_cons (NULL_TREE, fn, static_dtors); } /* Generate RTL for FN. */ @@ -3062,197 +3031,16 @@ nullify_returns_r (tree* tp, int* walk_subtrees, void* data) /* Start generating the RTL for FN. */ -static void -genrtl_start_function (tree fn) +void +cxx_expand_function_start (void) { - /* Tell everybody what function we're processing. */ - current_function_decl = fn; - /* Get the RTL machinery going for this function. */ - init_function_start (fn); /* Let everybody know that we're expanding this function, not doing semantic analysis. */ expanding_p = 1; - /* Even though we're inside a function body, we still don't want to - call expand_expr to calculate the size of a variable-sized array. - We haven't necessarily assigned RTL to all variables yet, so it's - not safe to try to expand expressions involving them. */ - immediate_size_expand = 0; - cfun->x_dont_save_pending_sizes_p = 1; - - /* Let the user know we're compiling this function. */ - announce_function (fn); - - /* Initialize the per-function data. */ - my_friendly_assert (!DECL_PENDING_INLINE_P (fn), 20000911); - if (DECL_SAVED_FUNCTION_DATA (fn)) - { - /* If we already parsed this function, and we're just expanding it - now, restore saved state. */ - *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn); - - /* This function is being processed in whole-function mode; we - already did semantic analysis. */ - cfun->x_whole_function_mode_p = 1; - - /* If we decided that we didn't want to inline this function, - make sure the back-end knows that. */ - if (!current_function_cannot_inline) - current_function_cannot_inline = cp_function_chain->cannot_inline; - - /* We don't need the saved data anymore. Unless this is an inline - function; we need the named return value info for - cp_copy_res_decl_for_inlining. */ - if (! DECL_INLINE (fn)) - DECL_SAVED_FUNCTION_DATA (fn) = NULL; - } - - /* Keep track of how many functions we're presently expanding. */ - ++function_depth; - - /* Create a binding level for the parameters. */ - expand_function_start (fn, /*parms_have_cleanups=*/0); - /* If this function is `main'. */ - if (DECL_MAIN_P (fn)) - expand_main_function (); - /* Give our named return value the same RTL as our RESULT_DECL. */ if (current_function_return_value) - COPY_DECL_RTL (DECL_RESULT (fn), current_function_return_value); -} - -/* Finish generating the RTL for FN. */ - -static void -genrtl_finish_function (tree fn) -{ - tree t; - -#if 0 - if (write_symbols != NO_DEBUG) - { - /* Keep this code around in case we later want to control debug info - based on whether a type is "used". (jason 1999-11-11) */ - - tree ttype = target_type (fntype); - tree parmdecl; - - if (IS_AGGR_TYPE (ttype)) - /* Let debugger know it should output info for this type. */ - note_debug_info_needed (ttype); - - for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl)) - { - ttype = target_type (TREE_TYPE (parmdecl)); - if (IS_AGGR_TYPE (ttype)) - /* Let debugger know it should output info for this type. */ - note_debug_info_needed (ttype); - } - } -#endif - - /* Clean house because we will need to reorder insns here. */ - do_pending_stack_adjust (); - - /* If we have a named return value, we need to force a return so that - the return register is USEd. */ - if (DECL_NAME (DECL_RESULT (fn))) - emit_jump (return_label); - - /* We hard-wired immediate_size_expand to zero in start_function. - Expand_function_end will decrement this variable. So, we set the - variable to one here, so that after the decrement it will remain - zero. */ - immediate_size_expand = 1; - - /* Generate rtl for function exit. */ - expand_function_end (); - - /* If this is a nested function (like a template instantiation that - we're compiling in the midst of compiling something else), push a - new GC context. That will keep local variables on the stack from - being collected while we're doing the compilation of this - function. */ - if (function_depth > 1) - ggc_push_context (); - - /* There's no need to defer outputting this function any more; we - know we want to output it. */ - DECL_DEFER_OUTPUT (fn) = 0; - - /* Run the optimizers and output the assembler code for this - function. */ - rest_of_compilation (fn); - - /* Undo the call to ggc_push_context above. */ - if (function_depth > 1) - ggc_pop_context (); - -#if 0 - /* Keep this code around in case we later want to control debug info - based on whether a type is "used". (jason 1999-11-11) */ - - if (ctype && TREE_ASM_WRITTEN (fn)) - note_debug_info_needed (ctype); -#endif - - /* If this function is marked with the constructor attribute, add it - to the list of functions to be called along with constructors - from static duration objects. */ - if (DECL_STATIC_CONSTRUCTOR (fn)) - static_ctors = tree_cons (NULL_TREE, fn, static_ctors); - - /* If this function is marked with the destructor attribute, add it - to the list of functions to be called along with destructors from - static duration objects. */ - if (DECL_STATIC_DESTRUCTOR (fn)) - static_dtors = tree_cons (NULL_TREE, fn, static_dtors); - - --function_depth; - - /* In C++, we should never be saving RTL for the function. */ - my_friendly_assert (!DECL_SAVED_INSNS (fn), 20010903); - - /* Since we don't need the RTL for this function anymore, stop - pointing to it. That's especially important for LABEL_DECLs, - since you can reach all the instructions in the function from the - CODE_LABEL stored in the DECL_RTL for the LABEL_DECL. Walk the - BLOCK-tree, clearing DECL_RTL for LABEL_DECLs and non-static - local variables. */ - walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), - clear_decl_rtl, - NULL); - - /* Clear out the RTL for the arguments. */ - for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t)) - { - SET_DECL_RTL (t, NULL_RTX); - DECL_INCOMING_RTL (t) = NULL_RTX; - } - - if (!(flag_inline_trees && DECL_INLINE (fn))) - /* DECL_INITIAL must remain nonzero so we know this was an - actual function definition. */ - DECL_INITIAL (fn) = error_mark_node; - - /* Let the error reporting routines know that we're outside a - function. For a nested function, this value is used in - pop_cp_function_context and then reset via pop_function_context. */ - current_function_decl = NULL_TREE; -} - -/* Clear out the DECL_RTL for the non-static variables in BLOCK and - its sub-blocks. */ - -static tree -clear_decl_rtl (tree* tp, - int* walk_subtrees ATTRIBUTE_UNUSED , - void* data ATTRIBUTE_UNUSED ) -{ - if (nonstatic_local_decl_p (*tp)) - SET_DECL_RTL (*tp, NULL_RTX); - - return NULL_TREE; + COPY_DECL_RTL (DECL_RESULT (cfun->decl), current_function_return_value); } /* Perform initialization related to this module. */ diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 56c24c79739..ee30749f536 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -123,6 +123,10 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *); #define LANG_HOOKS_FUNCTION_ENTER_NESTED lhd_do_nothing_f #define LANG_HOOKS_FUNCTION_LEAVE_NESTED lhd_do_nothing_f +#define LANG_HOOKS_RTL_EXPAND_START lhd_do_nothing +#define LANG_HOOKS_RTL_EXPAND_STMT (void *) abort +#define LANG_HOOKS_RTL_EXPAND_END lhd_do_nothing + /* Attribute hooks. */ #define LANG_HOOKS_ATTRIBUTE_TABLE NULL #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE NULL @@ -186,6 +190,12 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *); LANG_HOOKS_FUNCTION_LEAVE_NESTED \ } +#define LANG_HOOKS_RTL_EXPAND_INITIALIZER { \ + LANG_HOOKS_RTL_EXPAND_START, \ + LANG_HOOKS_RTL_EXPAND_STMT, \ + LANG_HOOKS_RTL_EXPAND_END \ +} + /* Tree dump hooks. */ extern bool lhd_tree_dump_dump_tree (void *, tree); extern int lhd_tree_dump_type_quals (tree); @@ -289,7 +299,8 @@ extern int lhd_tree_dump_type_quals (tree); LANG_HOOKS_CALLGRAPH_INITIALIZER, \ LANG_HOOKS_TREE_DUMP_INITIALIZER, \ LANG_HOOKS_DECLS, \ - LANG_HOOKS_FOR_TYPES_INITIALIZER \ + LANG_HOOKS_FOR_TYPES_INITIALIZER, \ + LANG_HOOKS_RTL_EXPAND_INITIALIZER \ } #endif /* GCC_LANG_HOOKS_DEF_H */ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 7bcd4353734..109dfa1a818 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -77,6 +77,19 @@ struct lang_hooks_for_functions void (*leave_nested) (struct function *); }; +/* Lang hooks for rtl code generation. */ +struct lang_hooks_for_rtl_expansion +{ + /* Called after expand_function_start, but before expanding the body. */ + void (*start) (void); + + /* Called to expand each statement. */ + void (*stmt) (tree); + + /* Called after expanding the body but before expand_function_end. */ + void (*end) (void); +}; + /* The following hooks are used by tree-dump.c. */ struct lang_hooks_for_tree_dump @@ -387,6 +400,8 @@ struct lang_hooks struct lang_hooks_for_types types; + struct lang_hooks_for_rtl_expansion rtl_expand; + /* Whenever you add entries here, make sure you adjust langhooks-def.h and langhooks.c accordingly. */ }; diff --git a/gcc/objc/objc-lang.c b/gcc/objc/objc-lang.c index 7a330ce3b61..3f70122302c 100644 --- a/gcc/objc/objc-lang.c +++ b/gcc/objc/objc-lang.c @@ -87,6 +87,9 @@ enum c_language_kind c_language = clk_objc; #undef LANG_HOOKS_FUNCTION_LEAVE_NESTED #define LANG_HOOKS_FUNCTION_LEAVE_NESTED c_pop_function_context +#undef LANG_HOOKS_RTL_EXPAND_STMT +#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt + /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table diff --git a/gcc/toplev.h b/gcc/toplev.h index 5adab615f91..3ebd8e493f2 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -66,6 +66,7 @@ extern void inform (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); extern void rest_of_decl_compilation (tree, const char *, int, int); extern void rest_of_type_compilation (tree, int); extern void rest_of_compilation (tree); +extern void tree_rest_of_compilation (tree); extern void announce_function (tree); diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c new file mode 100644 index 00000000000..e5bea3ea5bc --- /dev/null +++ b/gcc/tree-optimize.c @@ -0,0 +1,250 @@ +/* Control and data flow functions for trees. + Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "toplev.h" +#include "tree.h" +#include "tree-inline.h" +#include "flags.h" +#include "langhooks.h" +#include "cgraph.h" +#include "timevar.h" +#include "tm.h" +#include "function.h" +#include "ggc.h" + + +/* Called to move the SAVE_EXPRs for parameter declarations in a + nested function into the nested function. DATA is really the + nested FUNCTION_DECL. */ + +static tree +set_save_expr_context (tree *tp, + int *walk_subtrees, + void *data) +{ + if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp)) + SAVE_EXPR_CONTEXT (*tp) = (tree) data; + /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause + circularity. */ + else if (DECL_P (*tp)) + *walk_subtrees = 0; + + return NULL; +} + +/* Clear out the DECL_RTL for the non-static local variables in BLOCK and + its sub-blocks. DATA is the decl of the function being processed. */ + +static tree +clear_decl_rtl (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data) +{ + bool nonstatic_p, local_p; + tree t = *tp; + + switch (TREE_CODE (t)) + { + case VAR_DECL: + nonstatic_p = !TREE_STATIC (t) && !DECL_EXTERNAL (t); + local_p = DECL_CONTEXT (t) == data; + break; + + case PARM_DECL: + case LABEL_DECL: + nonstatic_p = true; + local_p = DECL_CONTEXT (t) == data; + break; + + case RESULT_DECL: + nonstatic_p = local_p = true; + break; + + default: + nonstatic_p = local_p = false; + break; + } + + if (nonstatic_p && local_p) + SET_DECL_RTL (t, NULL); + + return NULL; +} + +/* For functions-as-trees languages, this performs all optimization and + compilation for FNDECL. */ + +void +tree_rest_of_compilation (tree fndecl) +{ + static int nesting = -1; + + timevar_push (TV_EXPAND); + + ++nesting; + + if (flag_unit_at_a_time && !cgraph_global_info_ready) + abort (); + + if (nesting > 0) + /* Squirrel away our current state. */ + push_function_context (); + + /* Initialize the RTL code for the function. */ + current_function_decl = fndecl; + input_location = DECL_SOURCE_LOCATION (fndecl); + init_function_start (fndecl); + + /* This function is being processed in whole-function mode. */ + cfun->x_whole_function_mode_p = 1; + + /* Even though we're inside a function body, we still don't want to + call expand_expr to calculate the size of a variable-sized array. + We haven't necessarily assigned RTL to all variables yet, so it's + not safe to try to expand expressions involving them. */ + immediate_size_expand = 0; + cfun->x_dont_save_pending_sizes_p = 1; + + /* If the function has a variably modified type, there may be + SAVE_EXPRs in the parameter types. Their context must be set to + refer to this function; they cannot be expanded in the containing + function. */ + if (decl_function_context (fndecl) + && variably_modified_type_p (TREE_TYPE (fndecl))) + walk_tree (&TREE_TYPE (fndecl), set_save_expr_context, fndecl, + NULL); + + /* Set up parameters and prepare for return, for the function. */ + expand_function_start (fndecl, 0); + + /* Allow language dialects to perform special processing. */ + (*lang_hooks.rtl_expand.start) (); + + /* If this function is `main', emit a call to `__main' + to run global initializers, etc. */ + if (DECL_NAME (fndecl) + && MAIN_NAME_P (DECL_NAME (fndecl)) + && DECL_FILE_SCOPE_P (fndecl)) + expand_main_function (); + + /* Generate the RTL for this function. */ + (*lang_hooks.rtl_expand.stmt) (DECL_SAVED_TREE (fndecl)); + + /* We hard-wired immediate_size_expand to zero above. + expand_function_end will decrement this variable. So, we set the + variable to one here, so that after the decrement it will remain + zero. */ + immediate_size_expand = 1; + + /* Allow language dialects to perform special processing. */ + (*lang_hooks.rtl_expand.end) (); + + /* Generate rtl for function exit. */ + expand_function_end (); + + /* If this is a nested function, protect the local variables in the stack + above us from being collected while we're compiling this function. */ + if (nesting > 0) + ggc_push_context (); + + /* There's no need to defer outputting this function any more; we + know we want to output it. */ + DECL_DEFER_OUTPUT (fndecl) = 0; + + /* Run the optimizers and output the assembler code for this function. */ + rest_of_compilation (fndecl); + + /* Undo the GC context switch. */ + if (nesting > 0) + ggc_pop_context (); + + /* If requested, warn about function definitions where the function will + return a value (usually of some struct or union type) which itself will + take up a lot of stack space. */ + if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl)) + { + tree ret_type = TREE_TYPE (TREE_TYPE (fndecl)); + + if (ret_type && TYPE_SIZE_UNIT (ret_type) + && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST + && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type), + larger_than_size)) + { + const location_t *locus = &DECL_SOURCE_LOCATION (fndecl); + unsigned int size_as_int + = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type)); + + if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0) + warning ("%Hsize of return value of '%D' is %u bytes", + locus, fndecl, size_as_int); + else + warning ("%Hsize of return value of '%D' is larger than %wd bytes", + locus, fndecl, larger_than_size); + } + } + + /* ??? Looks like some of this could be combined. */ + + /* If possible, obliterate the body of the function so that it can + be garbage collected. */ + if (dump_enabled_p (TDI_all)) + /* Keep the body; we're going to dump it. */ + ; + else if (DECL_INLINE (fndecl) && flag_inline_trees) + /* We might need the body of this function so that we can expand + it inline somewhere else. */ + ; + else + /* We don't need the body; blow it away. */ + DECL_SAVED_TREE (fndecl) = NULL; + + /* Since we don't need the RTL for this function anymore, stop pointing to + it. That's especially important for LABEL_DECLs, since you can reach all + the instructions in the function from the CODE_LABEL stored in the + DECL_RTL for the LABEL_DECL. Walk the BLOCK-tree, clearing DECL_RTL for + LABEL_DECLs and non-static local variables. Note that we must check the + context of the variables, otherwise processing a nested function can kill + the rtl of a variable from an outer function. */ + walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), + clear_decl_rtl, + fndecl); + + if (DECL_SAVED_INSNS (fndecl) == 0 && ! nesting && ! flag_inline_trees) + { + /* Stop pointing to the local nodes about to be freed. + But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. + For a nested function, this is done in c_pop_function_context. + If rest_of_compilation set this to 0, leave it 0. */ + if (DECL_INITIAL (fndecl) != 0) + DECL_INITIAL (fndecl) = error_mark_node; + + DECL_ARGUMENTS (fndecl) = 0; + } + + if (nesting > 0) + /* Return to the enclosing function. */ + pop_function_context (); + + --nesting; + + timevar_pop (TV_EXPAND); +}