Commit 4985cde3 by Richard Henderson Committed by Richard Henderson

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 <jason@redhat.com>

From-SVN: r70933
parent fc2b8477
2003-08-29 Richard Henderson <rth@redhat.com> 2003-08-29 Richard Henderson <rth@redhat.com>
* 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 <rth@redhat.com>
* function.h (struct function): Add rtl_inline_init, saved_for_inline. * function.h (struct function): Add rtl_inline_init, saved_for_inline.
* integrate.c (save_for_inline): Set saved_for_inline. * integrate.c (save_for_inline): Set saved_for_inline.
* c-semantics.c (genrtl_scope_stmt): Check it. * c-semantics.c (genrtl_scope_stmt): Check it.
......
...@@ -845,7 +845,7 @@ OBJS-common = \ ...@@ -845,7 +845,7 @@ OBJS-common = \
OBJS-md = $(out_object_file) OBJS-md = $(out_object_file)
OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \ 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) 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 ...@@ -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) \ 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) \ $(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 $(EXPR_H) $(SPLAY_TREE_H) tree-dump.h
tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h $(INTEGRATE_H) \ $(TREE_H) $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h \
$(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h langhooks.h \ $(INTEGRATE_H) $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \
$(C_COMMON_H) tree-inline.h cgraph.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) \ print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(GGC_H) langhooks.h real.h $(GGC_H) langhooks.h real.h
stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
......
...@@ -6032,7 +6032,7 @@ store_parm_decls (void) ...@@ -6032,7 +6032,7 @@ store_parm_decls (void)
gen_aux_info_record (fndecl, 1, 0, prototype); gen_aux_info_record (fndecl, 1, 0, prototype);
/* Initialize the RTL code for the function. */ /* Initialize the RTL code for the function. */
init_function_start (fndecl); allocate_struct_function (fndecl);
/* Begin the statement tree for this function. */ /* Begin the statement tree for this function. */
begin_stmt_tree (&DECL_SAVED_TREE (fndecl)); begin_stmt_tree (&DECL_SAVED_TREE (fndecl));
...@@ -6142,11 +6142,8 @@ finish_function (int nested, int can_defer_p) ...@@ -6142,11 +6142,8 @@ finish_function (int nested, int can_defer_p)
&& DECL_INLINE (fndecl)) && DECL_INLINE (fndecl))
warning ("no return statement in function returning non-void"); warning ("no return statement in function returning non-void");
/* Clear out memory we no longer need. */ /* We're leaving the context of this function, so zap cfun. It's still in
free_after_parsing (cfun); DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation. */
/* Since we never call rest_of_compilation, we never clear
CFUN. Do so explicitly. */
free_after_compilation (cfun);
cfun = NULL; cfun = NULL;
if (flag_unit_at_a_time && can_defer_p) if (flag_unit_at_a_time && can_defer_p)
...@@ -6239,25 +6236,6 @@ c_expand_deferred_function (tree fndecl) ...@@ -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, /* 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 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 function. If can_defer_p is zero, we won't attempt to defer the
...@@ -6266,78 +6244,14 @@ set_save_expr_context (tree *tp, ...@@ -6266,78 +6244,14 @@ set_save_expr_context (tree *tp,
static void static void
c_expand_body_1 (tree fndecl, int nested_p) c_expand_body_1 (tree fndecl, int nested_p)
{ {
timevar_push (TV_EXPAND);
if (nested_p) if (nested_p)
{ {
/* Make sure that we will evaluate variable-sized types involved /* Make sure that we will evaluate variable-sized types involved
in our function's type. */ in our function's type. */
expand_pending_sizes (DECL_LANG_SPECIFIC (fndecl)->pending_sizes); expand_pending_sizes (DECL_LANG_SPECIFIC (fndecl)->pending_sizes);
/* Squirrel away our current state. */
push_function_context ();
} }
/* Initialize the RTL code for the function. */ tree_rest_of_compilation (fndecl);
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 ();
/* With just -Wextra, complain only if function returns both with /* With just -Wextra, complain only if function returns both with
and without a value. */ and without a value. */
...@@ -6346,46 +6260,6 @@ c_expand_body_1 (tree fndecl, int nested_p) ...@@ -6346,46 +6260,6 @@ c_expand_body_1 (tree fndecl, int nested_p)
&& current_function_returns_null) && current_function_returns_null)
warning ("this function may return with or without a value"); 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 (DECL_STATIC_CONSTRUCTOR (fndecl))
{ {
if (targetm.have_ctors_dtors) if (targetm.have_ctors_dtors)
...@@ -6403,11 +6277,6 @@ c_expand_body_1 (tree fndecl, int nested_p) ...@@ -6403,11 +6277,6 @@ c_expand_body_1 (tree fndecl, int nested_p)
else else
static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors); 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. */ /* Like c_expand_body_1 but only for unnested functions. */
......
...@@ -90,6 +90,9 @@ enum c_language_kind c_language = clk_c; ...@@ -90,6 +90,9 @@ enum c_language_kind c_language = clk_c;
#undef LANG_HOOKS_DECL_UNINIT #undef LANG_HOOKS_DECL_UNINIT
#define LANG_HOOKS_DECL_UNINIT c_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. */ /* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table
......
...@@ -289,20 +289,43 @@ static void ...@@ -289,20 +289,43 @@ static void
expand_deferred_fns (void) expand_deferred_fns (void)
{ {
unsigned int i; unsigned int i;
bool reconsider;
for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++) do
{ {
tree decl = VARRAY_TREE (deferred_fns, i); reconsider = false;
for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++)
if (! TREE_ASM_WRITTEN (decl))
{ {
/* For static inline functions, delay the decision whether to tree decl = VARRAY_TREE (deferred_fns, i);
emit them or not until wrapup_global_declarations. */
if (! TREE_PUBLIC (decl)) if (TREE_ASM_WRITTEN (decl))
DECL_DEFER_OUTPUT (decl) = 1; 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); c_expand_deferred_function (decl);
} }
} }
while (reconsider);
deferred_fns = 0; deferred_fns = 0;
} }
......
2003-08-29 Richard Henderson <rth@redhat.com>
Jason Merrill <jason@redhat.com>
* 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 <gdr@integrable-solutions.net> 2003-08-29 Gabriel Dos Reis <gdr@integrable-solutions.net>
PR c++/11811 PR c++/11811
......
...@@ -115,6 +115,11 @@ static void cxx_initialize_diagnostics (diagnostic_context *); ...@@ -115,6 +115,11 @@ static void cxx_initialize_diagnostics (diagnostic_context *);
#undef LANG_HOOKS_FUNCTION_FINAL #undef LANG_HOOKS_FUNCTION_FINAL
#define LANG_HOOKS_FUNCTION_FINAL cxx_pop_function_context #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. */ /* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table
......
...@@ -4137,6 +4137,7 @@ extern tree finish_alignof (tree); ...@@ -4137,6 +4137,7 @@ extern tree finish_alignof (tree);
extern void finish_decl_cleanup (tree, tree); extern void finish_decl_cleanup (tree, tree);
extern void finish_eh_cleanup (tree); extern void finish_eh_cleanup (tree);
extern void expand_body (tree); extern void expand_body (tree);
extern void cxx_expand_function_start (void);
extern tree nullify_returns_r (tree *, int *, void *); extern tree nullify_returns_r (tree *, int *, void *);
extern void do_pushlevel (scope_kind); extern void do_pushlevel (scope_kind);
extern tree do_poplevel (void); extern tree do_poplevel (void);
......
...@@ -13539,7 +13539,7 @@ start_function (tree declspecs, tree declarator, tree attrs, int flags) ...@@ -13539,7 +13539,7 @@ start_function (tree declspecs, tree declarator, tree attrs, int flags)
CFUN set up, and our per-function variables initialized. CFUN set up, and our per-function variables initialized.
FIXME factor out the non-RTL stuff. */ FIXME factor out the non-RTL stuff. */
bl = current_binding_level; bl = current_binding_level;
init_function_start (decl1); allocate_struct_function (decl1);
current_binding_level = bl; current_binding_level = bl;
/* Even though we're inside a function body, we still don't want to /* Even though we're inside a function body, we still don't want to
...@@ -14084,6 +14084,10 @@ finish_function (int flags) ...@@ -14084,6 +14084,10 @@ finish_function (int flags)
} }
poplevel (1, 0, 1); 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 /* 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 eliminate the copy from the nrv into the RESULT_DECL and any cleanup
for the nrv. genrtl_start_function and declare_return_variable for the nrv. genrtl_start_function and declare_return_variable
...@@ -14154,12 +14158,9 @@ finish_function (int flags) ...@@ -14154,12 +14158,9 @@ finish_function (int flags)
inline function, as we might never be compiled separately. */ inline function, as we might never be compiled separately. */
&& (DECL_INLINE (fndecl) || processing_template_decl)) && (DECL_INLINE (fndecl) || processing_template_decl))
warning ("no return statement in function returning non-void"); warning ("no return statement in function returning non-void");
/* Clear out memory we no longer need. */ /* We're leaving the context of this function, so zap cfun. It's still in
free_after_parsing (cfun); DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation. */
/* Since we never call rest_of_compilation, we never clear
CFUN. Do so explicitly. */
free_after_compilation (cfun);
cfun = NULL; cfun = NULL;
/* If this is an in-class inline definition, we may have to pop the /* 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) ...@@ -14479,6 +14480,31 @@ cxx_push_function_context (struct function * f)
/* Whenever we start a new function, we destroy temporaries in the /* Whenever we start a new function, we destroy temporaries in the
usual way. */ usual way. */
current_stmt_tree ()->stmts_are_full_exprs_p = 1; 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 /* Free the language-specific parts of F, now that we've finished
......
...@@ -49,17 +49,6 @@ optimize_function (tree fn) ...@@ -49,17 +49,6 @@ optimize_function (tree fn)
{ {
dump_function (TDI_original, 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 if (flag_inline_trees
/* We do not inline thunks, as (a) the backend tries to optimize /* We do not inline thunks, as (a) the backend tries to optimize
the call to the thunkee, (b) tree based inlining breaks that the call to the thunkee, (b) tree based inlining breaks that
...@@ -72,9 +61,6 @@ optimize_function (tree fn) ...@@ -72,9 +61,6 @@ optimize_function (tree fn)
dump_function (TDI_inlined, fn); dump_function (TDI_inlined, fn);
} }
/* Undo the call to ggc_push_context above. */
--function_depth;
dump_function (TDI_optimized, fn); dump_function (TDI_optimized, fn);
} }
......
...@@ -123,6 +123,10 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *); ...@@ -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_ENTER_NESTED lhd_do_nothing_f
#define LANG_HOOKS_FUNCTION_LEAVE_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. */ /* Attribute hooks. */
#define LANG_HOOKS_ATTRIBUTE_TABLE NULL #define LANG_HOOKS_ATTRIBUTE_TABLE NULL
#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE NULL #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE NULL
...@@ -186,6 +190,12 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *); ...@@ -186,6 +190,12 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *);
LANG_HOOKS_FUNCTION_LEAVE_NESTED \ 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. */ /* Tree dump hooks. */
extern bool lhd_tree_dump_dump_tree (void *, tree); extern bool lhd_tree_dump_dump_tree (void *, tree);
extern int lhd_tree_dump_type_quals (tree); extern int lhd_tree_dump_type_quals (tree);
...@@ -289,7 +299,8 @@ 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_CALLGRAPH_INITIALIZER, \
LANG_HOOKS_TREE_DUMP_INITIALIZER, \ LANG_HOOKS_TREE_DUMP_INITIALIZER, \
LANG_HOOKS_DECLS, \ LANG_HOOKS_DECLS, \
LANG_HOOKS_FOR_TYPES_INITIALIZER \ LANG_HOOKS_FOR_TYPES_INITIALIZER, \
LANG_HOOKS_RTL_EXPAND_INITIALIZER \
} }
#endif /* GCC_LANG_HOOKS_DEF_H */ #endif /* GCC_LANG_HOOKS_DEF_H */
...@@ -77,6 +77,19 @@ struct lang_hooks_for_functions ...@@ -77,6 +77,19 @@ struct lang_hooks_for_functions
void (*leave_nested) (struct function *); 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. */ /* The following hooks are used by tree-dump.c. */
struct lang_hooks_for_tree_dump struct lang_hooks_for_tree_dump
...@@ -387,6 +400,8 @@ struct lang_hooks ...@@ -387,6 +400,8 @@ struct lang_hooks
struct lang_hooks_for_types types; 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 /* Whenever you add entries here, make sure you adjust langhooks-def.h
and langhooks.c accordingly. */ and langhooks.c accordingly. */
}; };
......
...@@ -87,6 +87,9 @@ enum c_language_kind c_language = clk_objc; ...@@ -87,6 +87,9 @@ enum c_language_kind c_language = clk_objc;
#undef LANG_HOOKS_FUNCTION_LEAVE_NESTED #undef LANG_HOOKS_FUNCTION_LEAVE_NESTED
#define LANG_HOOKS_FUNCTION_LEAVE_NESTED c_pop_function_context #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. */ /* Attribute hooks. */
#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table
......
...@@ -66,6 +66,7 @@ extern void inform (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2); ...@@ -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_decl_compilation (tree, const char *, int, int);
extern void rest_of_type_compilation (tree, int); extern void rest_of_type_compilation (tree, int);
extern void rest_of_compilation (tree); extern void rest_of_compilation (tree);
extern void tree_rest_of_compilation (tree);
extern void announce_function (tree); extern void announce_function (tree);
......
/* 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment