diff --git a/gcc/function.h b/gcc/function.h index b70d6b93d19..47bee4943db 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 106e4fe9ad4..f1e778a81d8 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 b5e60fc3fc6..61d712c6929 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 043b431eb6c..41801fa73b0 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"); + 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 () diff --git a/gcc/loop.c b/gcc/loop.c index 4ac5d76b36b..f4670fd0735 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 a30819753a5..ba4b72f147d 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 7ef8b2c61b1..8722b647590 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 20d34dbdc8e..93153d4b967 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 82acf33277f..c186cfc0699 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 #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,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 6d6443f43ef..b443fc428f3 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 3878e8b893e..67a31ca998c 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.