This is the mail archive of the gcc@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]

Re: [PATCH/RFA] SH: DWARF2 exception handling


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;
 }")
 


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