diff mbox

[RS6000] asynch exceptions and unwind info

Message ID 20110729125828.GY1081@bubble.grove.modra.org
State New
Headers show

Commit Message

Alan Modra July 29, 2011, 12:58 p.m. UTC
On Fri, Jul 29, 2011 at 10:57:48AM +0930, Alan Modra wrote:
> Except that any info about r2 in an indirect call sequence really
> belongs to the *called* function frame, not the callee.  I woke up
> this morning with the realization that what I'd done in
> frob_update_context for indirect call sequences was wrong.  Ditto for
> the r2 store that Michael moved into the prologue.  The only time we
> want the unwinder to restore from that particular save is if r2 isn't
> saved in the current frame.
> 
> Untested patch follows.

Here's a tested patch that fixes an issue with TOC_SINGLE_PIC_BASE and
enables Michael's save_toc_in_prologue optimization for all functions
except those that make dynamic stack adjustments.

Incidentally, the rs6000_emit_prologue comment I added below suggests
another solution.  Since all we need is the toc pointer for the frame,
it would be possible to tell the unwinder to simply load r2 from the
.opd entry.  I think..

libgcc/
	* config/rs6000/linux-unwind.h (frob_update_context <__powerpc64__>):
	Restore for indirect call bcrtl from correct stack slot, and only
	if cfa+40 isn't valid.
gcc/
	* config/rs6000/rs6000-protos.h (rs6000_save_toc_in_prologue_p): Delete.
	* config/rs6000/rs6000.c (rs6000_save_toc_in_prologue_p): Make static.
	(rs6000_emit_prologue): Don't prematurely return when
	TARGET_SINGLE_PIC_BASE.  Don't emit eh_frame info in
	save_toc_in_prologue case.
	(rs6000_call_indirect_aix): Only disallow save_toc_in_prologue for
	calls_alloca.

Comments

Alan Modra Aug. 1, 2011, 3:08 p.m. UTC | #1
On Fri, Jul 29, 2011 at 10:28:28PM +0930, Alan Modra wrote:
> libgcc/
> 	* config/rs6000/linux-unwind.h (frob_update_context <__powerpc64__>):
> 	Restore for indirect call bcrtl from correct stack slot, and only
> 	if cfa+40 isn't valid.
> gcc/
> 	* config/rs6000/rs6000-protos.h (rs6000_save_toc_in_prologue_p): Delete.
> 	* config/rs6000/rs6000.c (rs6000_save_toc_in_prologue_p): Make static.
> 	(rs6000_emit_prologue): Don't prematurely return when
> 	TARGET_SINGLE_PIC_BASE.  Don't emit eh_frame info in
> 	save_toc_in_prologue case.
> 	(rs6000_call_indirect_aix): Only disallow save_toc_in_prologue for
> 	calls_alloca.

Approved offline and applied with a comment change.
diff mbox

Patch

Index: libgcc/config/rs6000/linux-unwind.h
===================================================================
--- libgcc/config/rs6000/linux-unwind.h	(revision 176905)
+++ libgcc/config/rs6000/linux-unwind.h	(working copy)
@@ -354,20 +354,22 @@  frob_update_context (struct _Unwind_Cont
 	  /* We are in a plt call stub or r2 adjusting long branch stub,
 	     before r2 has been saved.  Keep REG_UNSAVED.  */
 	}
-      else if (pc[0] == 0x4E800421
-	       && pc[1] == 0xE8410028)
-	{
-	  /* We are at the bctrl instruction in a call via function
-	     pointer.  gcc always emits the load of the new r2 just
-	     before the bctrl.  */
-	  _Unwind_SetGRPtr (context, 2, context->cfa + 40);
-	}
       else
 	{
 	  unsigned int *insn
 	    = (unsigned int *) _Unwind_GetGR (context, R_LR);
 	  if (insn && *insn == 0xE8410028)
 	    _Unwind_SetGRPtr (context, 2, context->cfa + 40);
+	  else if (pc[0] == 0x4E800421
+		   && pc[1] == 0xE8410028)
+	    {
+	      /* We are at the bctrl instruction in a call via function
+		 pointer.  gcc always emits the load of the new R2 just
+		 before the bctrl so this is the first and only place
+		 we need to use the stored R2.  */
+	      _Unwind_Word sp = _Unwind_GetGR (context, 1);
+	      _Unwind_SetGRPtr (context, 2, sp + 40);
+	    }
 	}
     }
 #endif
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h	(revision 176905)
+++ gcc/config/rs6000/rs6000-protos.h	(working copy)
@@ -172,8 +172,6 @@  extern void rs6000_emit_epilogue (int);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern const char * output_isel (rtx *);
 extern void rs6000_call_indirect_aix (rtx, rtx, rtx);
-extern bool rs6000_save_toc_in_prologue_p (void);
-
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 
 /* Declare functions in rs6000-c.c */
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 176905)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1178,6 +1178,7 @@  static void rs6000_conditional_register_
 static void rs6000_trampoline_init (rtx, tree, rtx);
 static bool rs6000_cannot_force_const_mem (enum machine_mode, rtx);
 static bool rs6000_legitimate_constant_p (enum machine_mode, rtx);
+static bool rs6000_save_toc_in_prologue_p (void);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -20478,14 +20504,12 @@  rs6000_emit_prologue (void)
       insn = emit_insn (generate_set_vrsave (reg, info, 0));
     }
 
-  if (TARGET_SINGLE_PIC_BASE)
-    return; /* Do not set PIC register */
-
   /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
-  if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
-      || (DEFAULT_ABI == ABI_V4
-	  && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
-	  && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM)))
+  if (!TARGET_SINGLE_PIC_BASE
+      && ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
+	  || (DEFAULT_ABI == ABI_V4
+	      && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
+	      && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM))))
     {
       /* If emit_load_toc_table will use the link register, we need to save
 	 it.  We use R12 for this purpose because emit_load_toc_table
@@ -20513,7 +20537,8 @@  rs6000_emit_prologue (void)
     }
 
 #if TARGET_MACHO
-  if (DEFAULT_ABI == ABI_DARWIN
+  if (!TARGET_SINGLE_PIC_BASE
+      && DEFAULT_ABI == ABI_DARWIN
       && flag_pic && crtl->uses_pic_offset_table)
     {
       rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
@@ -20534,10 +20559,26 @@  rs6000_emit_prologue (void)
     }
 #endif
 
-  /* If we need to, save the TOC register after doing the stack setup.  */
+  /* If we need to, save the TOC register after doing the stack setup.
+     Do not emit eh frame info for this save.  We don't attempt to
+     write accurate DWARF EH frame info for R2 because code emitted by
+     gcc for a (non-pointer) function call doesn't save and restore
+     R2.  Instead, R2 is managed out-of-line by a linker generated plt
+     call stub when the function resides in a shared library.  This
+     behaviour is costly to describe in DWARF, both in terms of the
+     size of DWARF info and the time taken in the unwinder to
+     interpret it.  R2 changes, apart from the calls_eh_return case
+     earlier in this function, are handled by linux-unwind.h
+     frob_update_context.  Even in frob_update_context we don't try to
+     keep the unwinder's copy of R2 accurate on an instruction by
+     instruction basis, as we only need it set to the correct TOC
+     pointer for the current frame.  */ 
   if (rs6000_save_toc_in_prologue_p ())
-    emit_frame_save (sp_reg_rtx, sp_reg_rtx, reg_mode, TOC_REGNUM,
-		     5 * reg_size, info->total_size);
+    {
+      rtx addr = gen_rtx_PLUS (Pmode, sp_reg_rtx, GEN_INT (5 * reg_size));
+      rtx mem = gen_frame_mem (reg_mode, addr);
+      emit_move_insn (mem, gen_rtx_REG (reg_mode, TOC_REGNUM));
+    }
 }
 
 /* Write function prologue.  */
@@ -27795,10 +27838,7 @@  rs6000_call_indirect_aix (rtx value, rtx
 
   /* Can we optimize saving the TOC in the prologue or do we need to do it at
      every call?  */
-  if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca
-      && !cfun->calls_setjmp && !cfun->has_nonlocal_label
-      && !cfun->can_throw_non_call_exceptions
-      && ((flags_from_decl_or_type (cfun->decl) & ECF_NOTHROW) == ECF_NOTHROW))
+  if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
     cfun->machine->save_toc_in_prologue = true;
 
   else
@@ -27834,13 +27874,12 @@  rs6000_call_indirect_aix (rtx value, rtx
     insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem);
 
   emit_call_insn (insn);
-  return;
 }
 
 /* Return whether we need to always update the saved TOC pointer when we update
    the stack pointer.  */
 
-bool
+static bool
 rs6000_save_toc_in_prologue_p (void)
 {
   return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);