diff mbox

[RS6000] PR 45807 r2 eh_frame info error

Message ID 20100927142714.GS16376@bubble.grove.modra.org
State New
Headers show

Commit Message

Alan Modra Sept. 27, 2010, 2:27 p.m. UTC
This patch makes sure that we emit eh_frame info for r2 at the place
we actually save it.  Previously, __builtin_unwind_init saved r2,
while the prologue emitted the eh_frame info for r2.  This opened a
window for error, and Murphy did the rest.  In unwind-dw2.c
_Unwind_Resume_or_Rethrow we manage to insert a call before r2 is
saved.  See the PR for the ugly details.

Powerpc64-linux bootstrap and regression test in progress.  OK to
apply assuming no regressions?  I'd like to backport this to active
branches too.

	PR target/45807
	* config/rs6000/aix.h (SETUP_FRAME_ADDRESSES): Delete.
	* config/rs6000/linux64.h (SETUP_FRAME_ADDRESSES): Delete.
	* config/rs6000/rs6000-protos.h (rs6000_aix_emit_builtin_unwind_init):
	Delete.
	* config/rs6000/rs6000.c (rs6000_aix_emit_builtin_unwind_init): Delete.
	(rs6000_emit_prologue): Don't just create frame save info for r2,
	actually save r2.

Comments

David Edelsohn Sept. 27, 2010, 10:56 p.m. UTC | #1
On Mon, Sep 27, 2010 at 10:27 AM, Alan Modra <amodra@gmail.com> wrote:
> This patch makes sure that we emit eh_frame info for r2 at the place
> we actually save it.  Previously, __builtin_unwind_init saved r2,
> while the prologue emitted the eh_frame info for r2.  This opened a
> window for error, and Murphy did the rest.  In unwind-dw2.c
> _Unwind_Resume_or_Rethrow we manage to insert a call before r2 is
> saved.  See the PR for the ugly details.
>
> Powerpc64-linux bootstrap and regression test in progress.  OK to
> apply assuming no regressions?  I'd like to backport this to active
> branches too.
>
>        PR target/45807
>        * config/rs6000/aix.h (SETUP_FRAME_ADDRESSES): Delete.
>        * config/rs6000/linux64.h (SETUP_FRAME_ADDRESSES): Delete.
>        * config/rs6000/rs6000-protos.h (rs6000_aix_emit_builtin_unwind_init):
>        Delete.
>        * config/rs6000/rs6000.c (rs6000_aix_emit_builtin_unwind_init): Delete.
>        (rs6000_emit_prologue): Don't just create frame save info for r2,
>        actually save r2.

Okay.

Thanks, David
diff mbox

Patch

Index: gcc/config/rs6000/aix.h
===================================================================
--- gcc/config/rs6000/aix.h	(revision 164644)
+++ gcc/config/rs6000/aix.h	(working copy)
@@ -207,13 +207,6 @@ 
 /* And similarly for general purpose registers.  */
 #define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32)
 
-/* __throw will restore its own return address to be the same as the
-   return address of the function that the throw is being made to.
-   This is unfortunate, because we want to check the original
-   return address to see if we need to restore the TOC.
-   So we have to squirrel it away with this.  */
-#define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init ()
-
 /* If the current unwind info (FS) does not contain explicit info
    saving R2, then we have to do a minor amount of code reading to
    figure out if it was saved.  The big problem here is that the
Index: gcc/config/rs6000/linux64.h
===================================================================
--- gcc/config/rs6000/linux64.h	(revision 164644)
+++ gcc/config/rs6000/linux64.h	(working copy)
@@ -305,14 +308,6 @@  extern enum rs6000_cmodel cmodel;
 #define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
   (!(FIRST) ? upward : FUNCTION_ARG_PADDING (MODE, TYPE))
 
-/* __throw will restore its own return address to be the same as the
-   return address of the function that the throw is being made to.
-   This is unfortunate, because we want to check the original
-   return address to see if we need to restore the TOC.
-   So we have to squirrel it away with this.  */
-#define SETUP_FRAME_ADDRESSES() \
-  do { if (TARGET_64BIT) rs6000_aix_emit_builtin_unwind_init (); } while (0)
-
 /* Override svr4.h  */
 #undef MD_EXEC_PREFIX
 #undef MD_STARTFILE_PREFIX
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h	(revision 164644)
+++ gcc/config/rs6000/rs6000-protos.h	(working copy)
@@ -163,7 +163,6 @@  extern int rs6000_trampoline_size (void)
 extern alias_set_type get_TOC_alias_set (void);
 extern void rs6000_emit_prologue (void);
 extern void rs6000_emit_load_toc_table (int);
-extern void rs6000_aix_emit_builtin_unwind_init (void);
 extern unsigned int rs6000_dbx_register_number (unsigned int);
 extern void rs6000_emit_epilogue (int);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 164644)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -18916,42 +18924,6 @@  rs6000_aix_asm_output_dwarf_table_ref (c
   fprintf (asm_out_file, "\t.ref %s\n",
 	   TARGET_STRIP_NAME_ENCODING (frame_table_label));
 }
-
-/* If _Unwind_* has been called from within the same module,
-   toc register is not guaranteed to be saved to 40(1) on function
-   entry.  Save it there in that case.  */
-
-void
-rs6000_aix_emit_builtin_unwind_init (void)
-{
-  rtx mem;
-  rtx stack_top = gen_reg_rtx (Pmode);
-  rtx opcode_addr = gen_reg_rtx (Pmode);
-  rtx opcode = gen_reg_rtx (SImode);
-  rtx tocompare = gen_reg_rtx (SImode);
-  rtx no_toc_save_needed = gen_label_rtx ();
-
-  mem = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
-  emit_move_insn (stack_top, mem);
-
-  mem = gen_frame_mem (Pmode,
-		       gen_rtx_PLUS (Pmode, stack_top,
-				     GEN_INT (2 * GET_MODE_SIZE (Pmode))));
-  emit_move_insn (opcode_addr, mem);
-  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
-  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
-					   : 0xE8410028, SImode));
-
-  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
-			   SImode, NULL_RTX, NULL_RTX,
-			   no_toc_save_needed, -1);
-
-  mem = gen_frame_mem (Pmode,
-		       gen_rtx_PLUS (Pmode, stack_top,
-				     GEN_INT (5 * GET_MODE_SIZE (Pmode))));
-  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
-  emit_label (no_toc_save_needed);
-}
 
 /* This ties together stack memory (MEM with an alias set of frame_alias_set)
    and the change to the stack pointer.  */
@@ -20237,22 +20209,6 @@  rs6000_emit_prologue (void)
     {
       unsigned int i, regno;
 
-      /* In AIX ABI we need to pretend we save r2 here.  */
-      if (TARGET_AIX)
-	{
-	  rtx addr, reg, mem;
-
-	  reg = gen_rtx_REG (reg_mode, 2);
-	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-			       GEN_INT (sp_offset + 5 * reg_size));
-	  mem = gen_frame_mem (reg_mode, addr);
-
-	  insn = emit_move_insn (mem, reg);
-	  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-				NULL_RTX, NULL_RTX);
-	  PATTERN (insn) = gen_blockage ();
-	}
-
       for (i = 0; ; ++i)
 	{
 	  regno = EH_RETURN_DATA_REGNO (i);
@@ -20266,6 +20222,53 @@  rs6000_emit_prologue (void)
 	}
     }
 
+  /* In AIX ABI we need to make sure r2 is really saved.  */
+  if (TARGET_AIX && crtl->calls_eh_return)
+    {
+      rtx tmp_reg, tmp_reg_si, compare_result, toc_save_done, jump;
+      long toc_restore_insn;
+
+      gcc_assert (frame_reg_rtx == frame_ptr_rtx
+		  || frame_reg_rtx == sp_reg_rtx);
+      tmp_reg = gen_rtx_REG (Pmode, 11);
+      tmp_reg_si = gen_rtx_REG (SImode, 11);
+      if (using_static_chain_p)
+	emit_move_insn (gen_rtx_REG (Pmode, 0), tmp_reg);
+      gcc_assert (saving_GPRs_inline && saving_FPRs_inline);
+      emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, LR_REGNO));
+      /* Peek at instruction to which this function returns.  If it's
+	 restoring r2, then we know we've already saved r2.  We can't
+	 unconditionally save r2 because the value we have will already
+	 be updated if we arrived at this function via a plt call or
+	 toc adjusting stub.  */
+      emit_move_insn (tmp_reg_si, gen_rtx_MEM (SImode, tmp_reg));
+      toc_restore_insn = ((TARGET_32BIT ? 0x80410014 : 0xE8410028)
+			  ^ 0x80000000) - 0x80000000;
+      emit_insn (gen_xorsi3 (tmp_reg_si, tmp_reg_si,
+			     GEN_INT (toc_restore_insn & ~0xffff)));
+      compare_result = gen_rtx_REG (CCUNSmode, CR0_REGNO);
+      validate_condition_mode (EQ, CCUNSmode);
+      emit_insn (gen_rtx_SET (VOIDmode, compare_result,
+			      gen_rtx_COMPARE (CCUNSmode, tmp_reg_si,
+					       GEN_INT (toc_restore_insn
+							& 0xffff))));
+      toc_save_done = gen_label_rtx ();
+      jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+				   gen_rtx_EQ (VOIDmode, compare_result,
+					       const0_rtx),
+				   gen_rtx_LABEL_REF (VOIDmode, toc_save_done),
+				   pc_rtx);
+      jump = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, jump));
+      JUMP_LABEL (jump) = toc_save_done;
+      LABEL_NUSES (toc_save_done) += 1;
+
+      emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, 2,
+		       sp_offset + 5 * reg_size, info->total_size);
+      emit_label (toc_save_done);
+      if (using_static_chain_p)
+	emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, 0));
+    }
+
   /* Save CR if we use any that must be preserved.  */
   if (!WORLD_SAVE_P (info) && info->cr_save_p)
     {