unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.

* unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
	(uw_update_context_1): Use it.
	* config/rs6000/rs6000.c (insn_after_throw): Remove.
	(rs6000_aix_emit_builtin_unwind_init): Save $r2 to its location
	in parent frame if _Unwind_* called directly instead of through
	.plt.
	(rs6000_emit_eh_toc_restore): Remove.
	(rs6000_emit_prologue): Update stack pointer before doing any saving
	if current_function_calls_eh_return.  Generate unwind info for $r2.
	(rs6000_emit_epilogue): Restore stack pointer after doing all
	restoring if current_function_calls_eh_return.  Restore $r2.
	* config/rs6000/rs6000-protos.h (rs6000_emit_eh_toc_restore): Remove.
	* config/rs6000/rs6000.md (eh_return): Remove call to
	rs6000_emit_eh_toc_restore.
	* config/rs6000/linux64.h (MD_FROB_UPDATE_CONTEXT): Define.
	* config/rs6000/aix.h (MD_FROB_UPDATE_CONTEXT): Define.

	* gcc.dg/cleanup-8.c: New test.
	* gcc.dg/cleanup-9.c: New test.

From-SVN: r69450
This commit is contained in:
Jakub Jelinek 2003-07-16 13:52:55 +02:00 committed by Jakub Jelinek
parent 6972c506d4
commit fc4767bbb6
10 changed files with 334 additions and 118 deletions

View File

@ -1,3 +1,22 @@
2003-07-16 Jakub Jelinek <jakub@redhat.com>
* unwind-dw2.c (MD_FROB_UPDATE_CONTEXT): Define.
(uw_update_context_1): Use it.
* config/rs6000/rs6000.c (insn_after_throw): Remove.
(rs6000_aix_emit_builtin_unwind_init): Save $r2 to its location
in parent frame if _Unwind_* called directly instead of through
.plt.
(rs6000_emit_eh_toc_restore): Remove.
(rs6000_emit_prologue): Update stack pointer before doing any saving
if current_function_calls_eh_return. Generate unwind info for $r2.
(rs6000_emit_epilogue): Restore stack pointer after doing all
restoring if current_function_calls_eh_return. Restore $r2.
* config/rs6000/rs6000-protos.h (rs6000_emit_eh_toc_restore): Remove.
* config/rs6000/rs6000.md (eh_return): Remove call to
rs6000_emit_eh_toc_restore.
* config/rs6000/linux64.h (MD_FROB_UPDATE_CONTEXT): Define.
* config/rs6000/aix.h (MD_FROB_UPDATE_CONTEXT): Define.
2003-07-15 Jakub Jelinek <jakub@redhat.com>
* expr.c (emit_block_move): Don't move anything if size is const 0.

View File

@ -209,6 +209,38 @@
So we have to squirrel it away with this. */
#define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init ()
/* If the current unwind info (FS) does not contain explicit info
saving R2, then we have to do a minor amount of code reading to
figure out if it was saved. The big problem here is that the
code that does the save/restore is generated by the linker, so
we have no good way to determine at compile time what to do. */
#ifdef __powerpc64__
#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
do { \
if ((FS)->regs.reg[2].how == REG_UNSAVED) \
{ \
unsigned int *insn \
= (unsigned int *) \
_Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM); \
if (*insn == 0xE8410028) \
_Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \
} \
} while (0)
#else
#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
do { \
if ((FS)->regs.reg[2].how == REG_UNSAVED) \
{ \
unsigned int *insn \
= (unsigned int *) \
_Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM); \
if (*insn == 0x80410014) \
_Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20); \
} \
} while (0)
#endif
#define PROFILE_HOOK(LABEL) output_profile_hook (LABEL)
/* Print subsidiary information on the compiler version in use. */

View File

@ -553,6 +553,24 @@ enum { SIGNAL_FRAMESIZE = 64 };
#ifdef __powerpc64__
/* If the current unwind info (FS) does not contain explicit info
saving R2, then we have to do a minor amount of code reading to
figure out if it was saved. The big problem here is that the
code that does the save/restore is generated by the linker, so
we have no good way to determine at compile time what to do. */
#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \
do { \
if ((FS)->regs.reg[2].how == REG_UNSAVED) \
{ \
unsigned int *insn \
= (unsigned int *) \
_Unwind_GetGR ((CTX), LINK_REGISTER_REGNUM); \
if (*insn == 0xE8410028) \
_Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \
} \
} while (0)
#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
do { \
unsigned char *pc_ = (CONTEXT)->ra; \

View File

@ -126,7 +126,6 @@ extern int mfcr_operation PARAMS ((rtx, enum machine_mode));
extern int mtcrf_operation PARAMS ((rtx, enum machine_mode));
extern int lmw_operation PARAMS ((rtx, enum machine_mode));
extern struct rtx_def *create_TOC_reference PARAMS ((rtx));
extern void rs6000_emit_eh_toc_restore PARAMS ((rtx));
extern void rs6000_split_altivec_in_gprs (rtx *);
extern void rs6000_emit_move PARAMS ((rtx, rtx, enum machine_mode));
extern rtx rs6000_legitimize_address PARAMS ((rtx, rtx, enum machine_mode));

View File

@ -10800,132 +10800,40 @@ create_TOC_reference (symbol)
gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
}
/* __throw will restore its own return address to be the same as the
return address of the function that the throw is being made to.
This is unfortunate, because we want to check the original
return address to see if we need to restore the TOC.
So we have to squirrel it away here.
This is used only in compiling __throw and __rethrow.
/* If _Unwind_* has been called from within the same module,
toc register is not guaranteed to be saved to 40(1) on function
entry. Save it there in that case. */
Most of this code should be removed by CSE. */
static rtx insn_after_throw;
/* This does the saving... */
void
rs6000_aix_emit_builtin_unwind_init ()
{
rtx mem;
rtx stack_top = gen_reg_rtx (Pmode);
rtx opcode_addr = gen_reg_rtx (Pmode);
insn_after_throw = gen_reg_rtx (SImode);
rtx opcode = gen_reg_rtx (SImode);
rtx tocompare = gen_reg_rtx (SImode);
rtx no_toc_save_needed = gen_label_rtx ();
mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
emit_move_insn (stack_top, mem);
mem = gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode, stack_top,
GEN_INT (2 * GET_MODE_SIZE (Pmode))));
emit_move_insn (opcode_addr, mem);
emit_move_insn (insn_after_throw, gen_rtx_MEM (SImode, opcode_addr));
}
/* Emit insns to _restore_ the TOC register, at runtime (specifically
in _eh.o). Only used on AIX.
The idea is that on AIX, function calls look like this:
bl somefunction-trampoline
lwz r2,20(sp)
and later,
somefunction-trampoline:
stw r2,20(sp)
... load function address in the count register ...
bctr
or like this, if the linker determines that this is not a cross-module call
and so the TOC need not be restored:
bl somefunction
nop
or like this, if the compiler could determine that this is not a
cross-module call:
bl somefunction
now, the tricky bit here is that register 2 is saved and restored
by the _linker_, so we can't readily generate debugging information
for it. So we need to go back up the call chain looking at the
insns at return addresses to see which calls saved the TOC register
and so see where it gets restored from.
Oh, and all this gets done in RTL inside the eh_epilogue pattern,
just before the actual epilogue.
On the bright side, this incurs no space or time overhead unless an
exception is thrown, except for the extra code in libgcc.a.
The parameter STACKSIZE is a register containing (at runtime)
the amount to be popped off the stack in addition to the stack frame
of this routine (which will be __throw or __rethrow, and so is
guaranteed to have a stack frame). */
void
rs6000_emit_eh_toc_restore (stacksize)
rtx stacksize;
{
rtx top_of_stack;
rtx bottom_of_stack = gen_reg_rtx (Pmode);
rtx tocompare = gen_reg_rtx (SImode);
rtx opcode = gen_reg_rtx (SImode);
rtx opcode_addr = gen_reg_rtx (Pmode);
rtx mem;
rtx loop_start = gen_label_rtx ();
rtx no_toc_restore_needed = gen_label_rtx ();
rtx loop_exit = gen_label_rtx ();
mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
set_mem_alias_set (mem, rs6000_sr_alias_set);
emit_move_insn (bottom_of_stack, mem);
top_of_stack = expand_binop (Pmode, add_optab,
bottom_of_stack, stacksize,
NULL_RTX, 1, OPTAB_WIDEN);
emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
: 0xE8410028, SImode));
if (insn_after_throw == NULL_RTX)
abort ();
emit_move_insn (opcode, insn_after_throw);
emit_note (NOTE_INSN_LOOP_BEG);
emit_label (loop_start);
do_compare_rtx_and_jump (opcode, tocompare, NE, 1,
SImode, NULL_RTX, NULL_RTX,
no_toc_restore_needed);
mem = gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode, bottom_of_stack,
GEN_INT (5 * GET_MODE_SIZE (Pmode))));
emit_move_insn (gen_rtx_REG (Pmode, 2), mem);
emit_label (no_toc_restore_needed);
do_compare_rtx_and_jump (top_of_stack, bottom_of_stack, EQ, 1,
Pmode, NULL_RTX, NULL_RTX,
loop_exit);
mem = gen_rtx_MEM (Pmode, bottom_of_stack);
set_mem_alias_set (mem, rs6000_sr_alias_set);
emit_move_insn (bottom_of_stack, mem);
mem = gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode, bottom_of_stack,
mem = gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode, stack_top,
GEN_INT (2 * GET_MODE_SIZE (Pmode))));
emit_move_insn (opcode_addr, mem);
emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
: 0xE8410028, SImode));
emit_note (NOTE_INSN_LOOP_CONT);
emit_jump (loop_start);
emit_note (NOTE_INSN_LOOP_END);
emit_label (loop_exit);
do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
SImode, NULL_RTX, NULL_RTX,
no_toc_save_needed);
mem = gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode, stack_top,
GEN_INT (5 * GET_MODE_SIZE (Pmode))));
emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
emit_label (no_toc_save_needed);
}
/* This ties together stack memory (MEM with an alias set of
@ -11347,7 +11255,8 @@ rs6000_emit_prologue ()
|| FP_SAVE_INLINE (info->first_fp_reg_save));
/* For V.4, update stack before we do any saving and set back pointer. */
if (info->push_p && DEFAULT_ABI == ABI_V4)
if (info->push_p
&& (DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
{
if (info->total_size < 32767)
sp_offset = info->total_size;
@ -11575,6 +11484,23 @@ rs6000_emit_prologue ()
{
unsigned int i, regno;
/* In AIX ABI we need to pretend we save r2 here. */
if (TARGET_AIX)
{
rtx addr, reg, mem;
reg = gen_rtx_REG (reg_mode, 2);
addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (sp_offset + 5 * reg_size));
mem = gen_rtx_MEM (reg_mode, addr);
set_mem_alias_set (mem, rs6000_sr_alias_set);
insn = emit_move_insn (mem, reg);
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
NULL_RTX, NULL_RTX);
PATTERN (insn) = gen_blockage ();
}
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
@ -11633,7 +11559,8 @@ rs6000_emit_prologue ()
/* Update stack and set back pointer unless this is V.4,
for which it was done previously. */
if (info->push_p && DEFAULT_ABI != ABI_V4)
if (info->push_p
&& !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
rs6000_emit_allocate_stack (info->total_size, FALSE);
/* Set frame pointer, if needed. */
@ -11812,7 +11739,8 @@ rs6000_emit_epilogue (sibcall)
}
else if (info->push_p)
{
if (DEFAULT_ABI == ABI_V4)
if (DEFAULT_ABI == ABI_V4
|| current_function_calls_eh_return)
sp_offset = info->total_size;
else
{
@ -11897,6 +11825,17 @@ rs6000_emit_epilogue (sibcall)
{
unsigned int i, regno;
if (TARGET_AIX)
{
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (sp_offset + 5 * reg_size));
rtx mem = gen_rtx_MEM (reg_mode, addr);
set_mem_alias_set (mem, rs6000_sr_alias_set);
emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
}
for (i = 0; ; ++i)
{
rtx mem;
@ -12048,7 +11987,8 @@ rs6000_emit_epilogue (sibcall)
(which may not have any obvious dependency on the stack). This
doesn't hurt performance, because there is no scheduling that can
be done after this point. */
if (DEFAULT_ABI == ABI_V4)
if (DEFAULT_ABI == ABI_V4
|| current_function_calls_eh_return)
{
if (frame_reg_rtx != sp_reg_rtx)
rs6000_emit_stack_tie ();

View File

@ -14637,8 +14637,6 @@
""
"
{
if (TARGET_AIX)
rs6000_emit_eh_toc_restore (EH_RETURN_STACKADJ_RTX);
if (TARGET_32BIT)
emit_insn (gen_eh_set_lr_si (operands[0]));
else

View File

@ -1,3 +1,8 @@
2003-07-16 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/cleanup-8.c: New test.
* gcc.dg/cleanup-9.c: New test.
2003-07-16 Danny Smith <dannysmith@users.sourceforge.net>
* g++.dg/ext/dll-MI1.h: New file.

View File

@ -0,0 +1,97 @@
/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
/* Verify that cleanups work with exception handling through signal
frames. */
#include <unwind.h>
#include <stdlib.h>
#include <signal.h>
static _Unwind_Reason_Code
force_unwind_stop (int version, _Unwind_Action actions,
_Unwind_Exception_Class exc_class,
struct _Unwind_Exception *exc_obj,
struct _Unwind_Context *context,
void *stop_parameter)
{
if (actions & _UA_END_OF_STACK)
abort ();
return _URC_NO_REASON;
}
static void force_unwind ()
{
struct _Unwind_Exception *exc = malloc (sizeof (*exc));
exc->exception_class = 0;
exc->exception_cleanup = 0;
#ifndef __USING_SJLJ_EXCEPTIONS__
_Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
#else
_Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
#endif
abort ();
}
int count;
char *null;
static void counter (void *p __attribute__((unused)))
{
++count;
}
static void handler (void *p __attribute__((unused)))
{
if (count != 2)
abort ();
exit (0);
}
static int __attribute__((noinline)) fn5 ()
{
char dummy __attribute__((cleanup (counter)));
force_unwind ();
return 0;
}
static void fn4 (int sig)
{
char dummy __attribute__((cleanup (counter)));
fn5 ();
null = NULL;
}
static void fn3 ()
{
abort ();
}
static int __attribute__((noinline)) fn2 ()
{
*null = 0;
fn3 ();
return 0;
}
static int __attribute__((noinline)) fn1 ()
{
signal (SIGSEGV, fn4);
fn2 ();
return 0;
}
static int __attribute__((noinline)) fn0 ()
{
char dummy __attribute__((cleanup (handler)));
fn1 ();
null = 0;
return 0;
}
int main()
{
fn0 ();
abort ();
}

View File

@ -0,0 +1,101 @@
/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
/* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
/* Verify that cleanups work with exception handling through realtime
signal frames. */
#include <unwind.h>
#include <stdlib.h>
#include <signal.h>
static _Unwind_Reason_Code
force_unwind_stop (int version, _Unwind_Action actions,
_Unwind_Exception_Class exc_class,
struct _Unwind_Exception *exc_obj,
struct _Unwind_Context *context,
void *stop_parameter)
{
if (actions & _UA_END_OF_STACK)
abort ();
return _URC_NO_REASON;
}
static void force_unwind ()
{
struct _Unwind_Exception *exc = malloc (sizeof (*exc));
exc->exception_class = 0;
exc->exception_cleanup = 0;
#ifndef __USING_SJLJ_EXCEPTIONS__
_Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
#else
_Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
#endif
abort ();
}
int count;
char *null;
static void counter (void *p __attribute__((unused)))
{
++count;
}
static void handler (void *p __attribute__((unused)))
{
if (count != 2)
abort ();
exit (0);
}
static int __attribute__((noinline)) fn5 ()
{
char dummy __attribute__((cleanup (counter)));
force_unwind ();
return 0;
}
static void fn4 (int sig, siginfo_t *info, void *ctx)
{
char dummy __attribute__((cleanup (counter)));
fn5 ();
null = NULL;
}
static void fn3 ()
{
abort ();
}
static int __attribute__((noinline)) fn2 ()
{
*null = 0;
fn3 ();
return 0;
}
static int __attribute__((noinline)) fn1 ()
{
struct sigaction s;
sigemptyset (&s.sa_mask);
s.sa_sigaction = fn4;
s.sa_flags = SA_ONESHOT | SA_SIGINFO;
sigaction (SIGSEGV, &s, NULL);
fn2 ();
return 0;
}
static int __attribute__((noinline)) fn0 ()
{
char dummy __attribute__((cleanup (handler)));
fn1 ();
null = 0;
return 0;
}
int main()
{
fn0 ();
abort ();
}

View File

@ -54,6 +54,11 @@
#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
#endif
/* A target can do some update context frobbing. */
#ifndef MD_FROB_UPDATE_CONTEXT
#define MD_FROB_UPDATE_CONTEXT(CTX, FS) do { } while (0)
#endif
/* This is the register and unwind state for a particular frame. This
provides the information necessary to unwind up past a frame and return
to its caller. */
@ -1203,6 +1208,8 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
}
break;
}
MD_FROB_UPDATE_CONTEXT (context, fs);
}
/* CONTEXT describes the unwind state for a frame, and FS describes the FDE