aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/function.h8
-rw-r--r--gcc/integrate.c39
-rw-r--r--gcc/jump.c11
-rw-r--r--gcc/libgcc2.c36
-rw-r--r--gcc/loop.c14
-rw-r--r--gcc/optabs.c4
-rw-r--r--gcc/output.h3
-rw-r--r--gcc/print-rtl.c8
-rw-r--r--gcc/sched.c60
-rw-r--r--gcc/stmt.c15
-rw-r--r--gcc/varasm.c21
11 files changed, 179 insertions, 40 deletions
diff --git a/gcc/function.h b/gcc/function.h
index b70d6b9..47bee49 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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;
diff --git a/gcc/integrate.c b/gcc/integrate.c
index 106e4fe..f1e778a 100644
--- a/gcc/integrate.c
+++ b/gcc/integrate.c
@@ -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));
+ {
+ 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;
diff --git a/gcc/jump.c b/gcc/jump.c
index b5e60fc..61d712c 100644
--- a/gcc/jump.c
+++ b/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. */
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index 043b431..41801fa 100644
--- a/gcc/libgcc2.c
+++ b/gcc/libgcc2.c
@@ -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");
-#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
@@ -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 ()
diff --git a/gcc/loop.c b/gcc/loop.c
index 4ac5d76..f4670fd 100644
--- a/gcc/loop.c
+++ b/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
diff --git a/gcc/optabs.c b/gcc/optabs.c
index a308197..ba4b72f 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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");
diff --git a/gcc/output.h b/gcc/output.h
index 7ef8b2c..8722b64 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -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. */
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 20d34db..93153d4 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -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
diff --git a/gcc/sched.c b/gcc/sched.c
index 82acf33..c186cfc 100644
--- a/gcc/sched.c
+++ b/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,13 +2292,19 @@ 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,10 +3178,19 @@ 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);
}
}
@@ -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. */
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 6d6443f..b443fc4 100644
--- a/gcc/stmt.c
+++ b/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)
{
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 3878e8b..67a31ca 100644
--- a/gcc/varasm.c
+++ b/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.