Patchwork [3/6] Allow jumps in epilogues

login
register
mail settings
Submitter Bernd Schmidt
Date April 15, 2011, 4:12 p.m.
Message ID <4DA86E71.7050605@codesourcery.com>
Download mbox | patch
Permalink /patch/91413/
State New
Headers show

Comments

Bernd Schmidt - April 15, 2011, 4:12 p.m.
On 04/13/2011 02:38 PM, Bernd Schmidt wrote:
> This still requires the i386 output_set_got which I think I can cope
> with [...]

Patch below, to be applied on top of all the others. Only lightly tested
so far beyond standard (fairly useless) regression tests, by comparing
generated assembly before/after, for -fpic -march=pentium and core2, for
i686-linux and i686-apple-darwin10 (for TARGET_MACHO).

I've not found or managed to create a testcase for making MI thunks
generate a call to output_set_got. I think it should work, but it's not
tested.


Bernd
* config/i386/i386.c (output_set_got): Don't call
	dwarf2out_flush_queued_reg_saves.
	(ix86_reorg): Split set_got patterns.
	(i386_dwarf_handle_frame_unspec,
	i386_dwarf_flush_queued_register_saves): New static functions.
	(TARGET_DWARF_HANDLE_FRAME_UNSPEC,
	TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES): New macros.
	* config/i386/i386.md (set_got_call, set_got_pop, set_got_add):
	New patterns.
	* dwarf2out.c (scan_until_barrier): Use the target's
	dwarf_flush_queued_register_saves hook.
	* target.def (dwarf_flush_queued_register_saves): New hook.
	* doc/tm.texi: Regenerate.

Patch

Index: gcc/config/i386/i386.c
===================================================================
--- gcc.orig/config/i386/i386.c
+++ gcc/config/i386/i386.c
@@ -8953,6 +8953,8 @@  output_set_got (rtx dest, rtx label ATTR
 	output_asm_insn ("mov%z0\t{%2, %0|%0, %2}", xops);
       else
 	{
+	  /* For normal functions, this pattern is split, but we can still
+	     get here for thunks.  */
 	  output_asm_insn ("call\t%a2", xops);
 #ifdef DWARF2_UNWIND_INFO
 	  /* The call to next label acts as a push.  */
@@ -9010,12 +9012,6 @@  output_set_got (rtx dest, rtx label ATTR
       get_pc_thunk_name (name, REGNO (dest));
       pic_labels_used |= 1 << REGNO (dest);
 
-#ifdef DWARF2_UNWIND_INFO
-      /* Ensure all queued register saves are flushed before the
-	 call.  */
-      if (dwarf2out_do_frame ())
-	dwarf2out_flush_queued_reg_saves ();
-#endif
       xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
       xops[2] = gen_rtx_MEM (QImode, xops[2]);
       output_asm_insn ("call\t%X2", xops);
@@ -30458,6 +30454,56 @@  ix86_reorg (void)
      with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
   compute_bb_for_insn ();
 
+  /* Split any set_got patterns so that we interact correctly with
+     dwarf2out.  */
+  if (!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+      && flag_pic)
+    {
+      rtx insn, next;
+      for (insn = get_insns (); insn; insn = next)
+	{
+	  rtx pat, label, dest, cst, gotsym, new_insn;
+	  int icode;
+
+	  next = NEXT_INSN (insn);
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  icode = recog_memoized (insn);
+	  if (icode != CODE_FOR_set_got && icode != CODE_FOR_set_got_labelled)
+	    continue;
+
+	  extract_insn (insn);
+	  if (icode == CODE_FOR_set_got)
+	    {
+	      label = gen_label_rtx ();
+	      cst = const0_rtx;
+	    }
+	  else
+	    {
+	      label = recog_data.operand[1];
+	      cst = const1_rtx;
+	    }
+
+	  dest = recog_data.operand[0];
+	  pat = gen_set_got_call (label, cst);
+	  new_insn = emit_insn_before (pat, insn);
+	  RTX_FRAME_RELATED_P (new_insn) = 1;
+	  RTX_FRAME_RELATED_P (XVECEXP (PATTERN (new_insn), 0, 1)) = 1;
+	  gotsym = gen_rtx_SYMBOL_REF (Pmode, GOT_SYMBOL_NAME);
+	  pat = gen_set_got_pop (dest, label);
+	  new_insn = emit_insn_before (pat, insn);
+	  RTX_FRAME_RELATED_P (new_insn) = 1;
+	  RTX_FRAME_RELATED_P (XVECEXP (PATTERN (new_insn), 0, 1)) = 1;
+	  if (!TARGET_MACHO)
+	    {
+	      pat = gen_set_got_add (dest, gotsym, label);
+	      new_insn = emit_insn_before (pat, insn);
+	    }
+	  delete_insn (insn);
+	}
+    }
+
   if (optimize && optimize_function_for_speed_p (cfun))
     {
       if (TARGET_PAD_SHORT_FUNCTION)
@@ -30475,6 +30521,30 @@  ix86_reorg (void)
     move_or_delete_vzeroupper ();
 }
 
+/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
+   This is called from dwarf2out.c to emit call frame instructions
+   for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs.  */
+static void
+i386_dwarf_handle_frame_unspec (rtx pattern ATTRIBUTE_UNUSED,
+				int index ATTRIBUTE_UNUSED)
+{
+  gcc_assert (index == UNSPEC_SET_GOT);
+}
+
+/* Handle the TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES hook.
+   This is called from dwarf2out.c to decide whether all queued
+   register saves should be emitted before INSN.  */
+static bool
+i386_dwarf_flush_queued_register_saves (rtx insn)
+{
+  if (!TARGET_VXWORKS_RTP || !flag_pic)
+    {
+      int icode = recog_memoized (insn);
+      return (icode == CODE_FOR_set_got || icode == CODE_FOR_set_got_labelled);
+    }
+  return false;
+}
+
 /* Return nonzero when QImode register that must be represented via REX prefix
    is used.  */
 bool
@@ -35321,6 +35391,13 @@  ix86_autovectorize_vector_sizes (void)
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL i386_output_dwarf_dtprel
 #endif
 
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC i386_dwarf_handle_frame_unspec
+
+#undef TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES
+#define TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES \
+  i386_dwarf_flush_queued_register_saves
+
 #ifdef SUBTARGET_INSERT_ATTRIBUTES
 #undef TARGET_INSERT_ATTRIBUTES
 #define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
Index: gcc/config/i386/i386.md
===================================================================
--- gcc.orig/config/i386/i386.md
+++ gcc/config/i386/i386.md
@@ -11797,6 +11797,52 @@ 
   ""
   "ix86_expand_prologue (); DONE;")
 
+(define_insn "set_got_call"
+  [(unspec [(label_ref (match_operand 0 "" ""))
+	    (match_operand:SI 1 "const_int_operand" "")] UNSPEC_SET_GOT)
+   (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4)))]
+  "!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+   && flag_pic"
+{
+  output_asm_insn ("call\t%l0", operands);
+#if TARGET_MACHO
+  /* If this was for an unlabelled set_got instruction, output the Mach-O
+     "canonical" label name ("Lxx$pb") here too.  This is what will be
+     referenced by the Mach-O PIC subsystem.  */
+  if (operands[1] == const0_rtx)
+    ASM_OUTPUT_LABEL (asm_out_file, MACHOPIC_FUNCTION_BASE_NAME);
+#endif
+  targetm.asm_out.internal_label (asm_out_file, "L",
+				  CODE_LABEL_NUMBER (operands[0]));
+  return "";
+}
+  [(set_attr "type" "call")
+   (set_attr "length" "5")])
+
+(define_insn "set_got_pop"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec [(label_ref (match_operand 1 "" ""))] UNSPEC_SET_GOT))
+   (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+   && flag_pic"
+  "pop%z0\t%0"
+  [(set_attr "type" "multi")
+   (set_attr "length" "7")])
+
+(define_insn "set_got_add"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec [(match_dup 0)
+		 (match_operand 1 "" "")
+		 (label_ref (match_operand 2 "" ""))] UNSPEC_SET_GOT))
+   (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 4)))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && !TARGET_VXWORKS_RTP && !TARGET_DEEP_BRANCH_PREDICTION
+   && flag_pic"
+  "add%z0\t{%1+[.-%l2], %0|%0, %1+(.-%l2)}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "7")])
+
 (define_insn "set_got"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
Index: gcc/doc/tm.texi
===================================================================
--- gcc.orig/doc/tm.texi
+++ gcc/doc/tm.texi
@@ -3204,6 +3204,10 @@  terminate the stack backtrace.  New port
 @end defmac
 
 @deftypefn {Target Hook} void TARGET_DWARF_HANDLE_FRAME_UNSPEC (rtx @var{pattern}, int @var{index})
+
+@deftypefn {Target Hook} bool TARGET_DWARF_FLUSH_QUEUED_REGISTER_SAVES (rtx @var{insn})
+This target hook allows the backend to force dwarf2out to flush queued register saves before an insn when generating unwind information.  It is called with an insn as its argument and should return true if register saves must be flushed.
+@end deftypefn
 This target hook allows the backend to emit frame-related insns that
 contain UNSPECs or UNSPEC_VOLATILEs.  The DWARF 2 call frame debugging
 info engine will invoke it on insns of the form
Index: gcc/dwarf2out.c
===================================================================
--- gcc.orig/dwarf2out.c
+++ gcc/dwarf2out.c
@@ -2972,7 +2972,9 @@  scan_until_barrier (rtx insn, jump_targe
 	}
 
       if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)
-	  || (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END))
+	  || (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END)
+	  || (targetm.dwarf_flush_queued_register_saves != NULL
+	      && targetm.dwarf_flush_queued_register_saves (insn)))
 	{
 	  cfi_insn = PREV_INSN (insn);
 	  dwarf2out_flush_queued_reg_saves ();
Index: gcc/target.def
===================================================================
--- gcc.orig/target.def
+++ gcc/target.def
@@ -1794,6 +1794,14 @@  DEFHOOK
  "",
  void, (rtx pattern, int index), NULL)
 
+DEFHOOK
+(dwarf_flush_queued_register_saves,
+"This target hook allows the backend to force dwarf2out to flush queued\
+ register saves before an insn when generating unwind information.  It\
+ is called with an insn as its argument and should return true if\
+ register saves must be flushed.",
+ bool, (rtx insn), NULL)
+
 /* ??? Documenting this hook requires a GFDL license grant.  */
 DEFHOOK_UNDOC
 (stdarg_optimize_hook,