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]

Re: problem with -fno-sjlj-exceptions on alpha (ss 970907)


> The problem is that the generated __throw procedure wants to modify
> its return address, in order to peel off the outermost stack frame.

The problem in egcs 970907 is that __builtin_return_address isn't
actually implemented for the Alpha.

But this usage is annoying, since it prohibits a rather nicer
implementation of __b_r_a I'd worked up last week.  So here's one
that uses elimination to find its target on the stack.


r~


Wed Sep 10 19:13:25 1997  Richard Henderson  <rth@cygnus.com>

	* alpha.c (alpha_function_save_ra): New variable.
	([VMS] alpha_sa_mask, [*] alpha_sa_size): Respect it.
	([*] output_epilog): Reset it.

	* alpha.h (RETURN_ADDRESS_POINTER_REGNUM): New.
	(FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS,
	 REG_ALLOC_ORDER, REGISTER_NAMES): Account for new "hard" reg.
	(REGNO_OK_FOR_BASE_P): Account for new "hard" integer reg.
	(ELIMINABLE_REGS, CAN_ELIMINATE, INITIAL_ELIMINATION_OFFSET):
	Eliminations for RAP.
	(RETURN_ADDR_RTX): Use return_address_pointer_rtx.
	(INCOMING_RETURN_ADDR_RTX): New.

	* rtl.h (return_address_pointer_rtx): Add declaration.


Index: rtl.h
===================================================================
RCS file: /cvs/cvsfiles/egcs/gcc/rtl.h,v
retrieving revision 1.4
diff -u -p -d -r1.4 rtl.h
--- rtl.h	1997/08/28 13:08:51	1.4
+++ rtl.h	1997/09/11 02:09:35
@@ -862,6 +862,7 @@ extern rtx struct_value_rtx;
 extern rtx struct_value_incoming_rtx;
 extern rtx static_chain_rtx;
 extern rtx static_chain_incoming_rtx;
+extern rtx return_address_pointer_rtx;
 
 /* If HARD_FRAME_POINTER_REGNUM is defined, then a special dummy reg
    is used to represent the frame pointer.  This is because the
Index: config/alpha/alpha.c
===================================================================
RCS file: /cvs/cvsfiles/egcs/gcc/config/alpha/alpha.c,v
retrieving revision 1.1.1.1
diff -u -p -d -r1.1.1.1 alpha.c
--- alpha.c	1997/08/11 15:57:20	1.1.1.1
+++ alpha.c	1997/09/11 02:09:35
@@ -83,6 +83,10 @@ static int trap_pending = 0;
 
 int alpha_function_needs_gp;
 
+/* Nonzero if the current function needs ra to be saved.  */
+
+int alpha_function_save_ra;
+
 extern char *version_string;
 extern int rtx_equal_function_value_matters;
 
@@ -1663,6 +1667,8 @@ alpha_sa_mask (imaskP, fmaskP)
 
   if (is_stack_procedure)
     imask |= (1L << HARD_FRAME_POINTER_REGNUM);
+  if (alpha_function_save_ra)
+    imask |= (1L << 26);
 
   /* One for every register we have to save.  */
 
@@ -1697,7 +1703,8 @@ alpha_sa_size ()
   /* Start by assuming we can use a register procedure if we don't make any
      calls (REG_RA not used) or need to save any registers and a stack
      procedure if we do.  */
-  is_stack_procedure = regs_ever_live[REG_RA] || sa_size != 0;
+  is_stack_procedure = (regs_ever_live[REG_RA] || sa_size != 0
+			|| alpha_function_save_ra);
 
   /* Decide whether to refer to objects off our PV via FP or PV.
      If we need need FP for something else or if we receive a nonlocal
@@ -1760,7 +1767,7 @@ alpha_sa_size ()
 
   /* If some registers were saved but not reg 26, reg 26 must also
      be saved, so leave space for it.  */
-  if (size != 0 && ! regs_ever_live[26])
+  if ((size != 0 || alpha_function_save_ra) && ! regs_ever_live[26])
     size++;
 
   /* Our size must be even (multiple of 16 bytes).  */
@@ -2296,6 +2303,8 @@ output_epilog (file, size)
 
   /* Show that we know this function if it is called again.  */
   SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
+
+  alpha_function_save_ra = 0;
 }
 
 #else /* !OPEN_VMS */
@@ -2618,6 +2627,8 @@ output_epilog (file, size)
 
   /* Show that we know this function if it is called again.  */
   SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
+
+  alpha_function_save_ra = 0;
 }
 #endif /* !OPEN_VMS */
 
Index: config/alpha/alpha.h
===================================================================
RCS file: /cvs/cvsfiles/egcs/gcc/config/alpha/alpha.h,v
retrieving revision 1.3
diff -u -p -d -r1.3 alpha.h
--- alpha.h	1997/09/02 19:37:05	1.3
+++ alpha.h	1997/09/11 02:09:35
@@ -443,9 +443,11 @@ extern void override_options ();
 
    Likewise, we use $f31 for the frame pointer, which will always
    be eliminated in favor of the hardware frame pointer or the
-   stack pointer.  */
+   stack pointer.
 
-#define FIRST_PSEUDO_REGISTER 64
+   Finally, we use 64 for the return address pointer elimination target. */
+
+#define FIRST_PSEUDO_REGISTER 65
 
 /* 1 for registers that have pervasive standard uses
    and are not available for the register allocator.  */
@@ -454,7 +456,7 @@ extern void override_options ();
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, \
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }
 
 /* 1 for registers not available across function calls.
    These must include the FIXED_REGISTERS and also any
@@ -466,7 +468,7 @@ extern void override_options ();
  {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, \
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, \
   1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \
-  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
 
 /* List the order in which to allocate registers.  Each register must be
    listed once, even those in FIXED_REGISTERS.
@@ -507,7 +509,7 @@ extern void override_options ();
    26,					\
    15,					\
    29,					\
-   30, 31, 63 }
+   30, 31, 63, 64 }
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
    to hold something of mode MODE.
@@ -557,6 +559,10 @@ extern void override_options ();
 /* Base register for access to local variables of function.  */
 #define FRAME_POINTER_REGNUM 63
 
+/* Fake register that holds the address on the stack of the current
+   function's return address.  */
+#define RETURN_ADDRESS_POINTER_REGNUM 64
+
 /* Register in which static-chain is passed to a function. 
 
    For the Alpha, this is based on an example; the calling sequence
@@ -836,19 +842,19 @@ enum reg_class { NO_REGS, GENERAL_REGS, 
    followed by "to".  Eliminations of the same "from" register are listed
    in order of preference.  */
 
-#define ELIMINABLE_REGS				     \
-{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},	     \
- { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},   \
- { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},	     \
- { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
+#define ELIMINABLE_REGS						\
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM },			\
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM },		\
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM },		\
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM },		\
+ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM },	\
+ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }}
 
 /* Given FROM and TO register numbers, say whether this elimination is allowed.
-   Frame pointer elimination is automatically handled.
-
-   All eliminations are valid since the cases where FP can't be
-   eliminated are already handled.  */
+   Frame pointer elimination is automatically handled.  */
 
-#define CAN_ELIMINATE(FROM, TO) 1
+#define CAN_ELIMINATE(FROM, TO) \
+  (!frame_pointer_needed || (TO) == HARD_FRAME_POINTER_REGNUM)
 
 /* Round up to a multiple of 16 bytes.  */
 #define ALPHA_ROUND(X) (((X) + 15) & ~ 15)
@@ -856,16 +862,22 @@ enum reg_class { NO_REGS, GENERAL_REGS, 
 /* Define the offset between two registers, one to be eliminated, and the other
    its replacement, at the start of a routine.  */
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
-{ if ((FROM) == FRAME_POINTER_REGNUM)					\
-    (OFFSET) = (ALPHA_ROUND (current_function_outgoing_args_size)	\
-		+ alpha_sa_size ());					\
-  else if ((FROM) == ARG_POINTER_REGNUM)				\
-    (OFFSET) = (ALPHA_ROUND (current_function_outgoing_args_size)	\
-		+ alpha_sa_size ()					\
-		+ (ALPHA_ROUND (get_frame_size ()			\
-			       + current_function_pretend_args_size)	\
-		   - current_function_pretend_args_size));		\
-}
+do {									\
+  (OFFSET) = 0;								\
+  switch (FROM)								\
+    {									\
+    default: 								\
+      abort ();								\
+    case ARG_POINTER_REGNUM:						\
+      (OFFSET) += (ALPHA_ROUND (get_frame_size ()			\
+			        + current_function_pretend_args_size)	\
+		   - current_function_pretend_args_size);		\
+    case FRAME_POINTER_REGNUM:						\
+      (OFFSET) += alpha_sa_size ();					\
+    case RETURN_ADDRESS_POINTER_REGNUM:					\
+      (OFFSET) += ALPHA_ROUND (current_function_outgoing_args_size);	\
+    }									\
+} while (0)
 
 /* Define this if stack space is still allocated for a parameter passed
    in a register.  */
@@ -1254,16 +1266,22 @@ __enable_execute_stack (addr)						\
 /* A C expression whose value is RTL representing the value of the return
    address for the frame COUNT steps up from the current frame.
    FRAMEADDR is the frame pointer of the COUNT frame, or the frame pointer of
-   the COUNT-1 frame if RETURN_ADDR_IN_PREVIOUS_FRAME} is defined.
+   the COUNT-1 frame if RETURN_ADDR_IN_PREVIOUS_FRAME} is defined.  */
 
-   This definition for Alpha is broken, but is put in at the request of
-   Mike Stump.  */
+/* Sadly, the exception handling bits expect this to be a *writable*
+   value, so we can't use the trick of copying $26 into a pseudo at
+   the beginning of the function.  Not unless we arrange to copy it 
+   back at the end, and that would be very messy.
+
+   So we try elimination to the stack slot instead.  */
+
+extern int alpha_function_save_ra;
 
 #define RETURN_ADDR_RTX(COUNT, FRAME)					\
-((COUNT == 0 && alpha_sa_size () == 0 && 0 /* not right. */)		\
- ? gen_rtx (REG, Pmode, 26)						\
- : gen_rtx (MEM, Pmode,							\
-	    memory_address (Pmode, FRAME)))
+  ((COUNT) == 0								\
+   ? alpha_function_save_ra = 1,					\
+     gen_rtx (MEM, Pmode, return_address_pointer_rtx)			\
+   : const0_rtx)
 
 /* Addressing modes, and classification of registers for them.  */
 
@@ -1282,9 +1300,12 @@ __enable_execute_stack (addr)						\
    has been allocated, which happens in local-alloc.c.  */
 
 #define REGNO_OK_FOR_INDEX_P(REGNO) 0
-#define REGNO_OK_FOR_BASE_P(REGNO) \
-((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32  \
- || (REGNO) == 63 || reg_renumber[REGNO] == 63)
+#define REGNO_OK_FOR_BASE_P(REGNO)				\
+  ((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32		\
+   || (REGNO) == FRAME_POINTER_REGNUM				\
+   || reg_renumber[REGNO] == FRAME_POINTER_REGNUM		\
+   || (REGNO) == RETURN_ADDRESS_POINTER_REGNUM			\
+   || reg_renumber[REGNO] == RETURN_ADDRESS_POINTER_REGNUM)
 
 /* Maximum number of registers that can appear in a valid memory address.  */
 #define MAX_REGS_PER_ADDRESS 1
@@ -1324,8 +1345,11 @@ __enable_execute_stack (addr)						\
 #define REG_OK_FOR_INDEX_P(X) 0
 /* Nonzero if X is a hard reg that can be used as a base reg
    or if it is a pseudo reg.  */
-#define REG_OK_FOR_BASE_P(X)  \
-  (REGNO (X) < 32 || REGNO (X) == 63 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
+#define REG_OK_FOR_BASE_P(X)				\
+  (REGNO (X) < 32					\
+   || REGNO (X) == FRAME_POINTER_REGNUM			\
+   || REGNO (X) == RETURN_ADDRESS_POINTER_REGNUM	\
+   || REGNO (X) >= FIRST_PSEUDO_REGISTER)
 
 #else
 
@@ -1805,7 +1829,7 @@ literal_section ()						\
  "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8",	\
  "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",		\
  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",\
- "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "FP"}
+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "FP", "RAP" }
 
 /* How to renumber registers for dbx and gdb.  */
 


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