mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-22 15:11:15 +08:00
except.c (start_dynamic_handler): Fix so that we can use __builtin_setjmp...
* except.c (start_dynamic_handler): Fix so that we can use __builtin_setjmp, and default to using __builtin_setjmp instead of setjmp. * expr.c (expand_builtin_setjmp): New routine, split out from existing inline code from expand_builtin. (expand_builtin): Split out code into expand_builtin_setjmp. * expr.h (expand_builtin_setjmp): Add declaration. * libgcc2.c (__sjthrow): Default to using __builtin_setjmp instead of setjmp. (__sjpopnthrow): Likewise. * optabs.c (init_optabs): Likewise. From-SVN: r14045
This commit is contained in:
parent
24f2dbd6f7
commit
6e6a07d299
18
gcc/except.c
18
gcc/except.c
@ -693,9 +693,9 @@ add_partial_entry (handler)
|
||||
when there are no more elements in the dynamic handler chain, when
|
||||
the value is &top_elt from libgcc2.c. Immediately after the
|
||||
pointer, is an area suitable for setjmp/longjmp when
|
||||
USE_BUILTIN_SETJMP isn't defined, and an area suitable for
|
||||
__builtin_setjmp/__builtin_longjmp when USE_BUILTIN_SETJMP is
|
||||
defined.
|
||||
DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
|
||||
__builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
|
||||
isn't defined.
|
||||
|
||||
This routine is here to facilitate the porting of this code to
|
||||
systems with threads. One can either replace the routine we emit a
|
||||
@ -843,10 +843,10 @@ static void
|
||||
start_dynamic_handler ()
|
||||
{
|
||||
rtx dhc, dcc;
|
||||
rtx x, arg;
|
||||
rtx x, arg, buf;
|
||||
int size;
|
||||
|
||||
#ifdef USE_BUILTIN_SETJMP
|
||||
#ifndef DONT_USE_BUILTIN_SETJMP
|
||||
/* The number of Pmode words for the setjmp buffer, when using the
|
||||
builtin setjmp/longjmp, see expand_builtin, case
|
||||
BUILT_IN_LONGJMP. */
|
||||
@ -882,10 +882,14 @@ start_dynamic_handler ()
|
||||
emit_move_insn (dcc, const0_rtx);
|
||||
|
||||
/* The jmpbuf starts two words into the area allocated. */
|
||||
buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
|
||||
|
||||
#ifdef DONT_USE_BUILTIN_SETJMP
|
||||
x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
|
||||
plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2),
|
||||
Pmode);
|
||||
buf, Pmode);
|
||||
#else
|
||||
x = expand_builtin_setjmp (buf, NULL_RTX);
|
||||
#endif
|
||||
|
||||
/* If we come back here for a catch, transfer control to the
|
||||
handler. */
|
||||
|
315
gcc/expr.c
315
gcc/expr.c
@ -7880,6 +7880,169 @@ expand_builtin_return_addr (fndecl_code, count, tem)
|
||||
#endif
|
||||
return tem;
|
||||
}
|
||||
|
||||
/* __builtin_setjmp is passed a pointer to an array of five words (not
|
||||
all will be used on all machines). It operates similarly to the C
|
||||
library function of the same name, but is more efficient. Much of
|
||||
the code below (and for longjmp) is copied from the handling of
|
||||
non-local gotos.
|
||||
|
||||
NOTE: This is intended for use by GNAT and the exception handling
|
||||
scheme in the compiler and will only work in the method used by
|
||||
them. */
|
||||
|
||||
rtx
|
||||
expand_builtin_setjmp (buf_addr, target)
|
||||
rtx buf_addr;
|
||||
rtx target;
|
||||
{
|
||||
rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
|
||||
enum machine_mode sa_mode = Pmode, value_mode;
|
||||
rtx stack_save;
|
||||
int old_inhibit_defer_pop = inhibit_defer_pop;
|
||||
int return_pops
|
||||
= RETURN_POPS_ARGS (get_identifier ("__dummy"),
|
||||
build_function_type (void_type_node, NULL_TREE),
|
||||
0);
|
||||
rtx next_arg_reg;
|
||||
CUMULATIVE_ARGS args_so_far;
|
||||
rtx op0;
|
||||
int i;
|
||||
|
||||
value_mode = TYPE_MODE (integer_type_node);
|
||||
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
buf_addr = convert_memory_address (Pmode, buf_addr);
|
||||
#endif
|
||||
|
||||
buf_addr = force_reg (Pmode, buf_addr);
|
||||
|
||||
if (target == 0 || GET_CODE (target) != REG
|
||||
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
|
||||
target = gen_reg_rtx (value_mode);
|
||||
|
||||
emit_queue ();
|
||||
|
||||
CONST_CALL_P (emit_note (NULL_PTR, NOTE_INSN_SETJMP)) = 1;
|
||||
current_function_calls_setjmp = 1;
|
||||
|
||||
/* We store the frame pointer and the address of lab1 in the buffer
|
||||
and use the rest of it for the stack save area, which is
|
||||
machine-dependent. */
|
||||
emit_move_insn (gen_rtx (MEM, Pmode, buf_addr),
|
||||
virtual_stack_vars_rtx);
|
||||
emit_move_insn
|
||||
(validize_mem (gen_rtx (MEM, Pmode,
|
||||
plus_constant (buf_addr,
|
||||
GET_MODE_SIZE (Pmode)))),
|
||||
gen_rtx (LABEL_REF, Pmode, lab1));
|
||||
|
||||
#ifdef HAVE_save_stack_nonlocal
|
||||
if (HAVE_save_stack_nonlocal)
|
||||
sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
|
||||
#endif
|
||||
|
||||
stack_save = gen_rtx (MEM, sa_mode,
|
||||
plus_constant (buf_addr,
|
||||
2 * GET_MODE_SIZE (Pmode)));
|
||||
emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
|
||||
|
||||
#ifdef HAVE_setjmp
|
||||
if (HAVE_setjmp)
|
||||
emit_insn (gen_setjmp ());
|
||||
#endif
|
||||
|
||||
/* Set TARGET to zero and branch around the other case. */
|
||||
emit_move_insn (target, const0_rtx);
|
||||
emit_jump_insn (gen_jump (lab2));
|
||||
emit_barrier ();
|
||||
emit_label (lab1);
|
||||
|
||||
/* Note that setjmp clobbers FP when we get here, so we have to make
|
||||
sure it's marked as used by this function. */
|
||||
emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
|
||||
|
||||
/* Mark the static chain as clobbered here so life information
|
||||
doesn't get messed up for it. */
|
||||
emit_insn (gen_rtx (CLOBBER, VOIDmode, static_chain_rtx));
|
||||
|
||||
/* Now put in the code to restore the frame pointer, and argument
|
||||
pointer, if needed. The code below is from expand_end_bindings
|
||||
in stmt.c; see detailed documentation there. */
|
||||
#ifdef HAVE_nonlocal_goto
|
||||
if (! HAVE_nonlocal_goto)
|
||||
#endif
|
||||
emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
|
||||
|
||||
current_function_has_nonlocal_goto = 1;
|
||||
|
||||
#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|
||||
if (fixed_regs[ARG_POINTER_REGNUM])
|
||||
{
|
||||
#ifdef ELIMINABLE_REGS
|
||||
static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
|
||||
|
||||
for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
|
||||
if (elim_regs[i].from == ARG_POINTER_REGNUM
|
||||
&& elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
|
||||
break;
|
||||
|
||||
if (i == sizeof elim_regs / sizeof elim_regs [0])
|
||||
#endif
|
||||
{
|
||||
/* Now restore our arg pointer from the address at which it
|
||||
was saved in our stack frame.
|
||||
If there hasn't be space allocated for it yet, make
|
||||
some now. */
|
||||
if (arg_pointer_save_area == 0)
|
||||
arg_pointer_save_area
|
||||
= assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
|
||||
emit_move_insn (virtual_incoming_args_rtx,
|
||||
copy_to_reg (arg_pointer_save_area));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_nonlocal_goto_receiver
|
||||
if (HAVE_nonlocal_goto_receiver)
|
||||
emit_insn (gen_nonlocal_goto_receiver ());
|
||||
#endif
|
||||
/* The static chain pointer contains the address of dummy function.
|
||||
We need to call it here to handle some PIC cases of restoring a
|
||||
global pointer. Then return 1. */
|
||||
op0 = copy_to_mode_reg (Pmode, static_chain_rtx);
|
||||
|
||||
/* We can't actually call emit_library_call here, so do everything
|
||||
it does, which isn't much for a libfunc with no args. */
|
||||
op0 = memory_address (FUNCTION_MODE, op0);
|
||||
|
||||
INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE,
|
||||
gen_rtx (SYMBOL_REF, Pmode, "__dummy"), 1);
|
||||
next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
|
||||
|
||||
#ifndef ACCUMULATE_OUTGOING_ARGS
|
||||
#ifdef HAVE_call_pop
|
||||
if (HAVE_call_pop)
|
||||
emit_call_insn (gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, op0),
|
||||
const0_rtx, next_arg_reg,
|
||||
GEN_INT (return_pops)));
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_call
|
||||
if (HAVE_call)
|
||||
emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, op0),
|
||||
const0_rtx, next_arg_reg, const0_rtx));
|
||||
else
|
||||
#endif
|
||||
abort ();
|
||||
|
||||
emit_move_insn (target, const1_rtx);
|
||||
emit_label (lab2);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/* Expand an expression EXP that calls a built-in function,
|
||||
with result going to TARGET if that's convenient
|
||||
@ -8718,15 +8881,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* __builtin_setjmp is passed a pointer to an array of five words
|
||||
(not all will be used on all machines). It operates similarly to
|
||||
the C library function of the same name, but is more efficient.
|
||||
Much of the code below (and for longjmp) is copied from the handling
|
||||
of non-local gotos.
|
||||
|
||||
NOTE: This is intended for use by GNAT and will only work in
|
||||
the method used by it. This code will likely NOT survive to
|
||||
the GCC 2.8.0 release. */
|
||||
case BUILT_IN_SETJMP:
|
||||
if (arglist == 0
|
||||
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
|
||||
@ -8735,148 +8889,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
{
|
||||
rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
|
||||
VOIDmode, 0);
|
||||
rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
|
||||
enum machine_mode sa_mode = Pmode;
|
||||
rtx stack_save;
|
||||
int old_inhibit_defer_pop = inhibit_defer_pop;
|
||||
int return_pops
|
||||
= RETURN_POPS_ARGS (get_identifier ("__dummy"),
|
||||
build_function_type (void_type_node, NULL_TREE),
|
||||
0);
|
||||
rtx next_arg_reg;
|
||||
CUMULATIVE_ARGS args_so_far;
|
||||
int i;
|
||||
|
||||
#ifdef POINTERS_EXTEND_UNSIGNED
|
||||
buf_addr = convert_memory_address (Pmode, buf_addr);
|
||||
#endif
|
||||
|
||||
buf_addr = force_reg (Pmode, buf_addr);
|
||||
|
||||
if (target == 0 || GET_CODE (target) != REG
|
||||
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
|
||||
target = gen_reg_rtx (value_mode);
|
||||
|
||||
emit_queue ();
|
||||
|
||||
CONST_CALL_P (emit_note (NULL_PTR, NOTE_INSN_SETJMP)) = 1;
|
||||
current_function_calls_setjmp = 1;
|
||||
|
||||
/* We store the frame pointer and the address of lab1 in the buffer
|
||||
and use the rest of it for the stack save area, which is
|
||||
machine-dependent. */
|
||||
emit_move_insn (gen_rtx (MEM, Pmode, buf_addr),
|
||||
virtual_stack_vars_rtx);
|
||||
emit_move_insn
|
||||
(validize_mem (gen_rtx (MEM, Pmode,
|
||||
plus_constant (buf_addr,
|
||||
GET_MODE_SIZE (Pmode)))),
|
||||
gen_rtx (LABEL_REF, Pmode, lab1));
|
||||
|
||||
#ifdef HAVE_save_stack_nonlocal
|
||||
if (HAVE_save_stack_nonlocal)
|
||||
sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
|
||||
#endif
|
||||
|
||||
stack_save = gen_rtx (MEM, sa_mode,
|
||||
plus_constant (buf_addr,
|
||||
2 * GET_MODE_SIZE (Pmode)));
|
||||
emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
|
||||
|
||||
#ifdef HAVE_setjmp
|
||||
if (HAVE_setjmp)
|
||||
emit_insn (gen_setjmp ());
|
||||
#endif
|
||||
|
||||
/* Set TARGET to zero and branch around the other case. */
|
||||
emit_move_insn (target, const0_rtx);
|
||||
emit_jump_insn (gen_jump (lab2));
|
||||
emit_barrier ();
|
||||
emit_label (lab1);
|
||||
|
||||
/* Note that setjmp clobbers FP when we get here, so we have to
|
||||
make sure it's marked as used by this function. */
|
||||
emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
|
||||
|
||||
/* Mark the static chain as clobbered here so life information
|
||||
doesn't get messed up for it. */
|
||||
emit_insn (gen_rtx (CLOBBER, VOIDmode, static_chain_rtx));
|
||||
|
||||
/* Now put in the code to restore the frame pointer, and argument
|
||||
pointer, if needed. The code below is from expand_end_bindings
|
||||
in stmt.c; see detailed documentation there. */
|
||||
#ifdef HAVE_nonlocal_goto
|
||||
if (! HAVE_nonlocal_goto)
|
||||
#endif
|
||||
emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
|
||||
|
||||
current_function_has_nonlocal_goto = 1;
|
||||
|
||||
#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
|
||||
if (fixed_regs[ARG_POINTER_REGNUM])
|
||||
{
|
||||
#ifdef ELIMINABLE_REGS
|
||||
static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
|
||||
|
||||
for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
|
||||
if (elim_regs[i].from == ARG_POINTER_REGNUM
|
||||
&& elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
|
||||
break;
|
||||
|
||||
if (i == sizeof elim_regs / sizeof elim_regs [0])
|
||||
#endif
|
||||
{
|
||||
/* Now restore our arg pointer from the address at which it
|
||||
was saved in our stack frame.
|
||||
If there hasn't be space allocated for it yet, make
|
||||
some now. */
|
||||
if (arg_pointer_save_area == 0)
|
||||
arg_pointer_save_area
|
||||
= assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
|
||||
emit_move_insn (virtual_incoming_args_rtx,
|
||||
copy_to_reg (arg_pointer_save_area));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_nonlocal_goto_receiver
|
||||
if (HAVE_nonlocal_goto_receiver)
|
||||
emit_insn (gen_nonlocal_goto_receiver ());
|
||||
#endif
|
||||
/* The static chain pointer contains the address of dummy function.
|
||||
We need to call it here to handle some PIC cases of restoring
|
||||
a global pointer. Then return 1. */
|
||||
op0 = copy_to_mode_reg (Pmode, static_chain_rtx);
|
||||
|
||||
/* We can't actually call emit_library_call here, so do everything
|
||||
it does, which isn't much for a libfunc with no args. */
|
||||
op0 = memory_address (FUNCTION_MODE, op0);
|
||||
|
||||
INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE,
|
||||
gen_rtx (SYMBOL_REF, Pmode, "__dummy"), 1);
|
||||
next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
|
||||
|
||||
#ifndef ACCUMULATE_OUTGOING_ARGS
|
||||
#ifdef HAVE_call_pop
|
||||
if (HAVE_call_pop)
|
||||
emit_call_insn (gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, op0),
|
||||
const0_rtx, next_arg_reg,
|
||||
GEN_INT (return_pops)));
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_call
|
||||
if (HAVE_call)
|
||||
emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, op0),
|
||||
const0_rtx, next_arg_reg, const0_rtx));
|
||||
else
|
||||
#endif
|
||||
abort ();
|
||||
|
||||
emit_move_insn (target, const1_rtx);
|
||||
emit_label (lab2);
|
||||
return target;
|
||||
return expand_builtin_setjmp (buf_addr, target);
|
||||
}
|
||||
|
||||
/* __builtin_longjmp is passed a pointer to an array of five words
|
||||
|
@ -685,6 +685,8 @@ extern rtx store_expr PROTO((tree, rtx, int));
|
||||
Useful after calling expand_expr with 1 as sum_ok. */
|
||||
extern rtx force_operand PROTO((rtx, rtx));
|
||||
|
||||
extern rtx expand_builtin_setjmp PROTO((rtx, rtx));
|
||||
|
||||
#ifdef TREE_CODE
|
||||
/* Generate code for computing expression EXP.
|
||||
An rtx for the computed value is returned. The value is never null.
|
||||
|
@ -3120,7 +3120,7 @@ __terminate ()
|
||||
is raised when using the setjmp/longjmp exception handling codegen
|
||||
method. */
|
||||
|
||||
extern longjmp (void *, int);
|
||||
extern void longjmp (void *, int);
|
||||
|
||||
extern void *__eh_type;
|
||||
|
||||
@ -3169,7 +3169,11 @@ __sjthrow ()
|
||||
buf[0] = (*dhc);
|
||||
|
||||
/* try { */
|
||||
#ifdef DONT_USE_BUILTIN_SETJMP
|
||||
if (! setjmp (&buf[2]))
|
||||
#else
|
||||
if (! __builtin_setjmp (&buf[2]))
|
||||
#endif
|
||||
{
|
||||
*dhc = buf;
|
||||
while (cleanup[0])
|
||||
@ -3206,10 +3210,10 @@ __sjthrow ()
|
||||
|
||||
/* And then we jump to the handler. */
|
||||
|
||||
#ifdef USE_BUILTIN_SETJMP
|
||||
__builtin_longjmp (jmpbuf, 1);
|
||||
#else
|
||||
#ifdef DONT_USE_BUILTIN_SETJMP
|
||||
longjmp (jmpbuf, 1);
|
||||
#else
|
||||
__builtin_longjmp (jmpbuf, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -3240,7 +3244,11 @@ __sjpopnthrow ()
|
||||
buf[0] = (*dhc);
|
||||
|
||||
/* try { */
|
||||
#ifdef DONT_USE_BUILTIN_SETJMP
|
||||
if (! setjmp (&buf[2]))
|
||||
#else
|
||||
if (! __builtin_setjmp (&buf[2]))
|
||||
#endif
|
||||
{
|
||||
*dhc = buf;
|
||||
while (cleanup[0])
|
||||
|
@ -4277,7 +4277,7 @@ init_optabs ()
|
||||
sjthrow_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__sjthrow");
|
||||
sjpopnthrow_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__sjpopnthrow");
|
||||
terminate_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__terminate");
|
||||
#ifdef USE_BUILTIN_SETJMP
|
||||
#ifndef DONT_USE_BUILTIN_SETJMP
|
||||
setjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__builtin_setjmp");
|
||||
longjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__builtin_longjmp");
|
||||
#else
|
||||
|
Loading…
x
Reference in New Issue
Block a user