Commit 6e6a07d2 by Mike Stump

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
parent 24f2dbd6
...@@ -693,9 +693,9 @@ add_partial_entry (handler) ...@@ -693,9 +693,9 @@ add_partial_entry (handler)
when there are no more elements in the dynamic handler chain, when when there are no more elements in the dynamic handler chain, when
the value is &top_elt from libgcc2.c. Immediately after the the value is &top_elt from libgcc2.c. Immediately after the
pointer, is an area suitable for setjmp/longjmp when pointer, is an area suitable for setjmp/longjmp when
USE_BUILTIN_SETJMP isn't defined, and an area suitable for DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
__builtin_setjmp/__builtin_longjmp when USE_BUILTIN_SETJMP is __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
defined. isn't defined.
This routine is here to facilitate the porting of this code to This routine is here to facilitate the porting of this code to
systems with threads. One can either replace the routine we emit a systems with threads. One can either replace the routine we emit a
...@@ -843,10 +843,10 @@ static void ...@@ -843,10 +843,10 @@ static void
start_dynamic_handler () start_dynamic_handler ()
{ {
rtx dhc, dcc; rtx dhc, dcc;
rtx x, arg; rtx x, arg, buf;
int size; int size;
#ifdef USE_BUILTIN_SETJMP #ifndef DONT_USE_BUILTIN_SETJMP
/* The number of Pmode words for the setjmp buffer, when using the /* The number of Pmode words for the setjmp buffer, when using the
builtin setjmp/longjmp, see expand_builtin, case builtin setjmp/longjmp, see expand_builtin, case
BUILT_IN_LONGJMP. */ BUILT_IN_LONGJMP. */
...@@ -882,10 +882,14 @@ start_dynamic_handler () ...@@ -882,10 +882,14 @@ start_dynamic_handler ()
emit_move_insn (dcc, const0_rtx); emit_move_insn (dcc, const0_rtx);
/* The jmpbuf starts two words into the area allocated. */ /* 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, x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2), buf, Pmode);
Pmode); #else
x = expand_builtin_setjmp (buf, NULL_RTX);
#endif
/* If we come back here for a catch, transfer control to the /* If we come back here for a catch, transfer control to the
handler. */ handler. */
......
...@@ -7880,6 +7880,169 @@ expand_builtin_return_addr (fndecl_code, count, tem) ...@@ -7880,6 +7880,169 @@ expand_builtin_return_addr (fndecl_code, count, tem)
#endif #endif
return tem; 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, /* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient with result going to TARGET if that's convenient
...@@ -8718,15 +8881,6 @@ expand_builtin (exp, target, subtarget, mode, ignore) ...@@ -8718,15 +8881,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
break; break;
#endif #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: case BUILT_IN_SETJMP:
if (arglist == 0 if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
...@@ -8735,148 +8889,7 @@ expand_builtin (exp, target, subtarget, mode, ignore) ...@@ -8735,148 +8889,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
{ {
rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget, rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
VOIDmode, 0); VOIDmode, 0);
rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx (); return expand_builtin_setjmp (buf_addr, target);
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;
} }
/* __builtin_longjmp is passed a pointer to an array of five words /* __builtin_longjmp is passed a pointer to an array of five words
......
...@@ -685,6 +685,8 @@ extern rtx store_expr PROTO((tree, rtx, int)); ...@@ -685,6 +685,8 @@ extern rtx store_expr PROTO((tree, rtx, int));
Useful after calling expand_expr with 1 as sum_ok. */ Useful after calling expand_expr with 1 as sum_ok. */
extern rtx force_operand PROTO((rtx, rtx)); extern rtx force_operand PROTO((rtx, rtx));
extern rtx expand_builtin_setjmp PROTO((rtx, rtx));
#ifdef TREE_CODE #ifdef TREE_CODE
/* Generate code for computing expression EXP. /* Generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null. An rtx for the computed value is returned. The value is never null.
......
...@@ -3120,7 +3120,7 @@ __terminate () ...@@ -3120,7 +3120,7 @@ __terminate ()
is raised when using the setjmp/longjmp exception handling codegen is raised when using the setjmp/longjmp exception handling codegen
method. */ method. */
extern longjmp (void *, int); extern void longjmp (void *, int);
extern void *__eh_type; extern void *__eh_type;
...@@ -3169,7 +3169,11 @@ __sjthrow () ...@@ -3169,7 +3169,11 @@ __sjthrow ()
buf[0] = (*dhc); buf[0] = (*dhc);
/* try { */ /* try { */
#ifdef DONT_USE_BUILTIN_SETJMP
if (! setjmp (&buf[2])) if (! setjmp (&buf[2]))
#else
if (! __builtin_setjmp (&buf[2]))
#endif
{ {
*dhc = buf; *dhc = buf;
while (cleanup[0]) while (cleanup[0])
...@@ -3206,10 +3210,10 @@ __sjthrow () ...@@ -3206,10 +3210,10 @@ __sjthrow ()
/* And then we jump to the handler. */ /* And then we jump to the handler. */
#ifdef USE_BUILTIN_SETJMP #ifdef DONT_USE_BUILTIN_SETJMP
__builtin_longjmp (jmpbuf, 1);
#else
longjmp (jmpbuf, 1); longjmp (jmpbuf, 1);
#else
__builtin_longjmp (jmpbuf, 1);
#endif #endif
} }
...@@ -3240,7 +3244,11 @@ __sjpopnthrow () ...@@ -3240,7 +3244,11 @@ __sjpopnthrow ()
buf[0] = (*dhc); buf[0] = (*dhc);
/* try { */ /* try { */
#ifdef DONT_USE_BUILTIN_SETJMP
if (! setjmp (&buf[2])) if (! setjmp (&buf[2]))
#else
if (! __builtin_setjmp (&buf[2]))
#endif
{ {
*dhc = buf; *dhc = buf;
while (cleanup[0]) while (cleanup[0])
......
...@@ -4277,7 +4277,7 @@ init_optabs () ...@@ -4277,7 +4277,7 @@ init_optabs ()
sjthrow_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__sjthrow"); sjthrow_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__sjthrow");
sjpopnthrow_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__sjpopnthrow"); sjpopnthrow_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__sjpopnthrow");
terminate_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__terminate"); 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"); setjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__builtin_setjmp");
longjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__builtin_longjmp"); longjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__builtin_longjmp");
#else #else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment