rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK): Define.
authorAlan Modra <amodra@gmail.com>
Wed, 20 May 2015 01:26:28 +0000 (10:56 +0930)
committerAlan Modra <amodra@gcc.gnu.org>
Wed, 20 May 2015 01:26:28 +0000 (10:56 +0930)
gcc/
* common/config/rs6000/rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK):
Define.
(rs6000_supports_split_stack): New function.
* gcc/config/rs6000/rs6000.c (machine_function): Add
split_stack_arg_pointer.
(TARGET_EXTRA_LIVE_ON_ENTRY, TARGET_INTERNAL_ARG_POINTER): Define.
(setup_incoming_varargs): Use crtl->args.internal_arg_pointer
rather than virtual_incoming_args_rtx.
(rs6000_va_start): Likewise.
(split_stack_arg_pointer_used_p): New function.
(rs6000_emit_prologue): Set up arg pointer for -fsplit-stack.
(morestack_ref): New var.
(gen_add3_const, rs6000_expand_split_stack_prologue,
rs6000_internal_arg_pointer, rs6000_live_on_entry,
rs6000_split_stack_space_check): New functions.
(rs6000_elf_file_end): Call file_end_indicate_split_stack.
* gcc/config/rs6000/rs6000.md (UNSPEC_STACK_CHECK): Define.
(UNSPECV_SPLIT_STACK_RETURN): Define.
(split_stack_prologue, load_split_stack_limit,
load_split_stack_limit_di, load_split_stack_limit_si,
split_stack_return, split_stack_space_check): New expands and insns.
* gcc/config/rs6000/rs6000-protos.h
(rs6000_expand_split_stack_prologue): Declare.
(rs6000_split_stack_space_check): Declare.
libgcc/
* config/rs6000/morestack.S: New.
* config/rs6000/t-stack-rs6000: New.
* config.host (powerpc*-*-linux*): Add t-stack and t-stack-rs6000
to tmake_file.
* generic-morestack.c: Don't build for powerpc 32-bit.

From-SVN: r223426

gcc/ChangeLog
gcc/common/config/rs6000/rs6000-common.c
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
libgcc/ChangeLog
libgcc/config.host
libgcc/config/rs6000/morestack.S [new file with mode: 0644]
libgcc/config/rs6000/t-stack-rs6000 [new file with mode: 0644]
libgcc/generic-morestack.c

index 56b028d7c5334a4375b9d9b24bf09873f4541b5c..471291ceebf414e3a91310425b07135402cfff7e 100644 (file)
@@ -1,3 +1,30 @@
+2015-05-20  Alan Modra  <amodra@gmail.com>
+
+       * common/config/rs6000/rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK):
+       Define.
+       (rs6000_supports_split_stack): New function.
+       * gcc/config/rs6000/rs6000.c (machine_function): Add
+       split_stack_arg_pointer.
+       (TARGET_EXTRA_LIVE_ON_ENTRY, TARGET_INTERNAL_ARG_POINTER): Define.
+       (setup_incoming_varargs): Use crtl->args.internal_arg_pointer
+       rather than virtual_incoming_args_rtx.
+       (rs6000_va_start): Likewise.
+       (split_stack_arg_pointer_used_p): New function.
+       (rs6000_emit_prologue): Set up arg pointer for -fsplit-stack.
+       (morestack_ref): New var.
+       (gen_add3_const, rs6000_expand_split_stack_prologue,
+       rs6000_internal_arg_pointer, rs6000_live_on_entry,
+       rs6000_split_stack_space_check): New functions.
+       (rs6000_elf_file_end): Call file_end_indicate_split_stack.
+       * gcc/config/rs6000/rs6000.md (UNSPEC_STACK_CHECK): Define.
+       (UNSPECV_SPLIT_STACK_RETURN): Define.
+       (split_stack_prologue, load_split_stack_limit,
+       load_split_stack_limit_di, load_split_stack_limit_si,
+       split_stack_return, split_stack_space_check): New expands and insns.
+       * gcc/config/rs6000/rs6000-protos.h
+       (rs6000_expand_split_stack_prologue): Declare.
+       (rs6000_split_stack_space_check): Declare.
+
 2015-05-20  Alan Modra  <amodra@gmail.com>
 
        * config/rs6000/rs6000.c (struct rs6000_stack): Correct comments.
index e0e158fa76a3d74f965719a96568fd59c76aecb6..891bc554dcfe023fb578dc40e7b3479664357c74 100644 (file)
@@ -288,6 +288,31 @@ rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
   return true;
 }
 
+/* -fsplit-stack uses a field in the TCB, available with glibc-2.19.
+   We also allow 2.18 because alignment padding guarantees that the
+   space is available there too.  */
+
+static bool
+rs6000_supports_split_stack (bool report,
+                            struct gcc_options *opts ATTRIBUTE_UNUSED)
+{
+#ifndef TARGET_GLIBC_MAJOR
+#define TARGET_GLIBC_MAJOR 0
+#endif
+#ifndef TARGET_GLIBC_MINOR
+#define TARGET_GLIBC_MINOR 0
+#endif
+  /* Note: Can't test DEFAULT_ABI here, it isn't set until later.  */
+  if (TARGET_GLIBC_MAJOR * 1000 + TARGET_GLIBC_MINOR >= 2018
+      && TARGET_64BIT
+      && TARGET_ELF)
+    return true;
+
+  if (report)
+    error ("%<-fsplit-stack%> currently only supported on PowerPC64 GNU/Linux with glibc-2.18 or later");
+  return false;
+}
+
 #undef TARGET_HANDLE_OPTION
 #define TARGET_HANDLE_OPTION rs6000_handle_option
 
@@ -300,4 +325,7 @@ rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
 #undef TARGET_OPTION_OPTIMIZATION_TABLE
 #define TARGET_OPTION_OPTIMIZATION_TABLE rs6000_option_optimization_table
 
+#undef TARGET_SUPPORTS_SPLIT_STACK
+#define TARGET_SUPPORTS_SPLIT_STACK rs6000_supports_split_stack
+
 struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
index 739f1c6955319b441d64450c71f98bd5591054c0..bd1ede18cdb0d8926f6d3ecb1780a80f1451070c 100644 (file)
@@ -191,6 +191,8 @@ extern void rs6000_emit_prologue (void);
 extern void rs6000_emit_load_toc_table (int);
 extern unsigned int rs6000_dbx_register_number (unsigned int, unsigned int);
 extern void rs6000_emit_epilogue (int);
+extern void rs6000_expand_split_stack_prologue (void);
+extern void rs6000_split_stack_space_check (rtx, rtx);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern const char * output_isel (rtx *);
 extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
index 92ebd82fadc0d9d2f9ae2569c33b0367d01335f1..8947849a73e4061f195c3919a5c029413f42e0bb 100644 (file)
@@ -187,6 +187,8 @@ typedef struct GTY(()) machine_function
      64-bits wide and is allocated early enough so that the offset
      does not overflow the 16-bit load/store offset field.  */
   rtx sdmode_stack_slot;
+  /* Alternative internal arg pointer for -fsplit-stack.  */
+  rtx split_stack_arg_pointer;
   /* Flag if r2 setup is needed with ELFv2 ABI.  */
   bool r2_setup_needed;
 } machine_function;
@@ -1190,6 +1192,7 @@ static bool rs6000_debug_cannot_change_mode_class (machine_mode,
                                                   machine_mode,
                                                   enum reg_class);
 static bool rs6000_save_toc_in_prologue_p (void);
+static rtx rs6000_internal_arg_pointer (void);
 
 rtx (*rs6000_legitimize_reload_address_ptr) (rtx, machine_mode, int, int,
                                             int, int *)
@@ -1411,6 +1414,12 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_SET_UP_BY_PROLOGUE
 #define TARGET_SET_UP_BY_PROLOGUE rs6000_set_up_by_prologue
 
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY rs6000_live_on_entry
+
+#undef TARGET_INTERNAL_ARG_POINTER
+#define TARGET_INTERNAL_ARG_POINTER rs6000_internal_arg_pointer
+
 #undef TARGET_HAVE_TLS
 #define TARGET_HAVE_TLS HAVE_AS_TLS
 
@@ -11150,7 +11159,7 @@ setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
   else
     {
       first_reg_offset = next_cum.words;
-      save_area = virtual_incoming_args_rtx;
+      save_area = crtl->args.internal_arg_pointer;
 
       if (targetm.calls.must_pass_in_stack (mode, type))
        first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
@@ -11344,7 +11353,7 @@ rs6000_va_start (tree valist, rtx nextarg)
     }
 
   /* Find the overflow area.  */
-  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+  t = make_tree (TREE_TYPE (ovf), crtl->args.internal_arg_pointer);
   if (words != 0)
     t = fold_build_pointer_plus_hwi (t, words * MIN_UNITS_PER_WORD);
   t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
@@ -23424,6 +23433,48 @@ rs6000_reg_live_or_pic_offset_p (int reg)
                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic))));
 }
 
+/* Return whether the split-stack arg pointer (r12) is used.  */
+
+static bool
+split_stack_arg_pointer_used_p (void)
+{
+  /* If the pseudo holding the arg pointer is no longer a pseudo,
+     then the arg pointer is used.  */
+  if (cfun->machine->split_stack_arg_pointer != NULL_RTX
+      && (!REG_P (cfun->machine->split_stack_arg_pointer)
+         || (REGNO (cfun->machine->split_stack_arg_pointer)
+             < FIRST_PSEUDO_REGISTER)))
+    return true;
+
+  /* Unfortunately we also need to do some code scanning, since
+     r12 may have been substituted for the pseudo.  */
+  rtx_insn *insn;
+  basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  FOR_BB_INSNS (bb, insn)
+    if (NONDEBUG_INSN_P (insn))
+      {
+       /* A call destroys r12.  */
+       if (CALL_P (insn))
+         return false;
+
+       df_ref use;
+       FOR_EACH_INSN_USE (use, insn)
+         {
+           rtx x = DF_REF_REG (use);
+           if (REG_P (x) && REGNO (x) == 12)
+             return true;
+         }
+       df_ref def;
+       FOR_EACH_INSN_DEF (def, insn)
+         {
+           rtx x = DF_REF_REG (def);
+           if (REG_P (x) && REGNO (x) == 12)
+             return false;
+         }
+      }
+  return bitmap_bit_p (DF_LR_OUT (bb), 12);
+}
+
 /* Emit function prologue as insns.  */
 
 void
@@ -24375,6 +24426,40 @@ rs6000_emit_prologue (void)
       rtx reg = gen_rtx_REG (reg_mode, TOC_REGNUM);
       emit_insn (gen_frame_store (reg, sp_reg_rtx, RS6000_TOC_SAVE_SLOT));
     }
+
+  if (flag_split_stack && split_stack_arg_pointer_used_p ())
+    {
+      /* Set up the arg pointer (r12) for -fsplit-stack code.  If
+        __morestack was called, it left the arg pointer to the old
+        stack in r29.  Otherwise, the arg pointer is the top of the
+        current frame.  */
+      if (frame_off != 0 || REGNO (frame_reg_rtx) != 12)
+       {
+         rtx r12 = gen_rtx_REG (Pmode, 12);
+         if (frame_off == 0)
+           emit_move_insn (r12, frame_reg_rtx);
+         else
+           emit_insn (gen_add3_insn (r12, frame_reg_rtx, GEN_INT (frame_off)));
+       }
+      if (info->push_p)
+       {
+         rtx r12 = gen_rtx_REG (Pmode, 12);
+         rtx r29 = gen_rtx_REG (Pmode, 29);
+         rtx cr7 = gen_rtx_REG (CCUNSmode, CR7_REGNO);
+         rtx not_more = gen_label_rtx ();
+         rtx jump;
+
+         jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+                                      gen_rtx_GEU (VOIDmode, cr7, const0_rtx),
+                                      gen_rtx_LABEL_REF (VOIDmode, not_more),
+                                      pc_rtx);
+         jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
+         JUMP_LABEL (jump) = not_more;
+         LABEL_NUSES (not_more) += 1;
+         emit_move_insn (r12, r29);
+         emit_label (not_more);
+       }
+    }
 }
 
 /* Output .extern statements for the save/restore routines we use.  */
@@ -25802,6 +25887,178 @@ rs6000_output_function_epilogue (FILE *file,
       fputs ("\t.align 2\n", file);
     }
 }
+
+/* -fsplit-stack support.  */
+
+/* A SYMBOL_REF for __morestack.  */
+static GTY(()) rtx morestack_ref;
+
+static rtx
+gen_add3_const (rtx rt, rtx ra, long c)
+{
+  if (TARGET_64BIT)
+    return gen_adddi3 (rt, ra, GEN_INT (c));
+ else
+    return gen_addsi3 (rt, ra, GEN_INT (c));
+}
+
+/* Emit -fsplit-stack prologue, which goes before the regular function
+   prologue (at local entry point in the case of ELFv2).  */
+
+void
+rs6000_expand_split_stack_prologue (void)
+{
+  rs6000_stack_t *info = rs6000_stack_info ();
+  unsigned HOST_WIDE_INT allocate;
+  long alloc_hi, alloc_lo;
+  rtx r0, r1, r12, lr, ok_label, compare, jump, call_fusage;
+  rtx_insn *insn;
+
+  gcc_assert (flag_split_stack && reload_completed);
+
+  if (!info->push_p)
+    return;
+
+  allocate = info->total_size;
+  if (allocate > (unsigned HOST_WIDE_INT) 1 << 31)
+    {
+      sorry ("Stack frame larger than 2G is not supported for -fsplit-stack");
+      return;
+    }
+  if (morestack_ref == NULL_RTX)
+    {
+      morestack_ref = gen_rtx_SYMBOL_REF (Pmode, "__morestack");
+      SYMBOL_REF_FLAGS (morestack_ref) |= (SYMBOL_FLAG_LOCAL
+                                          | SYMBOL_FLAG_FUNCTION);
+    }
+
+  r0 = gen_rtx_REG (Pmode, 0);
+  r1 = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+  r12 = gen_rtx_REG (Pmode, 12);
+  emit_insn (gen_load_split_stack_limit (r0));
+  /* Always emit two insns here to calculate the requested stack,
+     so that the linker can edit them when adjusting size for calling
+     non-split-stack code.  */
+  alloc_hi = (-allocate + 0x8000) & ~0xffffL;
+  alloc_lo = -allocate - alloc_hi;
+  if (alloc_hi != 0)
+    {
+      emit_insn (gen_add3_const (r12, r1, alloc_hi));
+      if (alloc_lo != 0)
+       emit_insn (gen_add3_const (r12, r12, alloc_lo));
+      else
+       emit_insn (gen_nop ());
+    }
+  else
+    {
+      emit_insn (gen_add3_const (r12, r1, alloc_lo));
+      emit_insn (gen_nop ());
+    }
+
+  compare = gen_rtx_REG (CCUNSmode, CR7_REGNO);
+  emit_insn (gen_rtx_SET (compare, gen_rtx_COMPARE (CCUNSmode, r12, r0)));
+  ok_label = gen_label_rtx ();
+  jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+                              gen_rtx_GEU (VOIDmode, compare, const0_rtx),
+                              gen_rtx_LABEL_REF (VOIDmode, ok_label),
+                              pc_rtx);
+  jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
+  JUMP_LABEL (jump) = ok_label;
+  /* Mark the jump as very likely to be taken.  */
+  add_int_reg_note (jump, REG_BR_PROB,
+                   REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100);
+
+  lr = gen_rtx_REG (Pmode, LR_REGNO);
+  insn = emit_move_insn (r0, lr);
+  RTX_FRAME_RELATED_P (insn) = 1;
+  insn = emit_insn (gen_frame_store (r0, r1, info->lr_save_offset));
+  RTX_FRAME_RELATED_P (insn) = 1;
+
+  insn = emit_call_insn (gen_call (gen_rtx_MEM (SImode, morestack_ref),
+                                  const0_rtx, const0_rtx));
+  call_fusage = NULL_RTX;
+  use_reg (&call_fusage, r12);
+  add_function_usage_to (insn, call_fusage);
+  emit_insn (gen_frame_load (r0, r1, info->lr_save_offset));
+  insn = emit_move_insn (lr, r0);
+  add_reg_note (insn, REG_CFA_RESTORE, lr);
+  RTX_FRAME_RELATED_P (insn) = 1;
+  emit_insn (gen_split_stack_return ());
+
+  emit_label (ok_label);
+  LABEL_NUSES (ok_label) = 1;
+}
+
+/* Return the internal arg pointer used for function incoming
+   arguments.  When -fsplit-stack, the arg pointer is r12 so we need
+   to copy it to a pseudo in order for it to be preserved over calls
+   and suchlike.  We'd really like to use a pseudo here for the
+   internal arg pointer but data-flow analysis is not prepared to
+   accept pseudos as live at the beginning of a function.  */
+
+static rtx
+rs6000_internal_arg_pointer (void)
+{
+  if (flag_split_stack)
+    {
+      if (cfun->machine->split_stack_arg_pointer == NULL_RTX)
+       {
+         rtx pat;
+
+         cfun->machine->split_stack_arg_pointer = gen_reg_rtx (Pmode);
+         REG_POINTER (cfun->machine->split_stack_arg_pointer) = 1;
+
+         /* Put the pseudo initialization right after the note at the
+            beginning of the function.  */
+         pat = gen_rtx_SET (cfun->machine->split_stack_arg_pointer,
+                            gen_rtx_REG (Pmode, 12));
+         push_topmost_sequence ();
+         emit_insn_after (pat, get_insns ());
+         pop_topmost_sequence ();
+       }
+      return plus_constant (Pmode, cfun->machine->split_stack_arg_pointer,
+                           FIRST_PARM_OFFSET (current_function_decl));
+    }
+  return virtual_incoming_args_rtx;
+}
+
+/* We may have to tell the dataflow pass that the split stack prologue
+   is initializing a register.  */
+
+static void
+rs6000_live_on_entry (bitmap regs)
+{
+  if (flag_split_stack)
+    bitmap_set_bit (regs, 12);
+}
+
+/* Emit -fsplit-stack dynamic stack allocation space check.  */
+
+void
+rs6000_split_stack_space_check (rtx size, rtx label)
+{
+  rtx sp = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+  rtx limit = gen_reg_rtx (Pmode);
+  rtx requested = gen_reg_rtx (Pmode);
+  rtx cmp = gen_reg_rtx (CCUNSmode);
+  rtx jump;
+
+  emit_insn (gen_load_split_stack_limit (limit));
+  if (CONST_INT_P (size))
+    emit_insn (gen_add3_insn (requested, sp, GEN_INT (-INTVAL (size))));
+  else
+    {
+      size = force_reg (Pmode, size);
+      emit_move_insn (requested, gen_rtx_MINUS (Pmode, sp, size));
+    }
+  emit_insn (gen_rtx_SET (cmp, gen_rtx_COMPARE (CCUNSmode, requested, limit)));
+  jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+                              gen_rtx_GEU (VOIDmode, cmp, const0_rtx),
+                              gen_rtx_LABEL_REF (VOIDmode, label),
+                              pc_rtx);
+  jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
+  JUMP_LABEL (jump) = label;
+}
 \f
 /* A C compound statement that outputs the assembler code for a thunk
    function, used to implement C++ virtual function calls with
@@ -29810,6 +30067,9 @@ rs6000_elf_file_end (void)
   if (TARGET_32BIT || DEFAULT_ABI == ABI_ELFv2)
     file_end_indicate_exec_stack ();
 #endif
+
+  if (flag_split_stack)
+    file_end_indicate_split_stack ();
 }
 #endif
 
index e156e1409d93372a139017f2fd6db6b5599b9d2f..5d3e04be819077506a0d450496e711a6c0bf706f 100644 (file)
    UNSPEC_PACK_128BIT
    UNSPEC_LSQ
    UNSPEC_FUSION_GPR
+   UNSPEC_STACK_CHECK
   ])
 
 ;;
    UNSPECV_NLGR                        ; non-local goto receiver
    UNSPECV_MFFS                        ; Move from FPSCR
    UNSPECV_MTFSF               ; Move to FPSCR Fields
+   UNSPECV_SPLIT_STACK_RETURN   ; A camouflaged return
   ])
 
 \f
 }"
   [(set_attr "type" "load")])
 \f
+;; Handle -fsplit-stack.
+
+(define_expand "split_stack_prologue"
+  [(const_int 0)]
+  ""
+{
+  rs6000_expand_split_stack_prologue ();
+  DONE;
+})
+
+(define_expand "load_split_stack_limit"
+  [(set (match_operand 0)
+       (unspec [(const_int 0)] UNSPEC_STACK_CHECK))]
+  ""
+{
+  emit_insn (gen_rtx_SET (operands[0],
+                         gen_rtx_UNSPEC (Pmode,
+                                         gen_rtvec (1, const0_rtx),
+                                         UNSPEC_STACK_CHECK)));
+  DONE;
+})
+
+(define_insn "load_split_stack_limit_di"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (unspec:DI [(const_int 0)] UNSPEC_STACK_CHECK))]
+  "TARGET_64BIT"
+  "ld %0,-0x7040(13)"
+  [(set_attr "type" "load")
+   (set_attr "update" "no")
+   (set_attr "indexed" "no")])
+
+(define_insn "load_split_stack_limit_si"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+       (unspec:SI [(const_int 0)] UNSPEC_STACK_CHECK))]
+  "!TARGET_64BIT"
+  "lwz %0,-0x7020(2)"
+  [(set_attr "type" "load")
+   (set_attr "update" "no")
+   (set_attr "indexed" "no")])
+
+;; A return instruction which the middle-end doesn't see.
+(define_insn "split_stack_return"
+  [(unspec_volatile [(const_int 0)] UNSPECV_SPLIT_STACK_RETURN)]
+  ""
+  "blr"
+  [(set_attr "type" "jmpreg")])
+
+;; If there are operand 0 bytes available on the stack, jump to
+;; operand 1.
+(define_expand "split_stack_space_check"
+  [(set (match_dup 2)
+       (unspec [(const_int 0)] UNSPEC_STACK_CHECK))
+   (set (match_dup 3)
+       (minus (reg STACK_POINTER_REGNUM)
+              (match_operand 0)))
+   (set (match_dup 4) (compare:CCUNS (match_dup 3) (match_dup 2)))
+   (set (pc) (if_then_else
+             (geu (match_dup 4) (const_int 0))
+             (label_ref (match_operand 1))
+             (pc)))]
+  ""
+{
+  rs6000_split_stack_space_check (operands[0], operands[1]);
+  DONE;
+})
+\f
 (define_insn "bpermd_<mode>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=r")
        (unspec:P [(match_operand:P 1 "gpc_reg_operand" "r")
index 51b6cf28445c9a2dab7262f3d680ac015b48d492..c4e716e996d4ed875d4261dcaefe630cdf66636f 100644 (file)
@@ -1,3 +1,11 @@
+2015-05-20  Alan Modra  <amodra@gmail.com>
+
+       * config/rs6000/morestack.S: New.
+       * config/rs6000/t-stack-rs6000: New.
+       * config.host (powerpc*-*-linux*): Add t-stack and t-stack-rs6000
+       to tmake_file.
+       * generic-morestack.c: Don't build for powerpc 32-bit.
+
 2015-05-19  Eric Botcazou  <ebotcazou@adacore.com>
 
        * Makefile.in (LIBUNWIND): Move dependency for shared libgcc.
index d6242211adabac853f1030fda6be00895b5c7b3e..8d826806d2ab3379ea1ac9d01a3091334b45f210 100644 (file)
@@ -1027,6 +1027,7 @@ powerpc-*-rtems*)
        ;;
 powerpc*-*-linux*)
        tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff rs6000/t-linux t-dfprules rs6000/t-ppc64-fp t-slibgcc-libgcc"
+       tmake_file="${tmake_file} t-stack rs6000/t-stack-rs6000"
        case $ppc_fp_type in
        64)
                ;;
diff --git a/libgcc/config/rs6000/morestack.S b/libgcc/config/rs6000/morestack.S
new file mode 100644 (file)
index 0000000..ecd1bf4
--- /dev/null
@@ -0,0 +1,351 @@
+#ifdef __powerpc64__
+# PowerPC64 support for -fsplit-stack.
+# Copyright (C) 2009-2015 Free Software Foundation, Inc.
+# Contributed by Alan Modra <amodra@gmail.com>.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3, or (at your option) any later
+# version.
+
+# GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+# <http://www.gnu.org/licenses/>.
+
+#if _CALL_ELF == 2
+       .abiversion 2
+#define PARAMS 32
+#else
+       .abiversion 1
+#define PARAMS 48
+#endif
+#define MORESTACK_FRAMESIZE    (PARAMS+96)
+#define PARAMREG_SAVE          -MORESTACK_FRAMESIZE+PARAMS+0
+#define STATIC_CHAIN_SAVE      -MORESTACK_FRAMESIZE+PARAMS+64
+#define R29_SAVE               -MORESTACK_FRAMESIZE+PARAMS+72
+#define LINKREG_SAVE           -MORESTACK_FRAMESIZE+PARAMS+80
+#define NEWSTACKSIZE_SAVE      -MORESTACK_FRAMESIZE+PARAMS+88
+
+# Excess space needed to call ld.so resolver for lazy plt
+# resolution.  Go uses sigaltstack so this doesn't need to
+# also cover signal frame size.
+#define BACKOFF 4096
+# Large excess allocated when calling non-split-stack code.
+#define NON_SPLIT_STACK 0x100000
+
+
+#if _CALL_ELF == 2
+
+#define BODY_LABEL(name) name
+
+#define ENTRY0(name)                                   \
+       .global name;                                   \
+       .hidden name;                                   \
+       .type name,@function;                           \
+name##:
+
+#define ENTRY(name)                                    \
+       ENTRY0(name);                                   \
+0:     addis %r2,%r12,.TOC.-0b@ha;                     \
+        addi %r2,%r2,.TOC.-0b@l;                       \
+       .localentry name, .-name
+
+#else
+
+#define BODY_LABEL(name) .L.##name
+
+#define ENTRY0(name)                                   \
+       .global name;                                   \
+       .hidden name;                                   \
+       .type name,@function;                           \
+       .pushsection ".opd","aw";                       \
+       .p2align 3;                                     \
+name##: .quad BODY_LABEL (name), .TOC.@tocbase, 0;     \
+       .popsection;                                    \
+BODY_LABEL(name)##:
+
+#define ENTRY(name) ENTRY0(name)
+
+#endif
+
+#define SIZE(name) .size name, .-BODY_LABEL(name)
+
+
+       .text
+# Just like __morestack, but with larger excess allocation
+ENTRY0(__morestack_non_split)
+.LFB1:
+       .cfi_startproc
+# We use a cleanup to restore the tcbhead_t.__private_ss if
+# an exception is thrown through this code.
+#ifdef __PIC__
+       .cfi_personality 0x9b,DW.ref.__gcc_personality_v0
+       .cfi_lsda 0x1b,.LLSDA1
+#else
+       .cfi_personality 0x3,__gcc_personality_v0
+       .cfi_lsda 0x3,.LLSDA1
+#endif
+# LR is already saved by the split-stack prologue code.
+# We may as well have the unwinder skip over the call in the
+# prologue too.
+       .cfi_offset %lr,16
+
+       addis %r12,%r12,-NON_SPLIT_STACK@h
+       SIZE (__morestack_non_split)
+# Fall through into __morestack
+
+
+# This function is called with non-standard calling conventions.
+# On entry, r12 is the requested stack pointer.  One version of the
+# split-stack prologue that calls __morestack looks like
+#      ld %r0,-0x7000-64(%r13)
+#      addis %r12,%r1,-allocate@ha
+#      addi %r12,%r12,-allocate@l
+#      cmpld %r12,%r0
+#      bge+ enough
+#      mflr %r0
+#      std %r0,16(%r1)
+#      bl __morestack
+#      ld %r0,16(%r1)
+#      mtlr %r0
+#      blr
+# enough:
+# The normal function prologue follows here, with a small addition at
+# the end to set up the arg pointer.  The arg pointer is set up with:
+#      addi %r12,%r1,offset
+#      bge %cr7,.+8
+#      mr %r12,%r29
+#
+# Note that the lr save slot 16(%r1) has already been used.
+# r3 thru r11 possibly contain arguments and a static chain
+# pointer for the function we're calling, so must be preserved.
+# cr7 must also be preserved.
+
+ENTRY0(__morestack)
+# Save parameter passing registers, our arguments, lr, r29
+# and use r29 as a frame pointer.
+       std %r3,PARAMREG_SAVE+0(%r1)
+       sub %r3,%r1,%r12                # calculate requested stack size
+       mflr %r12
+       std %r4,PARAMREG_SAVE+8(%r1)
+       std %r5,PARAMREG_SAVE+16(%r1)
+       std %r6,PARAMREG_SAVE+24(%r1)
+       std %r7,PARAMREG_SAVE+32(%r1)
+       addi %r3,%r3,BACKOFF
+       std %r8,PARAMREG_SAVE+40(%r1)
+       std %r9,PARAMREG_SAVE+48(%r1)
+       std %r10,PARAMREG_SAVE+56(%r1)
+       std %r11,STATIC_CHAIN_SAVE(%r1)
+       std %r29,R29_SAVE(%r1)
+       std %r12,LINKREG_SAVE(%r1)
+       std %r3,NEWSTACKSIZE_SAVE(%r1)  # new stack size
+       mr %r29,%r1
+       .cfi_offset %r29,R29_SAVE
+       .cfi_def_cfa_register %r29
+       stdu %r1,-MORESTACK_FRAMESIZE(%r1)
+
+       # void __morestack_block_signals (void)
+       bl __morestack_block_signals
+
+       # void *__generic_morestack (size_t *pframe_size,
+       #                            void *old_stack,
+       #                            size_t param_size)
+       addi %r3,%r29,NEWSTACKSIZE_SAVE
+       mr %r4,%r29
+       li %r5,0                        # no copying from old stack
+       bl __generic_morestack
+
+# Start using new stack
+       stdu %r29,-32(%r3)              # back-chain
+       mr %r1,%r3
+
+# Set __private_ss stack guard for the new stack.
+       ld %r12,NEWSTACKSIZE_SAVE(%r29) # modified size
+       addi %r3,%r3,BACKOFF-32
+       sub %r3,%r3,%r12
+# Note that a signal frame has $pc pointing at the instruction
+# where the signal occurred.  For something like a timer
+# interrupt this means the instruction has already executed,
+# thus the region starts at the instruction modifying
+# __private_ss, not one instruction after.
+.LEHB0:
+       std %r3,-0x7000-64(%r13)        # tcbhead_t.__private_ss
+
+       # void __morestack_unblock_signals (void)
+       bl __morestack_unblock_signals
+
+# Set up for a call to the target function, located 3
+# instructions after __morestack's return address.
+#
+       ld %r12,LINKREG_SAVE(%r29)
+       ld %r3,PARAMREG_SAVE+0(%r29)    # restore arg regs
+       ld %r4,PARAMREG_SAVE+8(%r29)
+       ld %r5,PARAMREG_SAVE+16(%r29)
+       ld %r6,PARAMREG_SAVE+24(%r29)
+       ld %r7,PARAMREG_SAVE+32(%r29)
+       ld %r8,PARAMREG_SAVE+40(%r29)
+       ld %r9,PARAMREG_SAVE+48(%r29)
+       addi %r0,%r12,12                # add 3 instructions
+       ld %r10,PARAMREG_SAVE+56(%r29)
+       ld %r11,STATIC_CHAIN_SAVE(%r29)
+       cmpld %cr7,%r12,%r0             # indicate we were called
+       mtctr %r0
+       bctrl                           # call caller!
+
+# On return, save regs possibly used to return a value, and
+# possibly trashed by calls to __morestack_block_signals,
+# __generic_releasestack and __morestack_unblock_signals.
+# Assume those calls don't use vector or floating point regs.
+       std %r3,PARAMREG_SAVE+0(%r29)
+       std %r4,PARAMREG_SAVE+8(%r29)
+       std %r5,PARAMREG_SAVE+16(%r29)
+       std %r6,PARAMREG_SAVE+24(%r29)
+#if _CALL_ELF == 2
+       std %r7,PARAMREG_SAVE+32(%r29)
+       std %r8,PARAMREG_SAVE+40(%r29)
+       std %r9,PARAMREG_SAVE+48(%r29)
+       std %r10,PARAMREG_SAVE+56(%r29)
+#endif
+
+       bl __morestack_block_signals
+
+       # void *__generic_releasestack (size_t *pavailable)
+       addi %r3,%r29,NEWSTACKSIZE_SAVE
+       bl __generic_releasestack
+
+# Reset __private_ss stack guard to value for old stack
+       ld %r12,NEWSTACKSIZE_SAVE(%r29)
+       addi %r3,%r3,BACKOFF
+       sub %r3,%r3,%r12
+.LEHE0:
+       std %r3,-0x7000-64(%r13)        # tcbhead_t.__private_ss
+
+       bl __morestack_unblock_signals
+
+# Use old stack again.
+       mr %r1,%r29
+
+# Restore return value regs, and return.
+       ld %r0,LINKREG_SAVE(%r29)
+       mtlr %r0
+       ld %r3,PARAMREG_SAVE+0(%r29)
+       ld %r4,PARAMREG_SAVE+8(%r29)
+       ld %r5,PARAMREG_SAVE+16(%r29)
+       ld %r6,PARAMREG_SAVE+24(%r29)
+#if _CALL_ELF == 2
+       ld %r7,PARAMREG_SAVE+32(%r29)
+       ld %r8,PARAMREG_SAVE+40(%r29)
+       ld %r9,PARAMREG_SAVE+48(%r29)
+       ld %r10,PARAMREG_SAVE+56(%r29)
+#endif
+       ld %r29,R29_SAVE(%r29)
+       .cfi_def_cfa_register %r1
+       blr
+
+# This is the cleanup code called by the stack unwinder when
+# unwinding through code between .LEHB0 and .LEHE0 above.
+cleanup:
+       .cfi_def_cfa_register %r29
+       std %r3,PARAMREG_SAVE(%r29)     # Save exception header
+       # size_t __generic_findstack (void *stack)
+       mr %r3,%r29
+       bl __generic_findstack
+       sub %r3,%r29,%r3
+       addi %r3,%r3,BACKOFF
+       std %r3,-0x7000-64(%r13)        # tcbhead_t.__private_ss
+       ld %r3,PARAMREG_SAVE(%r29)
+       bl _Unwind_Resume
+       nop
+       .cfi_endproc
+       SIZE (__morestack)
+
+
+       .section .gcc_except_table,"a",@progbits
+       .p2align 2
+.LLSDA1:
+       .byte   0xff    # @LPStart format (omit)
+       .byte   0xff    # @TType format (omit)
+       .byte   0x1     # call-site format (uleb128)
+       .uleb128 .LLSDACSE1-.LLSDACSB1  # Call-site table length
+.LLSDACSB1:
+       .uleb128 .LEHB0-.LFB1   # region 0 start
+       .uleb128 .LEHE0-.LEHB0  # length
+       .uleb128 cleanup-.LFB1  # landing pad
+       .uleb128 0              # no action, ie. a cleanup
+.LLSDACSE1:
+
+
+#ifdef __PIC__
+# Build a position independent reference to the personality function.
+       .hidden DW.ref.__gcc_personality_v0
+       .weak DW.ref.__gcc_personality_v0
+       .section .data.DW.ref.__gcc_personality_v0,"awG",@progbits,DW.ref.__gcc_personality_v0,comdat
+       .p2align 3
+DW.ref.__gcc_personality_v0:
+       .quad __gcc_personality_v0
+       .type DW.ref.__gcc_personality_v0, @object
+       .size DW.ref.__gcc_personality_v0, 8
+#endif
+
+
+       .text
+# Initialize the stack guard when the program starts or when a
+# new thread starts.  This is called from a constructor.
+# void __stack_split_initialize (void)
+ENTRY(__stack_split_initialize)
+       addi %r3,%r1,-0x4000            # We should have at least 16K.
+       std %r3,-0x7000-64(%r13)        # tcbhead_t.__private_ss
+       # void __generic_morestack_set_initial_sp (void *sp, size_t len)
+       mr %r3,%r1
+       li %r4, 0x4000
+       b __generic_morestack_set_initial_sp
+       SIZE (__stack_split_initialize)
+
+
+# Return current __private_ss
+# void *__morestack_get_guard (void)
+ENTRY0(__morestack_get_guard)
+       ld %r3,-0x7000-64(%r13)         # tcbhead_t.__private_ss
+       blr
+       SIZE (__morestack_get_guard)
+
+
+# Set __private_ss
+# void __morestack_set_guard (void *ptr)
+ENTRY0(__morestack_set_guard)
+       std %r3,-0x7000-64(%r13)        # tcbhead_t.__private_ss
+       blr
+       SIZE (__morestack_set_guard)
+
+
+# Return the stack guard value for given stack
+# void *__morestack_make_guard (void *stack, size_t size)
+ENTRY0(__morestack_make_guard)
+       sub %r3,%r3,%r4
+       addi %r3,%r3,BACKOFF
+       blr
+       SIZE (__morestack_make_guard)
+
+
+# Make __stack_split_initialize a high priority constructor.
+       .section .ctors.65535,"aw",@progbits
+       .p2align 3
+       .quad __stack_split_initialize
+       .quad __morestack_load_mmap
+
+       .section .note.GNU-stack,"",@progbits
+       .section .note.GNU-split-stack,"",@progbits
+       .section .note.GNU-no-split-stack,"",@progbits
+#endif /* __powerpc64__ */
diff --git a/libgcc/config/rs6000/t-stack-rs6000 b/libgcc/config/rs6000/t-stack-rs6000
new file mode 100644 (file)
index 0000000..0690622
--- /dev/null
@@ -0,0 +1,2 @@
+# Makefile fragment to support -fsplit-stack for powerpc.
+LIB2ADD_ST += $(srcdir)/config/rs6000/morestack.S
index 76f94d2dc06a4510d1ad8daf8c06bec3417cae6c..a10559bd985faf6ccf97bf9f7ebfee1c08146f88 100644 (file)
@@ -23,6 +23,9 @@ a copy of the GCC Runtime Library Exception along with this program;
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+/* powerpc 32-bit not supported.  */
+#if !defined __powerpc__ || defined __powerpc64__
+
 #include "tconfig.h"
 #include "tsystem.h"
 #include "coretypes.h"
@@ -935,6 +938,7 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
       nsp -= 12 * sizeof (void *);
 #elif defined (__i386__)
       nsp -= 6 * sizeof (void *);
+#elif defined __powerpc64__
 #else
 #error "unrecognized target"
 #endif
@@ -1170,3 +1174,4 @@ __splitstack_find_context (void *context[NUMBER_OFFSETS], size_t *stack_size,
 }
 
 #endif /* !defined (inhibit_libc) */
+#endif /* not powerpc 32-bit */