This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH/RFA] SH: DWARF2 exception handling
- From: kaz Kojima <kkojima at rr dot iij4u dot or dot jp>
- To: joern dot rennecke at superh dot com
- Cc: gcc-patches at gcc dot gnu dot org, aoliva at redhat dot com, stephen dot clarke at earthling dot net, gcc at gcc dot gnu dot org
- Date: Wed, 13 Nov 2002 12:27:48 +0900
- Subject: Re: [PATCH/RFA] SH: DWARF2 exception handling
- References: <3DD13E47.34271D79@superh.com>
Thanks a lot for reviewing it.
Joern Rennecke <joern.rennecke@superh.com> wrote:
> Please describe the purpose of all the changes.
The first parts of the patch
> * config.gcc (sh*-*-linux*): Add t-slibgcc-elf-ver and t-linux
> to tmake_file. Remove setting gas and gnu_ld here.
> * config/sh/libgcc-glibc.ver: New file.
> * config/sh/t-linux (EXTRA_MULTILIB_PARTS): Add crtbeginT.o.
> (SHLIB_MAPFILES): New.
> * config/sh/linux.h (MD_EXEC_PREFIX): Undefine.
> (MD_STARTFILE_PREFIX): Likewise.
are to make sh-linux port more compatible with the other linux ports.
The remains are to implement dwarf2 exception handling.
> New functions should also have comments at the top to describe what
> they do.
I'd like to add "Emit code to change the current function's return
address to RA." as a comment for sh_set_return_address (ra, temp).
> It seems that you actually know sh-linux (for SH1 .. SH4) better
> than me. Would you be interested in becoming a gcc sub-maintainer
> for sh-linux?
I'll gladly do so if it will help to reduce the maintainer's load
a little bit.
>> * config/sh/sh.c (push_reg): Push PR_MEDIA_REG last.
>
> This bit doesn't make sense. push_regs is not executed for TARGET_SH5.
Duh! I've missed it. I'd like to revert that part and handle
SH-5 cases in sh_expand_prologue and sh_expand_epilogue directly.
>> * config/sh/sh.h (SH_DBX_REGISTER_NUMBER): Handle PR_MEDIA_REG.
>
> I just happened to find this independently last week - it is also needed
> to get valid call frame debugging information.
Hmm... I'd like to wait your patch about it.
>> Don't abort even if the number is mapped to -1.
>
> Why? When is that expected to be valid?
dwarf2out.c:expand_builtin_init_dwarf_reg_sizes tests the result
of DWARF_FRAME_REGNUM, which is SH_DBX_REGISTER_NUMBER in our case,
for all numbers from 0 to (FIRST_PSEUDO_REGISTER - 1).
Attached is the revised patch, though it would be better to wait
Steve's comments since I can't test it for sh64-linux at all.
Thanks again for your suggestions.
Regards,
kaz
--
2002-11-13 Kaz Kojima <kkojima@gcc.gnu.org>
* config.gcc (sh*-*-linux*): Add t-slibgcc-elf-ver and t-linux
to tmake_file. Remove setting gas and gnu_ld here.
* config/sh/libgcc-glibc.ver: New file.
* config/sh/t-linux (EXTRA_MULTILIB_PARTS): Add crtbeginT.o.
(SHLIB_MAPFILES): New.
* config/sh/linux.h (MD_EXEC_PREFIX): Undefine.
(MD_STARTFILE_PREFIX): Likewise.
(HANDLE_PRAGMA_PACK_PACK_PUSH_POP): Define.
(DWARF2_UNWIND_INFO): Redefine.
(ASM_PREFERRED_EH_DATA_FORMAT): Define.
(LINK_EH_SPEC): Redefine.
(MD_FALLBACK_FRAME_STATE_FOR): Define except for SH-media.
(SH_FALLBACK_FRAME_FLOAT_STATE): Define.
(SH_DWARF_FRAME_GP0, SH_DWARF_FRAME_FP0, SH_DWARF_FRAME_XD0,
SH_DWARF_FRAME_BT0, SH_DWARF_FRAME_PR, SH_DWARF_FRAME_PR_MEDIA,
SH_DWARF_FRAME_GBR, SH_DWARF_FRAME_MACH, SH_DWARF_FRAME_MACL,
SH_DWARF_FRAME_PC, SH_DWARF_FRAME_SR, SH_DWARF_FRAME_FPUL,
SH_DWARF_FRAME_FPSCR): Likewise.
* config/sh/sh-protos.h (sh_set_return_address): Declare.
* config/sh/sh.c (sh_expand_prologue): Push PR_REG or
PR_MEDIA_REG last for TARGET_SH5.
(calc_live_regs): Count PR and EH_RETURN_DATA_REGNO registers
if the current function calls EH return.
(sh_expand_epilogue): Pop PR_REG or PR_MEDIA_REG first for
TARGET_SH5. Handle EH stack adjustments.
(sh_set_return_address): New function.
* config/sh/sh.h (SH_DBX_REGISTER_NUMBER): Handle PR_MEDIA_REG.
Don't abort even if the number is mapped to -1.
(DWARF_FRAME_RETURN_COLUMN): Map with DWARF_FRAME_REGNUM.
(EH_RETURN_DATA_REGNO): Define.
(EH_RETURN_STACKADJ_RTX): Define.
* config/sh/sh.md (UNSPEC_EH_RETURN): New.
(eh_return): New pattern.
(eh_set_ra_di, eh_set_ra_si): Likewise.
Add splitter to perform EH return after reload.
diff -u3prN ORIG/gccbib/gcc/config.gcc LOCAL/gccbib/gcc/config.gcc
--- ORIG/gccbib/gcc/config.gcc Wed Nov 6 04:11:52 2002
+++ LOCAL/gccbib/gcc/config.gcc Sat Nov 9 11:04:46 2002
@@ -2171,7 +2171,7 @@ sh-*-rtems*)
fi
;;
sh-*-linux* | sh[2346lbe]*-*-linux*)
- tmake_file="sh/t-sh sh/t-elf sh/t-linux"
+ tmake_file="sh/t-sh sh/t-elf t-slibgcc-elf-ver t-linux sh/t-linux"
case $machine in
sh*be-*-* | sh*eb-*-*) ;;
*)
@@ -2180,7 +2180,6 @@ sh-*-linux* | sh[2346lbe]*-*-linux*)
;;
esac
tm_file="${tm_file} dbxelf.h elfos.h svr4.h sh/elf.h sh/linux.h"
- gas=yes gnu_ld=yes
case $machine in
sh64*)
tmake_file="${tmake_file} sh/t-sh64"
diff -u3prN ORIG/gccbib/gcc/config/sh/libgcc-glibc.ver LOCAL/gccbib/gcc/config/sh/libgcc-glibc.ver
--- ORIG/gccbib/gcc/config/sh/libgcc-glibc.ver Thu Jan 1 09:00:00 1970
+++ LOCAL/gccbib/gcc/config/sh/libgcc-glibc.ver Sat Nov 9 11:04:46 2002
@@ -0,0 +1,21 @@
+# In order to work around the very problems that force us to now generally
+# create a libgcc.so, glibc reexported a number of routines from libgcc.a.
+# By now choosing the same version tags for these specific routines, we
+# maintain enough binary compatibility to allow future versions of glibc
+# to defer implementation of these routines to libgcc.so via DT_AUXILIARY.
+
+# Note that we cannot use the default libgcc-glibc.ver file on sh,
+# because GLIBC_2.0 does not exist on this architecture, as the first
+# ever glibc release on the platform was GLIBC_2.2.
+
+%inherit GCC_3.0 GLIBC_2.2
+GLIBC_2.2 {
+ __register_frame
+ __register_frame_table
+ __deregister_frame
+ __register_frame_info
+ __deregister_frame_info
+ __frame_state_for
+ __register_frame_info_table
+}
+
diff -u3prN ORIG/gccbib/gcc/config/sh/t-linux LOCAL/gccbib/gcc/config/sh/t-linux
--- ORIG/gccbib/gcc/config/sh/t-linux Wed Jun 19 04:56:53 2002
+++ LOCAL/gccbib/gcc/config/sh/t-linux Sat Nov 9 11:04:46 2002
@@ -8,4 +8,8 @@
MULTILIB_MATCHES =
MULTILIB_EXCEPTIONS=
-EXTRA_MULTILIB_PARTS= crtbegin.o crtend.o crtbeginS.o crtendS.o
+EXTRA_MULTILIB_PARTS= crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o
+
+# Override t-slibgcc-elf-ver to export some libgcc symbols with
+# the symbol versions that glibc used.
+SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver $(srcdir)/config/sh/libgcc-glibc.ver
diff -u3prN ORIG/gccbib/gcc/config/sh/linux.h LOCAL/gccbib/gcc/config/sh/linux.h
--- ORIG/gccbib/gcc/config/sh/linux.h Sun Oct 20 10:03:51 2002
+++ LOCAL/gccbib/gcc/config/sh/linux.h Wed Nov 13 11:50:53 2002
@@ -23,6 +23,22 @@ Boston, MA 02111-1307, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fputs (" (SH GNU/Linux with ELF)", stderr);
+/* We're not SYSVR4, not having /usr/ccs */
+#undef MD_EXEC_PREFIX
+#undef MD_STARTFILE_PREFIX
+
+/* This was defined in linux.h. Define it here also. */
+#define HANDLE_PRAGMA_PACK_PUSH_POP
+
+/* Enable DWARF 2 exceptions. */
+#undef DWARF2_UNWIND_INFO
+#define DWARF2_UNWIND_INFO 1
+
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \
+ (flag_pic \
+ ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4 \
+ : DW_EH_PE_absptr)
+
#undef SUBTARGET_CPP_SPEC
#define SUBTARGET_CPP_SPEC "\
%{posix:-D_POSIX_SOURCE} \
@@ -59,6 +75,11 @@ do { \
%{!shared: %{pthread:-lthread} \
%{profile:-lc_p} %{!profile: -lc}}"
+#if defined(HAVE_LD_EH_FRAME_HDR)
+#undef LINK_EH_SPEC
+#define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
+#endif
+
#undef STARTFILE_SPEC
#define STARTFILE_SPEC \
"%{!shared: \
@@ -66,3 +87,146 @@ do { \
%{!p:%{profile:gcrt1.o%s} \
%{!profile:crt1.o%s}}}} \
crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
+
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-dw2.c for the structs. */
+
+#ifdef IN_LIBGCC2
+#include <signal.h>
+#include <sys/ucontext.h>
+#include "insn-constants.h"
+
+# if defined (__SH5__)
+#define SH_DWARF_FRAME_GP0 0
+#define SH_DWARF_FRAME_FP0 (__SH5__ == 32 ? 245 : 77)
+#define SH_DWARF_FRAME_XD0 289
+#define SH_DWARF_FRAME_BT0 68
+#define SH_DWARF_FRAME_PR 241
+#define SH_DWARF_FRAME_PR_MEDIA 18
+#define SH_DWARF_FRAME_GBR 238
+#define SH_DWARF_FRAME_MACH 239
+#define SH_DWARF_FRAME_MACL 240
+#define SH_DWARF_FRAME_PC 64
+#define SH_DWARF_FRAME_SR 65
+#define SH_DWARF_FRAME_FPUL 244
+#define SH_DWARF_FRAME_FPSCR 243
+#else
+#define SH_DWARF_FRAME_GP0 0
+#define SH_DWARF_FRAME_FP0 25
+#define SH_DWARF_FRAME_XD0 87
+#define SH_DWARF_FRAME_PR 17
+#define SH_DWARF_FRAME_GBR 19
+#define SH_DWARF_FRAME_MACH 20
+#define SH_DWARF_FRAME_MACL 21
+#define SH_DWARF_FRAME_PC 16
+#define SH_DWARF_FRAME_SR 22
+#define SH_DWARF_FRAME_FPUL 23
+#define SH_DWARF_FRAME_FPSCR 24
+#endif /* defined (__SH5__) */
+
+#if defined (__SH5__) && __SH5__ != 32
+/* MD_FALLBACK_FRAME_STATE_FOR is not yet defiened for SHMEDIA. */
+#else /* defined (__SH5__) && __SH5__ != 32 */
+
+#if defined (__SH3E__) || defined (__SH4__) || defined (__SH5__)
+#define SH_FALLBACK_FRAME_FLOAT_STATE(SC, FS, CFA) \
+ do { \
+ int i_, r_; \
+ \
+ r_ = SH_DWARF_FRAME_FP0; \
+ for (i_ = 0; i_ < 16; i_++) \
+ { \
+ (FS)->regs.reg[r_+i_].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[r_+i_].loc.offset \
+ = (long)&((SC)->sc_fpregs[i_]) - (CFA); \
+ } \
+ \
+ r_ = SH_DWARF_FRAME_XD0 ; \
+ for (i_ = 0; i_ < 8; i_++) \
+ { \
+ (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[i_].loc.offset \
+ = (long)&((SC)->sc_xfpregs[2*i_]) - (CFA); \
+ } \
+ \
+ (FS)->regs.reg[SH_DWARF_FRAME_FPUL].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_FPUL].loc.offset \
+ = (long)&((SC)->sc_fpul) - (CFA); \
+ (FS)->regs.reg[SH_DWARF_FRAME_FPSCR].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_FPSCR].loc.offset \
+ = (long)&((SC)->sc_fpscr) - (CFA); \
+ } while (0)
+
+#else
+#define SH_FALLBACK_FRAME_FLOAT_STATE(SC, FS, CFA)
+#endif
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
+ do { \
+ unsigned char *pc_ = (CONTEXT)->ra; \
+ struct sigcontext *sc_; \
+ long new_cfa_; \
+ int i_; \
+ \
+ /* mov.w 1f,r3; trapa #0x10; 1: .short 0x77 (sigreturn) */ \
+ /* mov.w 1f,r3; trapa #0x10; 1: .short 0xad (rt_sigreturn) */ \
+ if ((*(unsigned short *) (pc_+0) == 0x9300) \
+ && (*(unsigned short *) (pc_+2) == 0xc310) \
+ && (*(unsigned short *) (pc_+4) == 0x0077)) \
+ sc_ = (CONTEXT)->cfa; \
+ else if ((*(unsigned short *) (pc_+0) == 0x9300) \
+ && (*(unsigned short *) (pc_+2) == 0xc310) \
+ && (*(unsigned short *) (pc_+4) == 0x00ad)) \
+ { \
+ struct rt_sigframe { \
+ struct siginfo info; \
+ struct ucontext uc; \
+ } *rt_ = (CONTEXT)->cfa; \
+ sc_ = (struct sigcontext *) &rt_->uc.uc_mcontext; \
+ } \
+ else \
+ break; \
+ \
+ new_cfa_ = sc_->sc_regs[15]; \
+ (FS)->cfa_how = CFA_REG_OFFSET; \
+ (FS)->cfa_reg = 15; \
+ (FS)->cfa_offset = new_cfa_ - (long) (CONTEXT)->cfa; \
+ \
+ for (i_ = 0; i_ < 15; i_++) \
+ { \
+ (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[i_].loc.offset \
+ = (long)&(sc_->sc_regs[i_]) - new_cfa_; \
+ } \
+ \
+ (FS)->regs.reg[SH_DWARF_FRAME_PR].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_PR].loc.offset \
+ = (long)&(sc_->sc_pr) - new_cfa_; \
+ (FS)->regs.reg[SH_DWARF_FRAME_SR].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_SR].loc.offset \
+ = (long)&(sc_->sc_sr) - new_cfa_; \
+ (FS)->regs.reg[SH_DWARF_FRAME_GBR].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_GBR].loc.offset \
+ = (long)&(sc_->sc_gbr) - new_cfa_; \
+ (FS)->regs.reg[SH_DWARF_FRAME_MACH].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_MACH].loc.offset \
+ = (long)&(sc_->sc_mach) - new_cfa_; \
+ (FS)->regs.reg[SH_DWARF_FRAME_MACL].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_MACL].loc.offset \
+ = (long)&(sc_->sc_macl) - new_cfa_; \
+ \
+ SH_FALLBACK_FRAME_FLOAT_STATE(sc_, (FS), new_cfa_); \
+ \
+ /* The unwinder expects the PC to point to the following insn, \
+ whereas the kernel returns the address of the actual \
+ faulting insn. */ \
+ sc_->sc_pc += 2; \
+ (FS)->regs.reg[SH_DWARF_FRAME_PC].how = REG_SAVED_OFFSET; \
+ (FS)->regs.reg[SH_DWARF_FRAME_PC].loc.offset \
+ = (long)&(sc_->sc_pc) - new_cfa_; \
+ (FS)->retaddr_column = SH_DWARF_FRAME_PC; \
+ goto SUCCESS; \
+ } while (0)
+
+#endif /* defined (__SH5__) && __SH5__ != 32 */
+#endif /* IN_LIBGCC2 */
diff -u3prN ORIG/gccbib/gcc/config/sh/sh-protos.h LOCAL/gccbib/gcc/config/sh/sh-protos.h
--- ORIG/gccbib/gcc/config/sh/sh-protos.h Wed Nov 6 04:12:15 2002
+++ LOCAL/gccbib/gcc/config/sh/sh-protos.h Sat Nov 9 11:04:46 2002
@@ -120,6 +120,7 @@ extern int sh_media_register_for_return
extern void sh_expand_prologue PARAMS ((void));
extern void sh_expand_epilogue PARAMS ((void));
extern int sh_need_epilogue PARAMS ((void));
+extern void sh_set_return_address PARAMS ((rtx, rtx));
extern int initial_elimination_offset PARAMS ((int, int));
extern int fldi_ok PARAMS ((void));
extern int sh_pr_n_sets PARAMS ((void));
diff -u3prN ORIG/gccbib/gcc/config/sh/sh.c LOCAL/gccbib/gcc/config/sh/sh.c
--- ORIG/gccbib/gcc/config/sh/sh.c Wed Nov 6 04:12:15 2002
+++ LOCAL/gccbib/gcc/config/sh/sh.c Wed Nov 13 11:29:44 2002
@@ -4432,6 +4432,8 @@ calc_live_regs (count_ptr, live_regs_mas
& ~ CALL_COOKIE_RET_TRAMP (1))
|| current_function_has_nonlocal_label))
pr_live = 1;
+ if (current_function_calls_eh_return)
+ pr_live = 1;
for (count = 0, reg = FIRST_PSEUDO_REGISTER - 1; reg >= 0; reg--)
{
if (reg == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG)
@@ -4446,7 +4448,12 @@ calc_live_regs (count_ptr, live_regs_mas
&& reg != RETURN_ADDRESS_POINTER_REGNUM
&& reg != T_REG && reg != GBR_REG)
: (/* Only push those regs which are used and need to be saved. */
- regs_ever_live[reg] && ! call_used_regs[reg]))
+ (regs_ever_live[reg] && ! call_used_regs[reg])
+ || (current_function_calls_eh_return
+ && (reg == EH_RETURN_DATA_REGNO (0)
+ || reg == EH_RETURN_DATA_REGNO (1)
+ || reg == EH_RETURN_DATA_REGNO (2)
+ || reg == EH_RETURN_DATA_REGNO (3)))))
{
live_regs_mask[reg / 32] |= 1 << (reg % 32);
count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
@@ -4619,6 +4626,9 @@ sh_expand_prologue ()
rtx r0 = gen_rtx_REG (Pmode, R0_REG);
int offset_in_r0 = -1;
int sp_in_r0 = 0;
+ int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
+ bool need_pr = false;
+ int next;
if (d % (STACK_BOUNDARY / BITS_PER_UNIT))
d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT)
@@ -4632,7 +4642,7 @@ sh_expand_prologue ()
proceed to saving 32-bit registers that don't need 8-byte
alignment. */
for (align = 1; align >= 0; align--)
- for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
+ for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i = next)
if (live_regs_mask[i/32] & (1 << (i % 32)))
{
enum machine_mode mode = REGISTER_NATURAL_MODE (i);
@@ -4648,6 +4658,24 @@ sh_expand_prologue ()
reg--;
}
+ if (i == pr_reg)
+ {
+ if (need_pr == false)
+ {
+ next = i - 1;
+ continue;
+ }
+
+ next = -1;
+ }
+ else if (align == 0 && i == 0)
+ {
+ need_pr = true;
+ next = pr_reg;
+ }
+ else
+ next = i - 1;
+
/* If we're doing the aligned pass and this is not aligned,
or we're doing the unaligned pass and this is aligned,
skip it. */
@@ -4757,6 +4785,23 @@ sh_expand_prologue ()
emit_move_insn (mem_rtx, reg_rtx);
}
+ else
+ {
+ if (i == pr_reg)
+ {
+ if (need_pr == false)
+ next = i - 1;
+ else
+ next = -1;
+ }
+ else if (align == 0 && i == 0)
+ {
+ need_pr = true;
+ next = pr_reg;
+ }
+ else
+ next = i - 1;
+ }
if (offset != d_rounding)
abort ();
@@ -4891,13 +4936,17 @@ sh_expand_epilogue ()
int sp_in_r0 = 0;
int align;
rtx r0 = gen_rtx_REG (Pmode, R0_REG);
+ int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
+ bool need_pr = true;
+ int first = pr_reg;
+ int next;
/* We loop twice: first, we save 8-byte aligned registers in the
higher addresses, that are known to be aligned. Then, we
proceed to saving 32-bit registers that don't need 8-byte
alignment. */
for (align = 0; align <= 1; align++)
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ for (i = first; i < FIRST_PSEUDO_REGISTER; i = next)
if (live_regs_mask[i/32] & (1 << (i % 32)))
{
enum machine_mode mode = REGISTER_NATURAL_MODE (i);
@@ -4912,6 +4961,21 @@ sh_expand_epilogue ()
i++;
}
+ if (i == pr_reg)
+ {
+ if (need_pr == false)
+ {
+ next = i + 1;
+ continue;
+ }
+
+ need_pr = false;
+ first = 0;
+ next = 0;
+ }
+ else
+ next = i + 1;
+
/* If we're doing the aligned pass and this is not aligned,
or we're doing the unaligned pass and this is aligned,
skip it. */
@@ -5015,6 +5079,22 @@ sh_expand_epilogue ()
offset += GET_MODE_SIZE (mode);
}
+ else
+ {
+ if (i == pr_reg)
+ {
+ if (need_pr == false)
+ next = i + 1;
+ else
+ {
+ need_pr = false;
+ first = 0;
+ next = 0;
+ }
+ }
+ else
+ next = i + 1;
+ }
if (offset != d + d_rounding)
abort ();
@@ -5042,6 +5122,10 @@ sh_expand_epilogue ()
+ current_function_args_info.stack_regs * 8,
stack_pointer_rtx, 7, emit_insn);
+ if (current_function_calls_eh_return)
+ emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx,
+ EH_RETURN_STACKADJ_RTX));
+
/* Switch back to the normal stack if necessary. */
if (sp_switch)
emit_insn (gen_sp_switch_2 ());
@@ -5070,6 +5154,32 @@ sh_need_epilogue ()
sh_need_epilogue_known = (epilogue == NULL ? -1 : 1);
}
return sh_need_epilogue_known > 0;
+}
+
+/* Emit code to change the current function's return address to RA. */
+
+void
+sh_set_return_address (ra, tmp)
+ rtx ra, tmp;
+{
+ HOST_WIDE_INT live_regs_mask[(FIRST_PSEUDO_REGISTER + 31) / 32];
+ int d;
+ int d_rounding = 0;
+ int frame_size;
+
+ calc_live_regs (&d, live_regs_mask);
+
+ if (TARGET_SH5 && d % (STACK_BOUNDARY / BITS_PER_UNIT))
+ d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT)
+ - d % (STACK_BOUNDARY / BITS_PER_UNIT));
+
+ frame_size = (rounded_frame_size (d) - d_rounding
+ + SHMEDIA_REGS_STACK_ADJUST ());
+ emit_insn (GEN_MOV (tmp, GEN_INT (frame_size)));
+ emit_insn (GEN_ADD3 (tmp, tmp, frame_pointer_rtx));
+
+ tmp = gen_rtx_MEM (Pmode, tmp);
+ emit_insn (GEN_MOV (tmp, ra));
}
/* Clear variables at function end. */
diff -u3prN ORIG/gccbib/gcc/config/sh/sh.h LOCAL/gccbib/gcc/config/sh/sh.h
--- ORIG/gccbib/gcc/config/sh/sh.h Wed Nov 6 04:12:16 2002
+++ LOCAL/gccbib/gcc/config/sh/sh.h Sat Nov 9 11:04:46 2002
@@ -2953,6 +2953,8 @@ while (0)
? ((REGNO) - FIRST_TARGET_REG + 68) \
: (REGNO) == PR_REG \
? (TARGET_SH5 ? 241 : 17) \
+ : (REGNO) == PR_MEDIA_REG \
+ ? (TARGET_SH5 ? 18 : -1) \
: (REGNO) == T_REG \
? (TARGET_SH5 ? 242 : 18) \
: (REGNO) == GBR_REG \
@@ -2963,7 +2965,7 @@ while (0)
? (TARGET_SH5 ? 240 : 21) \
: (REGNO) == FPUL_REG \
? (TARGET_SH5 ? 244 : 23) \
- : (abort(), -1))
+ : -1)
/* This is how to output a reference to a user-level label named NAME. */
#define ASM_OUTPUT_LABELREF(FILE, NAME) \
@@ -3302,7 +3304,13 @@ extern int rtx_equal_function_value_matt
#define MD_CAN_REDIRECT_BRANCH(INSN, SEQ) \
sh_can_redirect_branch ((INSN), (SEQ))
-#define DWARF_FRAME_RETURN_COLUMN (TARGET_SH5 ? PR_MEDIA_REG : PR_REG)
+#define DWARF_FRAME_RETURN_COLUMN \
+ DWARF_FRAME_REGNUM (TARGET_SH5 ? PR_MEDIA_REG : PR_REG)
+
+#define EH_RETURN_DATA_REGNO(N) \
+ ((N) < 4 ? (N) + (TARGET_SH5 ? 2 : 4) : INVALID_REGNUM)
+
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM)
#if (defined CRT_BEGIN || defined CRT_END) && ! __SHMEDIA__
/* SH constant pool breaks the devices in crtstuff.c to control section
diff -u3prN ORIG/gccbib/gcc/config/sh/sh.md LOCAL/gccbib/gcc/config/sh/sh.md
--- ORIG/gccbib/gcc/config/sh/sh.md Wed Nov 6 04:12:16 2002
+++ LOCAL/gccbib/gcc/config/sh/sh.md Sat Nov 9 11:04:46 2002
@@ -135,6 +135,7 @@
(UNSPEC_FSINA 16)
(UNSPEC_NSB 17)
(UNSPEC_ALLOCO 18)
+ (UNSPEC_EH_RETURN 19)
;; These are used with unspec_volatile.
(UNSPECV_BLOCKAGE 0)
@@ -7134,6 +7135,48 @@
{
sh_expand_epilogue ();
emit_jump_insn (gen_return ());
+ DONE;
+}")
+
+(define_expand "eh_return"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "register_operand" ""))]
+ ""
+{
+ rtx tmp, sa = operands[0], ra = operands[1];
+
+ if (TARGET_SHMEDIA64)
+ emit_insn (gen_eh_set_ra_di (ra));
+ else
+ emit_insn (gen_eh_set_ra_si (ra));
+
+ emit_move_insn (EH_RETURN_STACKADJ_RTX, sa);
+ DONE;
+})
+
+;; Clobber the return address on the stack. We can't expand this
+;; until we know where it will be put in the stack frame.
+
+(define_insn "eh_set_ra_si"
+ [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
+ (clobber (match_scratch:SI 1 "=&r"))]
+ "! TARGET_SHMEDIA64"
+ "#")
+
+(define_insn "eh_set_ra_di"
+ [(unspec [(match_operand:DI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
+ (clobber (match_scratch:DI 1 "=&r"))]
+ "TARGET_SHMEDIA64"
+ "#")
+
+(define_split
+ [(unspec [(match_operand 0 "register_operand" "")] UNSPEC_EH_RETURN)
+ (clobber (match_scratch 1 ""))]
+ "reload_completed"
+ [(const_int 0)]
+ "
+{
+ sh_set_return_address (operands[0], operands[1]);
DONE;
}")