From c6d481f72b62d28bdfc50bcf3b50099bdd72f918 Mon Sep 17 00:00:00 2001
From: krebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon, 15 Feb 2016 10:20:18 +0000
Subject: 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.



git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233421 138bc75d-0d04-0410-961f-82ee72b054a4
---
 libgcc/ChangeLog                |   7 +
 libgcc/config.host              |   4 +-
 libgcc/config/s390/morestack.S  | 611 ++++++++++++++++++++++++++++++++++++++++
 libgcc/config/s390/t-stack-s390 |   2 +
 libgcc/generic-morestack.c      |   4 +
 5 files changed, 626 insertions(+), 2 deletions(-)
 create mode 100644 libgcc/config/s390/morestack.S
 create mode 100644 libgcc/config/s390/t-stack-s390

(limited to 'libgcc')

diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 63ad30ec445..80b562caccf 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,10 @@
+2016-02-15  Marcin Koƛcielnicki  <koriakin@0x04.net>
+
+	* 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.
+
 2016-02-12  Walter Lee  <walt@tilera.com>
 
 	* config.host (tilegx*-*-linux*): remove ti from
diff --git a/libgcc/config.host b/libgcc/config.host
index 06de0deaeb0..ef7dfd02f5d 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -1114,11 +1114,11 @@ rx-*-elf)
 	tm_file="$tm_file rx/rx-abi.h rx/rx-lib.h"
 	;;
 s390-*-linux*)
-	tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux s390/32/t-floattodi"
+	tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux s390/32/t-floattodi t-stack s390/t-stack-s390"
 	md_unwind_header=s390/linux-unwind.h
 	;;
 s390x-*-linux*)
-	tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux"
+	tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux t-stack s390/t-stack-s390"
 	if test "${host_address}" = 32; then
 	   tmake_file="${tmake_file} s390/32/t-floattodi"
 	fi
diff --git a/libgcc/config/s390/morestack.S b/libgcc/config/s390/morestack.S
new file mode 100644
index 00000000000..fa6951badf0
--- /dev/null
+++ b/libgcc/config/s390/morestack.S
@@ -0,0 +1,611 @@
+# s390 support for -fsplit-stack.
+# Copyright (C) 2015 Free Software Foundation, Inc.
+# Contributed by Marcin Koƛcielnicki <koriakin@0x04.net>.
+
+# 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/>.
+
+# 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 0x1000
+
+# The __morestack function.
+
+	.global	__morestack
+	.hidden	__morestack
+
+	.type	__morestack,@function
+
+__morestack:
+.LFB1:
+	.cfi_startproc
+
+
+#ifndef __s390x__
+
+
+# The 31-bit __morestack function.
+
+	# We use a cleanup to restore the stack guard if an exception
+	# is thrown through this code.
+#ifndef __PIC__
+	.cfi_personality 0,__gcc_personality_v0
+	.cfi_lsda 0,.LLSDA1
+#else
+	.cfi_personality 0x9b,DW.ref.__gcc_personality_v0
+	.cfi_lsda 0x1b,.LLSDA1
+#endif
+
+	stm	%r2, %r15, 0x8(%r15)	# Save %r2-%r15.
+	.cfi_offset %r6, -0x48
+	.cfi_offset %r7, -0x44
+	.cfi_offset %r8, -0x40
+	.cfi_offset %r9, -0x3c
+	.cfi_offset %r10, -0x38
+	.cfi_offset %r11, -0x34
+	.cfi_offset %r12, -0x30
+	.cfi_offset %r13, -0x2c
+	.cfi_offset %r14, -0x28
+	.cfi_offset %r15, -0x24
+	lr	%r11, %r15		# Make frame pointer for vararg.
+	.cfi_def_cfa_register %r11
+	ahi	%r15, -0x60		# 0x60 for standard frame.
+	st	%r11, 0(%r15)		# Save back chain.
+	lr	%r8, %r0		# Save %r0 (static chain).
+	lr	%r10, %r1		# Save %r1 (address of parameter block).
+
+	l	%r7, 0(%r10)		# Required frame size to %r7
+	ear	%r1, %a0		# Extract thread pointer.
+	l	%r1, 0x20(%r1)		# Get stack bounduary
+	ar	%r1, %r7		# Stack bounduary + frame size
+	a	%r1, 4(%r10)		# + stack param size
+	clr	%r1, %r15		# Compare with current stack pointer
+	jle	.Lnoalloc		# guard > sp - frame-size: need alloc
+
+	brasl	%r14, __morestack_block_signals
+
+	# We abuse one of caller's fpr save slots (which we don't use for fprs)
+	# as a local variable.  Not needed here, but done to be consistent with
+	# the below use.
+	ahi	%r7, BACKOFF		# Bump requested size a bit.
+	st	%r7, 0x40(%r11)		# Stuff frame size on stack.
+	la	%r2, 0x40(%r11)		# Pass its address as parameter.
+	la	%r3, 0x60(%r11)		# Caller's stack parameters.
+	l	%r4, 4(%r10)		# Size of stack parameters.
+	brasl	%r14, __generic_morestack
+
+	lr	%r15, %r2		# Switch to the new stack.
+	ahi	%r15, -0x60		# Make a stack frame on it.
+	st	%r11, 0(%r15)		# Save back chain.
+
+	s	%r2, 0x40(%r11)		# The end of stack space.
+	ahi	%r2, BACKOFF		# Back off a bit.
+	ear	%r1, %a0		# Extract thread pointer.
+.LEHB0:
+	st	%r2, 0x20(%r1)	# Save the new stack boundary.
+
+	brasl	%r14, __morestack_unblock_signals
+
+	lr	%r0, %r8		# Static chain.
+	lm	%r2, %r6, 0x8(%r11)	# Paremeter registers.
+
+	# Third parameter is address of function meat - address of parameter
+	# block.
+	a	%r10, 0x8(%r10)
+
+	# Leave vararg pointer in %r1, in case function uses it
+	la	%r1, 0x60(%r11)
+
+	# State of registers:
+	# %r0: Static chain from entry.
+	# %r1: Vararg pointer.
+	# %r2-%r6: Parameters from entry.
+	# %r7-%r10: Indeterminate.
+	# %r11: Frame pointer (%r15 from entry).
+	# %r12-%r13: Indeterminate.
+	# %r14: Return address.
+	# %r15: Stack pointer.
+	basr	%r14, %r10		# Call our caller.
+
+	stm	%r2, %r3, 0x8(%r11)	# Save return registers.
+
+	brasl	%r14, __morestack_block_signals
+
+	# We need a stack slot now, but have no good way to get it - the frame
+	# on new stack had to be exactly 0x60 bytes, or stack parameters would
+	# be passed wrong.  Abuse fpr save area in caller's frame (we don't
+	# save actual fprs).
+	la	%r2, 0x40(%r11)
+	brasl	%r14, __generic_releasestack
+
+	s	%r2, 0x40(%r11)		# Subtract available space.
+	ahi	%r2, BACKOFF		# Back off a bit.
+	ear	%r1, %a0		# Extract thread pointer.
+.LEHE0:
+	st	%r2, 0x20(%r1)	# Save the new stack boundary.
+
+	# We need to restore the old stack pointer before unblocking signals.
+	# We also need 0x60 bytes for a stack frame.  Since we had a stack
+	# frame at this place before the stack switch, there's no need to
+	# write the back chain again.
+	lr	%r15, %r11
+	ahi	%r15, -0x60
+
+	brasl	%r14, __morestack_unblock_signals
+
+	lm	%r2, %r15, 0x8(%r11)	# Restore all registers.
+	.cfi_remember_state
+	.cfi_restore %r15
+	.cfi_restore %r14
+	.cfi_restore %r13
+	.cfi_restore %r12
+	.cfi_restore %r11
+	.cfi_restore %r10
+	.cfi_restore %r9
+	.cfi_restore %r8
+	.cfi_restore %r7
+	.cfi_restore %r6
+	.cfi_def_cfa_register %r15
+	br	%r14			# Return to caller's caller.
+
+# Executed if no new stack allocation is needed.
+
+.Lnoalloc:
+	.cfi_restore_state
+	# We may need to copy stack parameters.
+	l	%r9, 0x4(%r10)		# Load stack parameter size.
+	ltr	%r9, %r9		# And check if it's 0.
+	je	.Lnostackparm		# Skip the copy if not needed.
+	sr	%r15, %r9		# Make space on the stack.
+	la	%r8, 0x60(%r15)		# Destination.
+	la	%r12, 0x60(%r11)	# Source.
+	lr	%r13, %r9		# Source size.
+.Lcopy:
+	mvcle	%r8, %r12, 0		# Copy.
+	jo	.Lcopy
+
+.Lnostackparm:
+	# Third parameter is address of function meat - address of parameter
+	# block.
+	a	%r10, 0x8(%r10)
+
+	# Leave vararg pointer in %r1, in case function uses it
+	la	%r1, 0x60(%r11)
+
+	# OK, no stack allocation needed.  We still follow the protocol and
+	# call our caller - it doesn't cost much and makes sure vararg works.
+	# No need to set any registers here - %r0 and %r2-%r6 weren't modified.
+	basr	%r14, %r10		# Call our caller.
+
+	lm	%r6, %r15, 0x18(%r11)	# Restore all callee-saved registers.
+	.cfi_remember_state
+	.cfi_restore %r15
+	.cfi_restore %r14
+	.cfi_restore %r13
+	.cfi_restore %r12
+	.cfi_restore %r11
+	.cfi_restore %r10
+	.cfi_restore %r9
+	.cfi_restore %r8
+	.cfi_restore %r7
+	.cfi_restore %r6
+	.cfi_def_cfa_register %r15
+	br	%r14			# Return to caller's caller.
+
+# This is the cleanup code called by the stack unwinder when unwinding
+# through the code between .LEHB0 and .LEHE0 above.
+
+.L1:
+	.cfi_restore_state
+	lr	%r2, %r11		# Stack pointer after resume.
+	brasl	%r14, __generic_findstack
+	lr	%r3, %r11		# Get the stack pointer.
+	sr	%r3, %r2		# Subtract available space.
+	ahi	%r3, BACKOFF		# Back off a bit.
+	ear	%r1, %a0		# Extract thread pointer.
+	st	%r3, 0x20(%r1)	# Save the new stack boundary.
+
+	# We need GOT pointer in %r12 for PLT entry.
+	larl	%r12,_GLOBAL_OFFSET_TABLE_
+	lr	%r2, %r6		# Exception header.
+#ifdef __PIC__
+	brasl	%r14, _Unwind_Resume@PLT
+#else
+	brasl	%r14, _Unwind_Resume
+#endif
+
+#else /* defined(__s390x__) */
+
+
+# The 64-bit __morestack function.
+
+	# We use a cleanup to restore the stack guard if an exception
+	# is thrown through this code.
+#ifndef __PIC__
+	.cfi_personality 0x3,__gcc_personality_v0
+	.cfi_lsda 0x3,.LLSDA1
+#else
+	.cfi_personality 0x9b,DW.ref.__gcc_personality_v0
+	.cfi_lsda 0x1b,.LLSDA1
+#endif
+
+	stmg	%r2, %r15, 0x10(%r15)	# Save %r2-%r15.
+	.cfi_offset %r6, -0x70
+	.cfi_offset %r7, -0x68
+	.cfi_offset %r8, -0x60
+	.cfi_offset %r9, -0x58
+	.cfi_offset %r10, -0x50
+	.cfi_offset %r11, -0x48
+	.cfi_offset %r12, -0x40
+	.cfi_offset %r13, -0x38
+	.cfi_offset %r14, -0x30
+	.cfi_offset %r15, -0x28
+	lgr	%r11, %r15		# Make frame pointer for vararg.
+	.cfi_def_cfa_register %r11
+	aghi	%r15, -0xa0		# 0xa0 for standard frame.
+	stg	%r11, 0(%r15)		# Save back chain.
+	lgr	%r8, %r0		# Save %r0 (static chain).
+	lgr	%r10, %r1		# Save %r1 (address of parameter block).
+
+	lg	%r7, 0(%r10)		# Required frame size to %r7
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1		# Extract thread pointer.
+	lg	%r1, 0x38(%r1)		# Get stack bounduary
+	agr	%r1, %r7		# Stack bounduary + frame size
+	ag	%r1, 8(%r10)		# + stack param size
+	clgr	%r1, %r15		# Compare with current stack pointer
+	jle	.Lnoalloc		# guard > sp - frame-size: need alloc
+
+	brasl	%r14, __morestack_block_signals
+
+	# We abuse one of caller's fpr save slots (which we don't use for fprs)
+	# as a local variable.  Not needed here, but done to be consistent with
+	# the below use.
+	aghi	%r7, BACKOFF		# Bump requested size a bit.
+	stg	%r7, 0x80(%r11)		# Stuff frame size on stack.
+	la	%r2, 0x80(%r11)		# Pass its address as parameter.
+	la	%r3, 0xa0(%r11)		# Caller's stack parameters.
+	lg	%r4, 8(%r10)		# Size of stack parameters.
+	brasl	%r14, __generic_morestack
+
+	lgr	%r15, %r2		# Switch to the new stack.
+	aghi	%r15, -0xa0		# Make a stack frame on it.
+	stg	%r11, 0(%r15)		# Save back chain.
+
+	sg	%r2, 0x80(%r11)		# The end of stack space.
+	aghi	%r2, BACKOFF		# Back off a bit.
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1		# Extract thread pointer.
+.LEHB0:
+	stg	%r2, 0x38(%r1)	# Save the new stack boundary.
+
+	brasl	%r14, __morestack_unblock_signals
+
+	lgr	%r0, %r8		# Static chain.
+	lmg	%r2, %r6, 0x10(%r11)	# Paremeter registers.
+
+	# Third parameter is address of function meat - address of parameter
+	# block.
+	ag	%r10, 0x10(%r10)
+
+	# Leave vararg pointer in %r1, in case function uses it
+	la	%r1, 0xa0(%r11)
+
+	# State of registers:
+	# %r0: Static chain from entry.
+	# %r1: Vararg pointer.
+	# %r2-%r6: Parameters from entry.
+	# %r7-%r10: Indeterminate.
+	# %r11: Frame pointer (%r15 from entry).
+	# %r12-%r13: Indeterminate.
+	# %r14: Return address.
+	# %r15: Stack pointer.
+	basr	%r14, %r10		# Call our caller.
+
+	stg	%r2, 0x10(%r11)		# Save return register.
+
+	brasl	%r14, __morestack_block_signals
+
+	# We need a stack slot now, but have no good way to get it - the frame
+	# on new stack had to be exactly 0xa0 bytes, or stack parameters would
+	# be passed wrong.  Abuse fpr save area in caller's frame (we don't
+	# save actual fprs).
+	la	%r2, 0x80(%r11)
+	brasl	%r14, __generic_releasestack
+
+	sg	%r2, 0x80(%r11)		# Subtract available space.
+	aghi	%r2, BACKOFF		# Back off a bit.
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1		# Extract thread pointer.
+.LEHE0:
+	stg	%r2, 0x38(%r1)	# Save the new stack boundary.
+
+	# We need to restore the old stack pointer before unblocking signals.
+	# We also need 0xa0 bytes for a stack frame.  Since we had a stack
+	# frame at this place before the stack switch, there's no need to
+	# write the back chain again.
+	lgr	%r15, %r11
+	aghi	%r15, -0xa0
+
+	brasl	%r14, __morestack_unblock_signals
+
+	lmg	%r2, %r15, 0x10(%r11)	# Restore all registers.
+	.cfi_remember_state
+	.cfi_restore %r15
+	.cfi_restore %r14
+	.cfi_restore %r13
+	.cfi_restore %r12
+	.cfi_restore %r11
+	.cfi_restore %r10
+	.cfi_restore %r9
+	.cfi_restore %r8
+	.cfi_restore %r7
+	.cfi_restore %r6
+	.cfi_def_cfa_register %r15
+	br	%r14			# Return to caller's caller.
+
+# Executed if no new stack allocation is needed.
+
+.Lnoalloc:
+	.cfi_restore_state
+	# We may need to copy stack parameters.
+	lg	%r9, 0x8(%r10)		# Load stack parameter size.
+	ltgr	%r9, %r9		# Check if it's 0.
+	je	.Lnostackparm		# Skip the copy if not needed.
+	sgr	%r15, %r9		# Make space on the stack.
+	la	%r8, 0xa0(%r15)		# Destination.
+	la	%r12, 0xa0(%r11)	# Source.
+	lgr	%r13, %r9		# Source size.
+.Lcopy:
+	mvcle	%r8, %r12, 0		# Copy.
+	jo	.Lcopy
+
+.Lnostackparm:
+	# Third parameter is address of function meat - address of parameter
+	# block.
+	ag	%r10, 0x10(%r10)
+
+	# Leave vararg pointer in %r1, in case function uses it
+	la	%r1, 0xa0(%r11)
+
+	# OK, no stack allocation needed.  We still follow the protocol and
+	# call our caller - it doesn't cost much and makes sure vararg works.
+	# No need to set any registers here - %r0 and %r2-%r6 weren't modified.
+	basr	%r14, %r10		# Call our caller.
+
+	lmg	%r6, %r15, 0x30(%r11)	# Restore all callee-saved registers.
+	.cfi_remember_state
+	.cfi_restore %r15
+	.cfi_restore %r14
+	.cfi_restore %r13
+	.cfi_restore %r12
+	.cfi_restore %r11
+	.cfi_restore %r10
+	.cfi_restore %r9
+	.cfi_restore %r8
+	.cfi_restore %r7
+	.cfi_restore %r6
+	.cfi_def_cfa_register %r15
+	br	%r14			# Return to caller's caller.
+
+# This is the cleanup code called by the stack unwinder when unwinding
+# through the code between .LEHB0 and .LEHE0 above.
+
+.L1:
+	.cfi_restore_state
+	lgr	%r2, %r11		# Stack pointer after resume.
+	brasl	%r14, __generic_findstack
+	lgr	%r3, %r11		# Get the stack pointer.
+	sgr	%r3, %r2		# Subtract available space.
+	aghi	%r3, BACKOFF		# Back off a bit.
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1		# Extract thread pointer.
+	stg	%r3, 0x38(%r1)	# Save the new stack boundary.
+
+	lgr	%r2, %r6		# Exception header.
+#ifdef __PIC__
+	brasl	%r14, _Unwind_Resume@PLT
+#else
+	brasl	%r14, _Unwind_Resume
+#endif
+
+#endif /* defined(__s390x__) */
+
+	.cfi_endproc
+	.size	__morestack, . - __morestack
+
+
+# The exception table.  This tells the personality routine to execute
+# the exception handler.
+
+	.section	.gcc_except_table,"a",@progbits
+	.align	4
+.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 .L1-.LFB1	# landing pad
+	.uleb128 0		# action
+.LLSDACSE1:
+
+
+	.global __gcc_personality_v0
+#ifdef __PIC__
+	# Build a position independent reference to the basic
+	# 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
+	.type	DW.ref.__gcc_personality_v0, @object
+DW.ref.__gcc_personality_v0:
+#ifndef __LP64__
+	.align 4
+	.size	DW.ref.__gcc_personality_v0, 4
+	.long	__gcc_personality_v0
+#else
+	.align 8
+	.size	DW.ref.__gcc_personality_v0, 8
+	.quad	__gcc_personality_v0
+#endif
+#endif
+
+
+
+# Initialize the stack test value when the program starts or when a
+# new thread starts.  We don't know how large the main stack is, so we
+# guess conservatively.  We might be able to use getrlimit here.
+
+	.text
+	.global	__stack_split_initialize
+	.hidden	__stack_split_initialize
+
+	.type	__stack_split_initialize, @function
+
+__stack_split_initialize:
+
+#ifndef __s390x__
+
+	ear	%r1, %a0
+	lr	%r0, %r15
+	ahi	%r0, -0x4000	# We should have at least 16K.
+	st	%r0, 0x20(%r1)
+
+	lr	%r2, %r15
+	lhi	%r3, 0x4000
+#ifdef __PIC__
+	jg	__generic_morestack_set_initial_sp@PLT	# Tail call
+#else
+	jg	__generic_morestack_set_initial_sp	# Tail call
+#endif
+
+#else /* defined(__s390x__) */
+
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1
+	lgr	%r0, %r15
+	aghi	%r0, -0x4000	# We should have at least 16K.
+	stg	%r0, 0x38(%r1)
+
+	lgr	%r2, %r15
+	lghi	%r3, 0x4000
+#ifdef __PIC__
+	jg	__generic_morestack_set_initial_sp@PLT	# Tail call
+#else
+	jg	__generic_morestack_set_initial_sp	# Tail call
+#endif
+
+#endif /* defined(__s390x__) */
+
+	.size	__stack_split_initialize, . - __stack_split_initialize
+
+# Routines to get and set the guard, for __splitstack_getcontext,
+# __splitstack_setcontext, and __splitstack_makecontext.
+
+# void *__morestack_get_guard (void) returns the current stack guard.
+	.text
+	.global	__morestack_get_guard
+	.hidden	__morestack_get_guard
+
+	.type	__morestack_get_guard,@function
+
+__morestack_get_guard:
+
+#ifndef __s390x__
+	ear	%r1, %a0
+	l	%r2, 0x20(%r1)
+#else
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1
+	lg	%r2, 0x38(%r1)
+#endif
+	br %r14
+
+	.size	__morestack_get_guard, . - __morestack_get_guard
+
+# void __morestack_set_guard (void *) sets the stack guard.
+	.global	__morestack_set_guard
+	.hidden	__morestack_set_guard
+
+	.type	__morestack_set_guard,@function
+
+__morestack_set_guard:
+
+#ifndef __s390x__
+	ear	%r1, %a0
+	st	%r2, 0x20(%r1)
+#else
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1
+	stg	%r2, 0x38(%r1)
+#endif
+	br	%r14
+
+	.size	__morestack_set_guard, . - __morestack_set_guard
+
+# void *__morestack_make_guard (void *, size_t) returns the stack
+# guard value for a stack.
+	.global	__morestack_make_guard
+	.hidden	__morestack_make_guard
+
+	.type	__morestack_make_guard,@function
+
+__morestack_make_guard:
+
+#ifndef __s390x__
+	sr	%r2, %r3
+	ahi	%r2, BACKOFF
+#else
+	sgr	%r2, %r3
+	aghi	%r2, BACKOFF
+#endif
+	br	%r14
+
+	.size	__morestack_make_guard, . - __morestack_make_guard
+
+# Make __stack_split_initialize a high priority constructor.
+
+	.section .ctors.65535,"aw",@progbits
+
+#ifndef __LP64__
+	.align	4
+	.long	__stack_split_initialize
+	.long	__morestack_load_mmap
+#else
+	.align	8
+	.quad	__stack_split_initialize
+	.quad	__morestack_load_mmap
+#endif
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
+	.section	.note.GNU-no-split-stack,"",@progbits
diff --git a/libgcc/config/s390/t-stack-s390 b/libgcc/config/s390/t-stack-s390
new file mode 100644
index 00000000000..4c959b036de
--- /dev/null
+++ b/libgcc/config/s390/t-stack-s390
@@ -0,0 +1,2 @@
+# Makefile fragment to support -fsplit-stack for s390.
+LIB2ADD_ST += $(srcdir)/config/s390/morestack.S
diff --git a/libgcc/generic-morestack.c b/libgcc/generic-morestack.c
index 89765d45ede..b8eec4e7395 100644
--- a/libgcc/generic-morestack.c
+++ b/libgcc/generic-morestack.c
@@ -939,6 +939,10 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
 #elif defined (__i386__)
       nsp -= 6 * sizeof (void *);
 #elif defined __powerpc64__
+#elif defined __s390x__
+      nsp -= 2 * 160;
+#elif defined __s390__
+      nsp -= 2 * 96;
 #else
 #error "unrecognized target"
 #endif
-- 
cgit v1.2.1