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
This commit is contained in:
parent
fc2b84778b
commit
4985cde3ef
16 changed files with 422 additions and 401 deletions
|
@ -1,3 +1,22 @@
|
|||
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.
|
||||
|
|
|
@ -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) \
|
||||
|
|
139
gcc/c-decl.c
139
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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
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>
|
||||
|
||||
PR c++/11811
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
250
gcc/tree-optimize.c
Normal file
250
gcc/tree-optimize.c
Normal file
|
@ -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);
|
||||
}
|
Loading…
Add table
Reference in a new issue