diff options
author | obrien <obrien@FreeBSD.org> | 1999-10-16 06:09:09 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1999-10-16 06:09:09 +0000 |
commit | cae8fa8120c70195f34a2456f18c4c848a2d3e0c (patch) | |
tree | f7d3a3ab9c32694206552e767626366f016f2062 /contrib/gcc/except.c | |
parent | 84656b55b6e25e30322dc903a05de53706361d3d (diff) | |
download | FreeBSD-src-cae8fa8120c70195f34a2456f18c4c848a2d3e0c.zip FreeBSD-src-cae8fa8120c70195f34a2456f18c4c848a2d3e0c.tar.gz |
Virgin import of the GCC 2.95.1 compilers
Diffstat (limited to 'contrib/gcc/except.c')
-rw-r--r-- | contrib/gcc/except.c | 559 |
1 files changed, 416 insertions, 143 deletions
diff --git a/contrib/gcc/except.c b/contrib/gcc/except.c index ccd5a6b..f7d78d6 100644 --- a/contrib/gcc/except.c +++ b/contrib/gcc/except.c @@ -406,6 +406,8 @@ Boston, MA 02111-1307, USA. */ #include "recog.h" #include "output.h" #include "toplev.h" +#include "intl.h" +#include "obstack.h" /* One to use setjmp/longjmp method of generating code for exception handling. */ @@ -490,6 +492,29 @@ struct label_node *outer_context_label_stack = NULL; struct label_node *false_label_stack = NULL; +/* Pseudos used to hold exception return data in the interim between + __builtin_eh_return and the end of the function. */ + +static rtx eh_return_context; +static rtx eh_return_stack_adjust; +static rtx eh_return_handler; + +/* Used to mark the eh return stub for flow, so that the Right Thing + happens with the values for the hardregs therin. */ + +rtx eh_return_stub_label; + +/* This is used for targets which can call rethrow with an offset instead + of an address. This is subtracted from the rethrow label we are + interested in. */ + +static rtx first_rethrow_symbol = NULL_RTX; +static rtx final_rethrow = NULL_RTX; +static rtx last_rethrow_symbol = NULL_RTX; + + +/* Prototypes for local functions. */ + static void push_eh_entry PROTO((struct eh_stack *)); static struct eh_entry * pop_eh_entry PROTO((struct eh_stack *)); static void enqueue_eh_entry PROTO((struct eh_queue *, struct eh_entry *)); @@ -501,18 +526,40 @@ static void expand_rethrow PROTO((rtx)); static void output_exception_table_entry PROTO((FILE *, int)); static int can_throw PROTO((rtx)); static rtx scan_region PROTO((rtx, int, int *)); -static void eh_regs PROTO((rtx *, rtx *, int)); +static void eh_regs PROTO((rtx *, rtx *, rtx *, int)); static void set_insn_eh_region PROTO((rtx *, int)); #ifdef DONT_USE_BUILTIN_SETJMP static void jumpif_rtx PROTO((rtx, rtx)); #endif - rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx)); /* Various support routines to manipulate the various data structures used by the exception handling code. */ +extern struct obstack permanent_obstack; + +/* Generate a SYMBOL_REF for rethrow to use */ +static rtx +create_rethrow_ref (region_num) + int region_num; +{ + rtx def; + char *ptr; + char buf[60]; + + push_obstacks_nochange (); + end_temporary_allocation (); + + ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num); + ptr = (char *) obstack_copy0 (&permanent_obstack, buf, strlen (buf)); + def = gen_rtx_SYMBOL_REF (Pmode, ptr); + SYMBOL_REF_NEED_ADJUST (def) = 1; + + pop_obstacks (); + return def; +} + /* Push a label entry onto the given STACK. */ void @@ -570,11 +617,7 @@ rtx gen_exception_label () { rtx lab; - - push_obstacks_nochange (); - end_temporary_allocation (); lab = gen_label_rtx (); - pop_obstacks (); return lab; } @@ -587,10 +630,16 @@ push_eh_entry (stack) struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node)); struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry)); - entry->outer_context = gen_label_rtx (); + rtx rlab = gen_exception_label (); entry->finalization = NULL_TREE; entry->label_used = 0; - entry->exception_handler_label = gen_exception_label (); + entry->exception_handler_label = rlab; + entry->false_label = NULL_RTX; + if (! flag_new_exceptions) + entry->outer_context = gen_label_rtx (); + else + entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab)); + entry->rethrow_label = entry->outer_context; node->entry = entry; node->chain = stack->top; @@ -693,6 +742,7 @@ receive_exception_label (handler_label) struct func_eh_entry { int range_number; /* EH region number from EH NOTE insn's */ + rtx rethrow_label; /* Label for rethrow */ struct handler_info *handlers; }; @@ -705,12 +755,14 @@ static int current_func_eh_entry = 0; #define SIZE_FUNC_EH(X) (sizeof (struct func_eh_entry) * X) /* Add a new eh_entry for this function, and base it off of the information - in the EH_ENTRY parameter. A NULL parameter is invalid. The number + in the EH_ENTRY parameter. A NULL parameter is invalid. + OUTER_CONTEXT is a label which is used for rethrowing. The number returned is an number which uniquely identifies this exception range. */ -int -new_eh_region_entry (note_eh_region) +static int +new_eh_region_entry (note_eh_region, rethrow) int note_eh_region; + rtx rethrow; { if (current_func_eh_entry == num_func_eh_entries) { @@ -728,6 +780,11 @@ new_eh_region_entry (note_eh_region) } } function_eh_regions[current_func_eh_entry].range_number = note_eh_region; + if (rethrow == NULL_RTX) + function_eh_regions[current_func_eh_entry].rethrow_label = + create_rethrow_ref (note_eh_region); + else + function_eh_regions[current_func_eh_entry].rethrow_label = rethrow; function_eh_regions[current_func_eh_entry].handlers = NULL; return current_func_eh_entry++; @@ -753,8 +810,13 @@ add_new_handler (region, newhandler) function_eh_regions[region].handlers = newhandler; else { - for ( ; last->next != NULL; last = last->next) - ; + for ( ; ; last = last->next) + { + if (last->type_info == CATCH_ALL_TYPE) + pedwarn ("additional handler after ..."); + if (last->next == NULL) + break; + } last->next = newhandler; } } @@ -859,6 +921,7 @@ get_new_handler (handler, typeinfo) struct handler_info* ptr; ptr = (struct handler_info *) malloc (sizeof (struct handler_info)); ptr->handler_label = handler; + ptr->handler_number = CODE_LABEL_NUMBER (handler); ptr->type_info = typeinfo; ptr->next = NULL; @@ -910,34 +973,97 @@ clear_function_eh_region () } /* Make a duplicate of an exception region by copying all the handlers - for an exception region. Return the new handler index. */ + for an exception region. Return the new handler index. The final + parameter is a routine which maps old labels to new ones. */ int -duplicate_handlers (old_note_eh_region, new_note_eh_region) +duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map) int old_note_eh_region, new_note_eh_region; + rtx (*map) PARAMS ((rtx)); { struct handler_info *ptr, *new_ptr; int new_region, region; region = find_func_region (old_note_eh_region); if (region == -1) - error ("Cannot duplicate non-existant exception region."); + fatal ("Cannot duplicate non-existant exception region."); + + /* duplicate_eh_handlers may have been called during a symbol remap. */ + new_region = find_func_region (new_note_eh_region); + if (new_region != -1) + return (new_region); - if (find_func_region (new_note_eh_region) != -1) - error ("Cannot duplicate EH region because new note region already exists"); + new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX); - new_region = new_eh_region_entry (new_note_eh_region); ptr = function_eh_regions[region].handlers; for ( ; ptr; ptr = ptr->next) { - new_ptr = get_new_handler (ptr->handler_label, ptr->type_info); + new_ptr = get_new_handler (map (ptr->handler_label), ptr->type_info); add_new_handler (new_region, new_ptr); } return new_region; } + +/* Given a rethrow symbol, find the EH region number this is for. */ +int +eh_region_from_symbol (sym) + rtx sym; +{ + int x; + if (sym == last_rethrow_symbol) + return 1; + for (x = 0; x < current_func_eh_entry; x++) + if (function_eh_regions[x].rethrow_label == sym) + return function_eh_regions[x].range_number; + return -1; +} + + +/* When inlining/unrolling, we have to map the symbols passed to + __rethrow as well. This performs the remap. If a symbol isn't foiund, + the original one is returned. This is not an efficient routine, + so don't call it on everything!! */ +rtx +rethrow_symbol_map (sym, map) + rtx sym; + rtx (*map) PARAMS ((rtx)); +{ + int x, y; + for (x = 0; x < current_func_eh_entry; x++) + if (function_eh_regions[x].rethrow_label == sym) + { + /* We've found the original region, now lets determine which region + this now maps to. */ + rtx l1 = function_eh_regions[x].handlers->handler_label; + rtx l2 = map (l1); + y = CODE_LABEL_NUMBER (l2); /* This is the new region number */ + x = find_func_region (y); /* Get the new permanent region */ + if (x == -1) /* Hmm, Doesn't exist yet */ + { + x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map); + /* Since we're mapping it, it must be used. */ + SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1; + } + return function_eh_regions[x].rethrow_label; + } + return sym; +} + +int +rethrow_used (region) + int region; +{ + if (flag_new_exceptions) + { + rtx lab = function_eh_regions[find_func_region (region)].rethrow_label; + return (SYMBOL_REF_USED (lab)); + } + return 0; +} + /* Routine to see if exception handling is turned on. DO_WARN is non-zero if we want to inform the user that exception @@ -1252,7 +1378,7 @@ start_dynamic_handler () /* We are committed to this, so update the handler chain. */ - emit_move_insn (dhc, XEXP (arg, 0)); + emit_move_insn (dhc, force_operand (XEXP (arg, 0), NULL_RTX)); } /* Start an exception handling region for the given cleanup action. @@ -1391,6 +1517,7 @@ expand_eh_region_end (handler) { struct eh_entry *entry; rtx note; + int ret, r; if (! doing_eh (0)) return; @@ -1398,9 +1525,9 @@ expand_eh_region_end (handler) entry = pop_eh_entry (&ehstack); note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END); - NOTE_BLOCK_NUMBER (note) + ret = NOTE_BLOCK_NUMBER (note) = CODE_LABEL_NUMBER (entry->exception_handler_label); - if (exceptions_via_longjmp == 0 + if (exceptions_via_longjmp == 0 && ! flag_new_exceptions /* We share outer_context between regions; only emit it once. */ && INSN_UID (entry->outer_context) == 0) { @@ -1420,7 +1547,7 @@ expand_eh_region_end (handler) entry->finalization = handler; /* create region entry in final exception table */ - new_eh_region_entry (NOTE_BLOCK_NUMBER (note)); + r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label); enqueue_eh_entry (&ehqueue, entry); @@ -1616,6 +1743,62 @@ start_catch_handler (rtime) receive_exception_label (handler_label); add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime)); + + if (flag_new_exceptions && ! exceptions_via_longjmp) + return; + + /* Under the old mechanism, as well as setjmp/longjmp, we need to + issue code to compare 'rtime' to the value in eh_info, via the + matching function in eh_info. If its is false, we branch around + the handler we are about to issue. */ + + if (rtime != NULL_TREE && rtime != CATCH_ALL_TYPE) + { + rtx call_rtx, rtime_address; + + if (catchstack.top->entry->false_label != NULL_RTX) + fatal ("Compiler Bug: Never issued previous false_label"); + catchstack.top->entry->false_label = gen_exception_label (); + + rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER); +#ifdef POINTERS_EXTEND_UNSIGNED + rtime_address = convert_memory_address (Pmode, rtime_address); +#endif + rtime_address = force_reg (Pmode, rtime_address); + + /* Now issue the call, and branch around handler if needed */ + call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX, + 0, SImode, 1, rtime_address, Pmode); + + /* Did the function return true? */ + emit_cmp_and_jump_insns (call_rtx, const0_rtx, EQ, NULL_RTX, + GET_MODE (call_rtx), 0, 0, + catchstack.top->entry->false_label); + } +} + +/* Called to end a catch clause. If we aren't using the new exception + model tabel mechanism, we need to issue the branch-around label + for the end of the catch block. */ + +void +end_catch_handler () +{ + if (! doing_eh (1)) + return; + + if (flag_new_exceptions && ! exceptions_via_longjmp) + { + emit_barrier (); + return; + } + + /* A NULL label implies the catch clause was a catch all or cleanup */ + if (catchstack.top->entry->false_label == NULL_RTX) + return; + + emit_label (catchstack.top->entry->false_label); + catchstack.top->entry->false_label = NULL_RTX; } /* Generate RTL for the start of a group of catch clauses. @@ -1709,9 +1892,6 @@ expand_start_all_catch () ehstack.top->entry->outer_context = outer_context; } - /* We also have to start the handler if we aren't using the new model. */ - if (! flag_new_exceptions) - start_catch_handler (NULL); } /* Finish up the catch block. At this point all the insns for the @@ -1723,7 +1903,7 @@ expand_start_all_catch () void expand_end_all_catch () { - rtx new_catch_clause, outer_context = NULL_RTX; + rtx new_catch_clause; struct eh_entry *entry; if (! doing_eh (1)) @@ -1735,11 +1915,17 @@ expand_end_all_catch () if (! exceptions_via_longjmp) { - outer_context = ehstack.top->entry->outer_context; + rtx outer_context = ehstack.top->entry->outer_context; /* Finish the rethrow region. size_zero_node is just a NOP. */ expand_eh_region_end (size_zero_node); + /* New exceptions handling models will never have a fall through + of a catch clause */ + if (!flag_new_exceptions) + expand_rethrow (outer_context); } + else + expand_rethrow (NULL_RTX); /* Code to throw out to outer context, if we fall off end of catch handlers. This is rethrow (Lresume, same id, same obj) in the @@ -1750,7 +1936,6 @@ expand_end_all_catch () do a "throw" (using the address of Lresume as the point being thrown from) so that the outer EH region can then try to process the exception. */ - expand_rethrow (outer_context); /* Now we have the complete catch sequence. */ new_catch_clause = get_insns (); @@ -1779,7 +1964,28 @@ expand_rethrow (label) if (exceptions_via_longjmp) emit_throw (); else - emit_jump (label); + if (flag_new_exceptions) + { + rtx insn, val; + if (label == NULL_RTX) + label = last_rethrow_symbol; + emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode); + SYMBOL_REF_USED (label) = 1; + + /* Search backwards for the actual call insn. */ + insn = get_last_insn (); + while (GET_CODE (insn) != CALL_INSN) + insn = PREV_INSN (insn); + delete_insns_since (insn); + + /* Mark the label/symbol on the call. */ + val = GEN_INT (eh_region_from_symbol (label)); + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val, + REG_NOTES (insn)); + emit_barrier (); + } + else + emit_jump (label); } /* End all the pending exception regions on protect_list. The handlers @@ -1913,12 +2119,29 @@ output_exception_table_entry (file, n) { char buf[256]; rtx sym; - struct handler_info *handler; + struct handler_info *handler = get_first_handler (n); + int index = find_func_region (n); + rtx rethrow; + + /* form and emit the rethrow label, if needed */ + rethrow = function_eh_regions[index].rethrow_label; + if (rethrow != NULL_RTX && !flag_new_exceptions) + rethrow = NULL_RTX; + if (rethrow != NULL_RTX && handler == NULL) + if (! SYMBOL_REF_USED (rethrow)) + rethrow = NULL_RTX; - handler = get_first_handler (n); - for ( ; handler != NULL; handler = handler->next) + for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next) { + /* rethrow label should indicate the LAST entry for a region */ + if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL)) + { + ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n); + assemble_label(buf); + rethrow = NULL_RTX; + } + ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n); sym = gen_rtx_SYMBOL_REF (Pmode, buf); assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); @@ -1927,12 +2150,18 @@ output_exception_table_entry (file, n) sym = gen_rtx_SYMBOL_REF (Pmode, buf); assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); - assemble_integer (handler->handler_label, - POINTER_SIZE / BITS_PER_UNIT, 1); + if (handler == NULL) + assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1); + else + { + ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number); + sym = gen_rtx_SYMBOL_REF (Pmode, buf); + assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1); + } if (flag_new_exceptions) { - if (handler->type_info == NULL) + if (handler == NULL || handler->type_info == NULL) assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); else if (handler->type_info == CATCH_ALL_TYPE) @@ -1943,6 +2172,9 @@ output_exception_table_entry (file, n) POINTER_SIZE / BITS_PER_UNIT); } putc ('\n', file); /* blank line */ + /* We only output the first label under the old scheme */ + if (! flag_new_exceptions || handler == NULL) + break; } } @@ -1952,15 +2184,17 @@ static short language_code = 0; static short version_code = 0; /* This routine will set the language code for exceptions. */ -void set_exception_lang_code (code) - short code; +void +set_exception_lang_code (code) + int code; { language_code = code; } /* This routine will set the language version code for exceptions. */ -void set_exception_version_code (code) - short code; +void +set_exception_version_code (code) + int code; { version_code = code; } @@ -1970,6 +2204,7 @@ void output_exception_table () { int i; + char buf[256]; extern FILE *asm_out_file; if (! doing_eh (0) || ! eh_table) @@ -1994,6 +2229,10 @@ output_exception_table () ; if (i != 0) assemble_integer (const0_rtx, i , 1); + + /* Generate the label for offset calculations on rethrows */ + ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0); + assemble_label(buf); } for (i = 0; i < eh_table_size; ++i) @@ -2003,6 +2242,9 @@ output_exception_table () clear_function_eh_region (); /* Ending marker for table. */ + /* Generate the label for end of table. */ + ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow)); + assemble_label(buf); assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1); /* for binary compatability, the old __throw checked the second @@ -2053,6 +2295,14 @@ emit_eh_context () end_sequence (); emit_insns_before (insns, insn); + + /* At -O0, we must make the context register stay alive so + that the stupid.c register allocator doesn't get confused. */ + if (obey_regdecls != 0) + { + insns = gen_rtx_USE (GET_MODE (XEXP (reg,0)), XEXP (reg,0)); + emit_insn_before (insns, get_last_insn ()); + } } } } @@ -2153,6 +2403,9 @@ check_exception_handler_labels () void init_eh () { + first_rethrow_symbol = create_rethrow_ref (0); + final_rethrow = gen_exception_label (); + last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow)); } /* Initialize the per-function EH information. */ @@ -2168,6 +2421,10 @@ init_eh_for_function () caught_return_label_stack = 0; protect_list = NULL_TREE; current_function_ehc = NULL_RTX; + eh_return_context = NULL_RTX; + eh_return_stack_adjust = NULL_RTX; + eh_return_handler = NULL_RTX; + eh_return_stub_label = NULL_RTX; } /* Save some of the per-function EH info into the save area denoted by @@ -2190,6 +2447,7 @@ save_eh_status (p) p->caught_return_label_stack = caught_return_label_stack; p->protect_list = protect_list; p->ehc = current_function_ehc; + p->eh_return_stub_label = eh_return_stub_label; init_eh_for_function (); } @@ -2213,6 +2471,7 @@ restore_eh_status (p) ehstack = p->ehstack; catchstack = p->catchstack; current_function_ehc = p->ehc; + eh_return_stub_label = p->eh_return_stub_label; } /* This section is for the exception handling specific optimization @@ -2268,6 +2527,11 @@ scan_region (insn, n, delete_outer) /* Assume we can delete the region. */ int delete = 1; + int r = find_func_region (n); + /* Can't delete something which is rethrown to. */ + if (SYMBOL_REF_USED((function_eh_regions[r].rethrow_label))) + delete = 0; + if (insn == NULL_RTX || GET_CODE (insn) != NOTE || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG @@ -2424,79 +2688,72 @@ expand_builtin_frob_return_addr (addr_tree) return addr; } -/* Given an actual address in addr_tree, set the return address register up - so the epilogue will return to that address. If the return address is - not in a register, do nothing. */ - -void -expand_builtin_set_return_addr_reg (addr_tree) - tree addr_tree; -{ - rtx tmp; - rtx ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, - 0, hard_frame_pointer_rtx); - - if (GET_CODE (ra) != REG || REGNO (ra) >= FIRST_PSEUDO_REGISTER) - return; +/* Choose three registers for communication between the main body of + __throw and the epilogue (or eh stub) and the exception handler. + We must do this with hard registers because the epilogue itself + will be generated after reload, at which point we may not reference + pseudos at all. - tmp = force_operand (expand_builtin_frob_return_addr (addr_tree), ra); - if (tmp != ra) - emit_move_insn (ra, tmp); -} + The first passes the exception context to the handler. For this + we use the return value register for a void*. -/* Choose two registers for communication between the main body of - __throw and the stub for adjusting the stack pointer. The first register - is used to pass the address of the exception handler; the second register - is used to pass the stack pointer offset. + The second holds the stack pointer value to be restored. For + this we use the static chain register if it exists and is different + from the previous, otherwise some arbitrary call-clobbered register. - For register 1 we use the return value register for a void *. - For register 2 we use the static chain register if it exists and is - different from register 1, otherwise some arbitrary call-clobbered - register. */ + The third holds the address of the handler itself. Here we use + some arbitrary call-clobbered register. */ static void -eh_regs (r1, r2, outgoing) - rtx *r1, *r2; +eh_regs (pcontext, psp, pra, outgoing) + rtx *pcontext, *psp, *pra; int outgoing; { - rtx reg1, reg2; + rtx rcontext, rsp, rra; + int i; #ifdef FUNCTION_OUTGOING_VALUE if (outgoing) - reg1 = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node), - current_function_decl); + rcontext = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node), + current_function_decl); else #endif - reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node), - current_function_decl); + rcontext = FUNCTION_VALUE (build_pointer_type (void_type_node), + current_function_decl); #ifdef STATIC_CHAIN_REGNUM if (outgoing) - reg2 = static_chain_incoming_rtx; + rsp = static_chain_incoming_rtx; else - reg2 = static_chain_rtx; - if (REGNO (reg2) == REGNO (reg1)) + rsp = static_chain_rtx; + if (REGNO (rsp) == REGNO (rcontext)) #endif /* STATIC_CHAIN_REGNUM */ - reg2 = NULL_RTX; + rsp = NULL_RTX; - if (reg2 == NULL_RTX) + if (rsp == NULL_RTX) { - int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) - if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (reg1)) - { - reg2 = gen_rtx_REG (Pmode, i); - break; - } + if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (rcontext)) + break; + if (i == FIRST_PSEUDO_REGISTER) + abort(); - if (reg2 == NULL_RTX) - abort (); + rsp = gen_rtx_REG (Pmode, i); } - *r1 = reg1; - *r2 = reg2; -} + for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i) + if (call_used_regs[i] && ! fixed_regs[i] + && i != REGNO (rcontext) && i != REGNO (rsp)) + break; + if (i == FIRST_PSEUDO_REGISTER) + abort(); + + rra = gen_rtx_REG (Pmode, i); + *pcontext = rcontext; + *psp = rsp; + *pra = rra; +} /* Retrieve the register which contains the pointer to the eh_context structure set the __throw. */ @@ -2510,79 +2767,95 @@ get_reg_for_handler () return reg1; } +/* Set up the epilogue with the magic bits we'll need to return to the + exception handler. */ -/* Emit inside of __throw a stub which adjusts the stack pointer and jumps - to the exception handler. __throw will set up the necessary values - and then return to the stub. */ - -rtx -expand_builtin_eh_stub_old () +void +expand_builtin_eh_return (context, stack, handler) + tree context, stack, handler; { - rtx stub_start = gen_label_rtx (); - rtx after_stub = gen_label_rtx (); - rtx handler, offset; - - emit_jump (after_stub); - emit_label (stub_start); - - eh_regs (&handler, &offset, 0); + if (eh_return_context) + error("Duplicate call to __builtin_eh_return"); - adjust_stack (offset); - emit_indirect_jump (handler); - emit_label (after_stub); - return gen_rtx_LABEL_REF (Pmode, stub_start); + eh_return_context + = copy_to_reg (expand_expr (context, NULL_RTX, VOIDmode, 0)); + eh_return_stack_adjust + = copy_to_reg (expand_expr (stack, NULL_RTX, VOIDmode, 0)); + eh_return_handler + = copy_to_reg (expand_expr (handler, NULL_RTX, VOIDmode, 0)); } -rtx -expand_builtin_eh_stub () +void +expand_eh_return () { - rtx stub_start = gen_label_rtx (); - rtx after_stub = gen_label_rtx (); - rtx handler, offset; - rtx temp; + rtx reg1, reg2, reg3; + rtx stub_start, after_stub; + rtx ra, tmp; - emit_jump (after_stub); - emit_label (stub_start); + if (!eh_return_context) + return; - eh_regs (&handler, &offset, 0); + current_function_cannot_inline = N_("function uses __builtin_eh_return"); - adjust_stack (offset); + eh_regs (®1, ®2, ®3, 1); +#ifdef POINTERS_EXTEND_UNSIGNED + eh_return_context = convert_memory_address (Pmode, eh_return_context); + eh_return_stack_adjust = + convert_memory_address (Pmode, eh_return_stack_adjust); + eh_return_handler = convert_memory_address (Pmode, eh_return_handler); +#endif + emit_move_insn (reg1, eh_return_context); + emit_move_insn (reg2, eh_return_stack_adjust); + emit_move_insn (reg3, eh_return_handler); - /* Handler is in fact a pointer to the _eh_context structure, we need - to pick out the handler field (first element), and jump to there, - leaving the pointer to _eh_conext in the same hardware register. */ + /* Talk directly to the target's epilogue code when possible. */ - temp = gen_rtx_MEM (Pmode, handler); - MEM_IN_STRUCT_P (temp) = 1; - RTX_UNCHANGING_P (temp) = 1; - emit_move_insn (offset, temp); - emit_insn (gen_rtx_USE (Pmode, handler)); +#ifdef HAVE_eh_epilogue + if (HAVE_eh_epilogue) + { + emit_insn (gen_eh_epilogue (reg1, reg2, reg3)); + return; + } +#endif - emit_indirect_jump (offset); - - emit_label (after_stub); - return gen_rtx_LABEL_REF (Pmode, stub_start); -} + /* Otherwise, use the same stub technique we had before. */ -/* Set up the registers for passing the handler address and stack offset - to the stub above. */ + eh_return_stub_label = stub_start = gen_label_rtx (); + after_stub = gen_label_rtx (); -void -expand_builtin_set_eh_regs (handler, offset) - tree handler, offset; -{ - rtx reg1, reg2; + /* Set the return address to the stub label. */ - eh_regs (®1, ®2, 1); + ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, + 0, hard_frame_pointer_rtx); + if (GET_CODE (ra) == REG && REGNO (ra) >= FIRST_PSEUDO_REGISTER) + abort(); - store_expr (offset, reg2, 0); - store_expr (handler, reg1, 0); + tmp = memory_address (Pmode, gen_rtx_LABEL_REF (Pmode, stub_start)); +#ifdef RETURN_ADDR_OFFSET + tmp = plus_constant (tmp, -RETURN_ADDR_OFFSET); +#endif + tmp = force_operand (tmp, ra); + if (tmp != ra) + emit_move_insn (ra, tmp); - /* These will be used by the stub. */ + /* Indicate that the registers are in fact used. */ emit_insn (gen_rtx_USE (VOIDmode, reg1)); emit_insn (gen_rtx_USE (VOIDmode, reg2)); -} + emit_insn (gen_rtx_USE (VOIDmode, reg3)); + if (GET_CODE (ra) == REG) + emit_insn (gen_rtx_USE (VOIDmode, ra)); + + /* Generate the stub. */ + + emit_jump (after_stub); + emit_label (stub_start); + + eh_regs (®1, ®2, ®3, 0); + adjust_stack (reg2); + emit_indirect_jump (reg3); + emit_label (after_stub); +} /* This contains the code required to verify whether arbitrary instructions |