Reducing the cost of exception handling
Bruno Haible
haible@ilog.fr
Tue Feb 10 03:34:00 GMT 1998
Hi,
Currently the exception handling code is emitted by gcc in the text
section, thus enlarging the applications' text segment by 0%-80%,
depending on C++ programming style.
Here is a patch which causes all the exception handling code to be
emitted to an extra section, called ".eh_text" on ELF systems.
The patch causes no regressions in the testsuite (on i586-linux)
and works well with inline functions.
For a library which uses many stack-allocated variables of class type,
I got the following figures:
.text 572925 bytes
.eh_text 387104 bytes
Moving the exception code "out of the way" therefore reduces the working
set size by 40%.
The .eh_frame section increases for the moment, but I already have patches
which will drastically reduce that section's size.
As a side-effect, the jumps over the cleanup code near the end of the
function is optimized away in most cases.
For programs which don't use exceptions much, I expect an improvement in the
paging performance. You can test "-fexception-section" vs.
"-fno-exception-section". Can we put this patch in?
What about the following points:
- Is it possible to define an EH_TEXT_SECTION_ASM_OP for other platforms
than ELF?
- How do debuggers react on the fact that a function consists of two
totally disjoint address ranges? Should "-g" generally imply
"-fno-exception-section" ?
Bruno
------------------------------------------------------------------------------
Note: The patch below contains ^L characters which are not properly
displayed by Emacs.
For ChangeLog:
Sat Jan 10 04:23:00 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
* except.h (extra_section_for_exceptions): New variable.
* toplev.c (f_options): New flag -fexception-section.
(compile_file): Initialize extra_section_for_exceptions.
* rtl.h (NOTE_INSN_EH_HANDLER_{BEG,END}): Define.
* rtl.c (note_insn_name): Add NOTE_INSN_EH_HANDLER_{BEG,END}.
* except.c (extra_section_for_exceptions): Define.
(expand_eh_region_end): Enclose the rethrow stub in EH_HANDLER notes.
(add_eh_table_entry, exception_table_p): Adapt for multiple sections.
(output_exception_table_entry, output_exception_table): Likewise.
* function.c (expand_function_end): Enclose the cleanup code in
EH_HANDLER notes.
* jump.c (jump_optimize): Insert moved insns immediately before target
label.
* final.c (*eh_region*, eh_handler*): New variables.
(init_final, final_start_function): Initialize them.
(final_section_merge, final_jump_optimize): New functions.
(final): Call them.
(final_scan_insn): Change EH_REGION_* handling. Add EH_HANDLER_*
handling.
* tree.h (dwarf2out_goto_section): Declare.
* dwarf2out.c (force_call_frame_info, current_section): New variables.
(dwarf2out_goto_section): New function.
(add_fde_cfi, output_call_frame_info): Adapt for multiple sections.
(dwarf2out_begin_prologue, dwarf2out_end_epilogue): Likewise.
* output.h (function_eh_section): Declare.
* varasm.c (eh_text_section, function_eh_section): New functions.
* frame.c (fde_insert, add_fdes, frame_init): Use two-stack insertion
sort algorithm.
For cp/ChangeLog:
Sat Jan 10 04:23:00 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
* except.c (expand_exception_blocks): Enclose a TRY's exception
blocks in EH_HANDLER notes.
*** egcs-971225/gcc/except.h.bak Sat Dec 20 01:13:52 1997
--- egcs-971225/gcc/except.h Tue Jan 6 02:18:49 1998
*************** extern void init_eh PROTO((void));
*** 147,160 ****
extern void init_eh_for_function PROTO((void));
! /* Adds an EH table entry for EH entry number N. Called from
! final_scan_insn for NOTE_INSN_EH_REGION_BEG. */
! extern void add_eh_table_entry PROTO((int n));
! /* Returns a non-zero value if we need to output an exception table. */
! extern int exception_table_p PROTO((void));
/* Outputs the exception table if we have one. */
--- 147,162 ----
extern void init_eh_for_function PROTO((void));
! /* Adds an EH table entry for EH handler number N, protecting EH inverval
! number I. Called from final_scan_insn for NOTE_INSN_EH_REGION_BEG
! and NOTE_INSN_EH_HANDLER_BEG. */
! extern void add_eh_table_entry PROTO((int n, int i, int section));
! /* Returns a non-zero value if we need to output an exception table for
! a specified section. */
! extern int exception_table_p PROTO((int section));
/* Outputs the exception table if we have one. */
*************** extern int exceptions_via_longjmp;
*** 270,275 ****
--- 272,281 ----
/* One to enable asynchronous exception support. */
extern int asynchronous_exceptions;
+
+ /* One to emit exception handler code in a separate section. */
+
+ extern int extra_section_for_exceptions;
/* One to protect cleanup actions with a handler that calls
__terminate, zero otherwise. */
*** egcs-971225/gcc/toplev.c.bak Sat Jan 3 20:26:13 1998
--- egcs-971225/gcc/toplev.c Thu Jan 8 23:50:22 1998
*************** struct { char *string; int *variable; in
*** 749,754 ****
--- 749,755 ----
{"exceptions", &flag_exceptions, 1},
{"sjlj-exceptions", &exceptions_via_longjmp, 1},
{"asynchronous-exceptions", &asynchronous_exceptions, 1},
+ {"exception-section", &extra_section_for_exceptions, 1},
{"profile-arcs", &profile_arc_flag, 1},
{"test-coverage", &flag_test_coverage, 1},
{"branch-probabilities", &flag_branch_probabilities, 1},
*************** compile_file (name)
*** 2494,2499 ****
--- 2495,2523 ----
if (flag_function_sections && write_symbols != NO_DEBUG)
warning ("-ffunction-sections may affect debugging on some targets.");
+
+ #if defined (EH_TEXT_SECTION_ASM_OP) || defined (ASM_OUTPUT_SECTION_NAME)
+ #if defined (DBX_DEBUGGING_INFO) && defined (DBX_BLOCKS_FUNCTION_RELATIVE)
+ if (write_symbols == DBX_DEBUG)
+ {
+ if (extra_section_for_exceptions == 1)
+ warning ("-fexception-section disabled; it makes debugging impossible.");
+ extra_section_for_exceptions = 0;
+ }
+ #endif
+ if (profile_flag || profile_block_flag)
+ {
+ if (extra_section_for_exceptions == 1)
+ warning ("-fexception-section disabled; it makes profiling impossible.");
+ extra_section_for_exceptions = 0;
+ }
+ if (extra_section_for_exceptions == 2)
+ extra_section_for_exceptions = 1;
+ #else
+ if (extra_section_for_exceptions == 1)
+ warning ("-fexception-section not supported for this target.");
+ extra_section_for_exceptions = 0;
+ #endif
if (output_bytecode)
{
*** egcs-971225/gcc/rtl.h.bak Tue Dec 30 11:27:33 1997
--- egcs-971225/gcc/rtl.h Sun Jan 4 14:28:20 1998
*************** extern char *reg_note_name[];
*** 416,421 ****
--- 416,425 ----
one is output after the end of an inline function, in order to prevent
the line containing the inline call from being counted twice in gcov. */
#define NOTE_REPEATED_LINE_NUMBER -16
+ /* These note where exception handlers begin and end. For some targets,
+ exception handling code is put into a separate section. */
+ #define NOTE_INSN_EH_HANDLER_BEG -17
+ #define NOTE_INSN_EH_HANDLER_END -18
#if 0 /* These are not used, and I don't know what they were for. --rms. */
*** egcs-971225/gcc/rtl.c.bak Tue Dec 30 11:27:33 1997
--- egcs-971225/gcc/rtl.c Sun Jan 4 14:31:22 1998
*************** char *note_insn_name[] = { 0
*** 177,183 ****
"NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
"NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
"NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
! "NOTE_REPEATED_LINE_NUMBER" };
char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
--- 177,185 ----
"NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
"NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
"NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
! "NOTE_REPEATED_LINE_NUMBER",
! "NOTE_INSN_EH_HANDLER_BEG",
! "NOTE_INSN_EH_HANDLER_END" };
char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
*** egcs-971225/gcc/except.c.bak Thu Jan 1 14:32:08 1998
--- egcs-971225/gcc/except.c Wed Jan 7 02:42:56 1998
*************** int exceptions_via_longjmp = 2;
*** 422,427 ****
--- 422,431 ----
int asynchronous_exceptions = 0;
+ /* One to emit exception handler code in a separate section. */
+
+ int extra_section_for_exceptions = 2;
+
/* One to protect cleanup actions with a handler that calls
__terminate, zero otherwise. */
*************** expand_eh_region_end (handler)
*** 1123,1133 ****
--- 1127,1141 ----
label = gen_label_rtx ();
emit_jump (label);
+ emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_BEG);
+
/* Emit a label marking the end of this exception region that
is used for rethrowing into the outer context. */
emit_label (entry->outer_context);
expand_internal_throw ();
+ emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_END);
+
emit_label (label);
}
*************** protect_with_terminate (e)
*** 1508,1565 ****
dispatching exceptions, the current number of entries, and its
maximum size before we have to extend it.
! The number in eh_table is the code label number of the exception
! handler for the region. This is added by add_eh_table_entry and
! used by output_exception_table_entry. */
!
! static int *eh_table;
! static int eh_table_size;
! static int eh_table_max_size;
!
! /* Note the need for an exception table entry for region N. If we
! don't need to output an explicit exception table, avoid all of the
! extra work.
!
! Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
! N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
! label number of the exception handler for the region. */
void
! add_eh_table_entry (n)
! int n;
{
#ifndef OMIT_EH_TABLE
! if (eh_table_size >= eh_table_max_size)
{
! if (eh_table)
{
! eh_table_max_size += eh_table_max_size>>1;
! if (eh_table_max_size < 0)
abort ();
! eh_table = (int *) xrealloc (eh_table,
! eh_table_max_size * sizeof (int));
}
else
{
! eh_table_max_size = 252;
! eh_table = (int *) xmalloc (eh_table_max_size * sizeof (int));
}
}
! eh_table[eh_table_size++] = n;
#endif
}
! /* Return a non-zero value if we need to output an exception table.
On some platforms, we don't have to output a table explicitly.
This routine doesn't mean we don't have one. */
int
! exception_table_p ()
{
! if (eh_table)
return 1;
return 0;
--- 1516,1598 ----
dispatching exceptions, the current number of entries, and its
maximum size before we have to extend it.
! There is one table for the text section and one for the eh_text
! section.
!
! The number in eh_table[section].entries is the code label number of
! the exception handler for the region. This is added by
! add_eh_table_entry and used by output_exception_table_entry. */
!
! struct eh_table_entry
! {
! int n;
! int i;
! };
!
! static struct eh_table_struct
! {
! struct eh_table_entry *entries;
! int size;
! int max_size;
! }
! eh_table[2];
!
! /* Note the need for an exception table entry which protects interval I
! through handler N. If we don't need to output an explicit exception
! table, avoid all of the extra work.
!
! Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG or a
! NOTE_INSN_EH_HANDLER_BEG is seen. N is the code label number of the
! exception handler for the region. I is the code label number of the
! special start and end labels (output directly from final_scan_insn)
! of the regions. */
void
! add_eh_table_entry (n, i, section)
! int n, i, section;
{
#ifndef OMIT_EH_TABLE
! struct eh_table_struct *table = &eh_table[section];
!
! if (table->size >= table->max_size)
{
! if (table->entries)
{
! table->max_size += table->max_size>>1;
! if (table->max_size < 0)
abort ();
! table->entries =
! (struct eh_table_entry *)
! xrealloc (table->entries,
! table->max_size * sizeof (struct eh_table_entry));
}
else
{
! table->max_size = 252;
! table->entries =
! (struct eh_table_entry *)
! xmalloc (table->max_size * sizeof (struct eh_table_entry));
}
}
! table->entries[table->size].i = i;
! table->entries[table->size].n = n;
! table->size++;
#endif
}
! /* Return a non-zero value if we need to output an exception table for
! a specified section.
On some platforms, we don't have to output a table explicitly.
This routine doesn't mean we don't have one. */
int
! exception_table_p (section)
! int section;
{
! if (eh_table[section].entries)
return 1;
return 0;
*************** exception_table_p ()
*** 1572,1593 ****
region. */
static void
! output_exception_table_entry (file, n)
FILE *file;
! int n;
{
char buf[256];
rtx sym;
! ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
sym = gen_rtx (SYMBOL_REF, Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
! ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
sym = gen_rtx (SYMBOL_REF, Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
! ASM_GENERATE_INTERNAL_LABEL (buf, "L", n);
sym = gen_rtx (SYMBOL_REF, Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
--- 1605,1626 ----
region. */
static void
! output_exception_table_entry (file, entry)
FILE *file;
! const struct eh_table_entry *entry;
{
char buf[256];
rtx sym;
! ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", entry->i);
sym = gen_rtx (SYMBOL_REF, Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
! ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", entry->i);
sym = gen_rtx (SYMBOL_REF, Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
! ASM_GENERATE_INTERNAL_LABEL (buf, "L", entry->n);
sym = gen_rtx (SYMBOL_REF, Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
*************** output_exception_table_entry (file, n)
*** 1599,1626 ****
void
output_exception_table ()
{
! int i;
extern FILE *asm_out_file;
! if (! doing_eh (0) || ! eh_table)
return;
exception_section ();
! /* Beginning marker for table. */
! assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
! assemble_label ("__EXCEPTION_TABLE__");
!
! for (i = 0; i < eh_table_size; ++i)
! output_exception_table_entry (asm_out_file, eh_table[i]);
!
! free (eh_table);
!
! /* Ending marker for table. */
! assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! putc ('\n', asm_out_file); /* blank line */
}
/* Emit code to get EH context.
--- 1632,1671 ----
void
output_exception_table ()
{
! int section, i;
extern FILE *asm_out_file;
! if (! doing_eh (0))
! return;
!
! if (! eh_table[0].entries && ! eh_table[1].entries)
return;
exception_section ();
! for (section = 0; section < 2; section++)
! {
! struct eh_table_struct *table = &eh_table[section];
!
! if (table->size > 0)
! {
! /* Beginning marker for table. */
! assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
! assemble_label (section == 0 ? "__EXCEPTION_TABLE__"
! : "__EH_EXCEPTION_TABLE__");
!
! for (i = 0; i < table->size; i++)
! output_exception_table_entry (asm_out_file, &table->entries[i]);
!
! /* Ending marker for table. */
! assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! putc ('\n', asm_out_file); /* blank line */
! }
!
! free (table->entries);
! }
}
/* Emit code to get EH context.
*** egcs-971225/gcc/function.c.bak Thu Jan 1 14:04:35 1998
--- egcs-971225/gcc/function.c Fri Jan 9 00:19:01 1998
*************** expand_function_end (filename, line, end
*** 5901,5913 ****
created for the parameters. */
{
rtx last = get_last_insn ();
- rtx label;
expand_leftover_cleanups ();
/* If the above emitted any code, may sure we jump around it. */
if (last != get_last_insn ())
{
label = gen_label_rtx ();
last = emit_jump_insn_after (gen_jump (label), last);
last = emit_barrier_after (last);
--- 5901,5919 ----
created for the parameters. */
{
rtx last = get_last_insn ();
expand_leftover_cleanups ();
/* If the above emitted any code, may sure we jump around it. */
if (last != get_last_insn ())
{
+ rtx label;
+
+ /* If extra_section_for_exceptions is on, the cleanup code will be
+ moved to the eh_text section, and if we aren't already in the
+ eh_text section, the jump will be eliminated in final.c. */
+ emit_note_after (NOTE_INSN_EH_HANDLER_BEG, last);
+ emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_END);
label = gen_label_rtx ();
last = emit_jump_insn_after (gen_jump (label), last);
last = emit_barrier_after (last);
*** egcs-971225/gcc/jump.c.bak Thu Jan 1 15:20:20 1998
--- egcs-971225/gcc/jump.c Sun Jan 4 19:39:49 1998
*************** jump_optimize (f, cross_jump, noop_moves
*** 720,725 ****
--- 720,726 ----
{
if (GET_CODE (temp1) == BARRIER)
{
+ temp1 = PREV_INSN (JUMP_LABEL (insn));
emit_insn_after (PATTERN (temp), temp1);
temp1 = NEXT_INSN (temp1);
}
*** egcs-971225/gcc/final.c.bak Thu Jan 1 17:35:20 1998
--- egcs-971225/gcc/final.c Sat Jan 10 03:38:33 1998
*************** static int *pending_blocks;
*** 233,238 ****
--- 233,258 ----
static int block_depth;
+ /* Length so far allocated in PENDING_EH_REGIONS. */
+
+ static int max_eh_region_depth;
+
+ /* Stack of handler block numbers for open exception handling regions. */
+
+ static int *pending_eh_regions;
+
+ /* Number of elements currently in use in PENDING_EH_REGIONS. */
+
+ static int eh_region_depth;
+
+ /* Number of nested NOTE_INSN_EH_HANDLER_{BEG,END} notes seen. */
+
+ static int eh_handler_depth;
+
+ /* If eh_handler_depth > 0, a label used to protect an eh_text region. */
+
+ static rtx eh_handler_region_label;
+
/* Nonzero if have enabled APP processing of our assembler output. */
static int app_on;
*************** init_final (filename)
*** 310,316 ****
next_block_index = 2;
app_on = 0;
max_block_depth = 20;
! pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
final_sequence = 0;
#ifdef ASSEMBLER_DIALECT
--- 330,338 ----
next_block_index = 2;
app_on = 0;
max_block_depth = 20;
! pending_blocks = (int *) xmalloc (max_block_depth * sizeof (int));
! max_eh_region_depth = 10;
! pending_eh_regions = (int *) xmalloc (max_eh_region_depth * sizeof (int));
final_sequence = 0;
#ifdef ASSEMBLER_DIALECT
*************** final_start_function (first, file, optim
*** 951,956 ****
--- 973,981 ----
int optimize;
{
block_depth = 0;
+ eh_region_depth = 0;
+ eh_handler_depth = 0;
+ eh_handler_region_label = NULL_RTX;
this_is_asm_operands = 0;
*************** add_bb_string (string, perm_p)
*** 1266,1271 ****
--- 1291,1462 ----
}
+ /* We must make sure that we don't output the difference of two labels in
+ different sections: the text section and the eh_text section. Some pairs
+ of NOTE_INSN_EH_HANDLER_{BEG,END} insns must be deleted. */
+ static void
+ final_section_merge (rtx first)
+ {
+ int max_uid;
+ rtx *outer_table;
+ rtx insn;
+ rtx outer;
+
+ if (! extra_section_for_exceptions)
+ return;
+
+ max_uid = get_max_uid ();
+ outer_table = (rtx *) alloca (max_uid * sizeof (rtx));
+ bzero ((char *) outer_table, max_uid * sizeof (rtx));
+
+ /* Make a single pass through the code, registering the outer enclosing
+ NOTE_INSN_EH_HANDLER_BEG insn in OUTER_TABLE. Also let each
+ EH_HANDLER_BEG note point to its corresponding EH_HANDLER_END note. */
+ outer = NULL_RTX;
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ outer_table[INSN_UID (insn)] = outer;
+ if (INSN_DELETED_P (insn))
+ continue;
+ if (GET_CODE (insn) == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_BEG)
+ outer = insn;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_END)
+ {
+ NOTE_SOURCE_FILE (outer) = (char *) insn;
+ outer = outer_table[INSN_UID (outer)];
+ }
+ }
+ }
+ if (outer != NULL_RTX)
+ abort ();
+
+ /* Now go through the code once again, looking for suspicious label
+ differences. */
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ if (INSN_DELETED_P (insn))
+ continue;
+ if (GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+ {
+ rtx body = PATTERN (insn);
+ int vlen = XVECLEN (body, 1);
+ int idx;
+ for (idx = 0; idx < vlen; idx++)
+ {
+ rtx outer1, outer2;
+ int depth1, depth2;
+ outer1 = XEXP (XEXP (body, 0), 0);
+ outer2 = XEXP (XVECEXP (body, 1, idx), 0);
+ outer1 = outer_table[INSN_UID (outer1)];
+ outer2 = outer_table[INSN_UID (outer2)];
+ for (outer = outer1, depth1 = 0;
+ outer != NULL_RTX;
+ outer = outer_table[INSN_UID (outer)], depth1++);
+ for (outer = outer2, depth2 = 0;
+ outer != NULL_RTX;
+ outer = outer_table[INSN_UID (outer)], depth2++);
+ while (!(depth1 == depth2 && outer1 == outer2))
+ {
+ int kill1 = (depth1 >= depth2);
+ int kill2 = (depth1 <= depth2);
+ if (kill1)
+ {
+ /* Kill EH_HANDLER_{BEG,END} corresponding to outer1. */
+ NOTE_LINE_NUMBER ((rtx) NOTE_SOURCE_FILE (outer1))
+ = NOTE_INSN_DELETED;
+ NOTE_LINE_NUMBER (outer1) = NOTE_INSN_DELETED;
+ outer1 = outer_table[INSN_UID (outer1)];
+ depth1--;
+ }
+ if (kill2)
+ {
+ /* Kill EH_HANDLER_{BEG,END} corresponding to outer2. */
+ NOTE_LINE_NUMBER ((rtx) NOTE_SOURCE_FILE (outer2))
+ = NOTE_INSN_DELETED;
+ NOTE_LINE_NUMBER (outer2) = NOTE_INSN_DELETED;
+ outer2 = outer_table[INSN_UID (outer2)];
+ depth2--;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Remove simple jumps which jump "over" some code in another section.
+ The usual jump optimizations don't catch this because they don't know
+ about different code sections. In fact, the usual jump optimizations
+ cannot do this because the partitioning into sections is different
+ between an out-of-line copy and an inline copy of the same function. */
+ static void
+ final_jump_optimize (rtx first)
+ {
+ rtx insn, insn1, insn2, last_jump;
+ int eh_handler_depth;
+
+ if (optimize && extra_section_for_exceptions)
+ {
+ eh_handler_depth = 0;
+ last_jump = NULL_RTX;
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ if (INSN_DELETED_P (insn))
+ continue;
+ switch (GET_CODE (insn))
+ {
+ case NOTE:
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_BEG)
+ {
+ if (eh_handler_depth++ == 0)
+ {
+ if ((insn1 = PREV_INSN (insn))
+ && GET_CODE (insn1) == BARRIER
+ && (insn2 = PREV_INSN (insn1))
+ && simplejump_p (insn2))
+ last_jump = insn2;
+ }
+ break;
+ }
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_END)
+ {
+ if (--eh_handler_depth == 0)
+ {
+ if (last_jump)
+ {
+ for (insn1 = NEXT_INSN (insn);
+ insn1
+ && GET_CODE (insn1) == NOTE
+ && (NOTE_LINE_NUMBER (insn1)
+ != NOTE_INSN_EH_HANDLER_BEG);
+ insn1 = NEXT_INSN (insn1))
+ ;
+ if (GET_CODE (insn1) == CODE_LABEL
+ && JUMP_LABEL (last_jump) == insn1)
+ /* Delete the jump "over" the section and the
+ barrier in between. */
+ {
+ INSN_DELETED_P (last_jump) = 1;
+ INSN_DELETED_P (NEXT_INSN (last_jump)) = 1;
+ last_jump = NULL_RTX;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ default:
+ if (eh_handler_depth == 0)
+ last_jump = NULL_RTX;
+ break;
+ }
+ }
+ }
+ }
+
+
/* Output assembler code for some insns: all or part of a function.
For description of args, see `final_start_function', above.
*************** final (first, file, optimize, prescan)
*** 1292,1297 ****
--- 1483,1491 ----
check_exception_handler_labels ();
+ final_section_merge (first);
+ final_jump_optimize (first);
+
/* Make a map indicating which line numbers appear in this function.
When producing SDB debugging info, delete troublesome line number
notes from inlined functions in other files as well as duplicate
*************** final_scan_insn (insn, file, optimize, p
*** 1399,1422 ****
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
break;
! if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
! && ! exceptions_via_longjmp)
{
! ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
! add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
#ifdef ASM_OUTPUT_EH_REGION_BEG
! ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
#endif
break;
}
! if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
! && ! exceptions_via_longjmp)
{
! ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
#ifdef ASM_OUTPUT_EH_REGION_END
! ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
#endif
break;
}
--- 1593,1691 ----
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
break;
! if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
{
! int blockno = NOTE_BLOCK_NUMBER (insn);
!
! if (eh_region_depth == max_eh_region_depth)
! {
! /* PENDING_EH_REGIONS is full; make it longer. */
! max_eh_region_depth *= 2;
! pending_eh_regions =
! (int *) xrealloc (pending_eh_regions,
! max_eh_region_depth * sizeof (int));
! }
! pending_eh_regions[eh_region_depth++] = blockno;
!
! if (! exceptions_via_longjmp)
! {
! ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", blockno);
! add_eh_table_entry (blockno, blockno,
! extra_section_for_exceptions
! && eh_handler_depth > 0);
#ifdef ASM_OUTPUT_EH_REGION_BEG
! ASM_OUTPUT_EH_REGION_BEG (file, blockno);
#endif
+ }
+
break;
}
! if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
{
! int blockno = NOTE_BLOCK_NUMBER (insn);
!
! eh_region_depth--;
!
! if (! exceptions_via_longjmp)
! {
! ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", blockno);
#ifdef ASM_OUTPUT_EH_REGION_END
! ASM_OUTPUT_EH_REGION_END (file, blockno);
! #endif
! }
!
! break;
! }
!
! if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_BEG)
! {
! /* NOTE_INSN_EH_HANDLER_BEG followed by NOTE_INSN_EH_HANDLER_END
! cancel each other and can be ignored. */
! rtx next_insn = NEXT_INSN (insn);
! if (GET_CODE (next_insn) == NOTE
! && NOTE_LINE_NUMBER (next_insn) == NOTE_INSN_EH_HANDLER_END)
! return NEXT_INSN (next_insn);
!
! if (eh_handler_depth++ == 0 && extra_section_for_exceptions)
! {
! function_eh_section (current_function_decl);
! if (! exceptions_via_longjmp && eh_region_depth > 0)
! {
! int i, n;
! eh_handler_region_label = gen_label_rtx ();
! i = CODE_LABEL_NUMBER (eh_handler_region_label);
! n = pending_eh_regions[eh_region_depth - 1];
! ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", i);
! add_eh_table_entry (n, i, 1);
! }
! #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
! if (dwarf2out_do_frame ())
! dwarf2out_goto_section (1, eh_handler_region_label);
! #endif
! }
! break;
! }
!
! if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_END)
! {
! if (--eh_handler_depth == 0 && extra_section_for_exceptions)
! {
! #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
! if (dwarf2out_do_frame ())
! dwarf2out_goto_section (0, eh_handler_region_label);
#endif
+ if (! exceptions_via_longjmp && eh_region_depth > 0)
+ {
+ int i, n;
+ i = CODE_LABEL_NUMBER (eh_handler_region_label);
+ n = pending_eh_regions[eh_region_depth - 1];
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", i);
+ rtx_free (eh_handler_region_label);
+ eh_handler_region_label = NULL_RTX;
+ }
+ function_section (current_function_decl);
+ }
break;
}
*** egcs-971225/gcc/tree.h.bak Sat Dec 20 01:16:00 1997
--- egcs-971225/gcc/tree.h Wed Jan 7 00:43:10 1998
*************** extern void dwarf2out_return_save PROTO(
*** 1805,1810 ****
--- 1805,1814 ----
extern void dwarf2out_return_reg PROTO((char *, unsigned));
+ /* Entry point for switching to another section. */
+
+ extern void dwarf2out_goto_section PROTO((int, struct rtx_def *));
+
/* Output a marker (i.e. a label) for the beginning of a function, before
the prologue. */
*** egcs-971225/gcc/dwarf2out.c.bak Thu Jan 1 15:13:23 1998
--- egcs-971225/gcc/dwarf2out.c Fri Jan 9 02:55:44 1998
*************** typedef union dw_cfi_oprnd_struct
*** 79,84 ****
--- 79,85 ----
unsigned long dw_cfi_reg_num;
long int dw_cfi_offset;
char *dw_cfi_addr;
+ int dw_cfi_section;
}
dw_cfi_oprnd;
*************** dw_cfi_node;
*** 99,107 ****
typedef struct dw_fde_struct
{
! char *dw_fde_begin;
char *dw_fde_current_label;
! char *dw_fde_end;
dw_cfi_ref dw_fde_cfi;
}
dw_fde_node;
--- 100,108 ----
typedef struct dw_fde_struct
{
! char *dw_fde_begin[2];
char *dw_fde_current_label;
! char *dw_fde_end[2];
dw_cfi_ref dw_fde_cfi;
}
dw_fde_node;
*************** dwarf_cfi_name (cfi_opc)
*** 688,693 ****
--- 689,755 ----
}
}
+ /* If this is set to 1, CIEs and FDEs will be output even if no function
+ in the compilation uses exceptions. */
+ static int force_call_frame_info = 0;
+
+ /* The current section to which insns are being emitted. 0 means "text",
+ 1 means "eh_text". */
+ static int current_section;
+
+ /* Switch to another section.
+ When LABEL is non-NULL, it denotes an LEHB/LEHE label which is just being
+ output. */
+ void
+ dwarf2out_goto_section (section, label)
+ int section;
+ rtx label;
+ {
+ register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+ rtx templabel;
+ int labelno = -1;
+ char labelstring[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (section == 0)
+ {
+ /* Switching from section 1 to section 0. */
+ if (label)
+ labelno = CODE_LABEL_NUMBER (label);
+ else
+ {
+ templabel = gen_label_rtx ();
+ labelno = CODE_LABEL_NUMBER (templabel);
+ rtx_free (templabel);
+ }
+ ASM_GENERATE_INTERNAL_LABEL (labelstring, "LEHE", labelno);
+ if (! label)
+ ASM_OUTPUT_LABEL (asm_out_file, labelstring);
+ if (fde->dw_fde_end[1])
+ free (fde->dw_fde_end[1]);
+ fde->dw_fde_end[1] = xstrdup (labelstring);
+ }
+ else
+ {
+ /* Switching from section 0 to section 1. */
+ if (! fde->dw_fde_begin[1])
+ {
+ if (label)
+ labelno = CODE_LABEL_NUMBER (label);
+ else
+ {
+ templabel = gen_label_rtx ();
+ labelno = CODE_LABEL_NUMBER (templabel);
+ rtx_free (templabel);
+ }
+ ASM_GENERATE_INTERNAL_LABEL (labelstring, "LEHB", labelno);
+ if (! label)
+ ASM_OUTPUT_LABEL (asm_out_file, labelstring);
+ fde->dw_fde_begin[1] = xstrdup (labelstring);
+ }
+ }
+ current_section = section;
+ }
+
/* Return a pointer to a newly allocated Call Frame Instruction. */
static inline dw_cfi_ref
*************** add_fde_cfi (label, cfi)
*** 758,763 ****
--- 820,826 ----
xcfi = new_cfi ();
xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
+ xcfi->dw_cfi_oprnd2.dw_cfi_section = current_section;
add_cfi (&fde->dw_fde_cfi, xcfi);
}
*************** static void
*** 1579,1584 ****
--- 1642,1648 ----
output_call_frame_info (for_eh)
int for_eh;
{
+ int section;
register unsigned long i;
register dw_fde_ref fde;
register dw_cfi_ref cfi;
*************** output_call_frame_info (for_eh)
*** 1587,1595 ****
char ld[20];
#endif
- /* Do we want to include a pointer to the exception table? */
- int eh_ptr = for_eh && exception_table_p ();
-
fputc ('\n', asm_out_file);
/* We're going to be generating comments, so turn on app. */
--- 1651,1656 ----
*************** output_call_frame_info (for_eh)
*** 1608,1731 ****
ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
#endif
- assemble_label ("__FRAME_BEGIN__");
}
else
ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
! /* Output the CIE. */
! ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
! ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh);
! if (for_eh)
! ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
! else
! ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
! #else
! if (for_eh)
! ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
! else
! ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
! #endif
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s Length of Common Information Entry",
! ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
! ASM_OUTPUT_LABEL (asm_out_file, l1);
!
! if (for_eh)
! /* Now that the CIE pointer is PC-relative for EH,
! use 0 to identify the CIE. */
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
! else
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
!
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
! if (! for_eh && DWARF_OFFSET_SIZE == 8)
! {
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
! fputc ('\n', asm_out_file);
! }
!
! ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
! if (eh_ptr)
! {
! /* The CIE contains a pointer to the exception region info for the
! frame. Make the augmentation string three bytes (including the
! trailing null) so the pointer is 4-byte aligned. The Solaris ld
! can't handle unaligned relocs. */
! if (flag_debug_asm)
! {
! ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
! fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
! }
! else
! {
! ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
! }
! fputc ('\n', asm_out_file);
!
! ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s pointer to exception region info",
! ASM_COMMENT_START);
! }
! else
{
! ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
! ASM_COMMENT_START);
! }
!
! fputc ('\n', asm_out_file);
! output_uleb128 (1);
! if (flag_debug_asm)
! fprintf (asm_out_file, " (CIE Code Alignment Factor)");
!
! fputc ('\n', asm_out_file);
! output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
! if (flag_debug_asm)
! fprintf (asm_out_file, " (CIE Data Alignment Factor)");
!
! fputc ('\n', asm_out_file);
! ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
!
! for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
! output_cfi (cfi, NULL);
! /* Pad the CIE out to an address sized boundary. */
! ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
! ASM_OUTPUT_LABEL (asm_out_file, l2);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
! fputc ('\n', asm_out_file);
! #endif
!
! /* Loop through all of the FDE's. */
! for (i = 0; i < fde_table_in_use; ++i)
! {
! fde = &fde_table[i];
! ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2);
! ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2);
if (for_eh)
ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
else
--- 1669,1697 ----
ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
#endif
}
else
ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
! /* A CIE and a series of FDEs for each section. */
! for (section = 0; section < 1 + extra_section_for_exceptions; section++)
{
! /* Number to append to labels, to keep them distinct. */
! int nr = 2 * section + for_eh;
! if (for_eh
! && ! exception_table_p (section)
! && ! (section == 0 && force_call_frame_info))
! continue;
! /* Output the CIE. */
! if (for_eh)
! assemble_label (section == 0 ? "__FRAME_BEGIN__"
! : "__EH_FRAME_BEGIN__");
! ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, nr);
! ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, nr);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, nr);
if (for_eh)
ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
else
*************** output_call_frame_info (for_eh)
*** 1737,1790 ****
ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
#endif
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
ASM_OUTPUT_LABEL (asm_out_file, l1);
if (for_eh)
! ASM_OUTPUT_DWARF_DELTA (asm_out_file, l1, "__FRAME_BEGIN__");
else
! ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION));
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
! ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin);
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
! ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
! fde->dw_fde_end, fde->dw_fde_begin);
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
! /* Loop through the Call Frame Instructions associated with
! this FDE. */
! fde->dw_fde_current_label = fde->dw_fde_begin;
! for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
! output_cfi (cfi, fde);
! /* Pad the FDE out to an address sized boundary. */
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
ASM_OUTPUT_LABEL (asm_out_file, l2);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
#endif
! }
#ifndef EH_FRAME_SECTION
! if (for_eh)
! {
! /* Emit terminating zero for table. */
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
! fputc ('\n', asm_out_file);
! }
#endif
#ifdef MIPS_DEBUGGING_INFO
/* Work around Irix 6 assembler bug whereby labels at the end of a section
get a value of 0. Putting .align 0 after the label fixes it. */
--- 1703,1888 ----
ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
#endif
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s Length of Common Information Entry",
! ASM_COMMENT_START);
!
fputc ('\n', asm_out_file);
ASM_OUTPUT_LABEL (asm_out_file, l1);
if (for_eh)
! /* Now that the CIE pointer is PC-relative for EH,
! use 0 to identify the CIE. */
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
! else
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
!
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
! if (! for_eh && DWARF_OFFSET_SIZE == 8)
! {
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
! fputc ('\n', asm_out_file);
! }
!
! ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
! if (for_eh && exception_table_p (section))
! {
! /* The CIE contains a pointer to the exception region info for the
! frame. Make the augmentation string three bytes (including the
! trailing null) so the pointer is 4-byte aligned. The Solaris ld
! can't handle unaligned relocs. */
! if (flag_debug_asm)
! {
! ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
! fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
! }
! else
! {
! ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
! }
! fputc ('\n', asm_out_file);
!
! ASM_OUTPUT_DWARF_ADDR (asm_out_file, section == 0
! ? "__EXCEPTION_TABLE__"
! : "__EH_EXCEPTION_TABLE__");
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s pointer to exception region info",
! ASM_COMMENT_START);
! }
else
! {
! ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
! ASM_COMMENT_START);
! }
!
! fputc ('\n', asm_out_file);
! output_uleb128 (1);
if (flag_debug_asm)
! fprintf (asm_out_file, " (CIE Code Alignment Factor)");
fputc ('\n', asm_out_file);
! output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
if (flag_debug_asm)
! fprintf (asm_out_file, " (CIE Data Alignment Factor)");
fputc ('\n', asm_out_file);
! ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
! for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
! output_cfi (cfi, NULL);
! /* Pad the CIE out to an address sized boundary. */
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
ASM_OUTPUT_LABEL (asm_out_file, l2);
#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
fputc ('\n', asm_out_file);
#endif
!
! /* Loop through all of the FDE's. */
! for (i = 0; i < fde_table_in_use; ++i)
! {
! fde = &fde_table[i];
!
! if (for_eh && ! fde->dw_fde_begin[section])
! continue;
!
! ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, nr + i*4);
! ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, nr + i*4);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, nr + i*4);
! if (for_eh)
! ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
! else
! ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
! #else
! if (for_eh)
! ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
! else
! ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
! #endif
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
! fputc ('\n', asm_out_file);
! ASM_OUTPUT_LABEL (asm_out_file, l1);
!
! if (for_eh)
! ASM_OUTPUT_DWARF_DELTA (asm_out_file, l1, section == 0
! ? "__FRAME_BEGIN__"
! : "__EH_FRAME_BEGIN__");
! else
! ASM_OUTPUT_DWARF_OFFSET (asm_out_file,
! stripattributes (FRAME_SECTION));
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
! ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin[section]);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE initial location",
! ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
! ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
! fde->dw_fde_end[section],
! fde->dw_fde_begin[section]);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
!
! fputc ('\n', asm_out_file);
!
! /* Loop through the Call Frame Instructions associated with
! this FDE. */
! fde->dw_fde_current_label = fde->dw_fde_begin[section];
! for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
! {
! switch (cfi->dw_cfi_opc)
! {
! case DW_CFA_advance_loc:
! case DW_CFA_advance_loc1:
! case DW_CFA_advance_loc2:
! case DW_CFA_advance_loc4:
! case DW_CFA_MIPS_advance_loc8:
! if (cfi->dw_cfi_oprnd2.dw_cfi_section != section)
! continue;
! }
! output_cfi (cfi, fde);
! }
!
! /* Pad the FDE out to an address sized boundary. */
! ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
! ASM_OUTPUT_LABEL (asm_out_file, l2);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
! if (flag_debug_asm)
! fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
! fputc ('\n', asm_out_file);
! #endif
! }
#ifndef EH_FRAME_SECTION
! if (for_eh)
! {
! /* Emit terminating zero for table. */
! ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
! fputc ('\n', asm_out_file);
! }
#endif
+ }
+
#ifdef MIPS_DEBUGGING_INFO
/* Work around Irix 6 assembler bug whereby labels at the end of a section
get a value of 0. Putting .align 0 after the label fixes it. */
*************** dwarf2out_begin_prologue ()
*** 1807,1812 ****
--- 1905,1916 ----
++current_funcdef_number;
+ /* This is needed so that __throw(), the only function which calls
+ __builtin_unwind_init() and __builtin_eh_stub(), gets proper call
+ frame info. */
+ if (! strcmp (current_function_name, "__throw"))
+ force_call_frame_info = 1;
+
function_section (current_function_decl);
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_funcdef_number);
*************** dwarf2out_begin_prologue ()
*** 1826,1836 ****
/* Add the new FDE at the end of the fde_table. */
fde = &fde_table[fde_table_in_use++];
! fde->dw_fde_begin = xstrdup (label);
fde->dw_fde_current_label = NULL;
! fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
args_size = 0;
}
--- 1930,1943 ----
/* Add the new FDE at the end of the fde_table. */
fde = &fde_table[fde_table_in_use++];
! fde->dw_fde_begin[0] = xstrdup (label);
! fde->dw_fde_begin[1] = NULL;
fde->dw_fde_current_label = NULL;
! fde->dw_fde_end[0] = NULL;
! fde->dw_fde_end[1] = NULL;
fde->dw_fde_cfi = NULL;
+ current_section = 0;
args_size = 0;
}
*************** dwarf2out_end_epilogue ()
*** 1845,1855 ****
char label[MAX_ARTIFICIAL_LABEL_BYTES];
/* Output a label to mark the endpoint of the code generated for this
! function. */
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
ASM_OUTPUT_LABEL (asm_out_file, label);
fde = &fde_table[fde_table_in_use - 1];
! fde->dw_fde_end = xstrdup (label);
}
void
--- 1952,1962 ----
char label[MAX_ARTIFICIAL_LABEL_BYTES];
/* Output a label to mark the endpoint of the code generated for this
! function. */
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
ASM_OUTPUT_LABEL (asm_out_file, label);
fde = &fde_table[fde_table_in_use - 1];
! fde->dw_fde_end[0] = xstrdup (label);
}
void
*** egcs-971225/gcc/output.h.bak Sun Nov 2 09:40:38 1997
--- egcs-971225/gcc/output.h Wed Jan 7 02:22:35 1998
*************** extern void named_section PROTO((tree,
*** 147,152 ****
--- 147,156 ----
/* Tell assembler to switch to the section for function DECL. */
extern void function_section PROTO((tree));
+ /* Tell assembler to switch to the section for exception handling code of
+ function DECL. */
+ extern void function_eh_section PROTO((tree));
+
/* Tell assembler to switch to the section for the exception table. */
extern void exception_section PROTO((void));
*** egcs-971225/gcc/varasm.c.bak Thu Jan 1 15:07:31 1998
--- egcs-971225/gcc/varasm.c Wed Jan 7 03:10:53 1998
*************** static enum in_section { no_section, in_
*** 177,182 ****
--- 177,185 ----
#ifdef BSS_SECTION_ASM_OP
, in_bss
#endif
+ #ifdef EH_TEXT_SECTION_ASM_OP
+ , in_eh_text
+ #endif
#ifdef EH_FRAME_SECTION_ASM_OP
, in_eh_frame
#endif
*************** asm_output_aligned_bss (file, decl, name
*** 411,416 ****
--- 414,436 ----
#endif /* BSS_SECTION_ASM_OP */
+ void
+ eh_text_section (decl)
+ tree decl;
+ {
+ if (decl == NULL_TREE || TREE_CODE (decl) != FUNCTION_DECL)
+ abort ();
+ #ifdef EH_TEXT_SECTION_ASM_OP
+ if (in_section != in_eh_text)
+ {
+ fprintf (asm_out_file, "%s\n", EH_TEXT_SECTION_ASM_OP);
+ in_section = in_eh_text;
+ }
+ #else
+ named_section (decl, ".eh_text", 0);
+ #endif
+ }
+
#ifdef EH_FRAME_SECTION_ASM_OP
void
eh_frame_section ()
*************** function_section (decl)
*** 438,443 ****
--- 458,497 ----
named_section (decl, (char *) 0, 0);
else
text_section ();
+ }
+
+ /* Switch to the section for exception handling code of function DECL. */
+
+ void
+ function_eh_section (decl)
+ tree decl;
+ {
+ if (decl != NULL_TREE
+ && DECL_SECTION_NAME (decl) != NULL_TREE)
+ {
+ /* Small heuristic for finding the eh_text section name, given the
+ normal section name. This is here because we don't want to store
+ two section names in every decl. */
+ char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ char *name_eh;
+ if (! strncmp (name, ".gnu.linkonce.t.", 16))
+ {
+ name_eh = alloca (strlen (name) + 1);
+ strcpy (name_eh, name);
+ name_eh[14] = 'u';
+ }
+ else
+ {
+ name_eh = alloca (3 + strlen (name) + 1);
+ if (name[0] == '.')
+ sprintf (name_eh, ".eh_%s", &name[1]);
+ else
+ sprintf (name_eh, "eh_%s", name);
+ }
+ named_section (decl, name_eh, 0);
+ }
+ else
+ eh_text_section (decl);
}
/* Switch to section for variable DECL.
*** egcs-971225/gcc/frame.c.bak Fri Jan 9 01:41:32 1998
--- egcs-971225/gcc/frame.c Sat Jan 10 03:51:27 1998
*************** next_fde (fde *p)
*** 192,212 ****
}
/* One iteration of an insertion sort, for adding new FDEs to the array.
! Usually the new FDE will go in at the end, so we can expect close to
! O(n) performance. If this turns out to be overly optimistic, we can have
! the linker sort the FDEs so we don't have to do it at run time. */
static void
! fde_insert (fde **array, size_t i, fde *this_fde)
{
! array[i] = this_fde;
! for (; i > 0 && fde_compare (array[i], array[i-1]) < 0; --i)
{
- this_fde = array[i];
array[i] = array[i-1];
! array[i-1] = this_fde;
}
}
static size_t
--- 192,253 ----
}
/* One iteration of an insertion sort, for adding new FDEs to the array.
! This is a special kind of insertion sort, optimized for data sets that
! look like 101 102 103 201 202 105 203 204 106 107 205 206 207.
! Usually the new FDE will go in at the end or at the last insertio point,
! so we can expect O(n) performance, instead of the worst-case O(n^2).
! If this turns out to be overly optimistic, we can have the linker sort
! the FDEs so we don't have to do it at run time, or we can use an AVL
! tree for O(n log(n)) performance. */
!
! typedef struct fde_accumulator
! {
! fde **array1;
! size_t count1;
! fde **array2;
! size_t count2;
! } fde_accumulator;
static void
! fde_insert (fde_accumulator *accu, fde *this_fde)
{
! fde **array;
! size_t i;
! if (accu->count2 == 0 || fde_compare (this_fde, accu->array2[0]) < 0)
! {
! array = accu->array1;
! i = accu->count1;
! }
! else
! {
! array = accu->array2;
! i = accu->count2;
! }
!
! while (i > 0 && fde_compare (this_fde, array[i-1]) < 0)
{
array[i] = array[i-1];
! i--;
}
+ if (array == accu->array1)
+ {
+ if (i < accu->count1 && accu->count2 == 0)
+ {
+ fde **ptr1 = accu->array1 + i + 1;
+ fde **ptr2 = accu->array2;
+ size_t count = accu->count1 - i;
+ accu->count2 = count;
+ do *ptr2++ = *ptr1++; while (--count > 0);
+ accu->count1 = i;
+ }
+ accu->count1++;
+ }
+ else
+ {
+ accu->count2++;
+ }
+ array[i] = this_fde;
}
static size_t
*************** count_fdes (fde *this_fde)
*** 227,236 ****
}
static void
! add_fdes (fde *this_fde, fde **array, size_t *i_ptr,
! void **beg_ptr, void **end_ptr)
{
- size_t i = *i_ptr;
void *pc_begin = *beg_ptr;
void *pc_end = *end_ptr;
--- 268,275 ----
}
static void
! add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
{
void *pc_begin = *beg_ptr;
void *pc_end = *end_ptr;
*************** add_fdes (fde *this_fde, fde **array, si
*** 240,246 ****
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
! fde_insert (array, i++, this_fde);
if (this_fde->pc_begin < pc_begin)
pc_begin = this_fde->pc_begin;
--- 279,285 ----
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
! fde_insert (accu, this_fde);
if (this_fde->pc_begin < pc_begin)
pc_begin = this_fde->pc_begin;
*************** add_fdes (fde *this_fde, fde **array, si
*** 248,254 ****
pc_end = this_fde->pc_begin + this_fde->pc_range;
}
- *i_ptr = i;
*beg_ptr = pc_begin;
*end_ptr = pc_end;
}
--- 287,292 ----
*************** add_fdes (fde *this_fde, fde **array, si
*** 260,268 ****
static void
frame_init (struct object* ob)
{
- fde *this_fde;
size_t count;
! fde **array;
void *pc_begin, *pc_end;
if (ob->fde_array)
--- 298,305 ----
static void
frame_init (struct object* ob)
{
size_t count;
! fde_accumulator accu;
void *pc_begin, *pc_end;
if (ob->fde_array)
*************** frame_init (struct object* ob)
*** 275,296 ****
count = count_fdes (ob->fde_begin);
ob->count = count;
! array = (fde **) malloc (sizeof (fde *) * count);
pc_begin = (void*)(uaddr)-1;
pc_end = 0;
- count = 0;
if (ob->fde_array)
{
fde **p = ob->fde_array;
for (; *p; ++p)
! add_fdes (*p, array, &count, &pc_begin, &pc_end);
}
else
! add_fdes (ob->fde_begin, array, &count, &pc_begin, &pc_end);
! ob->fde_array = array;
ob->pc_begin = pc_begin;
ob->pc_end = pc_end;
}
--- 312,346 ----
count = count_fdes (ob->fde_begin);
ob->count = count;
! accu.array1 = (fde **) malloc (sizeof (fde *) * count);
! accu.array2 = (fde **) alloca (sizeof (fde *) * count);
! accu.count1 = 0;
! accu.count2 = 0;
pc_begin = (void*)(uaddr)-1;
pc_end = 0;
if (ob->fde_array)
{
fde **p = ob->fde_array;
for (; *p; ++p)
! add_fdes (*p, &accu, &pc_begin, &pc_end);
}
else
! add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
!
! if (accu.count1 + accu.count2 != count)
! abort ();
!
! if (accu.count2 > 0)
! {
! fde **ptr1 = accu.array1 + accu.count1;
! fde **ptr2 = accu.array2;
! size_t c = accu.count2;
! do *ptr1++ = *ptr2++; while (--c > 0);
! }
! ob->fde_array = accu.array1;
ob->pc_begin = pc_begin;
ob->pc_end = pc_end;
}
*** egcs-971225/gcc/cp/except.c.bak Thu Jan 1 16:36:26 1998
--- egcs-971225/gcc/cp/except.c Sun Jan 4 21:52:40 1998
*************** expand_exception_blocks ()
*** 842,847 ****
--- 842,849 ----
rtx funcend = gen_label_rtx ();
emit_jump (funcend);
+ emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_BEG);
+
/* We cannot protect n regions this way if we must flow into the
EH region through the top of the region, as we have to with
the setjmp/longjmp approach. */
*************** expand_exception_blocks ()
*** 855,860 ****
--- 857,864 ----
expand_eh_region_end (build_function_call (Terminate, NULL_TREE));
expand_leftover_cleanups ();
+
+ emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_END);
emit_label (funcend);
}
*** egcs-971225/gcc/testsuite/g++.old-deja/g++.eh/sections1.C.bak Sat Jan 10 03:53:45 1998
--- egcs-971225/gcc/testsuite/g++.old-deja/g++.eh/sections1.C Sat Jan 10 03:56:11 1998
***************
*** 0 ****
--- 1,33 ----
+ // Build don't link:
+ // Special g++ Options: -fPIC -O
+
+ // Test label differences (in PIC case table) across sections.
+
+ typedef int foov (int);
+ extern int foo1 (int);
+ extern int foo2 (int);
+ extern int foo3 (int);
+ extern int foo4 (int);
+ extern int foo5 (int);
+ extern int foo6 (int);
+ extern volatile foov foo7;
+
+ int foo (int x)
+ {
+ try {
+ switch (x) {
+ case 1: return foo1(x);
+ case 2: return foo2(x);
+ case 3: return foo3(x);
+ case 4: return foo4(x);
+ case 5: return foo5(x);
+ case 6: goto xx;
+ case 7: return foo6(x);
+ }
+ foo7(x);
+ }
+ catch (...) {
+ xx: ;
+ }
+ }
+
More information about the Gcc
mailing list