From 4573b4de233cd221a8ecbb8fee3ad533dc68ce93 Mon Sep 17 00:00:00 2001
From: Richard Henderson <rth@redhat.com>
Date: Wed, 28 Mar 2001 03:09:20 -0800
Subject: [PATCH] alpha.c (alpha_sa_mask): Add EH_RETURN_DATA_REGNOs.

        * config/alpha/alpha.c (alpha_sa_mask): Add EH_RETURN_DATA_REGNOs.
        (alpha_mark_machine_status): No eh_epilogue_sp_ofs ...
        (alpha_expand_epilogue): ... use EH_RETURN_STACKADJ_RTX instead.
        * config/alpha/alpha.h (machine_function): Remove eh_epilogue_sp_ofs.
        (EH_RETURN_DATA_REGNO): New.
        (EH_RETURN_STACKADJ_RTX, EH_RETURN_HANDLER_RTX): New.
        * config/alpha/alpha.md (eh_epilogue): Remove.
        (exception_receiver): Use $26 for ldgp input.
        * config/alpha/linux.h (MD_FALLBACK_FRAME_STATE_FOR): New.

From-SVN: r40925
---
 gcc/ChangeLog             | 12 +++++++++
 gcc/config/alpha/alpha.c  | 28 +++++++++++++++------
 gcc/config/alpha/alpha.h  | 10 +++++---
 gcc/config/alpha/alpha.md | 20 ++-------------
 gcc/config/alpha/linux.h  | 51 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 93 insertions(+), 28 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index deb12a56c028..66122d4f86ac 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2001-03-28  Richard Henderson  <rth@redhat.com>
+
+        * config/alpha/alpha.c (alpha_sa_mask): Add EH_RETURN_DATA_REGNOs.
+        (alpha_mark_machine_status): No eh_epilogue_sp_ofs ...
+        (alpha_expand_epilogue): ... use EH_RETURN_STACKADJ_RTX instead.
+        * config/alpha/alpha.h (machine_function): Remove eh_epilogue_sp_ofs.
+        (EH_RETURN_DATA_REGNO): New.
+        (EH_RETURN_STACKADJ_RTX, EH_RETURN_HANDLER_RTX): New.
+        * config/alpha/alpha.md (eh_epilogue): Remove.
+        (exception_receiver): Use $26 for ldgp input.
+	* config/alpha/linux.h (MD_FALLBACK_FRAME_STATE_FOR): New.
+
 2001-03-28  Richard Henderson  <rth@redhat.com>
 
 	* except.c: Rewrite entirely for IA-64 ABI exception handling.
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 997fb36e031f..18a61d6c7f6e 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -3664,7 +3664,6 @@ alpha_mark_machine_status (p)
 
   if (machine)
     {
-      ggc_mark_rtx (machine->eh_epilogue_sp_ofs);
       ggc_mark_rtx (machine->ra_rtx);
     }
 }
@@ -4416,6 +4415,18 @@ alpha_sa_mask (imaskP, fmaskP)
 	      fmask |= (1L << (i - 32));
 	  }
 
+      /* We need to restore these for the handler.  */
+      if (current_function_calls_eh_return)
+	{
+	  for (i = 0; ; ++i)
+	    {
+	      unsigned regno = EH_RETURN_DATA_REGNO (i);
+	      if (regno == INVALID_REGNUM)
+		break;
+	      imask |= 1L << regno;
+	    }
+	}
+
       if (imask || fmask || alpha_ra_ever_killed ())
 	imask |= (1L << REG_RA);
     }
@@ -5112,7 +5123,11 @@ alpha_expand_epilogue ()
   fp_offset = 0;
   sa_reg = stack_pointer_rtx;
 
-  eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
+  if (current_function_calls_eh_return)
+    eh_ofs = EH_RETURN_STACKADJ_RTX;
+  else
+    eh_ofs = NULL_RTX;
+
   if (sa_size)
     {
       /* If we have a frame pointer, restore SP from it.  */
@@ -5140,12 +5155,11 @@ alpha_expand_epilogue ()
 	  
       /* Restore registers in order, excepting a true frame pointer. */
 
+      mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
       if (! eh_ofs)
-	{
-	  mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset));
-	  MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
-          FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
-	}
+        MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+      FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
+
       reg_offset += 8;
       imask &= ~(1L << REG_RA);
 
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index dc2a1ec4439f..7d4c194b64b2 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -1213,9 +1213,6 @@ extern struct alpha_compare alpha_compare;
 
 struct machine_function
 {
-  /* An offset to apply to the stack pointer when unwinding from EH.  */
-  struct rtx_def *eh_epilogue_sp_ofs;
-
   /* If non-null, this rtx holds the return address for the function.  */
   struct rtx_def *ra_rtx;
 };
@@ -1342,6 +1339,13 @@ do {						\
 /* Before the prologue, RA lives in $26. */
 #define INCOMING_RETURN_ADDR_RTX  gen_rtx_REG (Pmode, 26)
 #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (26)
+
+/* Describe how we implement __builtin_eh_return.  */
+#define EH_RETURN_DATA_REGNO(N)	((N) < 4 ? (N) + 16 : INVALID_REGNUM)
+#define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (Pmode, 28)
+#define EH_RETURN_HANDLER_RTX \
+  gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, \
+				     current_function_outgoing_args_size))
 
 /* Addressing modes, and classification of registers for them.  */
 
diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md
index 01462c9d306a..3460d42691e8 100644
--- a/gcc/config/alpha/alpha.md
+++ b/gcc/config/alpha/alpha.md
@@ -5900,22 +5900,6 @@
   DONE;
 }")
 
-(define_expand "eh_epilogue"
-  [(use (match_operand:DI 0 "register_operand" "r"))
-   (use (match_operand:DI 1 "register_operand" "r"))
-   (use (match_operand:DI 2 "register_operand" "r"))]
-  "! TARGET_OPEN_VMS"
-  "
-{
-  cfun->machine->eh_epilogue_sp_ofs = operands[1];
-  if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 26)
-    {
-      rtx ra = gen_rtx_REG (Pmode, 26);
-      emit_move_insn (ra, operands[2]);
-      operands[2] = ra;
-    }
-}")
-
 ;; In creating a large stack frame, NT _must_ use ldah+lda to load
 ;; the frame size into a register.  We use this pattern to ensure
 ;; we get lda instead of addq.
@@ -5978,8 +5962,8 @@
 (define_insn "exception_receiver"
   [(unspec_volatile [(const_int 0)] 7)]
   "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
-  "br $29,$LSJ%=\\n$LSJ%=:\;ldgp $29,0($29)"
-  [(set_attr "length" "12")
+  "ldgp $29,0($26)"
+  [(set_attr "length" "8")
    (set_attr "type" "multi")])
 
 (define_expand "nonlocal_goto_receiver"
diff --git a/gcc/config/alpha/linux.h b/gcc/config/alpha/linux.h
index c8f649a75828..1be967e680e9 100644
--- a/gcc/config/alpha/linux.h
+++ b/gcc/config/alpha/linux.h
@@ -44,3 +44,54 @@ SUB_CPP_PREDEFINES
 
 /* Define this so that all GNU/Linux targets handle the same pragmas.  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP
+
+/* 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>
+#endif
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS)		\
+  do {									\
+    unsigned int *pc_ = (CONTEXT)->ra;					\
+    struct sigcontext *sc_;						\
+    long new_cfa_, i_;							\
+									\
+    if (pc_[0] != 0x47fe0410		/* mov $30,$16 */		\
+        || pc_[2] != 0x00000083		/* callsys */)			\
+      break;								\
+    if (pc_[1] == 0x201f0067)		/* lda $0,NR_sigreturn */	\
+      sc_ = (CONTEXT)->cfa;						\
+    else if (pc_[1] == 0x201f015f)	/* lda $0,NR_rt_sigreturn */	\
+      {									\
+	struct rt_sigframe {						\
+	  struct siginfo info;						\
+	  struct ucontext uc;						\
+	} *rt_ = (CONTEXT)->cfa;					\
+	sc_ = &rt_->uc.uc_mcontext;					\
+      }									\
+    else								\
+      break;								\
+    new_cfa_ = sc_->sc_regs[30];					\
+    (FS)->cfa_how = CFA_REG_OFFSET;					\
+    (FS)->cfa_reg = 30;							\
+    (FS)->cfa_offset = new_cfa_ - (long) (CONTEXT)->cfa;		\
+    for (i_ = 0; i_ < 30; ++i_)						\
+      {									\
+	(FS)->regs.reg[i_].how = REG_SAVED_OFFSET;			\
+	(FS)->regs.reg[i_].loc.offset					\
+	  = (long)&sc_->sc_regs[i_] - new_cfa_;				\
+      }									\
+    for (i_ = 0; i_ < 31; ++i_)						\
+      {									\
+	(FS)->regs.reg[i_+32].how = REG_SAVED_OFFSET;			\
+	(FS)->regs.reg[i_+32].loc.offset				\
+	  = (long)&sc_->sc_fpregs[i_] - new_cfa_;			\
+      }									\
+    (FS)->regs.reg[31].how = REG_SAVED_OFFSET;				\
+    (FS)->regs.reg[31].loc.offset = (long)&sc_->sc_pc - new_cfa_;	\
+    (FS)->retaddr_column = 31;						\
+    goto SUCCESS;							\
+  } while (0)
-- 
GitLab