install EH code
From-SVN: r12549
This commit is contained in:
parent
3d1953912d
commit
6adb4e3a29
@ -127,6 +127,14 @@ struct function
|
||||
int emit_lineno;
|
||||
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. */
|
||||
int pending_stack_adjust;
|
||||
int inhibit_defer_pop;
|
||||
|
@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "output.h"
|
||||
#include "integrate.h"
|
||||
#include "real.h"
|
||||
#include "except.h"
|
||||
#include "function.h"
|
||||
#include "bytecode.h"
|
||||
|
||||
@ -170,6 +171,19 @@ function_cannot_inline_p (fndecl)
|
||||
if (current_function_has_nonlocal_goto)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 number of bytes popped on return,
|
||||
the stack slot list,
|
||||
the labels that are forced to exist,
|
||||
some flags that are used to restore compiler globals,
|
||||
the value of current_function_outgoing_args_size,
|
||||
the original argument vector,
|
||||
@ -335,7 +350,7 @@ finish_inline (fndecl, head)
|
||||
tree fndecl;
|
||||
rtx head;
|
||||
{
|
||||
NEXT_INSN (head) = get_first_nonparm_insn ();
|
||||
FIRST_FUNCTION_INSN (head) = get_first_nonparm_insn ();
|
||||
FIRST_PARM_INSN (head) = get_insns ();
|
||||
DECL_SAVED_INSNS (fndecl) = head;
|
||||
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 (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);
|
||||
break;
|
||||
|
||||
@ -1872,7 +1896,18 @@ expand_inline_function (fndecl, parms, target, ignore, type,
|
||||
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
|
||||
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
|
||||
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
|
||||
{
|
||||
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
|
||||
copy = 0;
|
||||
break;
|
||||
|
11
gcc/jump.c
11
gcc/jump.c
@ -60,6 +60,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "insn-flags.h"
|
||||
#include "expr.h"
|
||||
#include "real.h"
|
||||
#include "except.h"
|
||||
|
||||
/* ??? Eventually must record somehow the labels used by jumps
|
||||
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))
|
||||
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.
|
||||
Also find the last insn. */
|
||||
|
||||
|
@ -2989,6 +2989,13 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
|
||||
#endif /* L_exit */
|
||||
|
||||
#ifdef L_eh
|
||||
|
||||
#ifdef EH_TABLE_LOOKUP
|
||||
|
||||
EH_TABLE_LOOKUP
|
||||
|
||||
#else
|
||||
|
||||
typedef struct {
|
||||
void *start;
|
||||
void *end;
|
||||
@ -3095,21 +3102,9 @@ void *pc;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
printf("find_first_eh_table_match(): else: returning NULL!\n");
|
||||
printf ("find_first_eh_table_match(): else: returning NULL!\n");
|
||||
#endif
|
||||
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;
|
||||
return (void *) 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -3140,6 +3135,19 @@ __register_exceptions (exception_table *table)
|
||||
node->next = exception_table_list;
|
||||
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
|
||||
__empty ()
|
||||
|
14
gcc/loop.c
14
gcc/loop.c
@ -47,6 +47,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "flags.h"
|
||||
#include "real.h"
|
||||
#include "loop.h"
|
||||
#include "except.h"
|
||||
|
||||
/* Vector mapping INSN_UIDs to luids.
|
||||
The luids are like uids but increase monotonically always.
|
||||
@ -2290,6 +2291,19 @@ find_and_verify_loops (f)
|
||||
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
|
||||
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
|
||||
|
@ -118,6 +118,8 @@ rtx bcmp_libfunc;
|
||||
rtx memset_libfunc;
|
||||
rtx bzero_libfunc;
|
||||
|
||||
rtx throw_libfunc;
|
||||
|
||||
rtx eqhf2_libfunc;
|
||||
rtx nehf2_libfunc;
|
||||
rtx gthf2_libfunc;
|
||||
@ -4247,6 +4249,8 @@ init_optabs ()
|
||||
memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
|
||||
bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
|
||||
|
||||
throw_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__throw");
|
||||
|
||||
eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
|
||||
nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
|
||||
gthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gthf2");
|
||||
|
@ -140,6 +140,9 @@ extern void named_section PROTO((tree, char *));
|
||||
/* Tell assembler to switch to the section for function DECL. */
|
||||
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.
|
||||
DECL is a FUNCTION_DECL node which describes which function.
|
||||
The rtl is stored into DECL. */
|
||||
|
@ -108,6 +108,14 @@ print_rtx (in_rtx)
|
||||
{
|
||||
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)
|
||||
fprintf (outfile, " \"\"");
|
||||
else
|
||||
|
54
gcc/sched.c
54
gcc/sched.c
@ -111,9 +111,11 @@ Boston, MA 02111-1307, USA. */
|
||||
reg_n_calls_crossed, and reg_live_length. Also, basic_block_head,
|
||||
basic_block_end.
|
||||
|
||||
The information in the line number notes is 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. */
|
||||
The information in the line number notes is carefully retained by
|
||||
this pass. Notes that refer to the starting and ending of
|
||||
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 "config.h"
|
||||
@ -2078,7 +2080,7 @@ sched_analyze_insn (x, insn, loop_notes)
|
||||
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.
|
||||
Otherwise, the reg_n_refs info (which depends on loop_depth) would
|
||||
become incorrect. */
|
||||
@ -2240,8 +2242,13 @@ sched_analyze (head, tail)
|
||||
}
|
||||
reg_pending_sets_all = 1;
|
||||
|
||||
/* Add a fake REG_NOTE which we will later convert
|
||||
back into a NOTE_INSN_SETJMP note. */
|
||||
/* Add a pair of fake REG_NOTEs which we will later
|
||||
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,
|
||||
GEN_INT (NOTE_INSN_SETJMP),
|
||||
REG_NOTES (insn));
|
||||
@ -2285,12 +2292,18 @@ sched_analyze (head, tail)
|
||||
last_function_call = insn;
|
||||
n_insns += 1;
|
||||
}
|
||||
|
||||
/* See comments on reemit_notes as to why we do this. */
|
||||
else if (GET_CODE (insn) == NOTE
|
||||
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
|
||||
|| 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
|
||||
&& 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,
|
||||
GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes);
|
||||
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
|
||||
immediately after the call they follow. We use a fake
|
||||
(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
|
||||
&& 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. */
|
||||
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,
|
||||
NOTE_INSN_LOOP_BEG, and NOTE_INSN_LOOP_END; and convert them back
|
||||
into NOTEs. LAST is the last instruction output by the instruction
|
||||
scheduler. Return the new value of LAST. */
|
||||
/* Search INSN for fake REG_DEAD note pairs for NOTE_INSN_SETJMP,
|
||||
NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
|
||||
NOTEs. The REG_DEAD note following first one is contains the saved
|
||||
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
|
||||
reemit_notes (insn, last)
|
||||
@ -3161,11 +3178,20 @@ reemit_notes (insn, last)
|
||||
&& GET_CODE (XEXP (note, 0)) == CONST_INT)
|
||||
{
|
||||
if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
|
||||
{
|
||||
CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
|
||||
= CONST_CALL_P (note);
|
||||
remove_note (insn, note);
|
||||
note = XEXP (note, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return last;
|
||||
@ -3961,8 +3987,8 @@ schedule_block (b, file)
|
||||
}
|
||||
}
|
||||
|
||||
/* Put back NOTE_INSN_SETJMP, NOTE_INSN_LOOP_BEGIN, and
|
||||
NOTE_INSN_LOOP_END notes. */
|
||||
/* Put back NOTE_INSN_SETJMP,
|
||||
NOTE_INSN_{LOOP,EHREGION}_{BEGIN,END} notes. */
|
||||
|
||||
/* To prime the loop. We need to handle INSN and all the insns in the
|
||||
sched group. */
|
||||
|
15
gcc/stmt.c
15
gcc/stmt.c
@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "rtl.h"
|
||||
#include "tree.h"
|
||||
#include "flags.h"
|
||||
#include "except.h"
|
||||
#include "function.h"
|
||||
#include "insn-flags.h"
|
||||
#include "insn-config.h"
|
||||
@ -134,8 +135,6 @@ extern tree rtl_expr_chain;
|
||||
cleanup list whenever an empty list is required. */
|
||||
static tree empty_cleanup_list;
|
||||
#endif
|
||||
|
||||
extern void (*interim_eh_hook) PROTO((tree));
|
||||
|
||||
/* Functions and data structures for expanding case statements. */
|
||||
|
||||
@ -473,9 +472,7 @@ void
|
||||
init_stmt ()
|
||||
{
|
||||
gcc_obstack_init (&stmt_obstack);
|
||||
#if 0
|
||||
empty_cleanup_list = build_tree_list (NULL_TREE, NULL_TREE);
|
||||
#endif
|
||||
init_eh ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -498,6 +495,8 @@ init_stmt_for_function ()
|
||||
/* We are not processing a ({...}) grouping. */
|
||||
expr_stmts_for_value = 0;
|
||||
last_expr_type = 0;
|
||||
|
||||
init_eh_for_function ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -518,6 +517,7 @@ save_stmt_status (p)
|
||||
p->emit_filename = emit_filename;
|
||||
p->emit_lineno = emit_lineno;
|
||||
p->goto_fixup_chain = goto_fixup_chain;
|
||||
save_eh_status (p);
|
||||
}
|
||||
|
||||
void
|
||||
@ -538,6 +538,7 @@ restore_stmt_status (p)
|
||||
emit_filename = p->emit_filename;
|
||||
emit_lineno = p->emit_lineno;
|
||||
goto_fixup_chain = p->goto_fixup_chain;
|
||||
restore_eh_status (p);
|
||||
}
|
||||
|
||||
/* Emit a no-op instruction. */
|
||||
@ -3730,7 +3731,7 @@ expand_decl_cleanup (decl, cleanup)
|
||||
= temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
|
||||
/* If this block has a cleanup, it belongs in stack_block_stack. */
|
||||
stack_block_stack = thisblock;
|
||||
(*interim_eh_hook) (NULL_TREE);
|
||||
expand_eh_region_start ();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -3831,7 +3832,7 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
|
||||
else
|
||||
{
|
||||
if (! in_fixup)
|
||||
(*interim_eh_hook) (TREE_VALUE (tail));
|
||||
expand_eh_region_end (TREE_VALUE (tail));
|
||||
|
||||
if (reachable)
|
||||
{
|
||||
|
21
gcc/varasm.c
21
gcc/varasm.c
@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "rtl.h"
|
||||
#include "tree.h"
|
||||
#include "flags.h"
|
||||
#include "except.h"
|
||||
#include "function.h"
|
||||
#include "expr.h"
|
||||
#include "output.h"
|
||||
@ -414,6 +415,26 @@ variable_section (decl, reloc)
|
||||
#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.
|
||||
DECL is a FUNCTION_DECL node which describes which function.
|
||||
|
Loading…
Reference in New Issue
Block a user