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:
Richard Henderson 1998-09-15 12:19:12 -07:00 committed by Richard Henderson
parent dfb16e8307
commit 710384268d
20 changed files with 385 additions and 290 deletions

View File

@ -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

View File

@ -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,

View File

@ -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. */

View File

@ -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 ();

View File

@ -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"

View File

@ -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),

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 (&reg1, &reg2, 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 (&reg1, &reg2, &reg3, 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 (&reg1, &reg2, &reg3, 0);
adjust_stack (reg2);
emit_indirect_jump (reg3);
emit_label (after_stub);
}
/* This contains the code required to verify whether arbitrary instructions

View File

@ -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. */

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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. */

View File

@ -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;

View File

@ -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. */

View File

@ -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 *));

View File

@ -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

View File

@ -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,