re PR target/83368 (alloca after setjmp breaks PIC base reg)
authorEric Botcazou <ebotcazou@adacore.com>
Fri, 12 Jan 2018 11:29:30 +0000 (11:29 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Fri, 12 Jan 2018 11:29:30 +0000 (11:29 +0000)
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.

From-SVN: r256575

gcc/ChangeLog
gcc/config/sparc/sparc.c
gcc/config/sparc/sparc.h
gcc/config/sparc/sparc.md
gcc/testsuite/gcc.target/sparc/setjmp-1.c [new file with mode: 0644]

index f23d68d..e13743d 100644 (file)
@@ -1,3 +1,26 @@
+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  Christophe Lyon  <christophe.lyon@linaro.org>
 
        * doc/sourcebuild.texi (Effective-Target Keywords, Other attributes):
index 668ccad..48669f1 100644 (file)
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #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 (void);
 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 mode, rtx addr, bool strict)
        }
 
       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 reg)
       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], unsigned int regno)
 /* 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, rtx op2, rtx op3)
   /* 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, rtx op2, rtx op3)
 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 thunk_fndecl ATTRIBUTE_UNUSED,
          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 1d10199..4199954 100644 (file)
@@ -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 ea75cf2..3255e5c 100644 (file)
   "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)
        (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 @@ visl")
 
 (define_expand "builtin_setjmp_receiver"
   [(label_ref (match_operand 0 "" ""))]
-  "flag_pic"
+  "TARGET_VXWORKS_RTP && flag_pic"
 {
   load_got_register ();
   DONE;
diff --git a/gcc/testsuite/gcc.target/sparc/setjmp-1.c b/gcc/testsuite/gcc.target/sparc/setjmp-1.c
new file mode 100644 (file)
index 0000000..d0fecb3
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR target/83368 */\r
+/* Testcase written by James Clarke <jrtc27@jrtc27.com> */\r
+\r
+/* { dg-do run { target *-*-solaris2.* *-*-linux* *-*-*bsd* } } */\r
+/* { dg-require-effective-target fpic } */\r
+/* { dg-options "-fPIC" } */\r
+\r
+#include <stdio.h>\r
+#include <alloca.h>\r
+#include <setjmp.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+\r
+jmp_buf jb;\r
+\r
+int foo = 99;\r
+int c = 0;\r
+\r
+void bar (void)\r
+{\r
+  c++;\r
+  longjmp (jb, 1);\r
+}\r
+\r
+int main (void)\r
+{\r
+  setjmp (jb);\r
+\r
+  char *p = alloca (256);\r
+  memset (p, 0, 256);\r
+  sprintf (p, "%d\n", foo);\r
+\r
+  if (c < 10)\r
+    bar();\r
+\r
+  return 0;\r
+}\r