dwarf2 frame note and eh patch for hppa-linux

John David Anglin dave@hiauly1.hia.nrc.ca
Wed Apr 3 19:15:00 GMT 2002


This patch fixes the majority of problems with dwarf2 frame notes and exception
handling under hppa-linux.  It has been bootstrapped and extensively tested
under hppa-linux.  It fixes many g++ and libstdc++ testsuite failures.
At this time, only the failure of new3.C is dwarf2 related and this appears
to be a problem with the dynamic loader rather than gcc.  The test passes
with static linkage.  I have also checked that it bootstraps and checks under
hppa2.0w-hp-hpux11.11 with no regressions.

I wish to thank Olivier Hainque for his support, debugging and testing
under hpux.  However, dwarf2 support under hpux is not yet implemented.
It should be possible in the near future to get dwarf2 debugging and
exception handling working under hpux, both for the 32 and 64-bit ports.

There are lots of things that I don't like about the current implementation.
We have lost a couple of optimizations and had to add a blockage in the
prologue to keep insns with frame notes out of the delay slot of call
insns.  Testing indicated that there are problems with the computed
length of calls insns.  This has been fixed for normal calls but not
for millicode calls.  However, the current fix is overly pessimistic
when frame notes are not being used and work needs to be done to
improve the generated code for long calls.  This is particularly a
problem under linux.  Anyway, I thought it time to get some real world
testing.

Installed on the trunk.

Dave
-- 
J. David Anglin                                  dave.anglin@nrc.ca
National Research Council of Canada              (613) 990-0752 (FAX: 952-6605)

2002-04-03  John David Anglin  <dave@hiauly1.hia.nrc.ca>

	* pa-linux.h (INCOMING_RETURN_ADDR_RTX): Move.
	(DWARF_FRAME_RETURN_COLUMN): Move.
	(ASM_PREFERRED_EH_DATA_FORMAT): Define.
	(ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Define.
	* pa.c (except.h, predict.h): Include.
	(FRP): Delete.
	(store_reg_modify, set_reg_plus_d): Revise prototypes.
	(output_ascii): Add cast.
	(store_reg_modify): Revise to add frame notes.
	(set_reg_plus_d): Likewise.
	(compute_frame_size): Include space for eh data registers in frame if
	the current function calls eh_return.
	(hppa_expand_prologue):  Ensure register %r2 is saved if the current
	function calls eh_return.  Save eh data registers if the current
	function calls eh_return.  Fix code to add frame notes.  Emit
	blockage to prevent insns with frame notes being scheduled in the
	delay slot of calls.
	(hppa_expand_epilogue): Restore eh data registers and do final stack
	adjustment if the current function calls eh_return.  Don't add frame
	notes.
	(output_call): Revise for change in length of call insn.  Don't do
	return pointer adjustment for an unconditional jump in the delay slot
	of a call when using frame notes.
	* pa.h (EH_RETURN_DATA_REGNO): Revise for TARGET_64BIT compatibility.
	(EH_RETURN_HANDLER_RTX): Use saved value on stack.
	(ARG_POINTER_CFA_OFFSET): Define.
	* pa.md (return_external_pic): New pattern.
	(prologue): Correct formatting.  Use return_external_pic if current
	function calls eh_return.
	(call_internal_symref, call_value_internal_symref,
	sibcall_internal_symref, sibcall_value_internal_symref): Change default
	lengths of short, long non-pic, and long pic calls to 8, 68, and 84,
	respectively.
	(exception_receiver): Use hppa_pic_save_rtx () to restore pic register.

Index: pa-linux.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa-linux.h,v
retrieving revision 1.14
diff -u -3 -p -r1.14 pa-linux.h
--- pa-linux.h	28 Mar 2002 23:13:01 -0000	1.14
+++ pa-linux.h	3 Apr 2002 18:02:40 -0000
@@ -24,6 +24,39 @@ Boston, MA 02111-1307, USA.  */
 #define DWARF2_ASM_LINE_DEBUG_INFO 1
 #define DWARF2_UNWIND_INFO 1
 
+/* A C expression whose value is RTL representing the location of the
+   incoming return address at the beginning of any function, before the
+   prologue.  You only need to define this macro if you want to support
+   call frame debugging information like that provided by DWARF 2.  */
+#define INCOMING_RETURN_ADDR_RTX (gen_rtx_REG (word_mode, 2))
+#define DWARF_FRAME_RETURN_COLUMN (DWARF_FRAME_REGNUM (2))
+
+/* This macro chooses the encoding of pointers embedded in the exception
+   handling sections.  If at all possible, this should be defined such
+   that the exception handling section will not require dynamic relocations,
+   and so may be read-only.
+
+   FIXME: We use DW_EH_PE_aligned to output a PLABEL constructor for
+   global function pointers.  */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL)			\
+  (CODE == 2 && GLOBAL ? DW_EH_PE_aligned : DW_EH_PE_absptr)
+
+/* Handle special EH pointer encodings.  Absolute, pc-relative, and
+   indirect are handled automatically.  Since pc-relative encoding is
+   not possible on the PA and we don't have the infrastructure for
+   data relative encoding, we use aligned plabels for global function
+   pointers.  */
+#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \
+  do {									\
+    if (((ENCODING) & 0x0F) == DW_EH_PE_aligned)			\
+      {									\
+	fputs (integer_asm_op (SIZE, FALSE), FILE);			\
+	fputs ("P%", FILE);						\
+	assemble_name (FILE, XSTR (ADDR, 0));				\
+	goto DONE;							\
+      }									\
+    } while (0)
+
 #undef CPP_PREDEFINES
 #define CPP_PREDEFINES "-D__ELF__ -Dunix -D__hppa__ -Dlinux -Asystem=unix -Asystem=posix -Acpu=hppa -Amachine=hppa -Amachine=bigendian"
 
@@ -63,12 +96,6 @@ Boston, MA 02111-1307, USA.  */
     data_section ();					\
   else							\
     readonly_data_section ();
-
-/* A C expression whose value is RTL representing the location of the
-   incoming return address at the beginning of any function, before the
-   prologue.  */
-#define INCOMING_RETURN_ADDR_RTX  (gen_rtx_REG (word_mode, 2))
-#define DWARF_FRAME_RETURN_COLUMN (DWARF_FRAME_REGNUM (2))
 
 /* Define the strings used for the special svr4 .type and .size directives.
    These strings generally do not vary from one system running svr4 to
Index: pa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.149
diff -u -3 -p -r1.149 pa.c
--- pa.c	6 Mar 2002 04:59:28 -0000	1.149
+++ pa.c	3 Apr 2002 18:02:41 -0000
@@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-attr.h"
 #include "flags.h"
 #include "tree.h"
+#include "except.h"
 #include "expr.h"
 #include "optabs.h"
 #include "libfuncs.h"
@@ -43,6 +44,7 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "ggc.h"
 #include "recog.h"
+#include "predict.h"
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
@@ -55,18 +57,6 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #endif
 
-#if DO_FRAME_NOTES
-#define FRP(INSN) \
-  do					\
-    {					\
-      rtx insn = INSN;			\
-      RTX_FRAME_RELATED_P (insn) = 1;	\
-    }					\
-  while (0)
-#else
-#define FRP(INSN) INSN
-#endif
-
 #ifndef FUNC_BEGIN_PROLOG_LABEL
 #define FUNC_BEGIN_PROLOG_LABEL        "LFBP"
 #endif
@@ -83,8 +73,9 @@ static int compute_movstrsi_length PARAM
 static bool pa_assemble_integer PARAMS ((rtx, unsigned int, int));
 static void remove_useless_addtr_insns PARAMS ((rtx, int));
 static void store_reg PARAMS ((int, int, int));
+static void store_reg_modify PARAMS ((int, int, int));
 static void load_reg PARAMS ((int, int, int));
-static void set_reg_plus_d PARAMS ((int, int, int));
+static void set_reg_plus_d PARAMS ((int, int, int, int));
 static void pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
 static int pa_adjust_cost PARAMS ((rtx, rtx, rtx, int));
 static int pa_adjust_priority PARAMS ((rtx, int));
@@ -2662,7 +2653,7 @@ output_ascii (file, p, size)
 	  fputs ("\"\n\t.STRING \"", file);
 	  chars_output = 0;
 	}
-      fwrite (partial_output, 1, co, file);
+      fwrite (partial_output, 1, (size_t) co, file);
       chars_output += co;
       co = 0;
     }
@@ -2933,15 +2924,60 @@ store_reg (reg, disp, base)
     RTX_FRAME_RELATED_P (insn) = 1;
 }
 
-/* Emit RTL to set REG to the value specified by BASE+DISP.
-   Handle case where DISP > 8k by using the add_high_const patterns.
+/* Emit RTL to store REG at the memory location specified by BASE and then
+   add MOD to BASE.  MOD must be <= 8k.  */
 
-   Note in DISP > 8k case, we will leave the high part of the address
-   in %r1.  There is code in expand_hppa_{prologue,epilogue} that knows this.*/
+static void
+store_reg_modify (base, reg, mod)
+     int base, reg, mod;
+{
+  rtx insn, basereg, srcreg, delta;
+
+  if (! VAL_14_BITS_P (mod))
+    abort ();
+
+  basereg = gen_rtx_REG (Pmode, base);
+  srcreg = gen_rtx_REG (word_mode, reg);
+  delta = GEN_INT (mod);
+
+  insn = emit_insn (gen_post_store (basereg, srcreg, delta));
+  if (DO_FRAME_NOTES)
+    {
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* RTX_FRAME_RELATED_P must be set on each frame related set
+	 in a parallel with more than one element.  Don't set
+	 RTX_FRAME_RELATED_P in the first set if reg is temporary
+	 register 1. The effect of this operation is recorded in
+	 the initial copy.  */
+      if (reg != 1)
+	{
+	  RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 0)) = 1;
+	  RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
+	}
+      else
+	{
+	  /* The first element of a PARALLEL is always processed if it is
+	     a SET.  Thus, we need an expression list for this case.  */
+	  REG_NOTES (insn)
+	    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+		gen_rtx_SET (VOIDmode, basereg,
+			     gen_rtx_PLUS (word_mode, basereg, delta)),
+                REG_NOTES (insn));
+	}
+    }
+}
+
+/* Emit RTL to set REG to the value specified by BASE+DISP.  Handle case
+   where DISP > 8k by using the add_high_const patterns.  NOTE indicates
+   whether to add a frame note or not.
+
+   In the DISP > 8k case, we leave the high part of the address in %r1.
+   There is code in expand_hppa_{prologue,epilogue} that knows about this.  */
 
 static void
-set_reg_plus_d (reg, base, disp)
-     int reg, base, disp;
+set_reg_plus_d (reg, base, disp, note)
+     int reg, base, disp, note;
 {
   rtx insn;
 
@@ -2963,7 +2999,7 @@ set_reg_plus_d (reg, base, disp)
 					     delta));
     }
 
-  if (DO_FRAME_NOTES && reg == STACK_POINTER_REGNUM)
+  if (DO_FRAME_NOTES && note)
     RTX_FRAME_RELATED_P (insn) = 1;
 }
 
@@ -2981,6 +3017,18 @@ compute_frame_size (size, fregs_live)
      of them at the same time.  */
   fsize = size + (size || frame_pointer_needed ? STARTING_FRAME_OFFSET : 0);
 
+  /* If the current function calls __builtin_eh_return, then we need
+     to allocate stack space for registers that will hold data for
+     the exception handler.  */
+  if (DO_FRAME_NOTES && current_function_calls_eh_return)
+    {
+      unsigned int i;
+
+      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
+	continue;
+      fsize += i * UNITS_PER_WORD;
+    }
+
   /* Account for space used by the callee general register saves.  */
   for (i = 18; i >= 3; i--)
     if (regs_ever_live[i])
@@ -3108,7 +3156,7 @@ hppa_expand_prologue ()
   int size = get_frame_size ();
   int merge_sp_adjust_with_store = 0;
   int i, offset;
-  rtx tmpreg, size_rtx;
+  rtx insn, tmpreg;
 
   gr_saved = 0;
   fr_saved = 0;
@@ -3126,12 +3174,11 @@ hppa_expand_prologue ()
 
   /* Compute a few things we will use often.  */
   tmpreg = gen_rtx_REG (word_mode, 1);
-  size_rtx = GEN_INT (actual_fsize);
 
   /* Save RP first.  The calling conventions manual states RP will
      always be stored into the caller's frame at sp - 20 or sp - 16
      depending on which ABI is in use.  */
-  if (regs_ever_live[2])
+  if (regs_ever_live[2] || current_function_calls_eh_return)
     store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
 
   /* Allocate the local frame and set up the frame pointer if needed.  */
@@ -3141,36 +3188,30 @@ hppa_expand_prologue ()
 	{
 	  /* Copy the old frame pointer temporarily into %r1.  Set up the
 	     new stack pointer, then store away the saved old frame pointer
-	     into the stack at sp+actual_fsize and at the same time update
-	     the stack pointer by actual_fsize bytes.  Two versions, first
+	     into the stack at sp and at the same time update the stack
+	     pointer by actual_fsize bytes.  Two versions, first
 	     handles small (<8k) frames.  The second handles large (>=8k)
 	     frames.  */
-	  emit_move_insn (tmpreg, frame_pointer_rtx);
-	  FRP (emit_move_insn (frame_pointer_rtx, stack_pointer_rtx));
-	  if (VAL_14_BITS_P (actual_fsize))
+	  insn = emit_move_insn (tmpreg, frame_pointer_rtx);
+	  if (DO_FRAME_NOTES)
 	    {
-	      rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
-						    size_rtx));
-	      if (DO_FRAME_NOTES)
-		{
-		  rtvec vec;
-		  RTX_FRAME_RELATED_P (insn) = 1;
-		  vec = gen_rtvec (2,
-				   gen_rtx_SET (VOIDmode,
-						gen_rtx_MEM (word_mode,
-							     stack_pointer_rtx),
-						frame_pointer_rtx),
-				   gen_rtx_SET (VOIDmode,
-						stack_pointer_rtx,
-						gen_rtx_PLUS (word_mode,
-							      stack_pointer_rtx,
-							      size_rtx)));
-		  REG_NOTES (insn)
-		    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-					 gen_rtx_SEQUENCE (VOIDmode, vec),
-					 REG_NOTES (insn));
-		}
-	    }
+	      /* We need to record the frame pointer save here since the
+	         new frame pointer is set in the following insn.  */
+	      RTX_FRAME_RELATED_P (insn) = 1;
+	      REG_NOTES (insn)
+		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+		    gen_rtx_SET (VOIDmode,
+				 gen_rtx_MEM (word_mode, stack_pointer_rtx),
+			         frame_pointer_rtx),
+		    REG_NOTES (insn));
+	    }
+
+	  insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+	  if (DO_FRAME_NOTES)
+	    RTX_FRAME_RELATED_P (insn) = 1;
+
+	  if (VAL_14_BITS_P (actual_fsize))
+	    store_reg_modify (STACK_POINTER_REGNUM, 1, actual_fsize);
 	  else
 	    {
 	      /* It is incorrect to store the saved frame pointer at *sp,
@@ -3181,32 +3222,12 @@ hppa_expand_prologue ()
 		 finish allocating the new frame.  */
 	      int adjust1 = 8192 - 64;
 	      int adjust2 = actual_fsize - adjust1;
-	      rtx delta = GEN_INT (adjust1);
-	      rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
-						    delta));
-	      if (DO_FRAME_NOTES)
-		{
-		  rtvec vec;
-		  RTX_FRAME_RELATED_P (insn) = 1;
-		  vec = gen_rtvec (2,
-				   gen_rtx_SET (VOIDmode,
-						gen_rtx_MEM (word_mode,
-							     stack_pointer_rtx),
-						frame_pointer_rtx),
-				   gen_rtx_SET (VOIDmode,
-						stack_pointer_rtx,
-						gen_rtx_PLUS (word_mode,
-							      stack_pointer_rtx,
-							      delta)));
-		  REG_NOTES (insn)
-		    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-					 gen_rtx_SEQUENCE (VOIDmode, vec),
-					 REG_NOTES (insn));
-		}
 
+	      store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
 	      set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
-			      adjust2);
+			      adjust2, 1);
 	    }
+
 	  /* Prevent register spills from being scheduled before the
 	     stack pointer is raised.  Necessary as we will be storing
 	     registers using the frame pointer as a base register, and
@@ -3226,7 +3247,7 @@ hppa_expand_prologue ()
 	     bytes.  */
 	  else
 	    set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
-			    actual_fsize);
+			    actual_fsize, 1);
 	}
     }
 
@@ -3236,7 +3257,27 @@ hppa_expand_prologue ()
      was done earlier.  */
   if (frame_pointer_needed)
     {
-      for (i = 18, offset = local_fsize; i >= 4; i--)
+      offset = local_fsize;
+
+      /* Saving the EH return data registers in the frame is the simplest
+	 way to get the frame unwind information emitted.  We put them
+	 just before the general registers.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+	{
+	  unsigned int i, regno;
+
+	  for (i = 0; ; ++i)
+	    {
+	      regno = EH_RETURN_DATA_REGNO (i);
+	      if (regno == INVALID_REGNUM)
+		break;
+
+	      store_reg (regno, offset, FRAME_POINTER_REGNUM);
+	      offset += UNITS_PER_WORD;
+	    }
+	}
+
+      for (i = 18; i >= 4; i--)
 	if (regs_ever_live[i] && ! call_used_regs[i])
 	  {
 	    store_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -3249,18 +3290,42 @@ hppa_expand_prologue ()
   /* No frame pointer needed.  */
   else
     {
-      for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
+      offset = local_fsize - actual_fsize;
+
+      /* Saving the EH return data registers in the frame is the simplest
+         way to get the frame unwind information emitted.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+	{
+	  unsigned int i, regno;
+
+	  for (i = 0; ; ++i)
+	    {
+	      regno = EH_RETURN_DATA_REGNO (i);
+	      if (regno == INVALID_REGNUM)
+		break;
+
+	      /* If merge_sp_adjust_with_store is nonzero, then we can
+		 optimize the first save.  */
+	      if (merge_sp_adjust_with_store)
+		{
+		  store_reg_modify (STACK_POINTER_REGNUM, regno, -offset);
+		  merge_sp_adjust_with_store = 0;
+		}
+	      else
+		store_reg (regno, offset, STACK_POINTER_REGNUM);
+	      offset += UNITS_PER_WORD;
+	    }
+	}
+
+      for (i = 18; i >= 3; i--)
       	if (regs_ever_live[i] && ! call_used_regs[i])
 	  {
 	    /* If merge_sp_adjust_with_store is nonzero, then we can
 	       optimize the first GR save.  */
 	    if (merge_sp_adjust_with_store)
 	      {
-		rtx delta = GEN_INT (-offset);
+		store_reg_modify (STACK_POINTER_REGNUM, i, -offset);
 		merge_sp_adjust_with_store = 0;
-	        FRP (emit_insn (gen_post_store (stack_pointer_rtx,
-						gen_rtx_REG (word_mode, i),
-						delta)));
 	      }
 	    else
 	      store_reg (i, offset, STACK_POINTER_REGNUM);
@@ -3272,7 +3337,7 @@ hppa_expand_prologue ()
 	 did any GR saves, then just emit the adjustment here.  */
       if (merge_sp_adjust_with_store)
 	set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
-			actual_fsize);
+			actual_fsize, 1);
     }
 
   /* The hppa calling conventions say that %r19, the pic offset
@@ -3290,12 +3355,20 @@ hppa_expand_prologue ()
   /* Floating point register store.  */
   if (save_fregs)
     {
+      rtx base;
+
       /* First get the frame or stack pointer to the start of the FP register
 	 save area.  */
       if (frame_pointer_needed)
-	set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+	{
+	  set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
+	  base = frame_pointer_rtx;
+	}
       else
-	set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+	{
+	  set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
+	  base = stack_pointer_rtx;
+	}
 
       /* Now actually save the FP registers.  */
       for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
@@ -3310,20 +3383,49 @@ hppa_expand_prologue ()
 	      if (DO_FRAME_NOTES)
 		{
 		  RTX_FRAME_RELATED_P (insn) = 1;
-		  REG_NOTES (insn)
-		    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-			gen_rtx_SET (VOIDmode,
-			  gen_rtx_MEM (DFmode,
-				       plus_constant (stack_pointer_rtx,
-						      offset)),
-			  reg),
-			REG_NOTES (insn));
+		  if (TARGET_64BIT)
+		    {
+		      rtx mem = gen_rtx_MEM (DFmode,
+					     plus_constant (base, offset));
+		      REG_NOTES (insn)
+			= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+					     gen_rtx_SET (VOIDmode, mem, reg),
+					     REG_NOTES (insn));
+		    }
+		  else
+		    {
+		      rtx meml = gen_rtx_MEM (SFmode,
+					      plus_constant (base, offset));
+		      rtx memr = gen_rtx_MEM (SFmode,
+					      plus_constant (base, offset + 4));
+		      rtx regl = gen_rtx_REG (SFmode, i);
+		      rtx regr = gen_rtx_REG (SFmode, i + 1);
+		      rtx setl = gen_rtx_SET (VOIDmode, meml, regl);
+		      rtx setr = gen_rtx_SET (VOIDmode, memr, regr);
+		      rtvec vec;
+
+		      RTX_FRAME_RELATED_P (setl) = 1;
+		      RTX_FRAME_RELATED_P (setr) = 1;
+		      vec = gen_rtvec (2, setl, setr);
+		      REG_NOTES (insn)
+			= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+					     gen_rtx_SEQUENCE (VOIDmode, vec),
+					     REG_NOTES (insn));
+		    }
 		}
 	      offset += GET_MODE_SIZE (DFmode);
 	      fr_saved++;
 	    }
 	}
     }
+
+  /* FIXME: expand_call and expand_millicode_call need to be fixed to
+     prevent insns with frame notes being scheduled in the delay slot
+     of calls.  This causes problems because the dwarf2 output code
+     processes the insn list serially.  For now, limit the migration
+     of prologue insns with a blockage.  */
+  if (DO_FRAME_NOTES)
+    emit_insn (gen_blockage ());
 }
 
 /* Emit RTL to load REG from the memory location specified by BASE+DISP.
@@ -3407,7 +3509,7 @@ hppa_expand_epilogue ()
   /* Try to restore RP early to avoid load/use interlocks when
      RP gets used in the return (bv) instruction.  This appears to still
      be necessary even when we schedule the prologue and epilogue.  */
-  if (regs_ever_live [2])
+  if (regs_ever_live [2] || current_function_calls_eh_return)
     {
       ret_off = TARGET_64BIT ? -16 : -20;
       if (frame_pointer_needed)
@@ -3429,7 +3531,26 @@ hppa_expand_epilogue ()
   /* General register restores.  */
   if (frame_pointer_needed)
     {
-      for (i = 18, offset = local_fsize; i >= 4; i--)
+      offset = local_fsize;
+
+      /* If the current function calls __builtin_eh_return, then we need
+         to restore the saved EH data registers.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+	{
+	  unsigned int i, regno;
+
+	  for (i = 0; ; ++i)
+	    {
+	      regno = EH_RETURN_DATA_REGNO (i);
+	      if (regno == INVALID_REGNUM)
+		break;
+
+	      load_reg (regno, offset, FRAME_POINTER_REGNUM);
+	      offset += UNITS_PER_WORD;
+	    }
+	}
+
+      for (i = 18; i >= 4; i--)
 	if (regs_ever_live[i] && ! call_used_regs[i])
 	  {
 	    load_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -3438,7 +3559,34 @@ hppa_expand_epilogue ()
     }
   else
     {
-      for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
+      offset = local_fsize - actual_fsize;
+
+      /* If the current function calls __builtin_eh_return, then we need
+         to restore the saved EH data registers.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+	{
+	  unsigned int i, regno;
+
+	  for (i = 0; ; ++i)
+	    {
+	      regno = EH_RETURN_DATA_REGNO (i);
+	      if (regno == INVALID_REGNUM)
+		break;
+
+	      /* Only for the first load.
+	         merge_sp_adjust_with_load holds the register load
+	         with which we will merge the sp adjustment.  */
+	      if (merge_sp_adjust_with_load == 0
+		  && local_fsize == 0
+		  && VAL_14_BITS_P (-actual_fsize))
+	        merge_sp_adjust_with_load = regno;
+	      else
+		load_reg (regno, offset, STACK_POINTER_REGNUM);
+	      offset += UNITS_PER_WORD;
+	    }
+	}
+
+      for (i = 18; i >= 3; i--)
 	{
 	  if (regs_ever_live[i] && ! call_used_regs[i])
 	    {
@@ -3464,9 +3612,9 @@ hppa_expand_epilogue ()
     {
       /* Adjust the register to index off of.  */
       if (frame_pointer_needed)
-	set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+	set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
       else
-	set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+	set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
 
       /* Actually do the restores now.  */
       for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
@@ -3491,45 +3639,36 @@ hppa_expand_epilogue ()
   if (frame_pointer_needed)
     {
       rtx delta = GEN_INT (-64);
-      rtx insn;
-      set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64);
-      insn = emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx,
-				      delta));
-      if (DO_FRAME_NOTES)
-	{
-	  RTX_FRAME_RELATED_P (insn) = 1;
-	  REG_NOTES (insn)
-	    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-		gen_rtx_SET (VOIDmode, stack_pointer_rtx,
-			     gen_rtx_PLUS (word_mode, stack_pointer_rtx,
-					   delta)),
-                REG_NOTES (insn));
-	}
+
+      set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64, 0);
+      emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx, delta));
     }
   /* If we were deferring a callee register restore, do it now.  */
   else if (merge_sp_adjust_with_load)
     {
       rtx delta = GEN_INT (-actual_fsize);
       rtx dest = gen_rtx_REG (word_mode, merge_sp_adjust_with_load);
-      rtx insn = emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
-      if (DO_FRAME_NOTES)
-	{
-	  RTX_FRAME_RELATED_P (insn) = 1;
-	  REG_NOTES (insn)
-	    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-		gen_rtx_SET (VOIDmode, stack_pointer_rtx,
-			     gen_rtx_PLUS (word_mode, stack_pointer_rtx,
-					   delta)),
-                REG_NOTES (insn));
-	}
+
+      emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
     }
   else if (actual_fsize != 0)
-    set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, - actual_fsize);
+    set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+		    - actual_fsize, 0);
 
   /* If we haven't restored %r2 yet (no frame pointer, and a stack
      frame greater than 8k), do so now.  */
   if (ret_off != 0)
     load_reg (2, ret_off, STACK_POINTER_REGNUM);
+
+  if (DO_FRAME_NOTES && current_function_calls_eh_return)
+    {
+      rtx sa = EH_RETURN_STACKADJ_RTX;
+
+      emit_insn (gen_blockage ());
+      emit_insn (TARGET_64BIT
+		 ? gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
+		 : gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
+    }
 }
 
 rtx
@@ -6029,10 +6168,10 @@ output_call (insn, call_dest, sibcall)
      and we're sure that the branch will reach the beginning of the $CODE$
      subspace.  */
   if ((dbr_sequence_length () == 0
-       && get_attr_length (insn) == 8)
+       && get_attr_length (insn) == 12)
       || (dbr_sequence_length () != 0
 	  && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
-	  && get_attr_length (insn) == 4))
+	  && get_attr_length (insn) == 8))
     {
       xoperands[0] = call_dest;
       xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
@@ -6041,7 +6180,7 @@ output_call (insn, call_dest, sibcall)
     }
 
   /* This call may not reach the beginning of the $CODE$ subspace.  */
-  if (get_attr_length (insn) > 8)
+  if (get_attr_length (insn) > 12)
     {
       int delay_insn_deleted = 0;
       rtx xoperands[2];
@@ -6241,14 +6380,16 @@ output_call (insn, call_dest, sibcall)
 	       - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8;
 
   /* If the branch was too far away, emit a normal call followed
-     by a nop, followed by the unconditional branch.
+     by a nop, followed by the unconditional branch.  We also don't
+     adjust %r2 when generating dwarf2 frame or unwind info since
+     the adjustment confuses the dwarf2 output.
 
      If the branch is close, then adjust %r2 from within the
      call's delay slot.  */
 
   xoperands[0] = call_dest;
   xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
-  if (! VAL_14_BITS_P (distance))
+  if (DO_FRAME_NOTES || ! VAL_14_BITS_P (distance))
     output_asm_insn ("{bl|b,l} %0,%%r2\n\tnop\n\tb,n %1", xoperands);
   else
     {
Index: pa.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.h,v
retrieving revision 1.144
diff -u -3 -p -r1.144 pa.h
--- pa.h	12 Mar 2002 05:28:10 -0000	1.144
+++ pa.h	3 Apr 2002 18:02:41 -0000
@@ -506,10 +506,22 @@ extern struct rtx_def *hppa_pic_save_rtx
 #define STRUCT_VALUE_REGNUM 28
 
 /* Describe how we implement __builtin_eh_return.  */
+/* FIXME: What's a good choice for the EH data registers on TARGET_64BIT?  */
 #define EH_RETURN_DATA_REGNO(N)	\
-  ((N) < 3 ? (N) + 20 : (N) == 4 ? 31 : INVALID_REGNUM)
+  (TARGET_64BIT								\
+   ? ((N) < 4 ? (N) + 4 : INVALID_REGNUM)				\
+   : ((N) < 3 ? (N) + 20 : (N) == 4 ? 31 : INVALID_REGNUM))
 #define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (Pmode, 29)
-#define EH_RETURN_HANDLER_RTX	gen_rtx_REG (Pmode, 2)
+#define EH_RETURN_HANDLER_RTX \
+  gen_rtx_MEM (word_mode,						\
+	       gen_rtx_PLUS (word_mode, frame_pointer_rtx,		\
+			     TARGET_64BIT ? GEN_INT (-16) : GEN_INT (-20)))
+			  	
+
+/* Offset from the argument pointer register value to the top of
+   stack.  This is different from FIRST_PARM_OFFSET because of the
+   frame marker.  */
+#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
 
 /* The letters I, J, K, L and M in a register constraint string
    can be used to stand for particular ranges of immediate operands.
Index: pa.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.md,v
retrieving revision 1.101
diff -u -3 -p -r1.101 pa.md
--- pa.md	4 Feb 2002 21:05:25 -0000	1.101
+++ pa.md	3 Apr 2002 18:02:42 -0000
@@ -5568,6 +5568,21 @@
   [(set_attr "type" "branch")
    (set_attr "length" "4")])
 
+;; Use the PIC register to ensure it's restored after a
+;; call in PIC mode.  This is used for eh returns which
+;; bypass the return stub.
+(define_insn "return_external_pic"
+  [(return)
+   (use (match_operand 0 "register_operand" "r"))
+   (use (reg:SI 2))
+   (clobber (reg:SI 1))]
+  "flag_pic
+   && current_function_calls_eh_return
+   && true_regnum (operands[0]) == PIC_OFFSET_TABLE_REGNUM"
+  "ldsid (%%sr0,%%r2),%%r1\;mtsp %%r1,%%sr0\;be%* 0(%%sr0,%%r2)"
+  [(set_attr "type" "branch")
+   (set_attr "length" "12")])
+
 (define_expand "prologue"
   [(const_int 0)]
   ""
@@ -5590,15 +5605,24 @@
   /* Try to use the trivial return first.  Else use the full
      epilogue.  */
   if (hppa_can_use_return_insn_p ())
-   emit_jump_insn (gen_return ());
+    emit_jump_insn (gen_return ());
   else
     {
       rtx x;
 
       hppa_expand_epilogue ();
       if (flag_pic)
-	x = gen_return_internal_pic (gen_rtx_REG (word_mode,
-						  PIC_OFFSET_TABLE_REGNUM));
+	{
+	  rtx pic = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
+
+	  /* EH returns bypass the normal return stub.  Thus, we must do an
+	     interspace branch to return from functions that call eh_return.
+	     This is only a problem for returns from shared code.  */
+	  if (current_function_calls_eh_return)
+	    x = gen_return_external_pic (pic);
+	  else
+	    x = gen_return_internal_pic (pic);
+	}
       else
 	x = gen_return_internal ();
       emit_jump_insn (x);
@@ -5856,18 +5880,19 @@
   [(set_attr "type" "call")
    (set (attr "length")
 ;;       If we're sure that we can either reach the target or that the
-;;	 linker can use a long-branch stub, then the length is 4 bytes.
+;;	 linker can use a long-branch stub, then the length is at most
+;;	 8 bytes.
 ;;
-;;	 For long-calls the length will be either 52 bytes (non-pic)
-;;	 or 68 bytes (pic).  */
+;;	 For long-calls the length will be at most 68 bytes (non-pic)
+;;	 or 84 bytes (pic).  */
 ;;	 Else we have to use a long-call;
       (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
 			(const_int 240000))
-		    (const_int 4)
+		    (const_int 8)
 		    (if_then_else (eq (symbol_ref "flag_pic")
 				      (const_int 0))
-				  (const_int 52)
-				  (const_int 68))))])
+				  (const_int 68)
+				  (const_int 84))))])
 
 (define_insn "call_internal_reg_64bit"
   [(call (mem:SI (match_operand:DI 0 "register_operand" "r"))
@@ -6029,18 +6054,19 @@
   [(set_attr "type" "call")
    (set (attr "length")
 ;;       If we're sure that we can either reach the target or that the
-;;	 linker can use a long-branch stub, then the length is 4 bytes.
+;;	 linker can use a long-branch stub, then the length is at most
+;;	 8 bytes.
 ;;
-;;	 For long-calls the length will be either 52 bytes (non-pic)
-;;	 or 68 bytes (pic).  */
+;;	 For long-calls the length will be at most 68 bytes (non-pic)
+;;	 or 84 bytes (pic).  */
 ;;	 Else we have to use a long-call;
       (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
 			(const_int 240000))
-		    (const_int 4)
+		    (const_int 8)
 		    (if_then_else (eq (symbol_ref "flag_pic")
 				      (const_int 0))
-				  (const_int 52)
-				  (const_int 68))))])
+				  (const_int 68)
+				  (const_int 84))))])
 
 (define_insn "call_value_internal_reg_64bit"
   [(set (match_operand 0 "" "=rf")
@@ -6200,18 +6226,19 @@
   [(set_attr "type" "call")
    (set (attr "length")
 ;;       If we're sure that we can either reach the target or that the
-;;	 linker can use a long-branch stub, then the length is 4 bytes.
+;;	 linker can use a long-branch stub, then the length is at most
+;;	 8 bytes.
 ;;
-;;	 For long-calls the length will be either 52 bytes (non-pic)
-;;	 or 68 bytes (pic).  */
+;;	 For long-calls the length will be at most 68 bytes (non-pic)
+;;	 or 84 bytes (pic).  */
 ;;	 Else we have to use a long-call;
       (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
 			(const_int 240000))
-		    (const_int 4)
+		    (const_int 8)
 		    (if_then_else (eq (symbol_ref "flag_pic")
 				      (const_int 0))
-				  (const_int 52)
-				  (const_int 68))))])
+				  (const_int 68)
+				  (const_int 84))))])
 
 (define_expand "sibcall_value"
   [(parallel [(set (match_operand 0 "" "")
@@ -6258,18 +6285,19 @@
   [(set_attr "type" "call")
    (set (attr "length")
 ;;       If we're sure that we can either reach the target or that the
-;;	 linker can use a long-branch stub, then the length is 4 bytes.
+;;	 linker can use a long-branch stub, then the length is at most
+;;	 8 bytes.
 ;;
-;;	 For long-calls the length will be either 52 bytes (non-pic)
-;;	 or 68 bytes (pic).  */
+;;	 For long-calls the length will be at most 68 bytes (non-pic)
+;;	 or 84 bytes (pic).  */
 ;;	 Else we have to use a long-call;
       (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
 			(const_int 240000))
-		    (const_int 4)
+		    (const_int 8)
 		    (if_then_else (eq (symbol_ref "flag_pic")
 				      (const_int 0))
-				  (const_int 52)
-				  (const_int 68))))])
+				  (const_int 68)
+				  (const_int 84))))])
 
 (define_insn "nop"
   [(const_int 0)]
@@ -7216,16 +7244,12 @@
 ;; restore the PIC register.
 (define_expand "exception_receiver"
   [(const_int 4)]
-  "!TARGET_PORTABLE_RUNTIME && flag_pic"
+  "flag_pic"
   "
 {
-  /* Load the PIC register from the stack slot (in our caller's
-     frame).  */
-  emit_move_insn (pic_offset_table_rtx,
-		  gen_rtx_MEM (SImode,
-			       plus_constant (stack_pointer_rtx, -32)));
-  emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
-  emit_insn (gen_blockage ());
+  /* Restore the PIC register using hppa_pic_save_rtx ().  The
+     PIC register is not saved in the frame in 64-bit ABI.  */
+  emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
   DONE;
 }")
 



More information about the Gcc-patches mailing list