aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarcin Koƛcielnicki <koriakin@0x04.net>2016-02-15 10:20:18 +0000
committerAndreas Krebbel <krebbel@gcc.gnu.org>2016-02-15 10:20:18 +0000
commit4cb4721f9371ac318e33cbed99a66a029353e10a (patch)
tree633620a331dce10653b1b110b0531b75f5ee2376 /gcc
parent17a3b967929eb6d344ae73bff4f28efc88c35ca9 (diff)
downloadgcc-4cb4721f9371ac318e33cbed99a66a029353e10a.zip
gcc-4cb4721f9371ac318e33cbed99a66a029353e10a.tar.gz
gcc-4cb4721f9371ac318e33cbed99a66a029353e10a.tar.bz2
S/390: Add -fsplit-stack support
libgcc/ChangeLog: * config.host: Use t-stack and t-stack-s390 for s390*-*-linux. * config/s390/morestack.S: New file. * config/s390/t-stack-s390: New file. * generic-morestack.c (__splitstack_find): Add s390-specific code. gcc/ChangeLog: * common/config/s390/s390-common.c (s390_supports_split_stack): New function. (TARGET_SUPPORTS_SPLIT_STACK): New macro. * config/s390/s390-protos.h: Add s390_expand_split_stack_prologue. * config/s390/s390.c (struct machine_function): New field split_stack_varargs_pointer. (s390_register_info): Mark r12 as clobbered if it'll be used as temp in s390_emit_prologue. (s390_emit_prologue): Use r12 as temp if r1 is taken by split-stack vararg pointer. (morestack_ref): New global. (SPLIT_STACK_AVAILABLE): New macro. (s390_expand_split_stack_prologue): New function. (s390_live_on_entry): New function. (s390_va_start): Use split-stack vararg pointer if appropriate. (s390_asm_file_end): Emit the split-stack note sections. (TARGET_EXTRA_LIVE_ON_ENTRY): New macro. * config/s390/s390.md (UNSPEC_STACK_CHECK): New unspec. (UNSPECV_SPLIT_STACK_CALL): New unspec. (UNSPECV_SPLIT_STACK_DATA): New unspec. (split_stack_prologue): New expand. (split_stack_space_check): New expand. (split_stack_data): New insn. (split_stack_call): New expand. (split_stack_call_*): New insn. (split_stack_cond_call): New expand. (split_stack_cond_call_*): New insn. From-SVN: r233421
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog30
-rw-r--r--gcc/common/config/s390/s390-common.c14
-rw-r--r--gcc/config/s390/s390-protos.h1
-rw-r--r--gcc/config/s390/s390.c214
-rw-r--r--gcc/config/s390/s390.md138
5 files changed, 392 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6ef134f..cf178e7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,33 @@
+2016-02-15 Marcin Koƛcielnicki <koriakin@0x04.net>
+
+ * common/config/s390/s390-common.c (s390_supports_split_stack):
+ New function.
+ (TARGET_SUPPORTS_SPLIT_STACK): New macro.
+ * config/s390/s390-protos.h: Add s390_expand_split_stack_prologue.
+ * config/s390/s390.c (struct machine_function): New field
+ split_stack_varargs_pointer.
+ (s390_register_info): Mark r12 as clobbered if it'll be used as temp
+ in s390_emit_prologue.
+ (s390_emit_prologue): Use r12 as temp if r1 is taken by split-stack
+ vararg pointer.
+ (morestack_ref): New global.
+ (SPLIT_STACK_AVAILABLE): New macro.
+ (s390_expand_split_stack_prologue): New function.
+ (s390_live_on_entry): New function.
+ (s390_va_start): Use split-stack vararg pointer if appropriate.
+ (s390_asm_file_end): Emit the split-stack note sections.
+ (TARGET_EXTRA_LIVE_ON_ENTRY): New macro.
+ * config/s390/s390.md (UNSPEC_STACK_CHECK): New unspec.
+ (UNSPECV_SPLIT_STACK_CALL): New unspec.
+ (UNSPECV_SPLIT_STACK_DATA): New unspec.
+ (split_stack_prologue): New expand.
+ (split_stack_space_check): New expand.
+ (split_stack_data): New insn.
+ (split_stack_call): New expand.
+ (split_stack_call_*): New insn.
+ (split_stack_cond_call): New expand.
+ (split_stack_cond_call_*): New insn.
+
2016-02-15 Richard Biener <rguenther@suse.de>
PR tree-optimization/69783
diff --git a/gcc/common/config/s390/s390-common.c b/gcc/common/config/s390/s390-common.c
index 4519c21..1e497e6 100644
--- a/gcc/common/config/s390/s390-common.c
+++ b/gcc/common/config/s390/s390-common.c
@@ -105,6 +105,17 @@ s390_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
}
}
+/* -fsplit-stack uses a field in the TCB, available with glibc-2.23.
+ We don't verify it, since earlier versions just have padding at
+ its place, which works just as well. */
+
+static bool
+s390_supports_split_stack (bool report ATTRIBUTE_UNUSED,
+ struct gcc_options *opts ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
#undef TARGET_DEFAULT_TARGET_FLAGS
#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT)
@@ -117,4 +128,7 @@ s390_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
#undef TARGET_OPTION_INIT_STRUCT
#define TARGET_OPTION_INIT_STRUCT s390_option_init_struct
+#undef TARGET_SUPPORTS_SPLIT_STACK
+#define TARGET_SUPPORTS_SPLIT_STACK s390_supports_split_stack
+
struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 633bc1e..09032c9 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -42,6 +42,7 @@ extern bool s390_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
extern HOST_WIDE_INT s390_initial_elimination_offset (int, int);
extern void s390_emit_prologue (void);
extern void s390_emit_epilogue (bool);
+extern void s390_expand_split_stack_prologue (void);
extern bool s390_can_use_simple_return_insn (void);
extern bool s390_can_use_return_insn (void);
extern void s390_function_profiler (FILE *, int);
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 9facd96..aa82d1c 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -428,6 +428,13 @@ struct GTY(()) machine_function
/* True if the current function may contain a tbegin clobbering
FPRs. */
bool tbegin_p;
+
+ /* For -fsplit-stack support: A stack local which holds a pointer to
+ the stack arguments for a function with a variable number of
+ arguments. This is set at the start of the function and is used
+ to initialize the overflow_arg_area field of the va_list
+ structure. */
+ rtx split_stack_varargs_pointer;
};
/* Few accessor macros for struct cfun->machine->s390_frame_layout. */
@@ -9371,9 +9378,13 @@ s390_register_info ()
cfun_frame_layout.high_fprs++;
}
- if (flag_pic)
- clobbered_regs[PIC_OFFSET_TABLE_REGNUM]
- |= !!df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM);
+ /* Register 12 is used for GOT address, but also as temp in prologue
+ for split-stack stdarg functions (unless r14 is available). */
+ clobbered_regs[12]
+ |= ((flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
+ || (flag_split_stack && cfun->stdarg
+ && (crtl->is_leaf || TARGET_TPF_PROFILING
+ || has_hard_reg_initial_val (Pmode, RETURN_REGNUM))));
clobbered_regs[BASE_REGNUM]
|= (cfun->machine->base_reg
@@ -10473,12 +10484,15 @@ s390_emit_prologue (void)
int next_fpr = 0;
/* Choose best register to use for temp use within prologue.
- See below for why TPF must use the register 1. */
+ TPF with profiling must avoid the register 14 - the tracing function
+ needs the original contents of r14 to be preserved. */
if (!has_hard_reg_initial_val (Pmode, RETURN_REGNUM)
&& !crtl->is_leaf
&& !TARGET_TPF_PROFILING)
temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
+ else if (flag_split_stack && cfun->stdarg)
+ temp_reg = gen_rtx_REG (Pmode, 12);
else
temp_reg = gen_rtx_REG (Pmode, 1);
@@ -10972,6 +10986,166 @@ s300_set_up_by_prologue (hard_reg_set_container *regs)
SET_HARD_REG_BIT (regs->set, REGNO (cfun->machine->base_reg));
}
+/* -fsplit-stack support. */
+
+/* A SYMBOL_REF for __morestack. */
+static GTY(()) rtx morestack_ref;
+
+/* When using -fsplit-stack, the allocation routines set a field in
+ the TCB to the bottom of the stack plus this much space, measured
+ in bytes. */
+
+#define SPLIT_STACK_AVAILABLE 1024
+
+/* Emit -fsplit-stack prologue, which goes before the regular function
+ prologue. */
+
+void
+s390_expand_split_stack_prologue (void)
+{
+ rtx r1, guard, cc = NULL;
+ rtx_insn *insn;
+ /* Offset from thread pointer to __private_ss. */
+ int psso = TARGET_64BIT ? 0x38 : 0x20;
+ /* Pointer size in bytes. */
+ /* Frame size and argument size - the two parameters to __morestack. */
+ HOST_WIDE_INT frame_size = cfun_frame_layout.frame_size;
+ /* Align argument size to 8 bytes - simplifies __morestack code. */
+ HOST_WIDE_INT args_size = crtl->args.size >= 0
+ ? ((crtl->args.size + 7) & ~7)
+ : 0;
+ /* Label to be called by __morestack. */
+ rtx_code_label *call_done = NULL;
+ rtx_code_label *parm_base = NULL;
+ rtx tmp;
+
+ gcc_assert (flag_split_stack && reload_completed);
+ if (!TARGET_CPU_ZARCH)
+ {
+ sorry ("CPUs older than z900 are not supported for -fsplit-stack");
+ return;
+ }
+
+ r1 = gen_rtx_REG (Pmode, 1);
+
+ /* If no stack frame will be allocated, don't do anything. */
+ if (!frame_size)
+ {
+ if (cfun->machine->split_stack_varargs_pointer != NULL_RTX)
+ {
+ /* If va_start is used, just use r15. */
+ emit_move_insn (r1,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET)));
+
+ }
+ 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);
+ }
+
+ if (CONST_OK_FOR_K (frame_size) || CONST_OK_FOR_Op (frame_size))
+ {
+ /* If frame_size will fit in an add instruction, do a stack space
+ check, and only call __morestack if there's not enough space. */
+
+ /* Get thread pointer. r1 is the only register we can always destroy - r0
+ could contain a static chain (and cannot be used to address memory
+ anyway), r2-r6 can contain parameters, and r6-r15 are callee-saved. */
+ emit_move_insn (r1, gen_rtx_REG (Pmode, TP_REGNUM));
+ /* Aim at __private_ss. */
+ guard = gen_rtx_MEM (Pmode, plus_constant (Pmode, r1, psso));
+
+ /* If less that 1kiB used, skip addition and compare directly with
+ __private_ss. */
+ if (frame_size > SPLIT_STACK_AVAILABLE)
+ {
+ emit_move_insn (r1, guard);
+ if (TARGET_64BIT)
+ emit_insn (gen_adddi3 (r1, r1, GEN_INT (frame_size)));
+ else
+ emit_insn (gen_addsi3 (r1, r1, GEN_INT (frame_size)));
+ guard = r1;
+ }
+
+ /* Compare the (maybe adjusted) guard with the stack pointer. */
+ cc = s390_emit_compare (LT, stack_pointer_rtx, guard);
+ }
+
+ call_done = gen_label_rtx ();
+ parm_base = gen_label_rtx ();
+
+ /* Emit the parameter block. */
+ tmp = gen_split_stack_data (parm_base, call_done,
+ GEN_INT (frame_size),
+ GEN_INT (args_size));
+ insn = emit_insn (tmp);
+ add_reg_note (insn, REG_LABEL_OPERAND, call_done);
+ LABEL_NUSES (call_done)++;
+ add_reg_note (insn, REG_LABEL_OPERAND, parm_base);
+ LABEL_NUSES (parm_base)++;
+
+ /* %r1 = litbase. */
+ insn = emit_move_insn (r1, gen_rtx_LABEL_REF (VOIDmode, parm_base));
+ add_reg_note (insn, REG_LABEL_OPERAND, parm_base);
+ LABEL_NUSES (parm_base)++;
+
+ /* Now, we need to call __morestack. It has very special calling
+ conventions: it preserves param/return/static chain registers for
+ calling main function body, and looks for its own parameters at %r1. */
+
+ if (cc != NULL)
+ {
+ tmp = gen_split_stack_cond_call (morestack_ref, cc, call_done);
+
+ insn = emit_jump_insn (tmp);
+ JUMP_LABEL (insn) = call_done;
+ LABEL_NUSES (call_done)++;
+
+ /* Mark the jump as very unlikely to be taken. */
+ add_int_reg_note (insn, REG_BR_PROB, REG_BR_PROB_BASE / 100);
+
+ if (cfun->machine->split_stack_varargs_pointer != NULL_RTX)
+ {
+ /* If va_start is used, and __morestack was not called, just use
+ r15. */
+ emit_move_insn (r1,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET)));
+ }
+ }
+ else
+ {
+ tmp = gen_split_stack_call (morestack_ref, call_done);
+ insn = emit_jump_insn (tmp);
+ JUMP_LABEL (insn) = call_done;
+ LABEL_NUSES (call_done)++;
+ emit_barrier ();
+ }
+
+ /* __morestack will call us here. */
+
+ emit_label (call_done);
+}
+
+/* We may have to tell the dataflow pass that the split stack prologue
+ is initializing a register. */
+
+static void
+s390_live_on_entry (bitmap regs)
+{
+ if (cfun->machine->split_stack_varargs_pointer != NULL_RTX)
+ {
+ gcc_assert (flag_split_stack);
+ bitmap_set_bit (regs, 1);
+ }
+}
+
/* Return true if the function can use simple_return to return outside
of a shrink-wrapped region. At present shrink-wrapping is supported
in all cases. */
@@ -11574,6 +11748,27 @@ s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
+ if (flag_split_stack
+ && (lookup_attribute ("no_split_stack", DECL_ATTRIBUTES (cfun->decl))
+ == NULL)
+ && cfun->machine->split_stack_varargs_pointer == NULL_RTX)
+ {
+ rtx reg;
+ rtx_insn *seq;
+
+ reg = gen_reg_rtx (Pmode);
+ cfun->machine->split_stack_varargs_pointer = reg;
+
+ start_sequence ();
+ emit_move_insn (reg, gen_rtx_REG (Pmode, 1));
+ seq = get_insns ();
+ end_sequence ();
+
+ push_topmost_sequence ();
+ emit_insn_after (seq, entry_of_function ());
+ pop_topmost_sequence ();
+ }
+
/* Find the overflow area.
FIXME: This currently is too pessimistic when the vector ABI is
enabled. In that case we *always* set up the overflow area
@@ -11582,7 +11777,10 @@ s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
|| n_fpr + cfun->va_list_fpr_size > FP_ARG_NUM_REG
|| TARGET_VX_ABI)
{
- t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+ if (cfun->machine->split_stack_varargs_pointer == NULL_RTX)
+ t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+ else
+ t = make_tree (TREE_TYPE (ovf), cfun->machine->split_stack_varargs_pointer);
off = INTVAL (crtl->args.arg_offset_rtx);
off = off < 0 ? 0 : off;
@@ -14502,6 +14700,9 @@ s390_asm_file_end (void)
s390_vector_abi);
#endif
file_end_indicate_exec_stack ();
+
+ if (flag_split_stack)
+ file_end_indicate_split_stack ();
}
/* Return true if TYPE is a vector bool type. */
@@ -14757,6 +14958,9 @@ s390_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1, const_tree ty
#undef TARGET_SET_UP_BY_PROLOGUE
#define TARGET_SET_UP_BY_PROLOGUE s300_set_up_by_prologue
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY s390_live_on_entry
+
#undef TARGET_USE_BY_PIECES_INFRASTRUCTURE_P
#define TARGET_USE_BY_PIECES_INFRASTRUCTURE_P \
s390_use_by_pieces_infrastructure_p
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index ccedead..6f0e172 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -114,6 +114,9 @@
UNSPEC_SP_SET
UNSPEC_SP_TEST
+ ; Split stack support
+ UNSPEC_STACK_CHECK
+
; Test Data Class (TDC)
UNSPEC_TDC_INSN
@@ -276,6 +279,10 @@
; Set and get floating point control register
UNSPECV_SFPC
UNSPECV_EFPC
+
+ ; Split stack support
+ UNSPECV_SPLIT_STACK_CALL
+ UNSPECV_SPLIT_STACK_DATA
])
;;
@@ -10909,3 +10916,134 @@
"TARGET_Z13"
"lcbb\t%0,%1,%b2"
[(set_attr "op_type" "VRX")])
+
+; Handle -fsplit-stack.
+
+(define_expand "split_stack_prologue"
+ [(const_int 0)]
+ ""
+{
+ s390_expand_split_stack_prologue ();
+ DONE;
+})
+
+;; If there are operand 0 bytes available on the stack, jump to
+;; operand 1.
+
+(define_expand "split_stack_space_check"
+ [(set (pc) (if_then_else
+ (ltu (minus (reg 15)
+ (match_operand 0 "register_operand"))
+ (unspec [(const_int 0)] UNSPEC_STACK_CHECK))
+ (label_ref (match_operand 1))
+ (pc)))]
+ ""
+{
+ /* Offset from thread pointer to __private_ss. */
+ int psso = TARGET_64BIT ? 0x38 : 0x20;
+ rtx tp = s390_get_thread_pointer ();
+ rtx guard = gen_rtx_MEM (Pmode, plus_constant (Pmode, tp, psso));
+ rtx reg = gen_reg_rtx (Pmode);
+ rtx cc;
+ if (TARGET_64BIT)
+ emit_insn (gen_subdi3 (reg, stack_pointer_rtx, operands[0]));
+ else
+ emit_insn (gen_subsi3 (reg, stack_pointer_rtx, operands[0]));
+ cc = s390_emit_compare (GT, reg, guard);
+ s390_emit_jump (operands[1], cc);
+
+ DONE;
+})
+
+;; __morestack parameter block for split stack prologue. Parameters are:
+;; parameter block label, label to be called by __morestack, frame size,
+;; stack parameter size.
+
+(define_insn "split_stack_data"
+ [(unspec_volatile [(match_operand 0 "" "X")
+ (match_operand 1 "" "X")
+ (match_operand 2 "const_int_operand" "X")
+ (match_operand 3 "const_int_operand" "X")]
+ UNSPECV_SPLIT_STACK_DATA)]
+ "TARGET_CPU_ZARCH"
+{
+ switch_to_section (targetm.asm_out.function_rodata_section
+ (current_function_decl));
+
+ if (TARGET_64BIT)
+ output_asm_insn (".align\t8", operands);
+ else
+ output_asm_insn (".align\t4", operands);
+ (*targetm.asm_out.internal_label) (asm_out_file, "L",
+ CODE_LABEL_NUMBER (operands[0]));
+ if (TARGET_64BIT)
+ {
+ output_asm_insn (".quad\t%2", operands);
+ output_asm_insn (".quad\t%3", operands);
+ output_asm_insn (".quad\t%1-%0", operands);
+ }
+ else
+ {
+ output_asm_insn (".long\t%2", operands);
+ output_asm_insn (".long\t%3", operands);
+ output_asm_insn (".long\t%1-%0", operands);
+ }
+
+ switch_to_section (current_function_section ());
+ return "";
+}
+ [(set_attr "length" "0")])
+
+
+;; A jg with minimal fuss for use in split stack prologue.
+
+(define_expand "split_stack_call"
+ [(match_operand 0 "bras_sym_operand" "X")
+ (match_operand 1 "" "")]
+ "TARGET_CPU_ZARCH"
+{
+ if (TARGET_64BIT)
+ emit_jump_insn (gen_split_stack_call_di (operands[0], operands[1]));
+ else
+ emit_jump_insn (gen_split_stack_call_si (operands[0], operands[1]));
+ DONE;
+})
+
+(define_insn "split_stack_call_<mode>"
+ [(set (pc) (label_ref (match_operand 1 "" "")))
+ (set (reg:P 1) (unspec_volatile [(match_operand 0 "bras_sym_operand" "X")
+ (reg:P 1)]
+ UNSPECV_SPLIT_STACK_CALL))]
+ "TARGET_CPU_ZARCH"
+ "jg\t%0"
+ [(set_attr "op_type" "RIL")
+ (set_attr "type" "branch")])
+
+;; Also a conditional one.
+
+(define_expand "split_stack_cond_call"
+ [(match_operand 0 "bras_sym_operand" "X")
+ (match_operand 1 "" "")
+ (match_operand 2 "" "")]
+ "TARGET_CPU_ZARCH"
+{
+ if (TARGET_64BIT)
+ emit_jump_insn (gen_split_stack_cond_call_di (operands[0], operands[1], operands[2]));
+ else
+ emit_jump_insn (gen_split_stack_cond_call_si (operands[0], operands[1], operands[2]));
+ DONE;
+})
+
+(define_insn "split_stack_cond_call_<mode>"
+ [(set (pc)
+ (if_then_else
+ (match_operand 1 "" "")
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (set (reg:P 1) (unspec_volatile [(match_operand 0 "bras_sym_operand" "X")
+ (reg:P 1)]
+ UNSPECV_SPLIT_STACK_CALL))]
+ "TARGET_CPU_ZARCH"
+ "jg%C1\t%0"
+ [(set_attr "op_type" "RIL")
+ (set_attr "type" "branch")])