mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-19 01:50:34 +08:00
tree.h (BUILT_IN_CALLER_RETURN_ADDRESS): Unused.
* tree.h (BUILT_IN_CALLER_RETURN_ADDRESS): Unused. Kill. (BUILT_IN_FP, BUILT_IN_SP, BUILT_IN_SET_RETURN_ADDR_REG): Kill. (BUILT_IN_EH_STUB_OLD, BUILT_IN_EH_STUB, BUILT_IN_SET_EH_REGS): Kill. (BUILT_IN_EH_RETURN, BUILT_IN_DWARF_CFA): New. * c-decl.c (init_decl_processing): Update accordingly. * expr.c (expand_builtin): Likewise. * cp/decl.c (init_decl_processing): Likewise. * rtl.h (global_rtl): Add cfa entry. (virtual_cfa_rtx, VIRTUAL_CFA_REGNUM): New. (LAST_VIRTUAL_REGISTER): Update. * emit-rtl.c (global_rtl): Add cfa entry. (init_emit): Initialize it. * function.c (cfa_offset): New. (instantiate_virtual_regs): Initialize it. (instantiate_virtual_regs_1): Instantiate virtual_cfa_rtx. (expand_function_end): Call expand_eh_return. * tm.texi (ARG_POINTER_CFA_OFFSET): New. * except.c (current_function_eh_stub_label): Kill. (current_function_eh_old_stub_label): Likwise; update all references. (expand_builtin_set_return_addr_reg): Kill. (expand_builtin_eh_stub_old, expand_builtin_eh_stub): Kill. (expand_builtin_set_eh_regs): Kill. (eh_regs): Produce a third reg for the actual handler address. (eh_return_context, eh_return_stack_adjust): New. (eh_return_handler, eh_return_stub_label): New. (init_eh_for_function): Initialize them. (expand_builtin_eh_return, expand_eh_return): New. * except.h: Update prototypes. * flow.c (find_basic_blocks_1): Update references to the stub label. * function.h (struct function): Kill stub label elements. * libgcc2.c (in_reg_window): For REG_SAVED_REG, check that the register number is one that would be in the previous window. Provide a dummy definition for non-windowed targets. (get_reg_addr): New function. (get_reg, put_reg, copy_reg): Use it. (__throw): Rely on in_reg_window, not INCOMING_REGNO. Kill stub generating code and use __builtin_eh_return. Use __builtin_dwarf_cfa. * alpha.c (alpha_eh_epilogue_sp_ofs): New. (alpha_init_expanders): Initialize it. (alpha_expand_epilogue): Use it. * alpha.h: Declare it. * alpha.md (eh_epilogue): New. * m68h.h (ARG_POINTER_CFA_OFFSET): New. * sparc.h (ARG_POINTER_CFA_OFFSET): New. From-SVN: r22436
This commit is contained in:
parent
dfb16e8307
commit
710384268d
@ -1,3 +1,54 @@
|
||||
Tue Sep 15 19:09:06 1998 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* tree.h (BUILT_IN_CALLER_RETURN_ADDRESS): Unused. Kill.
|
||||
(BUILT_IN_FP, BUILT_IN_SP, BUILT_IN_SET_RETURN_ADDR_REG): Kill.
|
||||
(BUILT_IN_EH_STUB_OLD, BUILT_IN_EH_STUB, BUILT_IN_SET_EH_REGS): Kill.
|
||||
(BUILT_IN_EH_RETURN, BUILT_IN_DWARF_CFA): New.
|
||||
* c-decl.c (init_decl_processing): Update accordingly.
|
||||
* expr.c (expand_builtin): Likewise.
|
||||
|
||||
* rtl.h (global_rtl): Add cfa entry.
|
||||
(virtual_cfa_rtx, VIRTUAL_CFA_REGNUM): New.
|
||||
(LAST_VIRTUAL_REGISTER): Update.
|
||||
* emit-rtl.c (global_rtl): Add cfa entry.
|
||||
(init_emit): Initialize it.
|
||||
* function.c (cfa_offset): New.
|
||||
(instantiate_virtual_regs): Initialize it.
|
||||
(instantiate_virtual_regs_1): Instantiate virtual_cfa_rtx.
|
||||
(expand_function_end): Call expand_eh_return.
|
||||
* tm.texi (ARG_POINTER_CFA_OFFSET): New.
|
||||
|
||||
* except.c (current_function_eh_stub_label): Kill.
|
||||
(current_function_eh_old_stub_label): Likwise; update all references.
|
||||
(expand_builtin_set_return_addr_reg): Kill.
|
||||
(expand_builtin_eh_stub_old, expand_builtin_eh_stub): Kill.
|
||||
(expand_builtin_set_eh_regs): Kill.
|
||||
(eh_regs): Produce a third reg for the actual handler address.
|
||||
(eh_return_context, eh_return_stack_adjust): New.
|
||||
(eh_return_handler, eh_return_stub_label): New.
|
||||
(init_eh_for_function): Initialize them.
|
||||
(expand_builtin_eh_return, expand_eh_return): New.
|
||||
* except.h: Update prototypes.
|
||||
* flow.c (find_basic_blocks_1): Update references to the stub label.
|
||||
* function.h (struct function): Kill stub label elements.
|
||||
|
||||
* libgcc2.c (in_reg_window): For REG_SAVED_REG, check that the
|
||||
register number is one that would be in the previous window.
|
||||
Provide a dummy definition for non-windowed targets.
|
||||
(get_reg_addr): New function.
|
||||
(get_reg, put_reg, copy_reg): Use it.
|
||||
(__throw): Rely on in_reg_window, not INCOMING_REGNO. Kill stub
|
||||
generating code and use __builtin_eh_return. Use __builtin_dwarf_cfa.
|
||||
|
||||
* alpha.c (alpha_eh_epilogue_sp_ofs): New.
|
||||
(alpha_init_expanders): Initialize it.
|
||||
(alpha_expand_epilogue): Use it.
|
||||
* alpha.h: Declare it.
|
||||
* alpha.md (eh_epilogue): New.
|
||||
|
||||
* m68h.h (ARG_POINTER_CFA_OFFSET): New.
|
||||
* sparc.h (ARG_POINTER_CFA_OFFSET): New.
|
||||
|
||||
Tue Sep 15 19:31:58 1998 Michael Meissner <meissner@cygnus.com>
|
||||
|
||||
* i960.h (CONST_COSTS): Fix thinko. Test flag, not the constant
|
||||
|
22
gcc/c-decl.c
22
gcc/c-decl.c
@ -3291,8 +3291,8 @@ init_decl_processing ()
|
||||
builtin_function ("__builtin_unwind_init",
|
||||
build_function_type (void_type_node, endlink),
|
||||
BUILT_IN_UNWIND_INIT, NULL_PTR);
|
||||
builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
|
||||
builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
|
||||
builtin_function ("__builtin_dwarf_cfa", ptr_ftype_void,
|
||||
BUILT_IN_DWARF_CFA, NULL_PTR);
|
||||
builtin_function ("__builtin_dwarf_fp_regnum",
|
||||
build_function_type (unsigned_type_node, endlink),
|
||||
BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
|
||||
@ -3302,24 +3302,16 @@ init_decl_processing ()
|
||||
BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
|
||||
builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
|
||||
BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
|
||||
builtin_function ("__builtin_set_return_addr_reg",
|
||||
build_function_type (void_type_node,
|
||||
tree_cons (NULL_TREE,
|
||||
ptr_type_node,
|
||||
endlink)),
|
||||
BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
|
||||
builtin_function ("__builtin_eh_stub_old", ptr_ftype_void,
|
||||
BUILT_IN_EH_STUB_OLD, NULL_PTR);
|
||||
builtin_function ("__builtin_eh_stub", ptr_ftype_void,
|
||||
BUILT_IN_EH_STUB, NULL_PTR);
|
||||
builtin_function
|
||||
("__builtin_set_eh_regs",
|
||||
("__builtin_eh_return",
|
||||
build_function_type (void_type_node,
|
||||
tree_cons (NULL_TREE, ptr_type_node,
|
||||
tree_cons (NULL_TREE,
|
||||
type_for_mode (ptr_mode, 0),
|
||||
endlink))),
|
||||
BUILT_IN_SET_EH_REGS, NULL_PTR);
|
||||
tree_cons (NULL_TREE,
|
||||
ptr_type_node,
|
||||
endlink)))),
|
||||
BUILT_IN_EH_RETURN, NULL_PTR);
|
||||
|
||||
builtin_function ("__builtin_alloca",
|
||||
build_function_type (ptr_type_node,
|
||||
|
@ -79,6 +79,10 @@ char *alpha_mlat_string; /* -mmemory-latency= */
|
||||
rtx alpha_compare_op0, alpha_compare_op1;
|
||||
int alpha_compare_fp_p;
|
||||
|
||||
/* Define the information needed to modify the epilogue for EH. */
|
||||
|
||||
rtx alpha_eh_epilogue_sp_ofs;
|
||||
|
||||
/* Non-zero if inside of a function, because the Alpha asm can't
|
||||
handle .files inside of functions. */
|
||||
|
||||
@ -2431,6 +2435,7 @@ void
|
||||
alpha_init_expanders ()
|
||||
{
|
||||
alpha_return_addr_rtx = NULL_RTX;
|
||||
alpha_eh_epilogue_sp_ofs = NULL_RTX;
|
||||
|
||||
/* Arrange to save and restore machine status around nested functions. */
|
||||
save_machine_status = alpha_save_machine_status;
|
||||
@ -3731,9 +3736,13 @@ alpha_expand_epilogue ()
|
||||
|
||||
/* Restore registers in order, excepting a true frame pointer. */
|
||||
|
||||
FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA),
|
||||
gen_rtx_MEM (DImode, plus_constant(sa_reg,
|
||||
reg_offset))));
|
||||
if (! alpha_eh_epilogue_sp_ofs)
|
||||
{
|
||||
FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA),
|
||||
gen_rtx_MEM (DImode,
|
||||
plus_constant(sa_reg,
|
||||
reg_offset))));
|
||||
}
|
||||
reg_offset += 8;
|
||||
imask &= ~(1L << REG_RA);
|
||||
|
||||
@ -3763,21 +3772,28 @@ alpha_expand_epilogue ()
|
||||
}
|
||||
}
|
||||
|
||||
if (frame_size)
|
||||
if (frame_size || alpha_eh_epilogue_sp_ofs)
|
||||
{
|
||||
sp_adj1 = stack_pointer_rtx;
|
||||
|
||||
if (alpha_eh_epilogue_sp_ofs)
|
||||
{
|
||||
sp_adj1 = gen_rtx_REG (DImode, 23);
|
||||
emit_move_insn (sp_adj1,
|
||||
gen_rtx_PLUS (Pmode, stack_pointer_rtx,
|
||||
alpha_eh_epilogue_sp_ofs));
|
||||
}
|
||||
|
||||
/* If the stack size is large, begin computation into a temporary
|
||||
register so as not to interfere with a potential fp restore,
|
||||
which must be consecutive with an SP restore. */
|
||||
if (frame_size < 32768)
|
||||
{
|
||||
sp_adj1 = stack_pointer_rtx;
|
||||
sp_adj2 = GEN_INT (frame_size);
|
||||
}
|
||||
sp_adj2 = GEN_INT (frame_size);
|
||||
else if (frame_size < 0x40007fffL)
|
||||
{
|
||||
int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000;
|
||||
|
||||
sp_adj2 = plus_constant (stack_pointer_rtx, frame_size - low);
|
||||
sp_adj2 = plus_constant (sp_adj1, frame_size - low);
|
||||
if (sa_reg_exp && rtx_equal_p (sa_reg_exp, sp_adj2))
|
||||
sp_adj1 = sa_reg;
|
||||
else
|
||||
@ -3789,21 +3805,20 @@ alpha_expand_epilogue ()
|
||||
}
|
||||
else
|
||||
{
|
||||
sp_adj2 = gen_rtx_REG (DImode, 23);
|
||||
FRP (sp_adj1 = alpha_emit_set_const (sp_adj2, DImode, frame_size, 3));
|
||||
if (!sp_adj1)
|
||||
rtx tmp = gen_rtx_REG (DImode, 23);
|
||||
FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3));
|
||||
if (!sp_adj2)
|
||||
{
|
||||
/* We can't drop new things to memory this late, afaik,
|
||||
so build it up by pieces. */
|
||||
#if HOST_BITS_PER_WIDE_INT == 64
|
||||
FRP (sp_adj1 = alpha_emit_set_long_const (sp_adj2, frame_size));
|
||||
if (!sp_adj1)
|
||||
FRP (sp_adj2 = alpha_emit_set_long_const (tmp, frame_size));
|
||||
if (!sp_adj2)
|
||||
abort ();
|
||||
#else
|
||||
abort ();
|
||||
#endif
|
||||
}
|
||||
sp_adj2 = stack_pointer_rtx;
|
||||
}
|
||||
|
||||
/* From now on, things must be in order. So emit blockages. */
|
||||
|
@ -1180,6 +1180,10 @@ extern struct rtx_def *alpha_builtin_saveregs ();
|
||||
extern struct rtx_def *alpha_compare_op0, *alpha_compare_op1;
|
||||
extern int alpha_compare_fp_p;
|
||||
|
||||
/* Define the information needed to modify the epilogue for EH. */
|
||||
|
||||
extern struct rtx_def *alpha_eh_epilogue_sp_ofs;
|
||||
|
||||
/* Make (or fake) .linkage entry for function call.
|
||||
IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. */
|
||||
extern void alpha_need_linkage ();
|
||||
|
@ -5144,6 +5144,22 @@
|
||||
""
|
||||
"alpha_expand_epilogue (); DONE;")
|
||||
|
||||
(define_expand "eh_epilogue"
|
||||
[(use (match_operand:DI 0 "register_operand" "r"))
|
||||
(use (match_operand:DI 1 "register_operand" "r"))
|
||||
(use (match_operand:DI 2 "register_operand" "r"))]
|
||||
"! TARGET_OPEN_VMS"
|
||||
"
|
||||
{
|
||||
alpha_eh_epilogue_sp_ofs = operands[1];
|
||||
if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 26)
|
||||
{
|
||||
rtx ra = gen_rtx_REG (Pmode, 26);
|
||||
emit_move_insn (ra, operands[2]);
|
||||
operands[2] = ra;
|
||||
}
|
||||
}")
|
||||
|
||||
(define_expand "builtin_longjmp"
|
||||
[(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)]
|
||||
"! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
|
||||
|
@ -858,6 +858,9 @@ extern enum reg_class regno_reg_class[];
|
||||
/* Offset of first parameter from the argument pointer register value. */
|
||||
#define FIRST_PARM_OFFSET(FNDECL) 8
|
||||
|
||||
/* Offset of the CFA from the argument pointer register value. */
|
||||
#define ARG_POINTER_CFA_OFFSET 8
|
||||
|
||||
/* Value is the number of byte of arguments automatically
|
||||
popped when returning from a subroutine call.
|
||||
FUNDECL is the declaration node of the function (as a tree),
|
||||
|
@ -1478,6 +1478,10 @@ extern char leaf_reg_remap[];
|
||||
(TARGET_ARCH64 ? (SPARC_STACK_BIAS + 16 * UNITS_PER_WORD) \
|
||||
: (STRUCT_VALUE_OFFSET + UNITS_PER_WORD))
|
||||
|
||||
/* Offset from the argument pointer register value to the CFA. */
|
||||
|
||||
#define ARG_POINTER_CFA_OFFSET SPARC_STACK_BIAS
|
||||
|
||||
/* When a parameter is passed in a register, stack space is still
|
||||
allocated for it.
|
||||
!v9: All 6 possible integer registers have backing store allocated.
|
||||
|
@ -1,3 +1,7 @@
|
||||
1998-09-16 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* decl.c (init_decl_processing): Kill __builtin_fp and __builtin_sp.
|
||||
|
||||
1998-09-15 Alexandre Oliva <oliva@dcc.unicamp.br>
|
||||
|
||||
* call.c (build_field_call): handle static data members too
|
||||
|
@ -5891,10 +5891,6 @@ init_decl_processing ()
|
||||
builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
|
||||
BUILT_IN_FRAME_ADDRESS, NULL_PTR);
|
||||
|
||||
ptr_ftype_void = build_function_type (ptr_type_node, endlink);
|
||||
builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
|
||||
builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
|
||||
|
||||
builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
|
||||
BUILT_IN_ALLOCA, "alloca");
|
||||
builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
|
||||
|
@ -103,6 +103,7 @@ struct _global_rtl global_rtl =
|
||||
{REG}, /* virtual_stack_vars_rtx */
|
||||
{REG}, /* virtual_stack_dynamic_rtx */
|
||||
{REG}, /* virtual_outgoing_args_rtx */
|
||||
{REG}, /* virtual_cfa_rtx */
|
||||
};
|
||||
|
||||
/* We record floating-point CONST_DOUBLEs in each floating-point mode for
|
||||
@ -3342,6 +3343,7 @@ init_emit ()
|
||||
regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
|
||||
regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
|
||||
regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
|
||||
regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
|
||||
|
||||
/* Indicate that the virtual registers and stack locations are
|
||||
all pointers. */
|
||||
@ -3354,6 +3356,7 @@ init_emit ()
|
||||
REGNO_POINTER_FLAG (VIRTUAL_STACK_VARS_REGNUM) = 1;
|
||||
REGNO_POINTER_FLAG (VIRTUAL_STACK_DYNAMIC_REGNUM) = 1;
|
||||
REGNO_POINTER_FLAG (VIRTUAL_OUTGOING_ARGS_REGNUM) = 1;
|
||||
REGNO_POINTER_FLAG (VIRTUAL_CFA_REGNUM) = 1;
|
||||
|
||||
#ifdef STACK_BOUNDARY
|
||||
REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
|
||||
@ -3370,6 +3373,7 @@ init_emit ()
|
||||
= STACK_BOUNDARY / BITS_PER_UNIT;
|
||||
REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM)
|
||||
= STACK_BOUNDARY / BITS_PER_UNIT;
|
||||
REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = UNITS_PER_WORD;
|
||||
#endif
|
||||
|
||||
#ifdef INIT_EXPANDERS
|
||||
@ -3504,6 +3508,8 @@ init_emit_once (line_numbers)
|
||||
PUT_MODE (virtual_stack_dynamic_rtx, Pmode);
|
||||
REGNO (virtual_outgoing_args_rtx) = VIRTUAL_OUTGOING_ARGS_REGNUM;
|
||||
PUT_MODE (virtual_outgoing_args_rtx, Pmode);
|
||||
REGNO (virtual_cfa_rtx) = VIRTUAL_CFA_REGNUM;
|
||||
PUT_MODE (virtual_cfa_rtx, Pmode);
|
||||
|
||||
#ifdef RETURN_ADDRESS_POINTER_REGNUM
|
||||
return_address_pointer_rtx
|
||||
|
268
gcc/except.c
268
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);
|
||||
The first passes the exception context to the handler. For this
|
||||
we use the return value register for a void*.
|
||||
|
||||
if (GET_CODE (ra) != REG || REGNO (ra) >= FIRST_PSEUDO_REGISTER)
|
||||
return;
|
||||
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.
|
||||
|
||||
tmp = force_operand (expand_builtin_frob_return_addr (addr_tree), ra);
|
||||
if (tmp != ra)
|
||||
emit_move_insn (ra, tmp);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* 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 ()
|
||||
{
|
||||
rtx stub_start = gen_label_rtx ();
|
||||
rtx after_stub = gen_label_rtx ();
|
||||
rtx handler, offset;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
rtx
|
||||
expand_builtin_eh_stub ()
|
||||
{
|
||||
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);
|
||||
|
||||
eh_regs (&handler, &offset, 0);
|
||||
|
||||
adjust_stack (offset);
|
||||
|
||||
/* 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. */
|
||||
|
||||
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));
|
||||
|
||||
emit_indirect_jump (offset);
|
||||
|
||||
emit_label (after_stub);
|
||||
return gen_rtx_LABEL_REF (Pmode, stub_start);
|
||||
}
|
||||
|
||||
/* Set up the registers for passing the handler address and stack offset
|
||||
to the stub above. */
|
||||
/* Set up the epilogue with the magic bits we'll need to return to the
|
||||
exception handler. */
|
||||
|
||||
void
|
||||
expand_builtin_set_eh_regs (handler, offset)
|
||||
tree handler, offset;
|
||||
expand_builtin_eh_return (context, stack, handler)
|
||||
tree context, stack, handler;
|
||||
{
|
||||
rtx reg1, reg2;
|
||||
if (eh_return_context)
|
||||
error("Duplicate call to __builtin_eh_return");
|
||||
|
||||
eh_regs (®1, ®2, 1);
|
||||
|
||||
store_expr (offset, reg2, 0);
|
||||
store_expr (handler, reg1, 0);
|
||||
|
||||
/* These will be used by the stub. */
|
||||
emit_insn (gen_rtx_USE (VOIDmode, reg1));
|
||||
emit_insn (gen_rtx_USE (VOIDmode, reg2));
|
||||
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));
|
||||
}
|
||||
|
||||
void
|
||||
expand_eh_return ()
|
||||
{
|
||||
rtx reg1, reg2, reg3;
|
||||
rtx stub_start, after_stub;
|
||||
rtx ra, tmp;
|
||||
|
||||
if (!eh_return_context)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
/* Talk directly to the target's epilogue code when possible. */
|
||||
|
||||
#ifdef HAVE_eh_epilogue
|
||||
if (HAVE_eh_epilogue)
|
||||
{
|
||||
emit_insn (gen_eh_epilogue (reg1, reg2, reg3));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Otherwise, use the same stub technique we had before. */
|
||||
|
||||
eh_return_stub_label = stub_start = gen_label_rtx ();
|
||||
after_stub = gen_label_rtx ();
|
||||
|
||||
/* Set the return address to the stub label. */
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
/* 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
|
||||
|
12
gcc/except.h
12
gcc/except.h
@ -24,11 +24,9 @@ typedef struct rtx_def *_except_rtx;
|
||||
#define rtx _except_rtx
|
||||
#endif
|
||||
|
||||
/* The labels generated by expand_builtin_eh_stub and
|
||||
expand_builtin_eh_stub_old. */
|
||||
/* The label generated by expand_builtin_eh_return. */
|
||||
|
||||
extern rtx current_function_eh_stub_label;
|
||||
extern rtx current_function_eh_old_stub_label;
|
||||
extern rtx eh_return_stub_label;
|
||||
|
||||
#ifdef TREE_CODE
|
||||
|
||||
@ -377,15 +375,13 @@ extern void expand_fixup_region_end PROTO((tree));
|
||||
|
||||
void expand_builtin_unwind_init PROTO((void));
|
||||
rtx expand_builtin_dwarf_fp_regnum PROTO((void));
|
||||
rtx expand_builtin_eh_stub PROTO((void));
|
||||
rtx expand_builtin_eh_stub_old PROTO((void));
|
||||
#ifdef TREE_CODE
|
||||
rtx expand_builtin_frob_return_addr PROTO((tree));
|
||||
rtx expand_builtin_extract_return_addr PROTO((tree));
|
||||
void expand_builtin_set_return_addr_reg PROTO((tree));
|
||||
void expand_builtin_set_eh_regs PROTO((tree, tree));
|
||||
rtx expand_builtin_dwarf_reg_size PROTO((tree, rtx));
|
||||
void expand_builtin_eh_return PROTO((tree, tree, tree));
|
||||
#endif
|
||||
void expand_eh_return PROTO((void));
|
||||
|
||||
|
||||
/* Checking whether 2 instructions are within the same exception region. */
|
||||
|
20
gcc/expr.c
20
gcc/expr.c
@ -9370,10 +9370,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
case BUILT_IN_UNWIND_INIT:
|
||||
expand_builtin_unwind_init ();
|
||||
return const0_rtx;
|
||||
case BUILT_IN_FP:
|
||||
return frame_pointer_rtx;
|
||||
case BUILT_IN_SP:
|
||||
return stack_pointer_rtx;
|
||||
case BUILT_IN_DWARF_CFA:
|
||||
return virtual_cfa_rtx;
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
case BUILT_IN_DWARF_FP_REGNUM:
|
||||
return expand_builtin_dwarf_fp_regnum ();
|
||||
@ -9384,16 +9382,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
|
||||
case BUILT_IN_EXTRACT_RETURN_ADDR:
|
||||
return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
|
||||
case BUILT_IN_SET_RETURN_ADDR_REG:
|
||||
expand_builtin_set_return_addr_reg (TREE_VALUE (arglist));
|
||||
return const0_rtx;
|
||||
case BUILT_IN_EH_STUB_OLD:
|
||||
return expand_builtin_eh_stub_old ();
|
||||
case BUILT_IN_EH_STUB:
|
||||
return expand_builtin_eh_stub ();
|
||||
case BUILT_IN_SET_EH_REGS:
|
||||
expand_builtin_set_eh_regs (TREE_VALUE (arglist),
|
||||
TREE_VALUE (TREE_CHAIN (arglist)));
|
||||
case BUILT_IN_EH_RETURN:
|
||||
expand_builtin_eh_return (TREE_VALUE (arglist),
|
||||
TREE_VALUE (TREE_CHAIN (arglist)),
|
||||
TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
|
||||
return const0_rtx;
|
||||
|
||||
default: /* just do library call, if unknown builtin */
|
||||
|
13
gcc/flow.c
13
gcc/flow.c
@ -485,8 +485,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
||||
/* Make a list of all labels referred to other than by jumps. */
|
||||
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
|
||||
if (REG_NOTE_KIND (note) == REG_LABEL
|
||||
&& XEXP (note, 0) != current_function_eh_stub_label
|
||||
&& XEXP (note, 0) != current_function_eh_old_stub_label)
|
||||
&& XEXP (note, 0) != eh_return_stub_label)
|
||||
label_value_list = gen_rtx_EXPR_LIST (VOIDmode, XEXP (note, 0),
|
||||
label_value_list);
|
||||
}
|
||||
@ -619,8 +618,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
||||
note = XEXP (note, 1))
|
||||
{
|
||||
if (REG_NOTE_KIND (note) == REG_LABEL
|
||||
&& XEXP (note, 0) != current_function_eh_stub_label
|
||||
&& XEXP (note, 0) != current_function_eh_old_stub_label)
|
||||
&& XEXP (note, 0) != eh_return_stub_label)
|
||||
{
|
||||
x = XEXP (note, 0);
|
||||
block_live[BLOCK_NUM (x)] = 1;
|
||||
@ -708,13 +706,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
|
||||
within it. So we have to make additional edges in the
|
||||
flow graph. */
|
||||
if (i + 1 == n_basic_blocks
|
||||
&& current_function_eh_stub_label != 0)
|
||||
&& eh_return_stub_label != 0)
|
||||
{
|
||||
mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
|
||||
current_function_eh_stub_label),
|
||||
basic_block_end[i], 0);
|
||||
mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
|
||||
current_function_eh_old_stub_label),
|
||||
eh_return_stub_label),
|
||||
basic_block_end[i], 0);
|
||||
}
|
||||
}
|
||||
|
@ -2688,6 +2688,7 @@ static int in_arg_offset;
|
||||
static int var_offset;
|
||||
static int dynamic_offset;
|
||||
static int out_arg_offset;
|
||||
static int cfa_offset;
|
||||
|
||||
/* In most machines, the stack pointer register is equivalent to the bottom
|
||||
of the stack. */
|
||||
@ -2726,6 +2727,13 @@ static int out_arg_offset;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* On a few machines, the CFA coincides with the arg pointer. */
|
||||
|
||||
#ifndef ARG_POINTER_CFA_OFFSET
|
||||
#define ARG_POINTER_CFA_OFFSET 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just had
|
||||
its address taken. DECL is the decl for the object stored in the
|
||||
register, for later use if we do need to force REG into the stack.
|
||||
@ -2910,6 +2918,7 @@ instantiate_virtual_regs (fndecl, insns)
|
||||
var_offset = STARTING_FRAME_OFFSET;
|
||||
dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
|
||||
out_arg_offset = STACK_POINTER_OFFSET;
|
||||
cfa_offset = ARG_POINTER_CFA_OFFSET;
|
||||
|
||||
/* Scan all variables and parameters of this function. For each that is
|
||||
in memory, instantiate all virtual registers if the result is a valid
|
||||
@ -3143,6 +3152,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
|
||||
new = stack_pointer_rtx, offset = - dynamic_offset;
|
||||
else if (SET_DEST (x) == virtual_outgoing_args_rtx)
|
||||
new = stack_pointer_rtx, offset = - out_arg_offset;
|
||||
else if (SET_DEST (x) == virtual_cfa_rtx)
|
||||
new = arg_pointer_rtx, offset = - cfa_offset;
|
||||
|
||||
if (new)
|
||||
{
|
||||
@ -3194,6 +3205,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
|
||||
new = stack_pointer_rtx, offset = dynamic_offset;
|
||||
else if (inner == virtual_outgoing_args_rtx)
|
||||
new = stack_pointer_rtx, offset = out_arg_offset;
|
||||
else if (inner == virtual_cfa_rtx)
|
||||
new = arg_pointer_rtx, offset = cfa_offset;
|
||||
else
|
||||
{
|
||||
loc = &XEXP (x, 0);
|
||||
@ -3213,6 +3226,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
|
||||
new = stack_pointer_rtx, offset = dynamic_offset;
|
||||
else if (XEXP (x, 0) == virtual_outgoing_args_rtx)
|
||||
new = stack_pointer_rtx, offset = out_arg_offset;
|
||||
else if (XEXP (x, 0) == virtual_cfa_rtx)
|
||||
new = arg_pointer_rtx, offset = cfa_offset;
|
||||
else
|
||||
{
|
||||
/* We know the second operand is a constant. Unless the
|
||||
@ -3420,6 +3435,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
|
||||
new = stack_pointer_rtx, offset = dynamic_offset;
|
||||
else if (x == virtual_outgoing_args_rtx)
|
||||
new = stack_pointer_rtx, offset = out_arg_offset;
|
||||
else if (x == virtual_cfa_rtx)
|
||||
new = arg_pointer_rtx, offset = cfa_offset;
|
||||
|
||||
if (new)
|
||||
{
|
||||
@ -5981,6 +5998,10 @@ expand_function_end (filename, line, end_bindings)
|
||||
use_variable (outgoing);
|
||||
}
|
||||
|
||||
/* If this is an implementation of __throw, do what's necessary to
|
||||
communicate between __builtin_eh_return and the epilogue. */
|
||||
expand_eh_return ();
|
||||
|
||||
/* Output a return insn if we are using one.
|
||||
Otherwise, let the rtl chain end here, to drop through
|
||||
into the epilogue. */
|
||||
|
@ -142,8 +142,6 @@ struct function
|
||||
rtx catch_clauses;
|
||||
struct label_node *false_label_stack;
|
||||
struct label_node *caught_return_label_stack;
|
||||
rtx eh_stub_label;
|
||||
rtx eh_old_stub_label;
|
||||
tree protect_list;
|
||||
rtx ehc;
|
||||
|
||||
|
148
gcc/libgcc2.c
148
gcc/libgcc2.c
@ -3492,31 +3492,71 @@ find_exception_handler (void *pc, exception_descriptor *table, void *eh_info)
|
||||
|
||||
typedef int ptr_type __attribute__ ((mode (pointer)));
|
||||
|
||||
/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
|
||||
#ifdef INCOMING_REGNO
|
||||
/* Is the saved value for register REG in frame UDATA stored in a register
|
||||
window in the previous frame? */
|
||||
|
||||
/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
|
||||
to use the macro here. One wonders, though, that perhaps TARGET_FLAT
|
||||
compiled functions won't work with the frame-unwind stuff here.
|
||||
Perhaps the entireity of in_reg_window should be conditional on having
|
||||
seen a DW_CFA_GNU_window_save? */
|
||||
#define target_flags 0
|
||||
|
||||
static int
|
||||
in_reg_window (int reg, frame_state *udata)
|
||||
{
|
||||
if (udata->saved[reg] == REG_SAVED_REG)
|
||||
return INCOMING_REGNO (reg) == reg;
|
||||
if (udata->saved[reg] != REG_SAVED_OFFSET)
|
||||
return 0;
|
||||
|
||||
#ifdef STACK_GROWS_DOWNWARD
|
||||
return udata->reg_or_offset[reg] > 0;
|
||||
#else
|
||||
return udata->reg_or_offset[reg] < 0;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline int in_reg_window (int reg, frame_state *udata) { return 0; }
|
||||
#endif /* INCOMING_REGNO */
|
||||
|
||||
/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
|
||||
frame called by UDATA or 0. */
|
||||
|
||||
static void*
|
||||
get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
|
||||
static word_type *
|
||||
get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
|
||||
{
|
||||
while (udata->saved[reg] == REG_SAVED_REG)
|
||||
{
|
||||
reg = udata->reg_or_offset[reg];
|
||||
if (in_reg_window (reg, udata))
|
||||
{
|
||||
udata = sub_udata;
|
||||
sub_udata = NULL;
|
||||
}
|
||||
}
|
||||
if (udata->saved[reg] == REG_SAVED_OFFSET)
|
||||
return (void *)(ptr_type)
|
||||
*(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
|
||||
else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
|
||||
return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
|
||||
return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
|
||||
else
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
|
||||
frame called by UDATA or 0. */
|
||||
|
||||
static inline void *
|
||||
get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
|
||||
{
|
||||
return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
|
||||
}
|
||||
|
||||
/* Overwrite the saved value for register REG in frame UDATA with VAL. */
|
||||
|
||||
static void
|
||||
static inline void
|
||||
put_reg (unsigned reg, void *val, frame_state *udata)
|
||||
{
|
||||
if (udata->saved[reg] == REG_SAVED_OFFSET)
|
||||
*(word_type *)(udata->cfa + udata->reg_or_offset[reg])
|
||||
= (word_type)(ptr_type) val;
|
||||
else
|
||||
abort ();
|
||||
*get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
|
||||
}
|
||||
|
||||
/* Copy the saved value for register REG from frame UDATA to frame
|
||||
@ -3526,17 +3566,13 @@ put_reg (unsigned reg, void *val, frame_state *udata)
|
||||
static void
|
||||
copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
|
||||
{
|
||||
if (udata->saved[reg] == REG_SAVED_OFFSET
|
||||
&& target_udata->saved[reg] == REG_SAVED_OFFSET)
|
||||
memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
|
||||
udata->cfa + udata->reg_or_offset[reg],
|
||||
__builtin_dwarf_reg_size (reg));
|
||||
else
|
||||
abort ();
|
||||
word_type *preg = get_reg_addr (reg, udata, NULL);
|
||||
word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
|
||||
|
||||
memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));
|
||||
}
|
||||
|
||||
/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
|
||||
frame called by UDATA or 0. */
|
||||
/* Retrieve the return address for frame UDATA. */
|
||||
|
||||
static inline void *
|
||||
get_return_addr (frame_state *udata, frame_state *sub_udata)
|
||||
@ -3576,24 +3612,6 @@ next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
|
||||
return caller_udata;
|
||||
}
|
||||
|
||||
#ifdef INCOMING_REGNO
|
||||
/* Is the saved value for register REG in frame UDATA stored in a register
|
||||
window in the previous frame? */
|
||||
|
||||
static int
|
||||
in_reg_window (int reg, frame_state *udata)
|
||||
{
|
||||
if (udata->saved[reg] != REG_SAVED_OFFSET)
|
||||
return 0;
|
||||
|
||||
#ifdef STACK_GROWS_DOWNWARD
|
||||
return udata->reg_or_offset[reg] > 0;
|
||||
#else
|
||||
return udata->reg_or_offset[reg] < 0;
|
||||
#endif
|
||||
}
|
||||
#endif /* INCOMING_REGNO */
|
||||
|
||||
/* We first search for an exception handler, and if we don't find
|
||||
it, we call __terminate on the current stack frame so that we may
|
||||
use the debugger to walk the stack and understand why no handler
|
||||
@ -3606,7 +3624,7 @@ void
|
||||
__throw ()
|
||||
{
|
||||
struct eh_context *eh = (*get_eh_context) ();
|
||||
void *saved_pc, *pc, *handler, *retaddr;
|
||||
void *saved_pc, *pc, *handler;
|
||||
frame_state ustruct, ustruct2;
|
||||
frame_state *udata = &ustruct;
|
||||
frame_state *sub_udata = &ustruct2;
|
||||
@ -3626,14 +3644,8 @@ label:
|
||||
if (! udata)
|
||||
__terminate ();
|
||||
|
||||
/* We need to get the value from the CFA register. At this point in
|
||||
compiling __throw we don't know whether or not we will use the frame
|
||||
pointer register for the CFA, so we check our unwind info. */
|
||||
if (udata->cfa_reg == __builtin_dwarf_fp_regnum ())
|
||||
udata->cfa = __builtin_fp ();
|
||||
else
|
||||
udata->cfa = __builtin_sp ();
|
||||
udata->cfa += udata->cfa_offset;
|
||||
/* We need to get the value from the CFA register. */
|
||||
udata->cfa = __builtin_dwarf_cfa ();
|
||||
|
||||
memcpy (my_udata, udata, sizeof (*udata));
|
||||
|
||||
@ -3712,7 +3724,6 @@ label:
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
|
||||
if (i != udata->retaddr_column && udata->saved[i])
|
||||
{
|
||||
#ifdef INCOMING_REGNO
|
||||
/* If you modify the saved value of the return address
|
||||
register on the SPARC, you modify the return address for
|
||||
your caller's frame. Don't do that here, as it will
|
||||
@ -3721,14 +3732,12 @@ label:
|
||||
&& udata->saved[udata->retaddr_column] == REG_SAVED_REG
|
||||
&& udata->reg_or_offset[udata->retaddr_column] == i)
|
||||
continue;
|
||||
#endif
|
||||
copy_reg (i, udata, my_udata);
|
||||
}
|
||||
|
||||
pc = get_return_addr (udata, sub_udata) - 1;
|
||||
}
|
||||
|
||||
#ifdef INCOMING_REGNO
|
||||
/* But we do need to update the saved return address register from
|
||||
the last frame we unwind, or the handler frame will have the wrong
|
||||
return address. */
|
||||
@ -3738,42 +3747,17 @@ label:
|
||||
if (in_reg_window (i, udata))
|
||||
copy_reg (i, udata, my_udata);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* udata now refers to the frame called by the handler frame. */
|
||||
|
||||
/* Emit the stub to adjust sp and jump to the handler. */
|
||||
if (new_exception_model)
|
||||
retaddr = __builtin_eh_stub ();
|
||||
else
|
||||
retaddr = __builtin_eh_stub_old ();
|
||||
/* Now go! */
|
||||
|
||||
/* And then set our return address to point to the stub. */
|
||||
if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
|
||||
put_return_addr (retaddr, my_udata);
|
||||
else
|
||||
__builtin_set_return_addr_reg (retaddr);
|
||||
|
||||
/* Set up the registers we use to communicate with the stub.
|
||||
We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
|
||||
|
||||
if (new_exception_model)
|
||||
__builtin_set_eh_regs ((void *)eh,
|
||||
__builtin_eh_return ((void *)eh,
|
||||
#ifdef STACK_GROWS_DOWNWARD
|
||||
udata->cfa - my_udata->cfa
|
||||
udata->cfa - my_udata->cfa,
|
||||
#else
|
||||
my_udata->cfa - udata->cfa
|
||||
my_udata->cfa - udata->cfa,
|
||||
#endif
|
||||
+ args_size);
|
||||
else
|
||||
__builtin_set_eh_regs (handler,
|
||||
|
||||
#ifdef STACK_GROWS_DOWNWARD
|
||||
udata->cfa - my_udata->cfa
|
||||
#else
|
||||
my_udata->cfa - udata->cfa
|
||||
#endif
|
||||
+ args_size);
|
||||
handler);
|
||||
|
||||
/* Epilogue: restore the handler frame's register values and return
|
||||
to the stub. */
|
||||
|
13
gcc/rtl.h
13
gcc/rtl.h
@ -1055,6 +1055,7 @@ extern struct _global_rtl
|
||||
struct rtx_def virtual_stack_vars_val;
|
||||
struct rtx_def virtual_stack_dynamic_val;
|
||||
struct rtx_def virtual_outgoing_args_val;
|
||||
struct rtx_def virtual_cfa_val;
|
||||
} global_rtl;
|
||||
|
||||
/* All references to certain hard regs, except those created
|
||||
@ -1159,7 +1160,17 @@ extern rtx gen_rtx_MEM PROTO((enum machine_mode, rtx));
|
||||
|
||||
#define VIRTUAL_OUTGOING_ARGS_REGNUM ((FIRST_VIRTUAL_REGISTER) + 3)
|
||||
|
||||
#define LAST_VIRTUAL_REGISTER ((FIRST_VIRTUAL_REGISTER) + 3)
|
||||
/* This points to the Canonical Frame Address of the function. This
|
||||
should corrospond to the CFA produced by INCOMING_FRAME_SP_OFFSET,
|
||||
but is calculated relative to the arg pointer for simplicity; the
|
||||
frame pointer nor stack pointer are necessarily fixed relative to
|
||||
the CFA until after reload. */
|
||||
|
||||
#define virtual_cfa_rtx (&global_rtl.virtual_cfa_val)
|
||||
|
||||
#define VIRTUAL_CFA_REGNUM ((FIRST_VIRTUAL_REGISTER) + 4)
|
||||
|
||||
#define LAST_VIRTUAL_REGISTER ((FIRST_VIRTUAL_REGISTER) + 4)
|
||||
|
||||
extern rtx find_next_ref PROTO((rtx, rtx));
|
||||
extern rtx *find_single_use PROTO((rtx, rtx, rtx *));
|
||||
|
11
gcc/tm.texi
11
gcc/tm.texi
@ -2275,6 +2275,17 @@ frame at the beginning of any function, before the prologue. The top of
|
||||
the frame is defined to be the value of the stack pointer in the
|
||||
previous frame, just before the call instruction.
|
||||
|
||||
You only need to define this macro if you want to support call frame
|
||||
debugging information like that provided by DWARF 2.
|
||||
|
||||
@findex ARG_POINTER_CFA_OFFSET
|
||||
@item ARG_POINTER_CFA_OFFSET
|
||||
A C expression whose value is an integer giving the offset, in bytes,
|
||||
from the argument pointer to the canonical frame address (cfa). The
|
||||
final value should coincide with that calculated by
|
||||
@code{INCOMING_FRAME_SP_OFFSET}. Which is unfortunately not usable
|
||||
during virtual register instantiation.
|
||||
|
||||
You only need to define this macro if you want to support call frame
|
||||
debugging information like that provided by DWARF 2.
|
||||
@end table
|
||||
|
@ -101,7 +101,6 @@ enum built_in_function
|
||||
BUILT_IN_FRAME_ADDRESS,
|
||||
BUILT_IN_RETURN_ADDRESS,
|
||||
BUILT_IN_AGGREGATE_INCOMING_ADDRESS,
|
||||
BUILT_IN_CALLER_RETURN_ADDRESS,
|
||||
BUILT_IN_APPLY_ARGS,
|
||||
BUILT_IN_APPLY,
|
||||
BUILT_IN_RETURN,
|
||||
@ -110,16 +109,13 @@ enum built_in_function
|
||||
BUILT_IN_TRAP,
|
||||
|
||||
/* Various hooks for the DWARF 2 __throw routine. */
|
||||
BUILT_IN_FP, BUILT_IN_SP,
|
||||
BUILT_IN_UNWIND_INIT,
|
||||
BUILT_IN_DWARF_CFA,
|
||||
BUILT_IN_DWARF_FP_REGNUM,
|
||||
BUILT_IN_DWARF_REG_SIZE,
|
||||
BUILT_IN_FROB_RETURN_ADDR,
|
||||
BUILT_IN_EXTRACT_RETURN_ADDR,
|
||||
BUILT_IN_SET_RETURN_ADDR_REG,
|
||||
BUILT_IN_EH_STUB_OLD,
|
||||
BUILT_IN_EH_STUB,
|
||||
BUILT_IN_SET_EH_REGS,
|
||||
BUILT_IN_EH_RETURN,
|
||||
|
||||
/* C++ extensions */
|
||||
BUILT_IN_NEW,
|
||||
|
Loading…
x
Reference in New Issue
Block a user