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;
#include "output.h"
#include "integrate.h"
#include "real.h"
+#include "except.h"
#include "function.h"
#include "bytecode.h"
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;
}
\f
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,
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 ();
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;
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));
+ {
+ 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;
#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. */
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. */
#endif /* L_exit */
\f
#ifdef L_eh
+
+#ifdef EH_TABLE_LOOKUP
+
+EH_TABLE_LOOKUP
+
+#else
+
typedef struct {
void *start;
void *end;
#endif
#if 0
- 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);
+ printf ("find_first_eh_table_match(): else: returning NULL!\n");
#endif
- if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
- return obj;
- return 0;
+ return (void *) 0;
}
void
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 ()
#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.
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
rtx memset_libfunc;
rtx bzero_libfunc;
+rtx throw_libfunc;
+
rtx eqhf2_libfunc;
rtx nehf2_libfunc;
rtx gthf2_libfunc;
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");
/* 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. */
{
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
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. */
\f
#include <stdio.h>
#include "config.h"
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. */
}
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));
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);
/* 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;
}
}
-/* 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)
&& 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);
+ {
+ 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);
+ {
+ 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);
}
}
}
}
- /* 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. */
#include "rtl.h"
#include "tree.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
#include "insn-flags.h"
#include "insn-config.h"
cleanup list whenever an empty list is required. */
static tree empty_cleanup_list;
#endif
-
-extern void (*interim_eh_hook) PROTO((tree));
\f
/* Functions and data structures for expanding case statements. */
init_stmt ()
{
gcc_obstack_init (&stmt_obstack);
-#if 0
- empty_cleanup_list = build_tree_list (NULL_TREE, NULL_TREE);
-#endif
+ init_eh ();
}
void
/* We are not processing a ({...}) grouping. */
expr_stmts_for_value = 0;
last_expr_type = 0;
+
+ init_eh_for_function ();
}
void
p->emit_filename = emit_filename;
p->emit_lineno = emit_lineno;
p->goto_fixup_chain = goto_fixup_chain;
+ save_eh_status (p);
}
void
emit_filename = p->emit_filename;
emit_lineno = p->emit_lineno;
goto_fixup_chain = p->goto_fixup_chain;
+ restore_eh_status (p);
}
\f
/* Emit a no-op instruction. */
= 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;
}
else
{
if (! in_fixup)
- (*interim_eh_hook) (TREE_VALUE (tail));
+ expand_eh_region_end (TREE_VALUE (tail));
if (reachable)
{
#include "rtl.h"
#include "tree.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
#include "expr.h"
#include "output.h"
#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
+}
\f
/* Create the rtl to represent a function, for a function definition.
DECL is a FUNCTION_DECL node which describes which function.