diff options
Diffstat (limited to 'gcc/except.c')
-rw-r--r-- | gcc/except.c | 242 |
1 files changed, 121 insertions, 121 deletions
diff --git a/gcc/except.c b/gcc/except.c index f0d0009..d1e8220 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -431,12 +431,6 @@ rtx exception_handler_labels; rtx current_function_ehc; -/* The labels generated by expand_builtin_eh_stub and - expand_builtin_eh_stub_old. */ - -rtx current_function_eh_stub_label; -rtx current_function_eh_old_stub_label; - /* A stack used for keeping track of the currently active exception handling region. As each exception region is started, an entry describing the region is pushed onto this stack. The current @@ -496,6 +490,20 @@ 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; + +/* 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 *)); @@ -507,13 +515,12 @@ 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 @@ -2203,8 +2210,10 @@ init_eh_for_function () caught_return_label_stack = 0; protect_list = NULL_TREE; current_function_ehc = NULL_RTX; - current_function_eh_stub_label = NULL_RTX; - current_function_eh_old_stub_label = 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 @@ -2227,8 +2236,6 @@ 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_stub_label = current_function_eh_stub_label; - p->eh_old_stub_label = current_function_eh_old_stub_label; init_eh_for_function (); } @@ -2252,8 +2259,6 @@ restore_eh_status (p) ehstack = p->ehstack; catchstack = p->catchstack; current_function_ehc = p->ehc; - current_function_eh_stub_label = p->eh_stub_label; - current_function_eh_old_stub_label = p->eh_old_stub_label; } /* This section is for the exception handling specific optimization @@ -2465,79 +2470,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. */ +/* 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. -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; - - 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. */ @@ -2551,83 +2549,85 @@ 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; + if (eh_return_context) + error("Duplicate call to __builtin_eh_return"); - current_function_eh_old_stub_label = stub_start; - - emit_jump (after_stub); - emit_label (stub_start); - - eh_regs (&handler, &offset, 0); - - 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; - - current_function_eh_stub_label = stub_start; - - emit_jump (after_stub); - emit_label (stub_start); + rtx reg1, reg2, reg3; + rtx stub_start, after_stub; + rtx ra, tmp; - eh_regs (&handler, &offset, 0); + if (!eh_return_context) + return; - adjust_stack (offset); + eh_regs (®1, ®2, ®3, 1); + 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 + 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 |