This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH/RFA] SH: DWARF2 exception handling


Hi,

This patch is mainly for exception handling using DWARF2 on
sh-linux targets.
Bootstrapped and no new regressions on sh4-unknown-linux-gnu.
I'm not certain this is ok for sh64-linux. Steve, does this
work for you?

BTW, I have a corresponding libffi/libjava patch, now it
reduces libjava regressions to 16.

Regards,
	kaz
--
2002-08-22  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 (push_reg): Push PR_MEDIA_REG last.
	(calc_live_regs): Count PR and EH_RETURN_DATA_REGNO registers
	if the current function calls EH return.
	(sh_expand_epilogue): Pop PR_MEDIA_REG first. 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 -urN ORIG/gcc/gcc/config.gcc LOCAL/gcc/gcc/config.gcc
--- ORIG/gcc/gcc/config.gcc	Tue Aug 20 19:54:31 2002
+++ LOCAL/gcc/gcc/config.gcc	Wed Aug 21 10:05:37 2002
@@ -2253,7 +2253,7 @@
 	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-*-*) ;;
 	*)
@@ -2262,7 +2262,6 @@
 		;;
 	esac
 	tm_file="${tm_file} dbxelf.h elfos.h svr4.h sh/elf.h sh/linux.h"
-	gas=yes gnu_ld=yes
 	float_format=sh
 	case $machine in
 	sh64*)
diff -urN ORIG/gcc/gcc/config/sh/libgcc-glibc.ver LOCAL/gcc/gcc/config/sh/libgcc-glibc.ver
--- ORIG/gcc/gcc/config/sh/libgcc-glibc.ver	Thu Jan  1 09:00:00 1970
+++ LOCAL/gcc/gcc/config/sh/libgcc-glibc.ver	Tue Aug 20 20:02:28 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 -urN ORIG/gcc/gcc/config/sh/t-linux LOCAL/gcc/gcc/config/sh/t-linux
--- ORIG/gcc/gcc/config/sh/t-linux	Fri Jun 21 13:20:24 2002
+++ LOCAL/gcc/gcc/config/sh/t-linux	Tue Aug 20 20:02:28 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 -urN ORIG/gcc/gcc/config/sh/linux.h LOCAL/gcc/gcc/config/sh/linux.h
--- ORIG/gcc/gcc/config/sh/linux.h	Fri Jun 14 17:43:23 2002
+++ LOCAL/gcc/gcc/config/sh/linux.h	Tue Aug 20 20:02:28 2002
@@ -23,6 +23,22 @@
 #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} \
@@ -58,6 +74,11 @@
    %{!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: \
@@ -65,3 +86,146 @@
 		       %{!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 0x77,r3; trapa #0x10  (sigreturn)  */			\
+    /* mov 0xad,r3; trapa #0x10  (rt_sigreturn)  */			\
+    if ((*(unsigned short *) (pc_+0) == 0xe377)				\
+	&& (*(unsigned short *) (pc_+2)  == 0xc310))			\
+      sc_ = (CONTEXT)->cfa;						\
+    else if ((*(unsigned short *) (pc_+0) == 0xe3ad)			\
+	&& (*(unsigned short *) (pc_+2)  == 0xc310))			\
+      {									\
+	struct rt_sigframe {						\
+	  struct siginfo *pinfo;					\
+	  void *puc;							\
+	  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 -urN ORIG/gcc/gcc/config/sh/sh-protos.h LOCAL/gcc/gcc/config/sh/sh-protos.h
--- ORIG/gcc/gcc/config/sh/sh-protos.h	Wed Aug 14 13:21:49 2002
+++ LOCAL/gcc/gcc/config/sh/sh-protos.h	Tue Aug 20 20:02:28 2002
@@ -120,6 +120,7 @@
 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 -urN ORIG/gcc/gcc/config/sh/sh.c LOCAL/gcc/gcc/config/sh/sh.c
--- ORIG/gcc/gcc/config/sh/sh.c	Wed Aug 14 13:21:50 2002
+++ LOCAL/gcc/gcc/config/sh/sh.c	Wed Aug 21 07:56:38 2002
@@ -4365,15 +4365,16 @@
      HOST_WIDE_INT *mask;
 {
   int i;
+  int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
 
   /* Push PR last; this gives better latencies after the prologue, and
      candidates for the return delay slot when there are no general
      registers pushed.  */
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (i != PR_REG && mask[i / 32] & (1 << (i % 32)))
+    if (i != pr_reg && mask[i / 32] & (1 << (i % 32)))
       push (i);
-  if (mask[PR_REG / 32] & (1 << (PR_REG % 32)))
-    push (PR_REG);
+  if (mask[pr_reg / 32] & (1 << (pr_reg % 32)))
+    push (pr_reg);
 }
 
 /* Work out the registers which need to be saved, both as a mask and a
@@ -4426,6 +4427,8 @@
 	   & ~ 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)
@@ -4440,7 +4443,12 @@
 	     && reg != RETURN_ADDRESS_POINTER_REGNUM
 	     && reg != T_REG && reg != GBR_REG && reg != FPSCR_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));
@@ -4828,6 +4836,7 @@
   HOST_WIDE_INT live_regs_mask[(FIRST_PSEUDO_REGISTER + 31) / 32];
   int d, i;
   int d_rounding = 0;
+  int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
 
   int save_flags = target_flags;
   int frame_size;
@@ -5017,13 +5026,13 @@
     }
   else
     d = 0;
-  if (live_regs_mask[PR_REG / 32] & (1 << (PR_REG % 32)))
-    pop (PR_REG);
+  if (live_regs_mask[pr_reg / 32] & (1 << (pr_reg % 32)))
+    pop (pr_reg);
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       int j = (FIRST_PSEUDO_REGISTER - 1) - i;
 
-      if (j != PR_REG && live_regs_mask[j / 32] & (1 << (j % 32)))
+      if (j != pr_reg && live_regs_mask[j / 32] & (1 << (j % 32)))
 	pop (j);
     }
  finish:
@@ -5036,6 +5045,10 @@
 		       + 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 ());
@@ -5064,6 +5077,30 @@
       sh_need_epilogue_known = (epilogue == NULL ? -1 : 1);
     }
   return sh_need_epilogue_known > 0;
+}
+
+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 -urN ORIG/gcc/gcc/config/sh/sh.h LOCAL/gcc/gcc/config/sh/sh.h
--- ORIG/gcc/gcc/config/sh/sh.h	Thu Aug  1 13:18:22 2002
+++ LOCAL/gcc/gcc/config/sh/sh.h	Tue Aug 20 20:02:28 2002
@@ -2956,6 +2956,8 @@
    ? ((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 \
@@ -2966,7 +2968,7 @@
    ? (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)			\
@@ -3307,7 +3309,13 @@
 #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 -urN ORIG/gcc/gcc/config/sh/sh.md LOCAL/gcc/gcc/config/sh/sh.md
--- ORIG/gcc/gcc/config/sh/sh.md	Thu Aug  1 13:18:22 2002
+++ LOCAL/gcc/gcc/config/sh/sh.md	Tue Aug 20 20:02:28 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)
@@ -7257,6 +7258,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 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;
 }")
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]