diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2f848a65fca..6cc23741e9f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,7 +1,30 @@ +Sat Oct 18 13:47:15 1997 Jason Merrill + + * tree.c (restore_tree_status): Also free up temporary storage + when we finish a toplevel function. + (dump_tree_statistics): Print stats for backend obstacks. + Sat Oct 18 12:47:31 1997 Doug Evans * expr.c (use_group_regs): Don't call use_reg for MEMs. +Sat Oct 18 09:49:46 1997 Jason Merrill + + * libgcc2.c (__throw): Don't copy the return address. + * dwarf2out.c (expand_builtin_dwarf_reg_size): Ignore return address. + + * except.c (exceptions_via_longjmp): Initialize to 2 (uninitialized). + * toplev.c (main): Initialize exceptions_via_longjmp. + + * tree.c: Add extra_inline_obstacks. + (save_tree_status): Use it. + (restore_tree_status): If this is a toplevel inline obstack and we + didn't want to save anything on it, recycle it. + (print_inline_obstack_statistics): New fn. + * function.c (pop_function_context_from): Pass context to + restore_tree_status. + * obstack.h (obstack_empty_p): New macro. + Sat Oct 18 00:43:59 1997 Jeffrey A Law (law@cygnus.com) * i386/freebsd.h (ASM_COMMENT_START): Fix. diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 7a49fd4be62..eebac520cac 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -520,27 +520,31 @@ expand_builtin_dwarf_reg_size (reg_tree, target) tree reg_tree; rtx target; { - int i, n_ranges, size; + int size; struct reg_size_range ranges[5]; tree t, t2; - ranges[0].beg = 0; - ranges[0].size = GET_MODE_SIZE (reg_raw_mode[0]); - n_ranges = 1; + int i = 0; + int n_ranges = 0; + int last_size = -1; - for (i = 1; i < FIRST_PSEUDO_REGISTER; ++i) + for (; i < FIRST_PSEUDO_REGISTER; ++i) { + /* The return address is out of order on the MIPS, and we don't use + copy_reg for it anyway, so we don't care here how large it is. */ + if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN) + continue; + size = GET_MODE_SIZE (reg_raw_mode[i]); - if (size != ranges[n_ranges-1].size) + if (size != last_size) { - ranges[n_ranges-1].end = i-1; ranges[n_ranges].beg = i; - ranges[n_ranges].size = GET_MODE_SIZE (reg_raw_mode[i]); + ranges[n_ranges].size = last_size = GET_MODE_SIZE (reg_raw_mode[i]); ++n_ranges; assert (n_ranges < 5); } + ranges[n_ranges-1].end = i; } - ranges[n_ranges-1].end = i-1; /* The usual case: fp regs surrounded by general regs. */ if (n_ranges == 3 && ranges[0].size == ranges[2].size) diff --git a/gcc/except.c b/gcc/except.c index 6f3de662f7d..2a2554bc15b 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -98,7 +98,7 @@ Boston, MA 02111-1307, USA. */ is stored in a section named .eh_frame and the information for the entire shared object or program is registered with a call to __register_frame. On other targets, the information for each - translation unit is registered separately with a static constructor. + translation unit is registered from the file generated by collect2. __register_frame is defined in frame.c, and is responsible for recording all of the unwind regions into one list (which is kept in a static variable named unwind_table_list). @@ -409,11 +409,7 @@ Boston, MA 02111-1307, USA. */ /* One to use setjmp/longjmp method of generating code for exception handling. */ -#if DWARF2_UNWIND_INFO -int exceptions_via_longjmp = 0; -#else -int exceptions_via_longjmp = 1; -#endif +int exceptions_via_longjmp = 2; /* One to enable asynchronous exception support. */ diff --git a/gcc/function.c b/gcc/function.c index 644cc72eb53..61a72fe7d96 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -610,7 +610,7 @@ pop_function_context_from (context) reg_renumber = 0; current_function_args_info = p->args_info; - restore_tree_status (p); + restore_tree_status (p, context); restore_storage_status (p); restore_expr_status (p); restore_emit_status (p); diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 78834df3373..ae97c5313ae 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -3733,7 +3733,7 @@ label: sub_udata = p; for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) - if (udata->saved[i]) + if (i != udata->retaddr_column && udata->saved[i]) { #ifdef INCOMING_REGNO /* If you modify the saved value of the return address diff --git a/gcc/obstack.h b/gcc/obstack.h index dd8e8612bea..1b172acab27 100644 --- a/gcc/obstack.h +++ b/gcc/obstack.h @@ -332,6 +332,11 @@ int obstack_chunk_size (struct obstack *obstack); ({ struct obstack *__o = (OBSTACK); \ (unsigned) (__o->chunk_limit - __o->next_free); }) +#define obstack_empty_p(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (__o->chunk->prev == 0 && __o->next_free - __o->chunk->contents == 0); }) + #define obstack_grow(OBSTACK,where,length) \ __extension__ \ ({ struct obstack *__o = (OBSTACK); \ @@ -460,6 +465,9 @@ __extension__ \ #define obstack_room(h) \ (unsigned) ((h)->chunk_limit - (h)->next_free) +#define obstack_empty_p(h) \ + ((h)->chunk->prev == 0 && (h)->next_free - (h)->chunk->contents == 0) + /* Note that the call to _obstack_newchunk is enclosed in (..., 0) so that we can avoid having void expressions in the arms of the conditional expression. diff --git a/gcc/toplev.c b/gcc/toplev.c index 225964b6f0f..41e2c5b87f0 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -4294,6 +4294,15 @@ main (argc, argv, envp) OVERRIDE_OPTIONS; #endif + if (exceptions_via_longjmp == 2) + { +#ifdef DWARF2_UNWIND_INFO + exceptions_via_longjmp = ! DWARF2_UNWIND_INFO; +#else + exceptions_via_longjmp = 1; +#endif + } + if (profile_block_flag == 3) { warning ("`-ax' and `-a' are conflicting options. `-a' ignored."); diff --git a/gcc/tree.c b/gcc/tree.c index 6812aa4aade..d5eabaea008 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -81,6 +81,10 @@ struct obstack maybepermanent_obstack; 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. */ @@ -381,12 +385,22 @@ save_tree_status (p, context) head = &f->inline_obstacks; } - current = ((struct simple_obstack_stack *) - xmalloc (sizeof (struct simple_obstack_stack))); + 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); + } - current->obstack = (struct obstack *) xmalloc (sizeof (struct obstack)); function_maybepermanent_obstack = current->obstack; - gcc_obstack_init (function_maybepermanent_obstack); current->next = *head; *head = current; @@ -411,8 +425,9 @@ save_tree_status (p, context) This is used after a nested function. */ void -restore_tree_status (p) +restore_tree_status (p, context) struct function *p; + tree context; { all_types_permanent = p->all_types_permanent; momentary_stack = p->momentary_stack; @@ -428,6 +443,29 @@ restore_tree_status (p) past the nested function's end. */ 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; + + 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 (function_obstack, 0); free (function_obstack); @@ -4469,24 +4507,58 @@ 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; + unsigned long 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, %lu bytes, %d chunks\n", + n_obstacks, n_alloc, n_chunks); +} + +/* Print debugging information about the obstack O, named STR. */ + void print_obstack_statistics (str, o) char *str; struct obstack *o; { struct _obstack_chunk *chunk = o->chunk; - int n_chunks = 0; - int n_alloc = 0; + int n_chunks = 1; + unsigned long n_alloc = 0; + n_alloc += o->next_free - chunk->contents; + chunk = chunk->prev; while (chunk) { n_chunks += 1; n_alloc += chunk->limit - &chunk->contents[0]; chunk = chunk->prev; } - fprintf (stderr, "obstack %s: %d bytes, %d chunks\n", + fprintf (stderr, "obstack %s: %lu bytes, %d chunks\n", str, n_alloc, n_chunks); } + +/* Print debugging information about tree nodes generated during the compile, + and any language-specific information. */ + void dump_tree_statistics () { @@ -4512,6 +4584,12 @@ dump_tree_statistics () #else fprintf (stderr, "(No per-node statistics)\n"); #endif + print_obstack_statistics ("permanent_obstack", &permanent_obstack); + print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack); + 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 (); }