Commit adf39f8f by Andreas Krebbel Committed by Ulrich Weigand

s390.c (struct s390_frame_layout): New struct as element of struct machine_function.

2004-08-12  Andreas Krebbel  <krebbel1@de.ibm.com>

	* config/s390/s390.c (struct s390_frame_layout): New struct as element
	of struct machine_function.
	(cfun->machine->frame_size): Moved into cfun->machine->frame_layout and
	changed all uses.
	(cfun->machine->save_fprs_p): Replaced by cfun_save_high_fprs and
	changed all uses.
	(cfun_frame_layout, cfun_save_high_fprs_p, cfun_gprs_save_area_size)
	(cfun_set_fpr_bit, cfun_fpr_bit_p): New macros.
	(s390_frame_area, s390_register_info): New functions.
	(s390_optimize_prolog): Renamed to s390_optimize_prologue.  Added check
	for base register.
	(s390_return_addr_rtx, s390_return_address_offset)
	(s390_va_start, s390_gimplify_va_arg)
	(s390_emit_prologue, s390_emit_epilogue): Adjusted for new stack
	layouts.
	(s390_frame_info): Functionality partly moved to s390_register_info.
	Made adaptions for new stack layout.
	(save_gprs, restore_gprs): Changed meaning of second parameter and
	adapted all callers.

	* config/s390/s390.h (s390_backchain_string): New global variable.
	(MASK_BACKCHAIN): Removed definition.
	(TARGET_BACKCHAIN): Changed check.
	(TARGET_KERNEL_BACKCHAIN): New macro.
	(TARGET_SWITCHES): Removed entries of "backchain" and "no-backchain".
	(TARGET_OPTIONS): Added "backchain", "no-backchain" and
	"kernel-backchain".
	(DYNAMIC_CHAIN_ADDRESS): Adjusted for new stack layouts.

	* config/s390/s390.md ("allocate_stack"): Added TARGET_KERNEL_BACKCHAIN
	as condition.  Adjusted for new stack layout.

	* doc/invoke.texi: Added documentation for new option
	"-mkernel-backchain" and adjusted documentation of "-mbackchain" and
	"-mno-backchain".

From-SVN: r85882
parent faa03cf1
2004-08-12 Andreas Krebbel <krebbel1@de.ibm.com>
* config/s390/s390.c (struct s390_frame_layout): New struct as element
of struct machine_function.
(cfun->machine->frame_size): Moved into cfun->machine->frame_layout and
changed all uses.
(cfun->machine->save_fprs_p): Replaced by cfun_save_high_fprs and
changed all uses.
(cfun_frame_layout, cfun_save_high_fprs_p, cfun_gprs_save_area_size)
(cfun_set_fpr_bit, cfun_fpr_bit_p): New macros.
(s390_frame_area, s390_register_info): New functions.
(s390_optimize_prolog): Renamed to s390_optimize_prologue. Added check
for base register.
(s390_return_addr_rtx, s390_return_address_offset)
(s390_va_start, s390_gimplify_va_arg)
(s390_emit_prologue, s390_emit_epilogue): Adjusted for new stack
layouts.
(s390_frame_info): Functionality partly moved to s390_register_info.
Made adaptions for new stack layout.
(save_gprs, restore_gprs): Changed meaning of second parameter and
adapted all callers.
* config/s390/s390.h (s390_backchain_string): New global variable.
(MASK_BACKCHAIN): Removed definition.
(TARGET_BACKCHAIN): Changed check.
(TARGET_KERNEL_BACKCHAIN): New macro.
(TARGET_SWITCHES): Removed entries of "backchain" and "no-backchain".
(TARGET_OPTIONS): Added "backchain", "no-backchain" and
"kernel-backchain".
(DYNAMIC_CHAIN_ADDRESS): Adjusted for new stack layouts.
* config/s390/s390.md ("allocate_stack"): Added TARGET_KERNEL_BACKCHAIN
as condition. Adjusted for new stack layout.
* doc/invoke.texi: Added documentation for new option
"-mkernel-backchain" and adjusted documentation of "-mbackchain" and
"-mno-backchain".
2004-08-12 Paul Brook <paul@codesourcery.com> 2004-08-12 Paul Brook <paul@codesourcery.com>
* config/arm/lib1funcs.asm (ARM_FUNC_ALIAS): Also alias _L__name. * config/arm/lib1funcs.asm (ARM_FUNC_ALIAS): Also alias _L__name.
......
...@@ -200,15 +200,21 @@ enum processor_flags s390_arch_flags; ...@@ -200,15 +200,21 @@ enum processor_flags s390_arch_flags;
const char *s390_tune_string; /* for -mtune=<xxx> */ const char *s390_tune_string; /* for -mtune=<xxx> */
const char *s390_arch_string; /* for -march=<xxx> */ const char *s390_arch_string; /* for -march=<xxx> */
/* Define the structure for the machine field in struct function. */ /* String to specify backchain mode. */
const char *s390_backchain_string = ""; /* "" no-backchain ,"1" backchain,
"2" kernel-backchain */
struct machine_function GTY(()) /* The following structure is embedded in the machine
{ specific part of struct function. */
/* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */
int save_fprs_p;
/* Set if return address needs to be saved. */ struct s390_frame_layout GTY (())
bool save_return_addr_p; {
/* Offset within stack frame. */
HOST_WIDE_INT gprs_offset;
HOST_WIDE_INT f0_offset;
HOST_WIDE_INT f4_offset;
HOST_WIDE_INT f8_offset;
HOST_WIDE_INT backchain_offset;
/* Number of first and last gpr to be saved, restored. */ /* Number of first and last gpr to be saved, restored. */
int first_save_gpr; int first_save_gpr;
...@@ -216,8 +222,32 @@ struct machine_function GTY(()) ...@@ -216,8 +222,32 @@ struct machine_function GTY(())
int last_save_gpr; int last_save_gpr;
int last_restore_gpr; int last_restore_gpr;
/* Bits standing for floating point registers. Set, if the
respective register has to be saved. Starting with reg 16 (f0)
at the rightmost bit.
Bit 15 - 8 7 6 5 4 3 2 1 0
fpr 15 - 8 7 5 3 1 6 4 2 0
reg 31 - 24 23 22 21 20 19 18 17 16 */
unsigned int fpr_bitmap;
/* Number of floating point registers f8-f15 which must be saved. */
int high_fprs;
/* Set if return address needs to be saved. */
bool save_return_addr_p;
/* Set if backchain needs to be saved. */
bool save_backchain_p;
/* Size of stack frame. */ /* Size of stack frame. */
HOST_WIDE_INT frame_size; HOST_WIDE_INT frame_size;
};
/* Define the structure for the machine field in struct function. */
struct machine_function GTY(())
{
struct s390_frame_layout frame_layout;
/* Literal pool base register. */ /* Literal pool base register. */
rtx base_reg; rtx base_reg;
...@@ -226,6 +256,17 @@ struct machine_function GTY(()) ...@@ -226,6 +256,17 @@ struct machine_function GTY(())
const char *some_ld_name; const char *some_ld_name;
}; };
/* Few accessor macros for struct cfun->machine->s390_frame_layout. */
#define cfun_frame_layout (cfun->machine->frame_layout)
#define cfun_save_high_fprs_p (!!cfun_frame_layout.high_fprs)
#define cfun_gprs_save_area_size ((cfun_frame_layout.last_save_gpr - \
cfun_frame_layout.first_save_gpr + 1) * UNITS_PER_WORD)
#define cfun_set_fpr_bit(BITNUM) (cfun->machine->frame_layout.fpr_bitmap |= \
(1 << (BITNUM)))
#define cfun_fpr_bit_p(BITNUM) (!!(cfun->machine->frame_layout.fpr_bitmap & \
(1 << (BITNUM))))
static int s390_match_ccmode_set (rtx, enum machine_mode); static int s390_match_ccmode_set (rtx, enum machine_mode);
static int s390_branch_condition_mask (rtx); static int s390_branch_condition_mask (rtx);
static const char *s390_branch_condition_mnemonic (rtx, int); static const char *s390_branch_condition_mnemonic (rtx, int);
...@@ -246,8 +287,10 @@ static void find_constant_pool_ref (rtx, rtx *); ...@@ -246,8 +287,10 @@ static void find_constant_pool_ref (rtx, rtx *);
static void replace_constant_pool_ref (rtx *, rtx, rtx); static void replace_constant_pool_ref (rtx *, rtx, rtx);
static rtx find_ltrel_base (rtx); static rtx find_ltrel_base (rtx);
static void replace_ltrel_base (rtx *); static void replace_ltrel_base (rtx *);
static void s390_optimize_prolog (bool); static void s390_optimize_prologue (bool);
static int find_unused_clobbered_reg (void); static int find_unused_clobbered_reg (void);
static void s390_frame_area (int *, int *);
static void s390_register_info (int, int);
static void s390_frame_info (int, int); static void s390_frame_info (int, int);
static rtx save_fpr (rtx, int, int); static rtx save_fpr (rtx, int, int);
static rtx restore_fpr (rtx, int, int); static rtx restore_fpr (rtx, int, int);
...@@ -4168,7 +4211,7 @@ s390_split_branches (void) ...@@ -4168,7 +4211,7 @@ s390_split_branches (void)
/* We are going to use the return register as scratch register, /* We are going to use the return register as scratch register,
make sure it will be saved/restored by the prologue/epilogue. */ make sure it will be saved/restored by the prologue/epilogue. */
cfun->machine->save_return_addr_p = 1; cfun_frame_layout.save_return_addr_p = 1;
if (!flag_pic) if (!flag_pic)
{ {
...@@ -5333,33 +5376,33 @@ s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align) ...@@ -5333,33 +5376,33 @@ s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align)
} }
/* Rework the prolog/epilog to avoid saving/restoring /* Rework the prologue/epilogue to avoid saving/restoring
registers unnecessarily. BASE_USED specifies whether registers unnecessarily. BASE_USED specifies whether
the literal pool base register needs to be saved. */ the literal pool base register needs to be saved. */
static void static void
s390_optimize_prolog (bool base_used) s390_optimize_prologue (bool base_used)
{ {
rtx insn, new_insn, next_insn; rtx insn, new_insn, next_insn;
/* Do a final recompute of the frame-related data. */ /* Do a final recompute of the frame-related data. */
s390_frame_info (base_used, cfun->machine->save_return_addr_p); s390_register_info (base_used, cfun_frame_layout.save_return_addr_p);
regs_ever_live[BASE_REGNUM] = base_used; regs_ever_live[BASE_REGNUM] = base_used;
regs_ever_live[RETURN_REGNUM] = cfun->machine->save_return_addr_p; regs_ever_live[RETURN_REGNUM] = cfun_frame_layout.save_return_addr_p;
regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0;
/* If all special registers are in fact used, there's nothing we /* If all special registers are in fact used, there's nothing we
can do, so no point in walking the insn list. */ can do, so no point in walking the insn list. */
if (cfun->machine->first_save_gpr <= BASE_REGNUM if (cfun_frame_layout.first_save_gpr <= BASE_REGNUM
&& cfun->machine->last_save_gpr >= BASE_REGNUM && cfun_frame_layout.last_save_gpr >= BASE_REGNUM
&& (TARGET_CPU_ZARCH && (TARGET_CPU_ZARCH
|| (cfun->machine->first_save_gpr <= RETURN_REGNUM || (cfun_frame_layout.first_save_gpr <= RETURN_REGNUM
&& cfun->machine->last_save_gpr >= RETURN_REGNUM))) && cfun_frame_layout.last_save_gpr >= RETURN_REGNUM)))
return; return;
/* Search for prolog/epilog insns and replace them. */ /* Search for prologue/epilogue insns and replace them. */
for (insn = get_insns (); insn; insn = next_insn) for (insn = get_insns (); insn; insn = next_insn)
{ {
...@@ -5379,17 +5422,23 @@ s390_optimize_prolog (bool base_used) ...@@ -5379,17 +5422,23 @@ s390_optimize_prolog (bool base_used)
last = first + XVECLEN (PATTERN (insn), 0) - 1; last = first + XVECLEN (PATTERN (insn), 0) - 1;
offset = const0_rtx; offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
off = INTVAL (offset) - first * UNITS_PER_WORD; off = INTVAL (offset);
if (GET_CODE (base) != REG || off < 0) if (GET_CODE (base) != REG || off < 0)
continue; continue;
if (REGNO (base) != STACK_POINTER_REGNUM
&& REGNO (base) != HARD_FRAME_POINTER_REGNUM)
continue;
if (first > BASE_REGNUM || last < BASE_REGNUM) if (first > BASE_REGNUM || last < BASE_REGNUM)
continue; continue;
if (cfun->machine->first_save_gpr != -1) if (cfun_frame_layout.first_save_gpr != -1)
{ {
new_insn = save_gprs (base, off, cfun->machine->first_save_gpr, new_insn = save_gprs (base,
cfun->machine->last_save_gpr); off + (cfun_frame_layout.first_save_gpr
- first) * UNITS_PER_WORD,
cfun_frame_layout.first_save_gpr,
cfun_frame_layout.last_save_gpr);
new_insn = emit_insn_before (new_insn, insn); new_insn = emit_insn_before (new_insn, insn);
INSN_ADDRESSES_NEW (new_insn, -1); INSN_ADDRESSES_NEW (new_insn, -1);
} }
...@@ -5406,15 +5455,20 @@ s390_optimize_prolog (bool base_used) ...@@ -5406,15 +5455,20 @@ s390_optimize_prolog (bool base_used)
set = PATTERN (insn); set = PATTERN (insn);
offset = const0_rtx; offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset); base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
off = INTVAL (offset) - BASE_REGNUM * UNITS_PER_WORD; off = INTVAL (offset);
if (GET_CODE (base) != REG || off < 0) if (GET_CODE (base) != REG || off < 0)
continue; continue;
if (REGNO (base) != STACK_POINTER_REGNUM
if (cfun->machine->first_save_gpr != -1) && REGNO (base) != HARD_FRAME_POINTER_REGNUM)
continue;
if (cfun_frame_layout.first_save_gpr != -1)
{ {
new_insn = save_gprs (base, off, cfun->machine->first_save_gpr, new_insn = save_gprs (base,
cfun->machine->last_save_gpr); off + (cfun_frame_layout.first_save_gpr
- BASE_REGNUM) * UNITS_PER_WORD,
cfun_frame_layout.first_save_gpr,
cfun_frame_layout.last_save_gpr);
new_insn = emit_insn_before (new_insn, insn); new_insn = emit_insn_before (new_insn, insn);
INSN_ADDRESSES_NEW (new_insn, -1); INSN_ADDRESSES_NEW (new_insn, -1);
} }
...@@ -5431,17 +5485,23 @@ s390_optimize_prolog (bool base_used) ...@@ -5431,17 +5485,23 @@ s390_optimize_prolog (bool base_used)
last = first + XVECLEN (PATTERN (insn), 0) - 1; last = first + XVECLEN (PATTERN (insn), 0) - 1;
offset = const0_rtx; offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
off = INTVAL (offset) - first * UNITS_PER_WORD; off = INTVAL (offset);
if (GET_CODE (base) != REG || off < 0) if (GET_CODE (base) != REG || off < 0)
continue; continue;
if (REGNO (base) != STACK_POINTER_REGNUM
&& REGNO (base) != HARD_FRAME_POINTER_REGNUM)
continue;
if (first > BASE_REGNUM || last < BASE_REGNUM) if (first > BASE_REGNUM || last < BASE_REGNUM)
continue; continue;
if (cfun->machine->first_restore_gpr != -1) if (cfun_frame_layout.first_restore_gpr != -1)
{ {
new_insn = restore_gprs (base, off, cfun->machine->first_restore_gpr, new_insn = restore_gprs (base,
cfun->machine->last_restore_gpr); off + (cfun_frame_layout.first_restore_gpr
- first) * UNITS_PER_WORD,
cfun_frame_layout.first_restore_gpr,
cfun_frame_layout.last_restore_gpr);
new_insn = emit_insn_before (new_insn, insn); new_insn = emit_insn_before (new_insn, insn);
INSN_ADDRESSES_NEW (new_insn, -1); INSN_ADDRESSES_NEW (new_insn, -1);
} }
...@@ -5458,15 +5518,20 @@ s390_optimize_prolog (bool base_used) ...@@ -5458,15 +5518,20 @@ s390_optimize_prolog (bool base_used)
set = PATTERN (insn); set = PATTERN (insn);
offset = const0_rtx; offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset); base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
off = INTVAL (offset) - BASE_REGNUM * UNITS_PER_WORD; off = INTVAL (offset);
if (GET_CODE (base) != REG || off < 0) if (GET_CODE (base) != REG || off < 0)
continue; continue;
if (REGNO (base) != STACK_POINTER_REGNUM
if (cfun->machine->first_restore_gpr != -1) && REGNO (base) != HARD_FRAME_POINTER_REGNUM)
continue;
if (cfun_frame_layout.first_restore_gpr != -1)
{ {
new_insn = restore_gprs (base, off, cfun->machine->first_restore_gpr, new_insn = restore_gprs (base,
cfun->machine->last_restore_gpr); off + (cfun_frame_layout.first_restore_gpr
- BASE_REGNUM) * UNITS_PER_WORD,
cfun_frame_layout.first_restore_gpr,
cfun_frame_layout.last_restore_gpr);
new_insn = emit_insn_before (new_insn, insn); new_insn = emit_insn_before (new_insn, insn);
INSN_ADDRESSES_NEW (new_insn, -1); INSN_ADDRESSES_NEW (new_insn, -1);
} }
...@@ -5567,7 +5632,7 @@ s390_reorg (void) ...@@ -5567,7 +5632,7 @@ s390_reorg (void)
break; break;
} }
s390_optimize_prolog (base_used); s390_optimize_prologue (base_used);
} }
...@@ -5578,11 +5643,12 @@ s390_reorg (void) ...@@ -5578,11 +5643,12 @@ s390_reorg (void)
rtx rtx
s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED) s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
{ {
int offset;
rtx addr; rtx addr;
/* Without backchain, we fail for all but the current frame. */ /* Without backchain, we fail for all but the current frame. */
if (!TARGET_BACKCHAIN && count > 0) if (!TARGET_BACKCHAIN && !TARGET_KERNEL_BACKCHAIN && count > 0)
return NULL_RTX; return NULL_RTX;
/* For the current frame, we need to make sure the initial /* For the current frame, we need to make sure the initial
...@@ -5590,11 +5656,16 @@ s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED) ...@@ -5590,11 +5656,16 @@ s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
if (count == 0) if (count == 0)
{ {
cfun->machine->save_return_addr_p = true; cfun_frame_layout.save_return_addr_p = true;
return gen_rtx_MEM (Pmode, return_address_pointer_rtx); return gen_rtx_MEM (Pmode, return_address_pointer_rtx);
} }
addr = plus_constant (frame, RETURN_REGNUM * UNITS_PER_WORD); if (TARGET_BACKCHAIN)
offset = RETURN_REGNUM * UNITS_PER_WORD;
else
offset = -2 * UNITS_PER_WORD;
addr = plus_constant (frame, offset);
addr = memory_address (Pmode, addr); addr = memory_address (Pmode, addr);
return gen_rtx_MEM (Pmode, addr); return gen_rtx_MEM (Pmode, addr);
} }
...@@ -5613,41 +5684,69 @@ find_unused_clobbered_reg (void) ...@@ -5613,41 +5684,69 @@ find_unused_clobbered_reg (void)
return 0; return 0;
} }
/* Fill cfun->machine with info about frame of current function. /* Determine the frame area which actually has to be accessed
BASE_USED and RETURN_ADDR_USED specify whether we assume the in the function epilogue. The values are stored at the
given pointers AREA_BOTTOM (address of the lowest used stack
address) and AREA_TOP (address of the first item which does
not belong to the stack frame). */
static void
s390_frame_area (int *area_bottom, int *area_top)
{
int b, t;
int i;
b = INT_MAX;
t = INT_MIN;
if (cfun_frame_layout.first_restore_gpr != -1)
{
b = (cfun_frame_layout.gprs_offset
+ cfun_frame_layout.first_restore_gpr * UNITS_PER_WORD);
t = b + (cfun_frame_layout.last_restore_gpr
- cfun_frame_layout.first_restore_gpr + 1) * UNITS_PER_WORD;
}
if (TARGET_64BIT && cfun_save_high_fprs_p)
{
b = MIN (b, cfun_frame_layout.f8_offset);
t = MAX (t, (cfun_frame_layout.f8_offset
+ cfun_frame_layout.high_fprs * 8));
}
if (!TARGET_64BIT)
for (i = 2; i < 4; i++)
if (cfun_fpr_bit_p (i))
{
b = MIN (b, cfun_frame_layout.f4_offset + (i - 2) * 8);
t = MAX (t, cfun_frame_layout.f4_offset + (i - 1) * 8);
}
*area_bottom = b;
*area_top = t;
}
/* Fill cfun->machine with info about register usage of current
function. BASE_USED and RETURN_ADDR_USED specify whether we assume the
base and return address register will need to be saved. */ base and return address register will need to be saved. */
static void static void
s390_frame_info (int base_used, int return_addr_used) s390_register_info (int base_used, int return_addr_used)
{ {
int live_regs[16]; int live_regs[16];
int i, j; int i, j;
HOST_WIDE_INT fsize = get_frame_size ();
if (!TARGET_64BIT && fsize > 0x7fff0000) /* fprs 8 - 15 are call saved for 64 Bit ABI. */
fatal_error ("Total size of local variables exceeds architecture limit."); cfun_frame_layout.fpr_bitmap = 0;
cfun_frame_layout.high_fprs = 0;
/* fprs 8 - 15 are caller saved for 64 Bit ABI. */
cfun->machine->save_fprs_p = 0;
if (TARGET_64BIT) if (TARGET_64BIT)
for (i = 24; i < 32; i++) for (i = 24; i < 32; i++)
if (regs_ever_live[i] && !global_regs[i]) if (regs_ever_live[i] && !global_regs[i])
{ {
cfun->machine->save_fprs_p = 1; cfun_set_fpr_bit (i - 16);
break; cfun_frame_layout.high_fprs++;
} }
cfun->machine->frame_size = fsize + cfun->machine->save_fprs_p * 64;
/* Does function need to setup frame and save area. */
if (!current_function_is_leaf
|| TARGET_TPF_PROFILING
|| cfun->machine->frame_size > 0
|| current_function_calls_alloca
|| current_function_stdarg)
cfun->machine->frame_size += STARTING_FRAME_OFFSET;
/* Find first and last gpr to be saved. We trust regs_ever_live /* Find first and last gpr to be saved. We trust regs_ever_live
data, except that we don't save and restore global registers. data, except that we don't save and restore global registers.
...@@ -5663,7 +5762,12 @@ s390_frame_info (int base_used, int return_addr_used) ...@@ -5663,7 +5762,12 @@ s390_frame_info (int base_used, int return_addr_used)
live_regs[BASE_REGNUM] = base_used; live_regs[BASE_REGNUM] = base_used;
live_regs[RETURN_REGNUM] = return_addr_used; live_regs[RETURN_REGNUM] = return_addr_used;
live_regs[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; live_regs[STACK_POINTER_REGNUM] = (!current_function_is_leaf
|| TARGET_TPF_PROFILING
|| cfun_save_high_fprs_p
|| get_frame_size () > 0
|| current_function_calls_alloca
|| current_function_stdarg);
for (i = 6; i < 16; i++) for (i = 6; i < 16; i++)
if (live_regs[i]) if (live_regs[i])
...@@ -5675,30 +5779,147 @@ s390_frame_info (int base_used, int return_addr_used) ...@@ -5675,30 +5779,147 @@ s390_frame_info (int base_used, int return_addr_used)
if (i == 16) if (i == 16)
{ {
/* Nothing to save/restore. */ /* Nothing to save/restore. */
cfun->machine->first_save_gpr = -1; cfun_frame_layout.first_save_gpr = -1;
cfun->machine->first_restore_gpr = -1; cfun_frame_layout.first_restore_gpr = -1;
cfun->machine->last_save_gpr = -1; cfun_frame_layout.last_save_gpr = -1;
cfun->machine->last_restore_gpr = -1; cfun_frame_layout.last_restore_gpr = -1;
} }
else else
{ {
/* Save / Restore from gpr i to j. */ /* Save / Restore from gpr i to j. */
cfun->machine->first_save_gpr = i; cfun_frame_layout.first_save_gpr = i;
cfun->machine->first_restore_gpr = i; cfun_frame_layout.first_restore_gpr = i;
cfun->machine->last_save_gpr = j; cfun_frame_layout.last_save_gpr = j;
cfun->machine->last_restore_gpr = j; cfun_frame_layout.last_restore_gpr = j;
} }
/* Varargs functions need to save gprs 2 to 6. */
if (current_function_stdarg) if (current_function_stdarg)
{ {
if (cfun->machine->first_save_gpr == -1 /* Varargs functions need to save gprs 2 to 6. */
|| cfun->machine->first_save_gpr > 2) if (cfun_frame_layout.first_save_gpr == -1
cfun->machine->first_save_gpr = 2; || cfun_frame_layout.first_save_gpr > 2)
cfun_frame_layout.first_save_gpr = 2;
if (cfun_frame_layout.last_save_gpr == -1
|| cfun_frame_layout.last_save_gpr < 6)
cfun_frame_layout.last_save_gpr = 6;
if (cfun->machine->last_save_gpr == -1 /* Mark f0, f2 for 31 bit and f0-f4 for 64 bit to be saved. */
|| cfun->machine->last_save_gpr < 6) for (i = 0; i < (TARGET_64BIT ? 4 : 2); i++)
cfun->machine->last_save_gpr = 6; cfun_set_fpr_bit (i);
}
if (!TARGET_64BIT)
for (i = 2; i < 4; i++)
if (regs_ever_live[i + 16] && !global_regs[i + 16])
cfun_set_fpr_bit (i);
}
/* Fill cfun->machine with info about frame of current
function. BASE_USED and RETURN_ADDR_USED specify whether we assume the
base and return address register will need to be saved. */
static void
s390_frame_info (int base_used, int return_addr_used)
{
int i;
cfun_frame_layout.frame_size = get_frame_size ();
s390_register_info (base_used, return_addr_used);
if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000)
fatal_error ("Total size of local variables exceeds architecture limit.");
cfun_frame_layout.save_backchain_p = (TARGET_BACKCHAIN
|| TARGET_KERNEL_BACKCHAIN);
if (TARGET_BACKCHAIN)
{
cfun_frame_layout.backchain_offset = 0;
cfun_frame_layout.f0_offset = 16 * UNITS_PER_WORD;
cfun_frame_layout.f4_offset = cfun_frame_layout.f0_offset + 2 * 8;
cfun_frame_layout.f8_offset = -cfun_frame_layout.high_fprs * 8;
cfun_frame_layout.gprs_offset = (cfun_frame_layout.first_save_gpr
* UNITS_PER_WORD);
}
else if (TARGET_KERNEL_BACKCHAIN)
{
cfun_frame_layout.backchain_offset = (STACK_POINTER_OFFSET
- UNITS_PER_WORD);
cfun_frame_layout.gprs_offset
= (cfun_frame_layout.backchain_offset
- (STACK_POINTER_REGNUM - cfun_frame_layout.first_save_gpr + 1)
* UNITS_PER_WORD);
if (TARGET_64BIT)
{
cfun_frame_layout.f4_offset
= (cfun_frame_layout.gprs_offset
- 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
cfun_frame_layout.f0_offset
= (cfun_frame_layout.f4_offset
- 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
}
else
{
cfun_frame_layout.f0_offset
= (cfun_frame_layout.gprs_offset
- 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
cfun_frame_layout.f4_offset
= (cfun_frame_layout.f0_offset
- 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
}
}
else /* no backchain */
{
cfun_frame_layout.f4_offset
= (STACK_POINTER_OFFSET
- 8 * (cfun_fpr_bit_p (2) + cfun_fpr_bit_p (3)));
cfun_frame_layout.f0_offset
= (cfun_frame_layout.f4_offset
- 8 * (cfun_fpr_bit_p (0) + cfun_fpr_bit_p (1)));
cfun_frame_layout.gprs_offset
= cfun_frame_layout.f0_offset - cfun_gprs_save_area_size;
}
if (current_function_is_leaf
&& !TARGET_TPF_PROFILING
&& cfun_frame_layout.frame_size == 0
&& !cfun_save_high_fprs_p
&& !current_function_calls_alloca
&& !current_function_stdarg)
return;
if (TARGET_BACKCHAIN)
cfun_frame_layout.frame_size += (STARTING_FRAME_OFFSET
+ cfun_frame_layout.high_fprs * 8);
else
{
cfun_frame_layout.frame_size += (cfun_frame_layout.save_backchain_p
* UNITS_PER_WORD);
cfun_frame_layout.f8_offset = (MIN (MIN (cfun_frame_layout.f0_offset,
cfun_frame_layout.f4_offset),
cfun_frame_layout.gprs_offset)
- cfun_frame_layout.high_fprs * 8);
cfun_frame_layout.frame_size += cfun_frame_layout.high_fprs * 8;
for (i = 0; i < 8; i++)
if (cfun_fpr_bit_p (i))
cfun_frame_layout.frame_size += 8;
cfun_frame_layout.frame_size += cfun_gprs_save_area_size;
cfun_frame_layout.frame_size = ((cfun_frame_layout.frame_size +
STACK_BOUNDARY / BITS_PER_UNIT - 1)
& ~(STACK_BOUNDARY / BITS_PER_UNIT - 1));
cfun_frame_layout.frame_size += current_function_outgoing_args_size;
} }
} }
...@@ -5713,10 +5934,11 @@ s390_arg_frame_offset (void) ...@@ -5713,10 +5934,11 @@ s390_arg_frame_offset (void)
int return_addr_used = !current_function_is_leaf int return_addr_used = !current_function_is_leaf
|| TARGET_TPF_PROFILING || TARGET_TPF_PROFILING
|| regs_ever_live[RETURN_REGNUM] || regs_ever_live[RETURN_REGNUM]
|| cfun->machine->save_return_addr_p; || cfun_frame_layout.save_return_addr_p;
s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used); s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used);
return cfun->machine->frame_size + STACK_POINTER_OFFSET;
return cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
} }
/* Return offset between return address pointer (location of r14 /* Return offset between return address pointer (location of r14
...@@ -5727,7 +5949,11 @@ s390_return_address_offset (void) ...@@ -5727,7 +5949,11 @@ s390_return_address_offset (void)
{ {
s390_frame_info (1, 1); s390_frame_info (1, 1);
return cfun->machine->frame_size + RETURN_REGNUM * UNITS_PER_WORD; if (cfun_frame_layout.last_save_gpr < RETURN_REGNUM)
abort ();
return (cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset
+ (RETURN_REGNUM - cfun_frame_layout.first_save_gpr) * UNITS_PER_WORD);
} }
/* Emit insn to save fpr REGNUM at offset OFFSET relative /* Emit insn to save fpr REGNUM at offset OFFSET relative
...@@ -5766,7 +5992,7 @@ save_gprs (rtx base, int offset, int first, int last) ...@@ -5766,7 +5992,7 @@ save_gprs (rtx base, int offset, int first, int last)
rtx addr, insn, note; rtx addr, insn, note;
int i; int i;
addr = plus_constant (base, offset + first * UNITS_PER_WORD); addr = plus_constant (base, offset);
addr = gen_rtx_MEM (Pmode, addr); addr = gen_rtx_MEM (Pmode, addr);
set_mem_alias_set (addr, s390_sr_alias_set); set_mem_alias_set (addr, s390_sr_alias_set);
...@@ -5812,7 +6038,7 @@ save_gprs (rtx base, int offset, int first, int last) ...@@ -5812,7 +6038,7 @@ save_gprs (rtx base, int offset, int first, int last)
} }
else if (last >= 6) else if (last >= 6)
{ {
addr = plus_constant (base, offset + 6 * UNITS_PER_WORD); addr = plus_constant (base, offset + (6 - first) * UNITS_PER_WORD);
note = gen_store_multiple (gen_rtx_MEM (Pmode, addr), note = gen_store_multiple (gen_rtx_MEM (Pmode, addr),
gen_rtx_REG (Pmode, 6), gen_rtx_REG (Pmode, 6),
GEN_INT (last - 6 + 1)); GEN_INT (last - 6 + 1));
...@@ -5841,7 +6067,7 @@ restore_gprs (rtx base, int offset, int first, int last) ...@@ -5841,7 +6067,7 @@ restore_gprs (rtx base, int offset, int first, int last)
{ {
rtx addr, insn; rtx addr, insn;
addr = plus_constant (base, offset + first * UNITS_PER_WORD); addr = plus_constant (base, offset);
addr = gen_rtx_MEM (Pmode, addr); addr = gen_rtx_MEM (Pmode, addr);
set_mem_alias_set (addr, s390_sr_alias_set); set_mem_alias_set (addr, s390_sr_alias_set);
...@@ -5913,6 +6139,8 @@ s390_emit_prologue (void) ...@@ -5913,6 +6139,8 @@ s390_emit_prologue (void)
rtx insn, addr; rtx insn, addr;
rtx temp_reg; rtx temp_reg;
int i; int i;
int offset;
int next_fpr = 0;
/* At this point, we decide whether we'll need to save/restore the /* At this point, we decide whether we'll need to save/restore the
return address register. This decision is final on zSeries machines; return address register. This decision is final on zSeries machines;
...@@ -5921,7 +6149,7 @@ s390_emit_prologue (void) ...@@ -5921,7 +6149,7 @@ s390_emit_prologue (void)
if (!current_function_is_leaf if (!current_function_is_leaf
|| TARGET_TPF_PROFILING || TARGET_TPF_PROFILING
|| regs_ever_live[RETURN_REGNUM]) || regs_ever_live[RETURN_REGNUM])
cfun->machine->save_return_addr_p = 1; cfun_frame_layout.save_return_addr_p = 1;
/* Decide which register to use as literal pool base. In small leaf /* Decide which register to use as literal pool base. In small leaf
functions, try to use an unused call-clobbered register as base functions, try to use an unused call-clobbered register as base
...@@ -5937,17 +6165,18 @@ s390_emit_prologue (void) ...@@ -5937,17 +6165,18 @@ s390_emit_prologue (void)
/* Compute frame info. Note that at this point, we assume the base /* Compute frame info. Note that at this point, we assume the base
register and -on S/390- the return register always need to be saved. register and -on S/390- the return register always need to be saved.
This is done because the usage of these registers might change even This is done because the usage of these registers might change even
after the prolog was emitted. If it turns out later that we really after the prologue was emitted. If it turns out later that we really
don't need them, the prolog/epilog code is modified again. */ don't need them, the prologue/epilogue code is modified again. */
s390_frame_info (1, !TARGET_CPU_ZARCH || cfun->machine->save_return_addr_p); s390_frame_info (1, !TARGET_CPU_ZARCH
|| cfun_frame_layout.save_return_addr_p);
/* We need to update regs_ever_live to avoid data-flow problems. */ /* We need to update regs_ever_live to avoid data-flow problems. */
regs_ever_live[BASE_REGNUM] = 1; regs_ever_live[BASE_REGNUM] = 1;
regs_ever_live[RETURN_REGNUM] = !TARGET_CPU_ZARCH regs_ever_live[RETURN_REGNUM] = (!TARGET_CPU_ZARCH
|| cfun->machine->save_return_addr_p; || cfun_frame_layout.save_return_addr_p);
regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0; regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0;
/* Annotate all constant pool references to let the scheduler know /* Annotate all constant pool references to let the scheduler know
they implicitly use the base register. */ they implicitly use the base register. */
...@@ -5963,50 +6192,86 @@ s390_emit_prologue (void) ...@@ -5963,50 +6192,86 @@ s390_emit_prologue (void)
/* Choose best register to use for temp use within prologue. /* Choose best register to use for temp use within prologue.
See below for why TPF must use the register 1. */ See below for why TPF must use the register 1. */
if (!current_function_is_leaf if (!current_function_is_leaf && !TARGET_TPF_PROFILING)
&& !TARGET_TPF_PROFILING)
temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM); temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
else else
temp_reg = gen_rtx_REG (Pmode, 1); temp_reg = gen_rtx_REG (Pmode, 1);
/* Save call saved gprs. */ /* Save call saved gprs. */
if (cfun_frame_layout.first_save_gpr != -1)
insn = save_gprs (stack_pointer_rtx, 0, insn = save_gprs (stack_pointer_rtx,
cfun->machine->first_save_gpr, cfun->machine->last_save_gpr); cfun_frame_layout.gprs_offset,
cfun_frame_layout.first_save_gpr,
cfun_frame_layout.last_save_gpr);
emit_insn (insn); emit_insn (insn);
/* Dummy insn to mark literal pool slot. */ /* Dummy insn to mark literal pool slot. */
emit_insn (gen_main_pool (cfun->machine->base_reg)); emit_insn (gen_main_pool (cfun->machine->base_reg));
/* Save fprs for variable args. */ offset = cfun_frame_layout.f0_offset;
if (current_function_stdarg) /* Save f0 and f2. */
for (i = 16; i < (TARGET_64BIT ? 20 : 18); i++) for (i = 0; i < 2; i++)
save_fpr (stack_pointer_rtx, 16*UNITS_PER_WORD + 8*(i-16), i); {
if (cfun_fpr_bit_p (i))
{
save_fpr (stack_pointer_rtx, offset, i + 16);
offset += 8;
}
else if (TARGET_BACKCHAIN)
offset += 8;
}
/* Save fprs 4 and 6 if used (31 bit ABI). */ /* Save f4 and f6. */
offset = cfun_frame_layout.f4_offset;
for (i = 2; i < 4; i++)
{
if (cfun_fpr_bit_p (i))
{
insn = save_fpr (stack_pointer_rtx, offset, i + 16);
offset += 8;
if (!TARGET_64BIT) /* If f4 and f6 are call clobbered they are saved due to stdargs and
for (i = 18; i < 20; i++) therefore are not frame related. */
if (regs_ever_live[i] && !global_regs[i]) if (!call_really_used_regs[i + 16])
RTX_FRAME_RELATED_P (insn) = 1;
}
else if (TARGET_BACKCHAIN)
offset += 8;
}
if (!TARGET_BACKCHAIN
&& cfun_save_high_fprs_p
&& cfun_frame_layout.f8_offset + cfun_frame_layout.high_fprs * 8 > 0)
{ {
insn = save_fpr (stack_pointer_rtx, 16*UNITS_PER_WORD + 8*(i-16), i); offset = (cfun_frame_layout.f8_offset
+ (cfun_frame_layout.high_fprs - 1) * 8);
for (i = 15; i > 7 && offset >= 0; i--)
if (cfun_fpr_bit_p (i))
{
insn = save_fpr (stack_pointer_rtx, offset, i + 16);
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
offset -= 8;
}
if (offset >= cfun_frame_layout.f8_offset)
next_fpr = i + 16;
} }
if (TARGET_BACKCHAIN)
next_fpr = cfun_save_high_fprs_p ? 31 : 0;
/* Decrement stack pointer. */ /* Decrement stack pointer. */
if (cfun->machine->frame_size > 0) if (cfun_frame_layout.frame_size > 0)
{ {
rtx frame_off = GEN_INT (-cfun->machine->frame_size); rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size);
/* Save incoming stack pointer into temp reg. */ /* Save incoming stack pointer into temp reg. */
if (cfun_frame_layout.save_backchain_p || next_fpr)
if (TARGET_BACKCHAIN || cfun->machine->save_fprs_p)
{
insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx)); insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
}
/* Subtract frame size from stack pointer. */ /* Subtract frame size from stack pointer. */
...@@ -6031,13 +6296,18 @@ s390_emit_prologue (void) ...@@ -6031,13 +6296,18 @@ s390_emit_prologue (void)
gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, stack_pointer_rtx, gen_rtx_SET (VOIDmode, stack_pointer_rtx,
gen_rtx_PLUS (Pmode, stack_pointer_rtx, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
GEN_INT (-cfun->machine->frame_size))), GEN_INT (-cfun_frame_layout.frame_size))),
REG_NOTES (insn)); REG_NOTES (insn));
/* Set backchain. */ /* Set backchain. */
if (TARGET_BACKCHAIN) if (cfun_frame_layout.save_backchain_p)
{ {
if (cfun_frame_layout.backchain_offset)
addr = gen_rtx_MEM (Pmode,
plus_constant (stack_pointer_rtx,
cfun_frame_layout.backchain_offset));
else
addr = gen_rtx_MEM (Pmode, stack_pointer_rtx); addr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
set_mem_alias_set (addr, s390_sr_alias_set); set_mem_alias_set (addr, s390_sr_alias_set);
insn = emit_insn (gen_move_insn (addr, temp_reg)); insn = emit_insn (gen_move_insn (addr, temp_reg));
...@@ -6047,7 +6317,7 @@ s390_emit_prologue (void) ...@@ -6047,7 +6317,7 @@ s390_emit_prologue (void)
we need to make sure the backchain pointer is set up we need to make sure the backchain pointer is set up
before any possibly trapping memory access. */ before any possibly trapping memory access. */
if (TARGET_BACKCHAIN && flag_non_call_exceptions) if (cfun_frame_layout.save_backchain_p && flag_non_call_exceptions)
{ {
addr = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)); addr = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode));
emit_insn (gen_rtx_CLOBBER (VOIDmode, addr)); emit_insn (gen_rtx_CLOBBER (VOIDmode, addr));
...@@ -6056,17 +6326,23 @@ s390_emit_prologue (void) ...@@ -6056,17 +6326,23 @@ s390_emit_prologue (void)
/* Save fprs 8 - 15 (64 bit ABI). */ /* Save fprs 8 - 15 (64 bit ABI). */
if (cfun->machine->save_fprs_p) if (cfun_save_high_fprs_p && next_fpr)
{ {
insn = emit_insn (gen_add2_insn (temp_reg, GEN_INT(-64))); insn = emit_insn (gen_add2_insn (temp_reg,
GEN_INT (cfun_frame_layout.f8_offset)));
for (i = 24; i < 32; i++) offset = 0;
if (regs_ever_live[i] && !global_regs[i])
for (i = 24; i <= next_fpr; i++)
if (cfun_fpr_bit_p (i - 16))
{ {
rtx addr = plus_constant (stack_pointer_rtx, rtx addr = plus_constant (stack_pointer_rtx,
cfun->machine->frame_size - 64 + (i-24)*8); cfun_frame_layout.frame_size
+ cfun_frame_layout.f8_offset
+ offset);
insn = save_fpr (temp_reg, (i-24)*8, i); insn = save_fpr (temp_reg, offset, i);
offset += 8;
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) = REG_NOTES (insn) =
gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
...@@ -6122,6 +6398,7 @@ s390_emit_epilogue (bool sibcall) ...@@ -6122,6 +6398,7 @@ s390_emit_epilogue (bool sibcall)
{ {
rtx frame_pointer, return_reg; rtx frame_pointer, return_reg;
int area_bottom, area_top, offset = 0; int area_bottom, area_top, offset = 0;
int next_offset;
rtvec p; rtvec p;
int i; int i;
...@@ -6141,43 +6418,10 @@ s390_emit_epilogue (bool sibcall) ...@@ -6141,43 +6418,10 @@ s390_emit_epilogue (bool sibcall)
/* Check whether to use frame or stack pointer for restore. */ /* Check whether to use frame or stack pointer for restore. */
frame_pointer = frame_pointer_needed ? frame_pointer = (frame_pointer_needed
hard_frame_pointer_rtx : stack_pointer_rtx; ? hard_frame_pointer_rtx : stack_pointer_rtx);
/* Compute which parts of the save area we need to access. */
if (cfun->machine->first_restore_gpr != -1)
{
area_bottom = cfun->machine->first_restore_gpr * UNITS_PER_WORD;
area_top = (cfun->machine->last_restore_gpr + 1) * UNITS_PER_WORD;
}
else
{
area_bottom = INT_MAX;
area_top = INT_MIN;
}
if (TARGET_64BIT) s390_frame_area (&area_bottom, &area_top);
{
if (cfun->machine->save_fprs_p)
{
if (area_bottom > -64)
area_bottom = -64;
if (area_top < 0)
area_top = 0;
}
}
else
{
for (i = 18; i < 20; i++)
if (regs_ever_live[i] && !global_regs[i])
{
if (area_bottom > 16*UNITS_PER_WORD + 8*(i-16))
area_bottom = 16*UNITS_PER_WORD + 8*(i-16);
if (area_top < 16*UNITS_PER_WORD + 8*(i-16) + 8)
area_top = 16*UNITS_PER_WORD + 8*(i-16) + 8;
}
}
/* Check whether we can access the register save area. /* Check whether we can access the register save area.
If not, increment the frame pointer as required. */ If not, increment the frame pointer as required. */
...@@ -6186,18 +6430,18 @@ s390_emit_epilogue (bool sibcall) ...@@ -6186,18 +6430,18 @@ s390_emit_epilogue (bool sibcall)
{ {
/* Nothing to restore. */ /* Nothing to restore. */
} }
else if (DISP_IN_RANGE (cfun->machine->frame_size + area_bottom) else if (DISP_IN_RANGE (cfun_frame_layout.frame_size + area_bottom)
&& DISP_IN_RANGE (cfun->machine->frame_size + area_top-1)) && DISP_IN_RANGE (cfun_frame_layout.frame_size + area_top - 1))
{ {
/* Area is in range. */ /* Area is in range. */
offset = cfun->machine->frame_size; offset = cfun_frame_layout.frame_size;
} }
else else
{ {
rtx insn, frame_off; rtx insn, frame_off;
offset = area_bottom < 0 ? -area_bottom : 0; offset = area_bottom < 0 ? -area_bottom : 0;
frame_off = GEN_INT (cfun->machine->frame_size - offset); frame_off = GEN_INT (cfun_frame_layout.frame_size - offset);
if (DISP_IN_RANGE (INTVAL (frame_off))) if (DISP_IN_RANGE (INTVAL (frame_off)))
{ {
...@@ -6219,18 +6463,36 @@ s390_emit_epilogue (bool sibcall) ...@@ -6219,18 +6463,36 @@ s390_emit_epilogue (bool sibcall)
if (TARGET_64BIT) if (TARGET_64BIT)
{ {
if (cfun->machine->save_fprs_p) if (cfun_save_high_fprs_p)
{
next_offset = cfun_frame_layout.f8_offset;
for (i = 24; i < 32; i++) for (i = 24; i < 32; i++)
if (regs_ever_live[i] && !global_regs[i]) {
if (cfun_fpr_bit_p (i - 16))
{
restore_fpr (frame_pointer, restore_fpr (frame_pointer,
offset - 64 + (i-24) * 8, i); offset + next_offset, i);
next_offset += 8;
}
}
}
} }
else else
{ {
next_offset = cfun_frame_layout.f4_offset;
for (i = 18; i < 20; i++) for (i = 18; i < 20; i++)
if (regs_ever_live[i] && !global_regs[i]) {
if (cfun_fpr_bit_p (i - 16))
{
restore_fpr (frame_pointer, restore_fpr (frame_pointer,
offset + 16*UNITS_PER_WORD + 8*(i-16), i); offset + next_offset, i);
next_offset += 8;
}
else if (TARGET_BACKCHAIN)
next_offset += 8;
}
} }
/* Return register. */ /* Return register. */
...@@ -6239,7 +6501,7 @@ s390_emit_epilogue (bool sibcall) ...@@ -6239,7 +6501,7 @@ s390_emit_epilogue (bool sibcall)
/* Restore call saved gprs. */ /* Restore call saved gprs. */
if (cfun->machine->first_restore_gpr != -1) if (cfun_frame_layout.first_restore_gpr != -1)
{ {
rtx insn, addr; rtx insn, addr;
int i; int i;
...@@ -6247,8 +6509,8 @@ s390_emit_epilogue (bool sibcall) ...@@ -6247,8 +6509,8 @@ s390_emit_epilogue (bool sibcall)
/* Check for global register and save them /* Check for global register and save them
to stack location from where they get restored. */ to stack location from where they get restored. */
for (i = cfun->machine->first_restore_gpr; for (i = cfun_frame_layout.first_restore_gpr;
i <= cfun->machine->last_restore_gpr; i <= cfun_frame_layout.last_restore_gpr;
i++) i++)
{ {
/* These registers are special and need to be /* These registers are special and need to be
...@@ -6262,7 +6524,9 @@ s390_emit_epilogue (bool sibcall) ...@@ -6262,7 +6524,9 @@ s390_emit_epilogue (bool sibcall)
if (global_regs[i]) if (global_regs[i])
{ {
addr = plus_constant (frame_pointer, addr = plus_constant (frame_pointer,
offset + i * UNITS_PER_WORD); offset + cfun_frame_layout.gprs_offset
+ (i - cfun_frame_layout.first_save_gpr)
* UNITS_PER_WORD);
addr = gen_rtx_MEM (Pmode, addr); addr = gen_rtx_MEM (Pmode, addr);
set_mem_alias_set (addr, s390_sr_alias_set); set_mem_alias_set (addr, s390_sr_alias_set);
emit_move_insn (addr, gen_rtx_REG (Pmode, i)); emit_move_insn (addr, gen_rtx_REG (Pmode, i));
...@@ -6274,9 +6538,9 @@ s390_emit_epilogue (bool sibcall) ...@@ -6274,9 +6538,9 @@ s390_emit_epilogue (bool sibcall)
/* Fetch return address from stack before load multiple, /* Fetch return address from stack before load multiple,
this will do good for scheduling. */ this will do good for scheduling. */
if (cfun->machine->save_return_addr_p if (cfun_frame_layout.save_return_addr_p
|| (cfun->machine->first_restore_gpr < BASE_REGNUM || (cfun_frame_layout.first_restore_gpr < BASE_REGNUM
&& cfun->machine->last_restore_gpr > RETURN_REGNUM)) && cfun_frame_layout.last_restore_gpr > RETURN_REGNUM))
{ {
int return_regnum = find_unused_clobbered_reg(); int return_regnum = find_unused_clobbered_reg();
if (!return_regnum) if (!return_regnum)
...@@ -6284,16 +6548,23 @@ s390_emit_epilogue (bool sibcall) ...@@ -6284,16 +6548,23 @@ s390_emit_epilogue (bool sibcall)
return_reg = gen_rtx_REG (Pmode, return_regnum); return_reg = gen_rtx_REG (Pmode, return_regnum);
addr = plus_constant (frame_pointer, addr = plus_constant (frame_pointer,
offset + RETURN_REGNUM * UNITS_PER_WORD); offset + cfun_frame_layout.gprs_offset
+ (RETURN_REGNUM
- cfun_frame_layout.first_save_gpr)
* UNITS_PER_WORD);
addr = gen_rtx_MEM (Pmode, addr); addr = gen_rtx_MEM (Pmode, addr);
set_mem_alias_set (addr, s390_sr_alias_set); set_mem_alias_set (addr, s390_sr_alias_set);
emit_move_insn (return_reg, addr); emit_move_insn (return_reg, addr);
} }
} }
insn = restore_gprs (frame_pointer, offset, insn = restore_gprs (frame_pointer,
cfun->machine->first_restore_gpr, offset + cfun_frame_layout.gprs_offset
cfun->machine->last_restore_gpr); + (cfun_frame_layout.first_restore_gpr
- cfun_frame_layout.first_save_gpr)
* UNITS_PER_WORD,
cfun_frame_layout.first_restore_gpr,
cfun_frame_layout.last_restore_gpr);
emit_insn (insn); emit_insn (insn);
} }
...@@ -6681,9 +6952,15 @@ s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) ...@@ -6681,9 +6952,15 @@ s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* Find the register save area. */ /* Find the register save area. */
t = make_tree (TREE_TYPE (sav), virtual_incoming_args_rtx); t = make_tree (TREE_TYPE (sav), return_address_pointer_rtx);
if (TARGET_KERNEL_BACKCHAIN)
t = build (PLUS_EXPR, TREE_TYPE (sav), t, t = build (PLUS_EXPR, TREE_TYPE (sav), t,
build_int_2 (-STACK_POINTER_OFFSET, -1)); build_int_2 (-(RETURN_REGNUM - 2) * UNITS_PER_WORD
- (TARGET_64BIT ? 4 : 2) * 8, -1));
else
t = build (PLUS_EXPR, TREE_TYPE (sav), t,
build_int_2 (-RETURN_REGNUM * UNITS_PER_WORD, -1));
t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t); t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
TREE_SIDE_EFFECTS (t) = 1; TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
...@@ -6747,7 +7024,8 @@ s390_gimplify_va_arg (tree valist, tree type, tree *pre_p, ...@@ -6747,7 +7024,8 @@ s390_gimplify_va_arg (tree valist, tree type, tree *pre_p,
indirect_p = 1; indirect_p = 1;
reg = gpr; reg = gpr;
n_reg = 1; n_reg = 1;
sav_ofs = 2 * UNITS_PER_WORD; sav_ofs = (TARGET_KERNEL_BACKCHAIN
? (TARGET_64BIT ? 4 : 2) * 8 : 2 * UNITS_PER_WORD);
sav_scale = UNITS_PER_WORD; sav_scale = UNITS_PER_WORD;
size = UNITS_PER_WORD; size = UNITS_PER_WORD;
max_reg = 4; max_reg = 4;
...@@ -6764,7 +7042,7 @@ s390_gimplify_va_arg (tree valist, tree type, tree *pre_p, ...@@ -6764,7 +7042,7 @@ s390_gimplify_va_arg (tree valist, tree type, tree *pre_p,
indirect_p = 0; indirect_p = 0;
reg = fpr; reg = fpr;
n_reg = 1; n_reg = 1;
sav_ofs = 16 * UNITS_PER_WORD; sav_ofs = TARGET_KERNEL_BACKCHAIN ? 0 : 16 * UNITS_PER_WORD;
sav_scale = 8; sav_scale = 8;
/* TARGET_64BIT has up to 4 parameter in fprs */ /* TARGET_64BIT has up to 4 parameter in fprs */
max_reg = TARGET_64BIT ? 3 : 1; max_reg = TARGET_64BIT ? 3 : 1;
...@@ -6781,7 +7059,8 @@ s390_gimplify_va_arg (tree valist, tree type, tree *pre_p, ...@@ -6781,7 +7059,8 @@ s390_gimplify_va_arg (tree valist, tree type, tree *pre_p,
indirect_p = 0; indirect_p = 0;
reg = gpr; reg = gpr;
n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
sav_ofs = 2 * UNITS_PER_WORD; sav_ofs = TARGET_KERNEL_BACKCHAIN ?
(TARGET_64BIT ? 4 : 2) * 8 : 2*UNITS_PER_WORD;
if (size < UNITS_PER_WORD) if (size < UNITS_PER_WORD)
sav_ofs += UNITS_PER_WORD - size; sav_ofs += UNITS_PER_WORD - size;
......
...@@ -60,6 +60,8 @@ extern enum processor_type s390_arch; ...@@ -60,6 +60,8 @@ extern enum processor_type s390_arch;
extern enum processor_flags s390_arch_flags; extern enum processor_flags s390_arch_flags;
extern const char *s390_arch_string; extern const char *s390_arch_string;
extern const char *s390_backchain_string;
#define TARGET_CPU_IEEE_FLOAT \ #define TARGET_CPU_IEEE_FLOAT \
(s390_arch_flags & PF_IEEE_FLOAT) (s390_arch_flags & PF_IEEE_FLOAT)
#define TARGET_CPU_ZARCH \ #define TARGET_CPU_ZARCH \
...@@ -89,7 +91,6 @@ extern const char *s390_arch_string; ...@@ -89,7 +91,6 @@ extern const char *s390_arch_string;
extern int target_flags; extern int target_flags;
#define MASK_HARD_FLOAT 0x01 #define MASK_HARD_FLOAT 0x01
#define MASK_BACKCHAIN 0x02
#define MASK_SMALL_EXEC 0x04 #define MASK_SMALL_EXEC 0x04
#define MASK_DEBUG_ARG 0x08 #define MASK_DEBUG_ARG 0x08
#define MASK_64BIT 0x10 #define MASK_64BIT 0x10
...@@ -100,7 +101,6 @@ extern int target_flags; ...@@ -100,7 +101,6 @@ extern int target_flags;
#define TARGET_HARD_FLOAT (target_flags & MASK_HARD_FLOAT) #define TARGET_HARD_FLOAT (target_flags & MASK_HARD_FLOAT)
#define TARGET_SOFT_FLOAT (!(target_flags & MASK_HARD_FLOAT)) #define TARGET_SOFT_FLOAT (!(target_flags & MASK_HARD_FLOAT))
#define TARGET_BACKCHAIN (target_flags & MASK_BACKCHAIN)
#define TARGET_SMALL_EXEC (target_flags & MASK_SMALL_EXEC) #define TARGET_SMALL_EXEC (target_flags & MASK_SMALL_EXEC)
#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG) #define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG)
#define TARGET_64BIT (target_flags & MASK_64BIT) #define TARGET_64BIT (target_flags & MASK_64BIT)
...@@ -110,6 +110,9 @@ extern int target_flags; ...@@ -110,6 +110,9 @@ extern int target_flags;
#define TARGET_NO_FUSED_MADD (target_flags & MASK_NO_FUSED_MADD) #define TARGET_NO_FUSED_MADD (target_flags & MASK_NO_FUSED_MADD)
#define TARGET_FUSED_MADD (! TARGET_NO_FUSED_MADD) #define TARGET_FUSED_MADD (! TARGET_NO_FUSED_MADD)
#define TARGET_BACKCHAIN (s390_backchain_string[0] == '1')
#define TARGET_KERNEL_BACKCHAIN (s390_backchain_string[0] == '2')
/* ??? Once this actually works, it could be made a runtime option. */ /* ??? Once this actually works, it could be made a runtime option. */
#define TARGET_IBM_FLOAT 0 #define TARGET_IBM_FLOAT 0
#define TARGET_IEEE_FLOAT 1 #define TARGET_IEEE_FLOAT 1
...@@ -123,8 +126,6 @@ extern int target_flags; ...@@ -123,8 +126,6 @@ extern int target_flags;
#define TARGET_SWITCHES \ #define TARGET_SWITCHES \
{ { "hard-float", 1, N_("Use hardware fp")}, \ { { "hard-float", 1, N_("Use hardware fp")}, \
{ "soft-float", -1, N_("Don't use hardware fp")}, \ { "soft-float", -1, N_("Don't use hardware fp")}, \
{ "backchain", 2, N_("Set backchain")}, \
{ "no-backchain", -2, N_("Don't set backchain (faster, but debug harder")},\
{ "small-exec", 4, N_("Use bras for executable < 64k")}, \ { "small-exec", 4, N_("Use bras for executable < 64k")}, \
{ "no-small-exec", -4, N_("Don't use bras")}, \ { "no-small-exec", -4, N_("Don't use bras")}, \
{ "debug", 8, N_("Additional debug prints")}, \ { "debug", 8, N_("Additional debug prints")}, \
...@@ -146,6 +147,12 @@ extern int target_flags; ...@@ -146,6 +147,12 @@ extern int target_flags;
N_("Schedule code for given CPU"), 0}, \ N_("Schedule code for given CPU"), 0}, \
{ "arch=", &s390_arch_string, \ { "arch=", &s390_arch_string, \
N_("Generate code for given CPU"), 0}, \ N_("Generate code for given CPU"), 0}, \
{ "backchain", &s390_backchain_string, \
N_("Set backchain"), "1"}, \
{ "no-backchain", &s390_backchain_string, \
N_("Do not set backchain"), ""}, \
{ "kernel-backchain", &s390_backchain_string, \
N_("Set backchain appropriate for the linux kernel"), "2"}, \
} }
/* Support for configure-time defaults. */ /* Support for configure-time defaults. */
...@@ -560,8 +567,12 @@ extern int current_function_outgoing_args_size; ...@@ -560,8 +567,12 @@ extern int current_function_outgoing_args_size;
the corresponding RETURN_REGNUM register was saved. */ the corresponding RETURN_REGNUM register was saved. */
#define DYNAMIC_CHAIN_ADDRESS(FRAME) \ #define DYNAMIC_CHAIN_ADDRESS(FRAME) \
(TARGET_BACKCHAIN ? \
((FRAME) != hard_frame_pointer_rtx ? (FRAME) : \ ((FRAME) != hard_frame_pointer_rtx ? (FRAME) : \
plus_constant (arg_pointer_rtx, -STACK_POINTER_OFFSET)) plus_constant (arg_pointer_rtx, -STACK_POINTER_OFFSET)) : \
((FRAME) != hard_frame_pointer_rtx ? \
plus_constant ((FRAME), STACK_POINTER_OFFSET - UNITS_PER_WORD) : \
plus_constant (arg_pointer_rtx, -UNITS_PER_WORD)))
#define RETURN_ADDR_RTX(COUNT, FRAME) \ #define RETURN_ADDR_RTX(COUNT, FRAME) \
s390_return_addr_rtx ((COUNT), DYNAMIC_CHAIN_ADDRESS ((FRAME))) s390_return_addr_rtx ((COUNT), DYNAMIC_CHAIN_ADDRESS ((FRAME)))
......
...@@ -7217,11 +7217,19 @@ ...@@ -7217,11 +7217,19 @@
(plus (reg 15) (match_operand 1 "general_operand" ""))) (plus (reg 15) (match_operand 1 "general_operand" "")))
(set (match_operand 0 "general_operand" "") (set (match_operand 0 "general_operand" "")
(reg 15))] (reg 15))]
"TARGET_BACKCHAIN" "TARGET_BACKCHAIN || TARGET_KERNEL_BACKCHAIN"
{ {
rtx stack = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); rtx stack = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
rtx chain = gen_rtx_MEM (Pmode, stack); rtx chain;
rtx temp = gen_reg_rtx (Pmode); rtx temp;
if (TARGET_KERNEL_BACKCHAIN)
chain = plus_constant (stack, STACK_POINTER_OFFSET - UNITS_PER_WORD);
else
chain = stack;
chain = gen_rtx_MEM (Pmode, chain);
temp = gen_reg_rtx (Pmode);
emit_move_insn (temp, chain); emit_move_insn (temp, chain);
......
...@@ -617,7 +617,7 @@ See RS/6000 and PowerPC Options. ...@@ -617,7 +617,7 @@ See RS/6000 and PowerPC Options.
@emph{S/390 and zSeries Options} @emph{S/390 and zSeries Options}
@gccoptlist{-mtune=@var{cpu-type} -march=@var{cpu-type} @gol @gccoptlist{-mtune=@var{cpu-type} -march=@var{cpu-type} @gol
-mhard-float -msoft-float -mbackchain -mno-backchain @gol -mhard-float -msoft-float -mbackchain -mno-backchain -mkernel-backchain @gol
-msmall-exec -mno-small-exec -mmvcle -mno-mvcle @gol -msmall-exec -mno-small-exec -mmvcle -mno-mvcle @gol
-m64 -m31 -mdebug -mno-debug -mesa -mzarch @gol -m64 -m31 -mdebug -mno-debug -mesa -mzarch @gol
-mtpf-trace -mno-tpf-trace -mfused-madd -mno-fused-madd} -mtpf-trace -mno-tpf-trace -mfused-madd -mno-fused-madd}
...@@ -10454,13 +10454,27 @@ generates IEEE floating-point instructions. This is the default. ...@@ -10454,13 +10454,27 @@ generates IEEE floating-point instructions. This is the default.
@item -mbackchain @item -mbackchain
@itemx -mno-backchain @itemx -mno-backchain
@itemx -mkernel-backchain
@opindex mbackchain @opindex mbackchain
@opindex mno-backchain @opindex mno-backchain
Generate (or do not generate) code which maintains an explicit @opindex mkernel-backchain
backchain within the stack frame that points to the caller's frame. In order to provide a backchain the address of the caller's frame
This may be needed to allow debugging using tools that do not understand is stored within the callee's stack frame.
DWARF-2 call frame information. The default is not to generate the A backchain may be needed to allow debugging using tools that do not understand
backchain. DWARF-2 call frame information.
For @option{-mno-backchain} no backchain is maintained at all which is the
default.
If one of the other options is present the backchain pointer is placed either
on top of the stack frame (@option{-mkernel-backchain}) or on
the bottom (@option{-mbackchain}).
Beside the different backchain location @option{-mkernel-backchain}
also changes stack frame layout breaking the ABI. This option
is intended to be used for code which internally needs a backchain but has
to get by with a limited stack size e.g. the linux kernel.
Internal unwinding code not using DWARF-2 info has to be able to locate the
return address of a function. That will be eased be the fact that
the return address of a function is placed two words below the backchain
pointer.
@item -msmall-exec @item -msmall-exec
@itemx -mno-small-exec @itemx -mno-small-exec
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment