Commit 36edd3cc by Bernd Schmidt Committed by Bernd Schmidt

Change memory mangement and constant pool handling for nested functions to match…

Change memory mangement and constant pool handling for nested functions to match that of normal functions; add init_machine_status mechanism.

From-SVN: r29101
parent 1b63ada4
No preview for this file type
......@@ -168,6 +168,18 @@ enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] =
struct rtx_def *ix86_compare_op0 = NULL_RTX;
struct rtx_def *ix86_compare_op1 = NULL_RTX;
#define MAX_386_STACK_LOCALS 2
/* Define the structure for the machine field in struct function. */
struct machine_function
{
rtx stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
};
static int pic_label_no = 0;
#define ix86_stack_locals (current_function->machine->stack_locals)
/* which cpu are we scheduling for */
enum processor_type ix86_cpu;
......@@ -235,6 +247,7 @@ static void ix86_dump_ppro_packet PROTO ((FILE *));
static void ix86_reorder_insn PROTO ((rtx *, rtx *));
static rtx * ix86_pent_find_pair PROTO ((rtx *, rtx *, enum attr_pent_pair,
rtx));
static void ix86_init_machine_status PROTO ((struct function *));
struct ix86_address
{
......@@ -338,6 +351,9 @@ override_options ()
target_flags |= processor_target_table[ix86_cpu].target_enable;
target_flags &= ~processor_target_table[ix86_cpu].target_disable;
/* Arrange to set up i386_stack_locals for all functions. */
init_machine_status = ix86_init_machine_status;
/* Validate registers in register allocation order. */
if (ix86_reg_alloc_order)
{
......@@ -4940,58 +4956,23 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
emit_label (end_0_label);
}
#define MAX_386_STACK_LOCALS 2
static rtx ix86_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
/* Define the structure for the machine field in struct function. */
struct machine_function
{
rtx ix86_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
};
/* Functions to save and restore ix86_stack_locals.
These will be called, via pointer variables,
from push_function_context and pop_function_context. */
void
save_386_machine_status (p)
struct function *p;
{
p->machine
= (struct machine_function *) xmalloc (sizeof (struct machine_function));
bcopy ((char *) ix86_stack_locals, (char *) p->machine->ix86_stack_locals,
sizeof ix86_stack_locals);
}
void
restore_386_machine_status (p)
struct function *p;
{
bcopy ((char *) p->machine->ix86_stack_locals, (char *) ix86_stack_locals,
sizeof ix86_stack_locals);
free (p->machine);
p->machine = NULL;
}
/* Clear stack slot assignments remembered from previous functions.
This is called from INIT_EXPANDERS once before RTL is emitted for each
function. */
void
clear_386_stack_locals ()
static void
ix86_init_machine_status (p)
struct function *p;
{
enum machine_mode mode;
int n;
p->machine
= (struct machine_function *) xmalloc (sizeof (struct machine_function));
for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
mode = (enum machine_mode) ((int) mode + 1))
for (n = 0; n < MAX_386_STACK_LOCALS; n++)
ix86_stack_locals[(int) mode][n] = NULL_RTX;
/* Arrange to save and restore ix86_stack_locals around nested functions. */
save_machine_status = save_386_machine_status;
restore_machine_status = restore_386_machine_status;
}
/* Return a MEM corresponding to a stack slot with mode MODE.
......
......@@ -1603,13 +1603,6 @@ do \
} \
while (0)
/* Initialize data used by insn expanders. This is called from
init_emit, once for each function, before code is generated.
For 386, clear stack slot assignments remembered from previous
functions. */
#define INIT_EXPANDERS clear_386_stack_locals ()
/* The `FINALIZE_PIC' macro serves as a hook to emit these special
codes once the function is being compiled into assembly code, but
not before. (It is not done before, because in the case of
......@@ -2498,9 +2491,6 @@ extern void ix86_split_ashrdi XPARAMS((xrtx *, xrtx));
extern void ix86_split_lshrdi XPARAMS((xrtx *, xrtx));
extern void ix86_expand_strlensi_unroll_1 XPARAMS((xrtx, xrtx, xrtx));
extern void save_386_machine_status XPARAMS((struct function *));
extern void restore_386_machine_status XPARAMS((struct function *));
extern void clear_386_stack_locals XPARAMS((void));
extern xrtx assign_386_stack_local XPARAMS((xmode, int));
extern int ix86_attr_length_default XPARAMS((xrtx));
......
......@@ -117,6 +117,7 @@ static int virtuals_instantiated;
/* These variables hold pointers to functions to
save and restore machine-specific data,
in push_function_context and pop_function_context. */
void (*init_machine_status) PROTO((struct function *));
void (*save_machine_status) PROTO((struct function *));
void (*restore_machine_status) PROTO((struct function *));
......@@ -300,7 +301,15 @@ void
push_function_context_to (context)
tree context;
{
struct function *p;
struct function *p, *context_data;
if (context)
{
context_data = (context == current_function_decl
? current_function
: find_function_data (context));
context_data->contains_functions = 1;
}
if (current_function == 0)
init_dummy_function_start ();
......@@ -311,8 +320,7 @@ push_function_context_to (context)
p->decl = current_function_decl;
p->fixup_var_refs_queue = 0;
save_tree_status (p, context);
save_varasm_status (p, context);
save_tree_status (p);
if (save_lang_status)
(*save_lang_status) (p);
if (save_machine_status)
......@@ -340,14 +348,11 @@ pop_function_context_from (context)
current_function = p;
outer_function_chain = p->next;
current_function_contains_functions
|= p->inline_obstacks || context == current_function_decl;
current_function_decl = p->decl;
reg_renumber = 0;
restore_tree_status (p, context);
restore_tree_status (p);
restore_emit_status (p);
restore_varasm_status (p);
if (restore_machine_status)
(*restore_machine_status) (p);
......@@ -365,7 +370,8 @@ pop_function_context_from (context)
virtuals_instantiated = 0;
}
void pop_function_context ()
void
pop_function_context ()
{
pop_function_context_from (current_function_decl);
}
......@@ -5576,7 +5582,7 @@ prepare_function_start ()
/* We haven't done register allocation yet. */
reg_renumber = 0;
init_const_rtx_hash_table ();
init_varasm_status (current_function);
/* Set if a call to setjmp is seen. */
current_function_calls_setjmp = 0;
......@@ -5640,6 +5646,9 @@ prepare_function_start ()
inhibit_defer_pop = 0;
current_function_outgoing_args_size = 0;
if (init_machine_status)
(*init_machine_status) (current_function);
}
/* Initialize the rtl expansion mechanism so that we can do simple things
......
......@@ -182,6 +182,7 @@ struct function
struct stmt_status *stmt;
struct expr_status *expr;
struct emit_status *emit;
struct varasm_status *varasm;
/* For function.c. */
......@@ -415,12 +416,9 @@ struct function
struct obstack *expression_obstack;
struct obstack *saveable_obstack;
struct obstack *rtl_obstack;
struct simple_obstack_stack *inline_obstacks;
/* For integrate.c. We duplicate some of the fields so that
save_for_inline_copying can keep two versions. */
/* For integrate.c. */
int inlinable;
struct emit_status *inl_emit;
/* This is in fact an rtvec. */
void *original_arg_vector;
tree original_decl_initial;
......@@ -448,13 +446,6 @@ struct function
/* If some insns can be deferred to the delay slots of the epilogue, the
delay list for them is recorded here. */
rtx epilogue_delay_list;
/* For varasm. */
struct constant_descriptor **const_rtx_hash_table;
struct pool_sym **const_rtx_sym_hash_table;
struct pool_constant *first_pool, *last_pool;
int pool_offset;
rtx const_double_chain;
};
extern struct function *current_function;
......@@ -534,25 +525,24 @@ extern tree *identify_blocks PROTO((tree, rtx));
/* Return size needed for stack frame based on slots so far allocated.
This size counts from zero. It is not rounded to STACK_BOUNDARY;
the caller may have to do that. */
extern HOST_WIDE_INT get_frame_size PROTO((void));
extern HOST_WIDE_INT get_frame_size PROTO((void));
/* Likewise, but for a different than the current function. */
extern HOST_WIDE_INT get_func_frame_size PROTO((struct function *));
extern HOST_WIDE_INT get_func_frame_size PROTO((struct function *));
/* These variables hold pointers to functions to
save and restore machine-specific data,
in push_function_context and pop_function_context. */
extern void (*save_machine_status) PROTO((struct function *));
extern void (*restore_machine_status) PROTO((struct function *));
extern void (*init_machine_status) PROTO((struct function *));
extern void (*save_machine_status) PROTO((struct function *));
extern void (*restore_machine_status) PROTO((struct function *));
/* Likewise, but for language-specific data. */
extern void (*save_lang_status) PROTO((struct function *));
extern void (*restore_lang_status) PROTO((struct function *));
/* Save and restore status information for a nested function. */
extern void save_tree_status PROTO((struct function *, tree));
extern void restore_tree_status PROTO((struct function *, tree));
extern void save_varasm_status PROTO((struct function *, tree));
extern void restore_varasm_status PROTO((struct function *));
extern void save_tree_status PROTO((struct function *));
extern void restore_tree_status PROTO((struct function *));
extern void restore_emit_status PROTO((struct function *));
extern rtx get_first_block_beg PROTO((void));
......
......@@ -309,9 +309,6 @@ extern void defer_addressed_constants PROTO((void));
and output now all those that have been deferred. */
extern void output_deferred_addressed_constants PROTO((void));
/* Initialize constant pool hashing for next function. */
extern void init_const_rtx_hash_table PROTO((void));
/* Return the size of the constant pool. */
extern int get_pool_size PROTO((void));
......
......@@ -21,6 +21,8 @@ Boston, MA 02111-1307, USA. */
#ifndef _RTL_H
#define _RTL_H
struct function;
#include "machmode.h"
#undef FFS /* Some systems predefine this symbol; don't let it interfere. */
......@@ -1001,6 +1003,8 @@ extern rtx force_const_mem PROTO((enum machine_mode, rtx));
extern rtx force_reg PROTO((enum machine_mode, rtx));
extern rtx get_pool_constant PROTO((rtx));
extern enum machine_mode get_pool_mode PROTO((rtx));
extern rtx get_pool_constant_for_function PROTO((struct function *, rtx));
extern enum machine_mode get_pool_mode_for_function PROTO((struct function *, rtx));
extern int get_pool_offset PROTO((rtx));
extern rtx simplify_subtraction PROTO((rtx));
extern rtx assign_stack_local PROTO((enum machine_mode,
......
......@@ -3648,30 +3648,16 @@ rest_of_compilation (decl)
compile it by itself, defer decision till end of compilation.
finish_compilation will call rest_of_compilation again
for those functions that need to be output. Also defer those
functions that we are supposed to defer. We cannot defer
functions containing nested functions since the nested function
data is in our non-saved obstack. We cannot defer nested
functions for the same reason. */
/* If this is a nested inline, remove ADDRESSOF now so we can
finish compiling ourselves. Otherwise, wait until EOF.
We have to do this because the purge_addressof transformation
changes the DECL_RTL for many variables, which confuses integrate.
Also, save_for_inline_copying can be very expensive. */
functions that we are supposed to defer. */
if (inlinable)
{
if (decl_function_context (decl))
purge_addressof (insns);
else
DECL_DEFER_OUTPUT (decl) = 1;
}
DECL_DEFER_OUTPUT (decl) = 1;
if (! current_function_contains_functions
&& (DECL_DEFER_OUTPUT (decl)
|| (DECL_INLINE (decl)
&& ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl)
&& ! flag_keep_inline_functions)
|| DECL_EXTERNAL (decl)))))
if (DECL_DEFER_OUTPUT (decl)
|| (DECL_INLINE (decl)
&& ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl)
&& ! flag_keep_inline_functions)
|| DECL_EXTERNAL (decl))))
{
DECL_DEFER_OUTPUT (decl) = 1;
......@@ -3720,40 +3706,6 @@ rest_of_compilation (decl)
goto exit_rest_of_compilation;
}
/* If we have to compile the function now, save its rtl and subdecls
so that its compilation will not affect what others get. */
if (inlinable || DECL_DEFER_OUTPUT (decl))
{
#ifdef DWARF_DEBUGGING_INFO
/* Generate the DWARF info for the "abstract" instance of
a function which we will generate an out-of-line instance
of almost immediately (and which we may also later generate
various inlined instances of). */
if (write_symbols == DWARF_DEBUG)
{
set_decl_abstract_flags (decl, 1);
TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 0));
set_decl_abstract_flags (decl, 0);
}
#endif
#ifdef DWARF2_DEBUGGING_INFO
/* Generate the DWARF2 info for the "abstract" instance of
a function which we will generate an out-of-line instance
of almost immediately (and which we may also later generate
various inlined instances of). */
if (write_symbols == DWARF2_DEBUG)
{
set_decl_abstract_flags (decl, 1);
TIMEVAR (symout_time, dwarf2out_decl (decl));
set_decl_abstract_flags (decl, 0);
}
#endif
saved_block_tree = DECL_INITIAL (decl);
saved_arguments = DECL_ARGUMENTS (decl);
TIMEVAR (integration_time, save_for_inline_copying (decl));
DECL_SAVED_INSNS (decl)->inlinable = inlinable;
}
/* If specified extern inline but we aren't inlining it, we are
done. This goes for anything that gets here with DECL_EXTERNAL
set, not just things with DECL_INLINE. */
......
......@@ -64,21 +64,6 @@ struct obstack *function_maybepermanent_obstack;
struct obstack maybepermanent_obstack;
/* This is a list of function_maybepermanent_obstacks for top-level inline
functions that are compiled in the middle of compiling other functions. */
struct simple_obstack_stack *toplev_inline_obstacks;
/* Former elements of toplev_inline_obstacks that have been recycled. */
struct simple_obstack_stack *extra_inline_obstacks;
/* This is a list of function_maybepermanent_obstacks for inline functions
nested in the current function that were compiled in the middle of
compiling other functions. */
struct simple_obstack_stack *inline_obstacks;
/* The contents of the current function definition are allocated
in this obstack, and all are freed at the end of the function.
For top-level functions, this is temporary_obstack.
......@@ -331,9 +316,8 @@ gcc_obstack_init (obstack)
compile; if it isn't current_function_decl, we have to play some games. */
void
save_tree_status (p, context)
save_tree_status (p)
struct function *p;
tree context;
{
p->all_types_permanent = all_types_permanent;
p->momentary_stack = momentary_stack;
......@@ -347,50 +331,10 @@ save_tree_status (p, context)
p->expression_obstack = expression_obstack;
p->saveable_obstack = saveable_obstack;
p->rtl_obstack = rtl_obstack;
p->inline_obstacks = inline_obstacks;
if (current_function_decl && context == current_function_decl)
/* Objects that need to be saved in this function can be in the nonsaved
obstack of the enclosing function since they can't possibly be needed
once it has returned. */
function_maybepermanent_obstack = function_obstack;
else
{
/* We're compiling a function which isn't nested in the current
function. We need to create a new maybepermanent_obstack for this
function, since it can't go onto any of the existing obstacks. */
struct simple_obstack_stack **head;
struct simple_obstack_stack *current;
if (context == NULL_TREE)
head = &toplev_inline_obstacks;
else
{
struct function *f = find_function_data (context);
head = &f->inline_obstacks;
}
if (context == NULL_TREE && extra_inline_obstacks)
{
current = extra_inline_obstacks;
extra_inline_obstacks = current->next;
}
else
{
current = ((struct simple_obstack_stack *)
xmalloc (sizeof (struct simple_obstack_stack)));
current->obstack
= (struct obstack *) xmalloc (sizeof (struct obstack));
gcc_obstack_init (current->obstack);
}
function_maybepermanent_obstack = current->obstack;
current->next = *head;
*head = current;
}
function_maybepermanent_obstack
= (struct obstack *) xmalloc (sizeof (struct obstack));
gcc_obstack_init (function_maybepermanent_obstack);
maybepermanent_firstobj
= (char *) obstack_finish (function_maybepermanent_obstack);
......@@ -410,9 +354,8 @@ save_tree_status (p, context)
This is used after a nested function. */
void
restore_tree_status (p, context)
restore_tree_status (p)
struct function *p;
tree context;
{
all_types_permanent = p->all_types_permanent;
momentary_stack = p->momentary_stack;
......@@ -420,41 +363,16 @@ restore_tree_status (p, context)
obstack_free (&momentary_obstack, momentary_function_firstobj);
/* Free saveable storage used by the function just compiled and not
saved.
CAUTION: This is in function_obstack of the containing function.
So we must be sure that we never allocate from that obstack during
the compilation of a nested function if we expect it to survive
past the nested function's end. */
saved. */
obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
/* If we were compiling a toplevel function, we can free this space now. */
if (context == NULL_TREE)
{
obstack_free (&temporary_obstack, temporary_firstobj);
obstack_free (&momentary_obstack, momentary_function_firstobj);
}
/* If we were compiling a toplevel function that we don't actually want
to save anything from, return the obstack to the pool. */
if (context == NULL_TREE
&& obstack_empty_p (function_maybepermanent_obstack))
{
struct simple_obstack_stack *current, **p = &toplev_inline_obstacks;
if ((*p) != NULL)
{
while ((*p)->obstack != function_maybepermanent_obstack)
p = &((*p)->next);
current = *p;
*p = current->next;
current->next = extra_inline_obstacks;
extra_inline_obstacks = current;
}
}
obstack_free (&temporary_obstack, temporary_firstobj);
obstack_free (&momentary_obstack, momentary_function_firstobj);
obstack_free (function_obstack, 0);
if (obstack_empty_p (function_maybepermanent_obstack))
free (function_maybepermanent_obstack);
free (function_obstack);
temporary_firstobj = p->temporary_firstobj;
......@@ -467,7 +385,6 @@ restore_tree_status (p, context)
expression_obstack = p->expression_obstack;
saveable_obstack = p->saveable_obstack;
rtl_obstack = p->rtl_obstack;
inline_obstacks = p->inline_obstacks;
}
/* Start allocating on the temporary (per function) obstack.
......@@ -484,7 +401,6 @@ temporary_allocation ()
expression_obstack = function_obstack;
rtl_obstack = saveable_obstack = function_maybepermanent_obstack;
momentary_stack = 0;
inline_obstacks = 0;
}
/* Start allocating on the permanent obstack but don't
......@@ -612,17 +528,6 @@ permanent_allocation (function_end)
obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
obstack_free (&temp_decl_obstack, temp_decl_firstobj);
/* Free up the maybepermanent_obstacks for any of our nested functions
which were compiled at a lower level. */
while (inline_obstacks)
{
struct simple_obstack_stack *current = inline_obstacks;
inline_obstacks = current->next;
obstack_free (current->obstack, 0);
free (current->obstack);
free (current);
}
current_obstack = &permanent_obstack;
expression_obstack = &permanent_obstack;
rtl_obstack = saveable_obstack = &permanent_obstack;
......@@ -4751,32 +4656,6 @@ decl_type_context (decl)
return NULL_TREE;
}
/* Print debugging information about the size of the
toplev_inline_obstacks. */
void
print_inline_obstack_statistics ()
{
struct simple_obstack_stack *current = toplev_inline_obstacks;
int n_obstacks = 0;
int n_alloc = 0;
int n_chunks = 0;
for (; current; current = current->next, ++n_obstacks)
{
struct obstack *o = current->obstack;
struct _obstack_chunk *chunk = o->chunk;
n_alloc += o->next_free - chunk->contents;
chunk = chunk->prev;
++n_chunks;
for (; chunk; chunk = chunk->prev, ++n_chunks)
n_alloc += chunk->limit - &chunk->contents[0];
}
fprintf (stderr, "inline obstacks: %d obstacks, %d bytes, %d chunks\n",
n_obstacks, n_alloc, n_chunks);
}
/* Print debugging information about the obstack O, named STR. */
void
......@@ -4835,7 +4714,6 @@ dump_tree_statistics ()
print_obstack_statistics ("temporary_obstack", &temporary_obstack);
print_obstack_statistics ("momentary_obstack", &momentary_obstack);
print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack);
print_inline_obstack_statistics ();
print_lang_statistics ();
}
......
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