Fix PR target/83368

Message ID 9596295.9SGXmIeu7d@polaris
State New
Headers show
Series
  • Fix PR target/83368
Related show

Commit Message

Eric Botcazou Jan. 12, 2018, 11:29 a.m.
This fixes a somewhat obscure interaction between alloca and setjmp/longjmp in 
PIC mode on the SPARC architecture.  The problem is that the canonical PIC 
register on SPARC (%l7) is call-saved like on other architectures but, unlike 
on other architectures, not (always) preserved by setjmp.  There is a note in 
the SCD about this quirk of setjmp so we must probably live with it.

Tested on SPARC64/Linux and SPARC/Solaris, applied on the mainline.


2018-01-12  Eric Botcazou  <ebotcazou@adacore.com>

	PR target/83368
	* config/sparc/sparc.h (PIC_OFFSET_TABLE_REGNUM): Set to INVALID_REGNUM
	in PIC mode except for TARGET_VXWORKS_RTP.
	* config/sparc/sparc.c: Include cfgrtl.h.
	(TARGET_INIT_PIC_REG): Define.
	(TARGET_USE_PSEUDO_PIC_REG): Likewise.
	(sparc_pic_register_p): New predicate.
	(sparc_legitimate_address_p): Use it.
	(sparc_legitimize_pic_address): Likewise.
	(sparc_delegitimize_address): Likewise.
	(sparc_mode_dependent_address_p): Likewise.
	(gen_load_pcrel_sym): Remove 4th parameter.
	(load_got_register): Adjust call to above.  Remove obsolete stuff.
	(sparc_expand_prologue): Do not call load_got_register here.
	(sparc_flat_expand_prologue): Likewise.
	(sparc_output_mi_thunk): Set the pic_offset_table_rtx object.
	(sparc_use_pseudo_pic_reg): New function.
	(sparc_init_pic_reg): Likewise.
	* config/sparc/sparc.md (vxworks_load_got): Set the GOT register.
	(builtin_setjmp_receiver): Enable only for TARGET_VXWORKS_RTP.


2018-01-12  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc.target/sparc/setjmp-1.c: New test.

Patch

Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 256275)
+++ config/sparc/sparc.c	(working copy)
@@ -51,6 +51,7 @@  along with GCC; see the file COPYING3.
 #include "explow.h"
 #include "expr.h"
 #include "debug.h"
+#include "cfgrtl.h"
 #include "common/common-target.h"
 #include "gimplify.h"
 #include "langhooks.h"
@@ -662,6 +663,8 @@  static bool sparc_frame_pointer_required
 static bool sparc_can_eliminate (const int, const int);
 static rtx sparc_builtin_setjmp_frame_value (void);
 static void sparc_conditional_register_usage (void);
+static bool sparc_use_pseudo_pic_reg (void);
+static void sparc_init_pic_reg (void);
 #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
 static const char *sparc_mangle_type (const_tree);
 #endif
@@ -877,6 +880,12 @@  char sparc_hard_reg_printed[8];
 #undef TARGET_CONDITIONAL_REGISTER_USAGE
 #define TARGET_CONDITIONAL_REGISTER_USAGE sparc_conditional_register_usage
 
+#undef TARGET_INIT_PIC_REG
+#define TARGET_INIT_PIC_REG sparc_init_pic_reg
+
+#undef TARGET_USE_PSEUDO_PIC_REG
+#define TARGET_USE_PSEUDO_PIC_REG sparc_use_pseudo_pic_reg
+
 #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE sparc_mangle_type
@@ -4361,6 +4370,25 @@  legitimate_pic_operand_p (rtx x)
   return true;
 }
 
+/* Return true if X is a representation of the PIC register.  */
+
+static bool
+sparc_pic_register_p (rtx x)
+{
+  if (!REG_P (x) || !pic_offset_table_rtx)
+    return false;
+
+  if (x == pic_offset_table_rtx)
+    return true;
+
+  if (!HARD_REGISTER_P (pic_offset_table_rtx)
+      && (HARD_REGISTER_P (x) || lra_in_progress)
+      && ORIGINAL_REGNO (x) == REGNO (pic_offset_table_rtx))
+    return true;
+
+  return false;
+}
+
 #define RTX_OK_FOR_OFFSET_P(X, MODE)			\
   (CONST_INT_P (X)					\
    && INTVAL (X) >= -0x1000				\
@@ -4401,7 +4429,7 @@  sparc_legitimate_address_p (machine_mode
 	}
 
       if ((flag_pic == 1
-	   && rs1 == pic_offset_table_rtx
+	   && sparc_pic_register_p (rs1)
 	   && !REG_P (rs2)
 	   && GET_CODE (rs2) != SUBREG
 	   && GET_CODE (rs2) != LO_SUM
@@ -4796,7 +4824,7 @@  sparc_legitimize_pic_address (rtx orig,
       rtx base, offset;
 
       if (GET_CODE (XEXP (orig, 0)) == PLUS
-	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+	  && sparc_pic_register_p (XEXP (XEXP (orig, 0), 0)))
 	return orig;
 
       if (reg == 0)
@@ -4901,8 +4929,7 @@  sparc_delegitimize_address (rtx x)
 
   /* This is generated by mov{si,di}_pic_label_ref in PIC mode.  */
   if (GET_CODE (x) == MINUS
-      && REG_P (XEXP (x, 0))
-      && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM
+      && sparc_pic_register_p (XEXP (x, 0))
       && GET_CODE (XEXP (x, 1)) == LO_SUM
       && GET_CODE (XEXP (XEXP (x, 1), 1)) == UNSPEC
       && XINT (XEXP (XEXP (x, 1), 1), 1) == UNSPEC_MOVE_PIC_LABEL)
@@ -4981,14 +5008,10 @@  static bool
 sparc_mode_dependent_address_p (const_rtx addr,
 				addr_space_t as ATTRIBUTE_UNUSED)
 {
-  if (flag_pic && GET_CODE (addr) == PLUS)
-    {
-      rtx op0 = XEXP (addr, 0);
-      rtx op1 = XEXP (addr, 1);
-      if (op0 == pic_offset_table_rtx
-	  && symbolic_operand (op1, VOIDmode))
-	return true;
-    }
+  if (GET_CODE (addr) == PLUS
+      && sparc_pic_register_p (XEXP (addr, 0))
+      && symbolic_operand (XEXP (addr, 1), VOIDmode))
+    return true;
 
   return false;
 }
@@ -5017,7 +5040,7 @@  get_pc_thunk_name (char name[32], unsign
 /* Wrapper around the load_pcrel_sym{si,di} patterns.  */
 
 static rtx
-gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2, rtx op3)
+gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2)
 {
   int orig_flag_pic = flag_pic;
   rtx insn;
@@ -5025,9 +5048,9 @@  gen_load_pcrel_sym (rtx op0, rtx op1, rt
   /* The load_pcrel_sym{si,di} patterns require absolute addressing.  */
   flag_pic = 0;
   if (TARGET_ARCH64)
-    insn = gen_load_pcrel_symdi (op0, op1, op2, op3);
+    insn = gen_load_pcrel_symdi (op0, op1, op2, GEN_INT (REGNO (op0)));
   else
-    insn = gen_load_pcrel_symsi (op0, op1, op2, op3);
+    insn = gen_load_pcrel_symsi (op0, op1, op2, GEN_INT (REGNO (op0)));
   flag_pic = orig_flag_pic;
 
   return insn;
@@ -5038,7 +5061,6 @@  gen_load_pcrel_sym (rtx op0, rtx op1, rt
 void
 load_got_register (void)
 {
-  /* In PIC mode, this will retrieve pic_offset_table_rtx.  */
   if (!global_offset_table_rtx)
     global_offset_table_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM);
 
@@ -5056,15 +5078,8 @@  load_got_register (void)
 	}
 
       emit_insn (gen_load_pcrel_sym (global_offset_table_rtx, sparc_got (),
-				     got_helper_rtx,
-				     GEN_INT (GLOBAL_OFFSET_TABLE_REGNUM)));
+				     got_helper_rtx));
     }
-
-  /* Need to emit this whether or not we obey regdecls,
-     since setjmp/longjmp can cause life info to screw up.
-     ??? In the case where we don't obey regdecls, this is not sufficient
-     since we may not fall out the bottom.  */
-  emit_use (global_offset_table_rtx);
 }
 
 /* Emit a call instruction with the pattern given by PAT.  ADDR is the
@@ -6039,10 +6054,6 @@  sparc_expand_prologue (void)
 					   - sparc_apparent_frame_size,
 					 SORR_SAVE);
 
-  /* Load the GOT register if needed.  */
-  if (crtl->uses_pic_offset_table)
-    load_got_register ();
-
   /* Advertise that the data calculated just above are now valid.  */
   sparc_prologue_data_valid_p = true;
 }
@@ -6161,10 +6172,6 @@  sparc_flat_expand_prologue (void)
 					   - sparc_apparent_frame_size,
 					 SORR_SAVE);
 
-  /* Load the GOT register if needed.  */
-  if (crtl->uses_pic_offset_table)
-    load_got_register ();
-
   /* Advertise that the data calculated just above are now valid.  */
   sparc_prologue_data_valid_p = true;
 }
@@ -12305,6 +12312,8 @@  sparc_output_mi_thunk (FILE *file, tree
 	  spill_reg = gen_rtx_REG (word_mode, 15);  /* %o7 */
 	  start_sequence ();
 	  load_got_register ();  /* clobbers %o7 */
+	  if (!TARGET_VXWORKS_RTP)
+	    pic_offset_table_rtx = global_offset_table_rtx;
 	  scratch = sparc_legitimize_pic_address (funexp, scratch);
 	  seq = get_insns ();
 	  end_sequence ();
@@ -12950,6 +12959,37 @@  sparc_conditional_register_usage (void)
     global_regs[SPARC_GSR_REG] = 1;
 }
 
+/* Implement TARGET_USE_PSEUDO_PIC_REG.  */
+
+static bool
+sparc_use_pseudo_pic_reg (void)
+{
+  return !TARGET_VXWORKS_RTP && flag_pic;
+}
+
+/* Implement TARGET_INIT_PIC_REG.  */
+
+static void
+sparc_init_pic_reg (void)
+{
+  edge entry_edge;
+  rtx_insn *seq;
+
+  if (!crtl->uses_pic_offset_table)
+    return;
+
+  start_sequence ();
+  load_got_register ();
+  if (!TARGET_VXWORKS_RTP)
+    emit_move_insn (pic_offset_table_rtx, global_offset_table_rtx);
+  seq = get_insns ();
+  end_sequence ();
+
+  entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  insert_insn_on_edge (seq, entry_edge);
+  commit_one_edge_insertion (entry_edge);
+}
+
 /* Implement TARGET_PREFERRED_RELOAD_CLASS:
 
    - We can't load constants into FP registers.
Index: config/sparc/sparc.h
===================================================================
--- config/sparc/sparc.h	(revision 256275)
+++ config/sparc/sparc.h	(working copy)
@@ -808,11 +808,14 @@  extern enum cmodel sparc_cmodel;
 
 #define GLOBAL_OFFSET_TABLE_REGNUM 23
 
-/* Register which holds offset table for position-independent
-   data references.  */
+/* Register which holds offset table for position-independent data references.
+   The original SPARC ABI imposes no requirement on the choice of the register
+   so we use a pseudo-register to make sure it is properly saved and restored
+   around calls to setjmp.  Now the ABI of VxWorks RTP makes it live on entry
+   to PLT entries so we use the canonical GOT register in this case.  */
 
 #define PIC_OFFSET_TABLE_REGNUM \
-  (flag_pic ? GLOBAL_OFFSET_TABLE_REGNUM : INVALID_REGNUM)
+  (TARGET_VXWORKS_RTP && flag_pic ? GLOBAL_OFFSET_TABLE_REGNUM : INVALID_REGNUM)
 
 /* Pick a default value we can notice from override_options:
    !v9: Default is on.
Index: config/sparc/sparc.md
===================================================================
--- config/sparc/sparc.md	(revision 256275)
+++ config/sparc/sparc.md	(working copy)
@@ -1797,7 +1797,7 @@  (define_insn "*movsi_lo_sum_pic_label_re
   "flag_pic"
   "or\t%1, %%lo(%a3-(%a2-.)), %0")
 
-;; Set up the PIC register for VxWorks.
+;; Set up the GOT register for VxWorks.
 
 (define_expand "vxworks_load_got"
   [(set (match_dup 0)
@@ -1808,7 +1808,7 @@  (define_expand "vxworks_load_got"
 	(mem:SI (lo_sum:SI (match_dup 0) (match_dup 2))))]
   "TARGET_VXWORKS_RTP"
 {
-  operands[0] = pic_offset_table_rtx;
+  operands[0] = global_offset_table_rtx;
   operands[1] = gen_rtx_SYMBOL_REF (SImode, VXWORKS_GOTT_BASE);
   operands[2] = gen_rtx_SYMBOL_REF (SImode, VXWORKS_GOTT_INDEX);
 })
@@ -7475,7 +7475,7 @@  (define_expand "nonlocal_goto"
 
 (define_expand "builtin_setjmp_receiver"
   [(label_ref (match_operand 0 "" ""))]
-  "flag_pic"
+  "TARGET_VXWORKS_RTP && flag_pic"
 {
   load_got_register ();
   DONE;