install EH code

From-SVN: r12549
This commit is contained in:
Mike Stump 1996-07-23 20:03:47 +00:00
parent 3d1953912d
commit 6adb4e3a29
11 changed files with 179 additions and 40 deletions

View File

@ -127,6 +127,14 @@ struct function
int emit_lineno; int emit_lineno;
struct goto_fixup *goto_fixup_chain; struct goto_fixup *goto_fixup_chain;
/* For exception handling information. */
struct eh_stack ehstack;
struct eh_queue ehqueue;
rtx catch_clauses;
struct label_node *false_label_stack;
struct label_node *caught_return_label_stack;
tree protect_list;
/* For expr.c. */ /* For expr.c. */
int pending_stack_adjust; int pending_stack_adjust;
int inhibit_defer_pop; int inhibit_defer_pop;

View File

@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */
#include "output.h" #include "output.h"
#include "integrate.h" #include "integrate.h"
#include "real.h" #include "real.h"
#include "except.h"
#include "function.h" #include "function.h"
#include "bytecode.h" #include "bytecode.h"
@ -170,6 +171,19 @@ function_cannot_inline_p (fndecl)
if (current_function_has_nonlocal_goto) if (current_function_has_nonlocal_goto)
return "function with nonlocal goto cannot be inline"; return "function with nonlocal goto cannot be inline";
/* This is a hack, until the inliner is taught about eh regions at
the start of the function. */
for (insn = get_insns ();
insn &&
! (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG);
insn = NEXT_INSN (insn))
{
if (insn && GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
return "function with complex parameters cannot be inline";
}
return 0; return 0;
} }
@ -309,6 +323,7 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
the size of the incoming stack area for parameters, the size of the incoming stack area for parameters,
the number of bytes popped on return, the number of bytes popped on return,
the stack slot list, the stack slot list,
the labels that are forced to exist,
some flags that are used to restore compiler globals, some flags that are used to restore compiler globals,
the value of current_function_outgoing_args_size, the value of current_function_outgoing_args_size,
the original argument vector, the original argument vector,
@ -335,7 +350,7 @@ finish_inline (fndecl, head)
tree fndecl; tree fndecl;
rtx head; rtx head;
{ {
NEXT_INSN (head) = get_first_nonparm_insn (); FIRST_FUNCTION_INSN (head) = get_first_nonparm_insn ();
FIRST_PARM_INSN (head) = get_insns (); FIRST_PARM_INSN (head) = get_insns ();
DECL_SAVED_INSNS (fndecl) = head; DECL_SAVED_INSNS (fndecl) = head;
DECL_FRAME_SIZE (fndecl) = get_frame_size (); DECL_FRAME_SIZE (fndecl) = get_frame_size ();
@ -565,6 +580,15 @@ save_for_inline_copying (fndecl)
NOTE_SOURCE_FILE (insn) = (char *) copy; NOTE_SOURCE_FILE (insn) = (char *) copy;
NOTE_SOURCE_FILE (copy) = 0; NOTE_SOURCE_FILE (copy) = 0;
} }
if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)
{
/* We have to forward these both to match the new exception
region. */
NOTE_BLOCK_NUMBER (copy)
= CODE_LABEL_NUMBER (label_map[NOTE_BLOCK_NUMBER (copy)]);
}
RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn); RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
break; break;
@ -1872,7 +1896,18 @@ expand_inline_function (fndecl, parms, target, ignore, type,
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED) && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn)); {
copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
if (copy && (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END))
{
rtx label = map->label_map[NOTE_BLOCK_NUMBER (copy)];
/* We have to forward these both to match the new exception
region. */
NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
}
}
else else
copy = 0; copy = 0;
break; break;

View File

@ -60,6 +60,7 @@ Boston, MA 02111-1307, USA. */
#include "insn-flags.h" #include "insn-flags.h"
#include "expr.h" #include "expr.h"
#include "real.h" #include "real.h"
#include "except.h"
/* ??? Eventually must record somehow the labels used by jumps /* ??? Eventually must record somehow the labels used by jumps
from nested functions. */ from nested functions. */
@ -234,6 +235,16 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
for (insn = forced_labels; insn; insn = XEXP (insn, 1)) for (insn = forced_labels; insn; insn = XEXP (insn, 1))
LABEL_NUSES (XEXP (insn, 0))++; LABEL_NUSES (XEXP (insn, 0))++;
check_exception_handler_labels ();
/* Keep track of labels used for marking handlers for exception
regions; they cannot usually be deleted. */
for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
LABEL_NUSES (XEXP (insn, 0))++;
exception_optimize ();
/* Delete all labels already not referenced. /* Delete all labels already not referenced.
Also find the last insn. */ Also find the last insn. */

View File

@ -2989,6 +2989,13 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
#endif /* L_exit */ #endif /* L_exit */
#ifdef L_eh #ifdef L_eh
#ifdef EH_TABLE_LOOKUP
EH_TABLE_LOOKUP
#else
typedef struct { typedef struct {
void *start; void *start;
void *end; void *end;
@ -3095,21 +3102,9 @@ void *pc;
#endif #endif
#if 0 #if 0
printf("find_first_eh_table_match(): else: returning NULL!\n"); printf ("find_first_eh_table_match(): else: returning NULL!\n");
#endif #endif
return (void*)0; return (void *) 0;
}
void *
__throw_type_match (void *catch_type, void *throw_type, void* obj)
{
#if 0
printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
catch_type, throw_type);
#endif
if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
return obj;
return 0;
} }
void void
@ -3140,6 +3135,19 @@ __register_exceptions (exception_table *table)
node->next = exception_table_list; node->next = exception_table_list;
exception_table_list = node; exception_table_list = node;
} }
#endif
void *
__throw_type_match (void *catch_type, void *throw_type, void *obj)
{
#if 0
printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
catch_type, throw_type);
#endif
if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
return obj;
return 0;
}
void void
__empty () __empty ()

View File

@ -47,6 +47,7 @@ Boston, MA 02111-1307, USA. */
#include "flags.h" #include "flags.h"
#include "real.h" #include "real.h"
#include "loop.h" #include "loop.h"
#include "except.h"
/* Vector mapping INSN_UIDs to luids. /* Vector mapping INSN_UIDs to luids.
The luids are like uids but increase monotonically always. The luids are like uids but increase monotonically always.
@ -2290,6 +2291,19 @@ find_and_verify_loops (f)
loop_invalid[loop_num] = 1; loop_invalid[loop_num] = 1;
} }
/* Any loop containing a label used for an exception handler must be
invalidated, because it can be jumped into from anywhere. */
for (label = exception_handler_labels; label; label = XEXP (label, 1))
{
int loop_num;
for (loop_num = uid_loop_num[INSN_UID (XEXP (label, 0))];
loop_num != -1;
loop_num = loop_outer_loop[loop_num])
loop_invalid[loop_num] = 1;
}
/* Now scan all insn's in the function. If any JUMP_INSN branches into a /* Now scan all insn's in the function. If any JUMP_INSN branches into a
loop that it is not contained within, that loop is marked invalid. loop that it is not contained within, that loop is marked invalid.
If any INSN or CALL_INSN uses a label's address, then the loop containing If any INSN or CALL_INSN uses a label's address, then the loop containing

View File

@ -118,6 +118,8 @@ rtx bcmp_libfunc;
rtx memset_libfunc; rtx memset_libfunc;
rtx bzero_libfunc; rtx bzero_libfunc;
rtx throw_libfunc;
rtx eqhf2_libfunc; rtx eqhf2_libfunc;
rtx nehf2_libfunc; rtx nehf2_libfunc;
rtx gthf2_libfunc; rtx gthf2_libfunc;
@ -4247,6 +4249,8 @@ init_optabs ()
memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset"); memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero"); bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
throw_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__throw");
eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2"); eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2"); nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
gthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gthf2"); gthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gthf2");

View File

@ -140,6 +140,9 @@ extern void named_section PROTO((tree, char *));
/* Tell assembler to switch to the section for function DECL. */ /* Tell assembler to switch to the section for function DECL. */
extern void function_section PROTO((tree)); extern void function_section PROTO((tree));
/* Tell assembler to switch to the section for the exception table. */
extern void exception_section PROTO((void));
/* Create the rtl to represent a function, for a function definition. /* Create the rtl to represent a function, for a function definition.
DECL is a FUNCTION_DECL node which describes which function. DECL is a FUNCTION_DECL node which describes which function.
The rtl is stored into DECL. */ The rtl is stored into DECL. */

View File

@ -108,6 +108,14 @@ print_rtx (in_rtx)
{ {
case 'S': case 'S':
case 's': case 's':
if (i == 3 && GET_CODE (in_rtx) == NOTE
&& (NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_EH_REGION_END))
{
fprintf (outfile, " %d", NOTE_BLOCK_NUMBER (in_rtx));
sawclose = 1;
break;
}
if (XSTR (in_rtx, i) == 0) if (XSTR (in_rtx, i) == 0)
fprintf (outfile, " \"\""); fprintf (outfile, " \"\"");
else else

View File

@ -111,9 +111,11 @@ Boston, MA 02111-1307, USA. */
reg_n_calls_crossed, and reg_live_length. Also, basic_block_head, reg_n_calls_crossed, and reg_live_length. Also, basic_block_head,
basic_block_end. basic_block_end.
The information in the line number notes is carefully retained by this The information in the line number notes is carefully retained by
pass. All other NOTE insns are grouped in their same relative order at this pass. Notes that refer to the starting and ending of
the beginning of basic blocks that have been scheduled. */ exception regions are also carefully retained by this pass. All
other NOTE insns are grouped in their same relative order at the
beginning of basic blocks that have been scheduled. */
#include <stdio.h> #include <stdio.h>
#include "config.h" #include "config.h"
@ -2078,7 +2080,7 @@ sched_analyze_insn (x, insn, loop_notes)
sched_analyze_2 (XEXP (link, 0), insn); sched_analyze_2 (XEXP (link, 0), insn);
} }
/* If there is a LOOP_{BEG,END} note in the middle of a basic block, then /* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic block, then
we must be sure that no instructions are scheduled across it. we must be sure that no instructions are scheduled across it.
Otherwise, the reg_n_refs info (which depends on loop_depth) would Otherwise, the reg_n_refs info (which depends on loop_depth) would
become incorrect. */ become incorrect. */
@ -2240,8 +2242,13 @@ sched_analyze (head, tail)
} }
reg_pending_sets_all = 1; reg_pending_sets_all = 1;
/* Add a fake REG_NOTE which we will later convert /* Add a pair of fake REG_NOTEs which we will later
back into a NOTE_INSN_SETJMP note. */ convert back into a NOTE_INSN_SETJMP note. See
reemit_notes for why we use a pair of of NOTEs. */
REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
GEN_INT (0),
REG_NOTES (insn));
REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
GEN_INT (NOTE_INSN_SETJMP), GEN_INT (NOTE_INSN_SETJMP),
REG_NOTES (insn)); REG_NOTES (insn));
@ -2285,12 +2292,18 @@ sched_analyze (head, tail)
last_function_call = insn; last_function_call = insn;
n_insns += 1; n_insns += 1;
} }
/* See comments on reemit_notes as to why we do this. */
else if (GET_CODE (insn) == NOTE else if (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
|| (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP || (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
&& GET_CODE (PREV_INSN (insn)) != CALL_INSN))) && GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
{ {
loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
GEN_INT (NOTE_BLOCK_NUMBER (insn)), loop_notes);
loop_notes = gen_rtx (EXPR_LIST, REG_DEAD, loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes); GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes);
CONST_CALL_P (loop_notes) = CONST_CALL_P (insn); CONST_CALL_P (loop_notes) = CONST_CALL_P (insn);
@ -3077,10 +3090,12 @@ unlink_notes (insn, tail)
/* Don't save away NOTE_INSN_SETJMPs, because they must remain /* Don't save away NOTE_INSN_SETJMPs, because they must remain
immediately after the call they follow. We use a fake immediately after the call they follow. We use a fake
(REG_DEAD (const_int -1)) note to remember them. (REG_DEAD (const_int -1)) note to remember them.
Likewise with NOTE_INSN_LOOP_BEG and NOTE_INSN_LOOP_END. */ Likewise with NOTE_INSN_{LOOP,EHREGION}_{BEG, END}. */
else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END) && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
{ {
/* Insert the note at the end of the notes list. */ /* Insert the note at the end of the notes list. */
PREV_INSN (insn) = note_list; PREV_INSN (insn) = note_list;
@ -3143,10 +3158,12 @@ finish_sometimes_live (regs_sometimes_live, sometimes_max)
} }
} }
/* Search INSN for fake REG_DEAD notes for NOTE_INSN_SETJMP, /* Search INSN for fake REG_DEAD note pairs for NOTE_INSN_SETJMP,
NOTE_INSN_LOOP_BEG, and NOTE_INSN_LOOP_END; and convert them back NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
into NOTEs. LAST is the last instruction output by the instruction NOTEs. The REG_DEAD note following first one is contains the saved
scheduler. Return the new value of LAST. */ value for NOTE_BLOCK_NUMBER which is useful for
NOTE_INSN_EH_REGION_{BEG,END} NOTEs. LAST is the last instruction
output by the instruction scheduler. Return the new value of LAST. */
static rtx static rtx
reemit_notes (insn, last) reemit_notes (insn, last)
@ -3161,10 +3178,19 @@ reemit_notes (insn, last)
&& GET_CODE (XEXP (note, 0)) == CONST_INT) && GET_CODE (XEXP (note, 0)) == CONST_INT)
{ {
if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP) if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn)) {
= CONST_CALL_P (note); CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
= CONST_CALL_P (note);
remove_note (insn, note);
note = XEXP (note, 1);
}
else else
last = emit_note_before (INTVAL (XEXP (note, 0)), last); {
last = emit_note_before (INTVAL (XEXP (note, 0)), last);
remove_note (insn, note);
note = XEXP (note, 1);
NOTE_BLOCK_NUMBER (last) = INTVAL (XEXP (note, 0));
}
remove_note (insn, note); remove_note (insn, note);
} }
} }
@ -3961,8 +3987,8 @@ schedule_block (b, file)
} }
} }
/* Put back NOTE_INSN_SETJMP, NOTE_INSN_LOOP_BEGIN, and /* Put back NOTE_INSN_SETJMP,
NOTE_INSN_LOOP_END notes. */ NOTE_INSN_{LOOP,EHREGION}_{BEGIN,END} notes. */
/* To prime the loop. We need to handle INSN and all the insns in the /* To prime the loop. We need to handle INSN and all the insns in the
sched group. */ sched group. */

View File

@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA. */
#include "rtl.h" #include "rtl.h"
#include "tree.h" #include "tree.h"
#include "flags.h" #include "flags.h"
#include "except.h"
#include "function.h" #include "function.h"
#include "insn-flags.h" #include "insn-flags.h"
#include "insn-config.h" #include "insn-config.h"
@ -134,8 +135,6 @@ extern tree rtl_expr_chain;
cleanup list whenever an empty list is required. */ cleanup list whenever an empty list is required. */
static tree empty_cleanup_list; static tree empty_cleanup_list;
#endif #endif
extern void (*interim_eh_hook) PROTO((tree));
/* Functions and data structures for expanding case statements. */ /* Functions and data structures for expanding case statements. */
@ -473,9 +472,7 @@ void
init_stmt () init_stmt ()
{ {
gcc_obstack_init (&stmt_obstack); gcc_obstack_init (&stmt_obstack);
#if 0 init_eh ();
empty_cleanup_list = build_tree_list (NULL_TREE, NULL_TREE);
#endif
} }
void void
@ -498,6 +495,8 @@ init_stmt_for_function ()
/* We are not processing a ({...}) grouping. */ /* We are not processing a ({...}) grouping. */
expr_stmts_for_value = 0; expr_stmts_for_value = 0;
last_expr_type = 0; last_expr_type = 0;
init_eh_for_function ();
} }
void void
@ -518,6 +517,7 @@ save_stmt_status (p)
p->emit_filename = emit_filename; p->emit_filename = emit_filename;
p->emit_lineno = emit_lineno; p->emit_lineno = emit_lineno;
p->goto_fixup_chain = goto_fixup_chain; p->goto_fixup_chain = goto_fixup_chain;
save_eh_status (p);
} }
void void
@ -538,6 +538,7 @@ restore_stmt_status (p)
emit_filename = p->emit_filename; emit_filename = p->emit_filename;
emit_lineno = p->emit_lineno; emit_lineno = p->emit_lineno;
goto_fixup_chain = p->goto_fixup_chain; goto_fixup_chain = p->goto_fixup_chain;
restore_eh_status (p);
} }
/* Emit a no-op instruction. */ /* Emit a no-op instruction. */
@ -3730,7 +3731,7 @@ expand_decl_cleanup (decl, cleanup)
= temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups); = temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
/* If this block has a cleanup, it belongs in stack_block_stack. */ /* If this block has a cleanup, it belongs in stack_block_stack. */
stack_block_stack = thisblock; stack_block_stack = thisblock;
(*interim_eh_hook) (NULL_TREE); expand_eh_region_start ();
} }
return 1; return 1;
} }
@ -3831,7 +3832,7 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
else else
{ {
if (! in_fixup) if (! in_fixup)
(*interim_eh_hook) (TREE_VALUE (tail)); expand_eh_region_end (TREE_VALUE (tail));
if (reachable) if (reachable)
{ {

View File

@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */
#include "rtl.h" #include "rtl.h"
#include "tree.h" #include "tree.h"
#include "flags.h" #include "flags.h"
#include "except.h"
#include "function.h" #include "function.h"
#include "expr.h" #include "expr.h"
#include "output.h" #include "output.h"
@ -414,6 +415,26 @@ variable_section (decl, reloc)
#endif #endif
} }
} }
/* Tell assembler to switch to the section for the exception handling
table. */
void
exception_section ()
{
#ifdef ASM_OUTPUT_SECTION_NAME
named_section (NULL_TREE, ".gcc_except_table");
#else
if (flag_pic)
data_section ();
else
#if defined (EXCEPTION_SECTION)
EXCEPTION_SECTION ();
#else
readonly_data_section ();
#endif
#endif
}
/* Create the rtl to represent a function, for a function definition. /* Create the rtl to represent a function, for a function definition.
DECL is a FUNCTION_DECL node which describes which function. DECL is a FUNCTION_DECL node which describes which function.