This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
S/390: More precise special register use tracking
- From: Ulrich Weigand <weigand at i1 dot informatik dot uni-erlangen dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 30 Sep 2004 23:25:10 +0200 (CEST)
- Subject: S/390: More precise special register use tracking
Hello,
this patch improves the handling of base and return address registers by
tracking more precisely at an early stage whether we will in fact need to
allocate them or not. The benefit is that if don't require them, we now
no longer allocate a stack slot in the packed stack layout for them; we
will also omit the dummy pool placeholder insn that in some cases seriously
interferes with optimal scheduling of the first basic block.
Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux.
Committed to mainline.
Bye,
Ulrich
ChangeLog:
* config/s390/s390-protos.h (s390_arg_frame_offset): Remove.
(s390_return_address_offset): Remove.
(s390_can_eliminate): Add prototype.
(s390_initial_elimination_offset): Add prototype.
* config/s390/s390.h (CAN_ELIMINATE): Call s390_can_eliminate.
(INITIAL_ELIMINATION_OFFSET): Call s390_initial_elimination_offset.
* config/s390/s390.c (s390_arg_frame_offset): Remove.
(s390_return_address_offset): Remove.
(s390_can_eliminate, s390_initial_elimination_offset): New functions.
(struct machine_function): New member split_branches_pending_p.
(s390_mainpool_start): Allow nonexistant pool insn for empty pool.
(s390_mainpool_finish): Likewise. Clear base_reg if pool empty.
(s390_optimize_prologue): Remove base_used argument. Call
s390_update_frame_layout instead of s390_register_info. Handle
prologue/epilogue insns that touch only RETURN_REGNUM.
(s390_reorg): Remove base_used. Clear split_branches_pending_p.
(s390_register_info): Remove base_used and return_addr_used
arguments, compute special register usage inline. Return live
register data to caller.
(s390_frame_info): Remove arguments, do not call s390_register_info.
(s390_init_frame_layout): New function.
(s390_update_frame_layout): Likewise.
(s390_emit_prologue): Call s390_update_frame_layout; some code
move to there. Do not emit pool placeholder insn if unnecessary.
Index: gcc/config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.58
diff -c -p -r1.58 s390-protos.h
*** gcc/config/s390/s390-protos.h 25 Sep 2004 00:16:55 -0000 1.58
--- gcc/config/s390/s390-protos.h 30 Sep 2004 13:40:16 -0000
*************** Software Foundation, 59 Temple Place - S
*** 23,30 ****
extern void optimization_options (int, int);
extern void override_options (void);
! extern HOST_WIDE_INT s390_arg_frame_offset (void);
! extern HOST_WIDE_INT s390_return_address_offset (void);
extern void s390_emit_prologue (void);
extern void s390_emit_epilogue (bool);
extern void s390_function_profiler (FILE *, int);
--- 23,30 ----
extern void optimization_options (int, int);
extern void override_options (void);
! extern bool s390_can_eliminate (int, int);
! 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_function_profiler (FILE *, int);
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.180
diff -c -p -r1.180 s390.c
*** gcc/config/s390/s390.c 28 Sep 2004 21:39:27 -0000 1.180
--- gcc/config/s390/s390.c 30 Sep 2004 13:40:17 -0000
*************** struct machine_function GTY(())
*** 254,259 ****
--- 254,262 ----
/* Literal pool base register. */
rtx base_reg;
+ /* True if we may need to perform branch splitting. */
+ bool split_branches_pending_p;
+
/* Some local-dynamic TLS symbol name. */
const char *some_ld_name;
};
*************** static void find_constant_pool_ref (rtx,
*** 289,299 ****
static void replace_constant_pool_ref (rtx *, rtx, rtx);
static rtx find_ltrel_base (rtx);
static void replace_ltrel_base (rtx *);
! static void s390_optimize_prologue (bool);
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 rtx save_fpr (rtx, int, int);
static rtx restore_fpr (rtx, int, int);
static rtx save_gprs (rtx, int, int, int);
--- 292,304 ----
static void replace_constant_pool_ref (rtx *, rtx, rtx);
static rtx find_ltrel_base (rtx);
static void replace_ltrel_base (rtx *);
! static void s390_optimize_prologue (void);
static int find_unused_clobbered_reg (void);
static void s390_frame_area (int *, int *);
! static void s390_register_info (int []);
! static void s390_frame_info (void);
! static void s390_init_frame_layout (void);
! static void s390_update_frame_layout (void);
static rtx save_fpr (rtx, int, int);
static rtx restore_fpr (rtx, int, int);
static rtx save_gprs (rtx, int, int, int);
*************** s390_mainpool_start (void)
*** 4887,4893 ****
}
}
! if (!pool->pool_insn)
abort ();
if (pool->size >= 4096)
--- 4886,4892 ----
}
}
! if (!pool->pool_insn && pool->size > 0)
abort ();
if (pool->size >= 4096)
*************** s390_mainpool_start (void)
*** 4910,4922 ****
static void
s390_mainpool_finish (struct constant_pool *pool)
{
! rtx base_reg = SET_DEST (PATTERN (pool->pool_insn));
rtx insn;
/* If the pool is empty, we're done. */
if (pool->size == 0)
{
! remove_insn (pool->pool_insn);
s390_free_pool (pool);
return;
}
--- 4909,4925 ----
static void
s390_mainpool_finish (struct constant_pool *pool)
{
! rtx base_reg = cfun->machine->base_reg;
rtx insn;
/* If the pool is empty, we're done. */
if (pool->size == 0)
{
! /* We don't actually need a base register after all. */
! cfun->machine->base_reg = NULL_RTX;
!
! if (pool->pool_insn)
! remove_insn (pool->pool_insn);
s390_free_pool (pool);
return;
}
*************** s390_output_pool_entry (rtx exp, enum ma
*** 5429,5448 ****
/* Rework the prologue/epilogue to avoid saving/restoring
! registers unnecessarily. BASE_USED specifies whether
! the literal pool base register needs to be saved. */
static void
! s390_optimize_prologue (bool base_used)
{
rtx insn, new_insn, next_insn;
/* Do a final recompute of the frame-related data. */
! s390_register_info (base_used, cfun_frame_layout.save_return_addr_p);
! regs_ever_live[BASE_REGNUM] = base_used;
! regs_ever_live[RETURN_REGNUM] = cfun_frame_layout.save_return_addr_p;
! regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0;
/* If all special registers are in fact used, there's nothing we
can do, so no point in walking the insn list. */
--- 5432,5447 ----
/* Rework the prologue/epilogue to avoid saving/restoring
! registers unnecessarily. */
static void
! s390_optimize_prologue (void)
{
rtx insn, new_insn, next_insn;
/* Do a final recompute of the frame-related data. */
! s390_update_frame_layout ();
/* If all special registers are in fact used, there's nothing we
can do, so no point in walking the insn list. */
*************** s390_optimize_prologue (bool base_used)
*** 5501,5510 ****
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == REG
! && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM
&& GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
{
set = PATTERN (insn);
offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
off = INTVAL (offset);
--- 5500,5512 ----
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == REG
! && (REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM
! || (!TARGET_CPU_ZARCH
! && REGNO (SET_SRC (PATTERN (insn))) == RETURN_REGNUM))
&& GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
{
set = PATTERN (insn);
+ first = REGNO (SET_SRC (set));
offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
off = INTVAL (offset);
*************** s390_optimize_prologue (bool base_used)
*** 5518,5524 ****
{
new_insn = save_gprs (base,
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);
--- 5520,5526 ----
{
new_insn = save_gprs (base,
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);
*************** s390_optimize_prologue (bool base_used)
*** 5564,5573 ****
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (insn))) == REG
! && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM
&& GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
{
set = PATTERN (insn);
offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
off = INTVAL (offset);
--- 5566,5578 ----
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (insn))) == REG
! && (REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM
! || (!TARGET_CPU_ZARCH
! && REGNO (SET_DEST (PATTERN (insn))) == RETURN_REGNUM))
&& GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
{
set = PATTERN (insn);
+ first = REGNO (SET_DEST (set));
offset = const0_rtx;
base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
off = INTVAL (offset);
*************** s390_optimize_prologue (bool base_used)
*** 5581,5587 ****
{
new_insn = restore_gprs (base,
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);
--- 5586,5592 ----
{
new_insn = restore_gprs (base,
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);
*************** s390_optimize_prologue (bool base_used)
*** 5599,5605 ****
static void
s390_reorg (void)
{
- bool base_used = false;
bool pool_overflow = false;
/* Make sure all splits have been performed; splits after
--- 5604,5609 ----
*************** s390_reorg (void)
*** 5672,5690 ****
/* If we made it up to here, both conditions are satisfied.
Finish up literal pool related changes. */
- if ((pool_overflow || pool->size > 0)
- && REGNO (cfun->machine->base_reg) == BASE_REGNUM)
- base_used = true;
-
if (pool_overflow)
s390_chunkify_finish (pool);
else
s390_mainpool_finish (pool);
break;
}
! s390_optimize_prologue (base_used);
}
--- 5676,5692 ----
/* If we made it up to here, both conditions are satisfied.
Finish up literal pool related changes. */
if (pool_overflow)
s390_chunkify_finish (pool);
else
s390_mainpool_finish (pool);
+ /* We're done splitting branches. */
+ cfun->machine->split_branches_pending_p = false;
break;
}
! s390_optimize_prologue ();
}
*************** s390_frame_area (int *area_bottom, int *
*** 5798,5811 ****
*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. */
static void
! s390_register_info (int base_used, int return_addr_used)
{
- int live_regs[16];
int i, j;
/* fprs 8 - 15 are call saved for 64 Bit ABI. */
--- 5800,5811 ----
*area_top = t;
}
! /* Fill cfun->machine with info about register usage of current function.
! Return in LIVE_REGS which GPRs are currently considered live. */
static void
! s390_register_info (int live_regs[])
{
int i, j;
/* fprs 8 - 15 are call saved for 64 Bit ABI. */
*************** s390_register_info (int base_used, int r
*** 5829,5845 ****
live_regs[i] = regs_ever_live[i] && !global_regs[i];
if (flag_pic)
! live_regs[PIC_OFFSET_TABLE_REGNUM] =
! regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
! live_regs[BASE_REGNUM] = base_used;
! live_regs[RETURN_REGNUM] = return_addr_used;
! 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++)
if (live_regs[i])
--- 5829,5852 ----
live_regs[i] = regs_ever_live[i] && !global_regs[i];
if (flag_pic)
! live_regs[PIC_OFFSET_TABLE_REGNUM]
! = regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
! live_regs[BASE_REGNUM]
! = cfun->machine->base_reg
! && REGNO (cfun->machine->base_reg) == BASE_REGNUM;
!
! live_regs[RETURN_REGNUM]
! = cfun->machine->split_branches_pending_p
! || cfun_frame_layout.save_return_addr_p;
!
! 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++)
if (live_regs[i])
*************** s390_register_info (int base_used, int r
*** 5887,5905 ****
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.");
--- 5894,5907 ----
cfun_set_fpr_bit (i);
}
! /* Fill cfun->machine with info about frame of current function. */
static void
! s390_frame_info (void)
{
int i;
cfun_frame_layout.frame_size = get_frame_size ();
if (!TARGET_64BIT && cfun_frame_layout.frame_size > 0x7fff0000)
fatal_error ("Total size of local variables exceeds architecture limit.");
*************** s390_frame_info (int base_used, int retu
*** 6003,6039 ****
}
}
! /* Return offset between argument pointer and frame pointer
! initially after prologue. */
! HOST_WIDE_INT
! s390_arg_frame_offset (void)
{
! /* See the comment in s390_emit_prologue about the assumptions we make
! whether or not the base and return address register need to be saved. */
! int return_addr_used = !current_function_is_leaf
! || TARGET_TPF_PROFILING
! || regs_ever_live[RETURN_REGNUM]
! || cfun_frame_layout.save_return_addr_p;
! s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used);
! return cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
}
! /* Return offset between return address pointer (location of r14
! on the stack) and frame pointer initially after prologue. */
HOST_WIDE_INT
! s390_return_address_offset (void)
{
! s390_frame_info (1, 1);
! 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
--- 6005,6140 ----
}
}
! /* Generate frame layout. Fills in register and frame data for the current
! function in cfun->machine. This routine can be called multiple times;
! it will re-do the complete frame layout every time. */
! static void
! s390_init_frame_layout (void)
! {
! HOST_WIDE_INT frame_size;
! int base_used;
! int live_regs[16];
!
! /* If return address register is explicitly used, we need to save it. */
! if (regs_ever_live[RETURN_REGNUM]
! || !current_function_is_leaf
! || TARGET_TPF_PROFILING
! || current_function_stdarg
! || current_function_calls_eh_return)
! cfun_frame_layout.save_return_addr_p = true;
!
! /* On S/390 machines, we may need to perform branch splitting, which
! will require both base and return address register. We have no
! choice but to assume we're going to need them until right at the
! end of the machine dependent reorg phase. */
! if (!TARGET_CPU_ZARCH)
! cfun->machine->split_branches_pending_p = true;
!
! do
! {
! frame_size = cfun_frame_layout.frame_size;
!
! /* Try to predict whether we'll need the base register. */
! base_used = cfun->machine->split_branches_pending_p
! || current_function_uses_const_pool
! || (!DISP_IN_RANGE (-frame_size)
! && !CONST_OK_FOR_CONSTRAINT_P (-frame_size, 'K', "K"));
!
! /* Decide which register to use as literal pool base. In small
! leaf functions, try to use an unused call-clobbered register
! as base register to avoid save/restore overhead. */
! if (!base_used)
! cfun->machine->base_reg = NULL_RTX;
! else if (current_function_is_leaf && !regs_ever_live[5])
! cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
! else
! cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
!
! s390_register_info (live_regs);
! s390_frame_info ();
! }
! while (frame_size != cfun_frame_layout.frame_size);
! }
!
! /* Update frame layout. Recompute actual register save data based on
! current info and update regs_ever_live for the special registers.
! May be called multiple times, but may never cause *more* registers
! to be saved than s390_init_frame_layout allocated room for. */
!
! static void
! s390_update_frame_layout (void)
{
! int live_regs[16];
!
! s390_register_info (live_regs);
! regs_ever_live[BASE_REGNUM] = live_regs[BASE_REGNUM];
! regs_ever_live[RETURN_REGNUM] = live_regs[RETURN_REGNUM];
! regs_ever_live[STACK_POINTER_REGNUM] = live_regs[STACK_POINTER_REGNUM];
! if (cfun->machine->base_reg)
! regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
}
! /* Return true if register FROM can be eliminated via register TO. */
!
! bool
! s390_can_eliminate (int from, int to)
! {
! gcc_assert (to == STACK_POINTER_REGNUM
! || to == HARD_FRAME_POINTER_REGNUM);
!
! gcc_assert (from == FRAME_POINTER_REGNUM
! || from == ARG_POINTER_REGNUM
! || from == RETURN_ADDRESS_POINTER_REGNUM);
!
! /* Make sure we actually saved the return address. */
! if (from == RETURN_ADDRESS_POINTER_REGNUM)
! if (!current_function_calls_eh_return
! && !current_function_stdarg
! && !cfun_frame_layout.save_return_addr_p)
! return false;
!
! return true;
! }
!
! /* Return offset between register FROM and TO initially after prolog. */
HOST_WIDE_INT
! s390_initial_elimination_offset (int from, int to)
{
! HOST_WIDE_INT offset;
! int index;
! /* ??? Why are we called for non-eliminable pairs? */
! if (!s390_can_eliminate (from, to))
! return 0;
! switch (from)
! {
! case FRAME_POINTER_REGNUM:
! offset = 0;
! break;
!
! case ARG_POINTER_REGNUM:
! s390_init_frame_layout ();
! offset = cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
! break;
!
! case RETURN_ADDRESS_POINTER_REGNUM:
! s390_init_frame_layout ();
! index = RETURN_REGNUM - cfun_frame_layout.first_save_gpr;
! gcc_assert (index >= 0);
! offset = cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset;
! offset += index * UNITS_PER_WORD;
! break;
!
! default:
! gcc_unreachable ();
! }
!
! return offset;
}
/* Emit insn to save fpr REGNUM at offset OFFSET relative
*************** s390_emit_prologue (void)
*** 6222,6262 ****
int offset;
int next_fpr = 0;
! /* At this point, we decide whether we'll need to save/restore the
! return address register. This decision is final on zSeries machines;
! on S/390 it can still be overridden in s390_split_branches. */
!
! if (!current_function_is_leaf
! || TARGET_TPF_PROFILING
! || regs_ever_live[RETURN_REGNUM])
! cfun_frame_layout.save_return_addr_p = 1;
!
! /* Decide which register to use as literal pool base. In small leaf
! functions, try to use an unused call-clobbered register as base
! register to avoid save/restore overhead. */
!
! if (current_function_is_leaf && !regs_ever_live[5])
! cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
! else
! cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
!
! regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
!
! /* 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.
! This is done because the usage of these registers might change even
! after the prologue was emitted. If it turns out later that we really
! don't need them, the prologue/epilogue code is modified again. */
!
! 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. */
! regs_ever_live[BASE_REGNUM] = 1;
! regs_ever_live[RETURN_REGNUM] = (!TARGET_CPU_ZARCH
! || cfun_frame_layout.save_return_addr_p);
! regs_ever_live[STACK_POINTER_REGNUM] = cfun_frame_layout.frame_size > 0;
/* Annotate all constant pool references to let the scheduler know
they implicitly use the base register. */
--- 6323,6331 ----
int offset;
int next_fpr = 0;
! /* Complete frame layout. */
! s390_update_frame_layout ();
/* Annotate all constant pool references to let the scheduler know
they implicitly use the base register. */
*************** s390_emit_prologue (void)
*** 6289,6295 ****
/* Dummy insn to mark literal pool slot. */
! emit_insn (gen_main_pool (cfun->machine->base_reg));
offset = cfun_frame_layout.f0_offset;
--- 6358,6365 ----
/* Dummy insn to mark literal pool slot. */
! if (cfun->machine->base_reg)
! emit_insn (gen_main_pool (cfun->machine->base_reg));
offset = cfun_frame_layout.f0_offset;
Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.120
diff -c -p -r1.120 s390.h
*** gcc/config/s390/s390.h 22 Sep 2004 13:57:38 -0000 1.120
--- gcc/config/s390/s390.h 30 Sep 2004 13:40:17 -0000
*************** extern int current_function_outgoing_arg
*** 652,677 ****
{ RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
! #define CAN_ELIMINATE(FROM, TO) (1)
! #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
! { if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
! { (OFFSET) = 0; } \
! else if ((FROM) == FRAME_POINTER_REGNUM \
! && (TO) == HARD_FRAME_POINTER_REGNUM) \
! { (OFFSET) = 0; } \
! else if ((FROM) == ARG_POINTER_REGNUM \
! && (TO) == HARD_FRAME_POINTER_REGNUM) \
! { (OFFSET) = s390_arg_frame_offset (); } \
! else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
! { (OFFSET) = s390_arg_frame_offset (); } \
! else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM \
! && ((TO) == STACK_POINTER_REGNUM \
! || (TO) == HARD_FRAME_POINTER_REGNUM)) \
! { (OFFSET) = s390_return_address_offset (); } \
! else \
! abort(); \
! }
/* Stack arguments. */
--- 652,662 ----
{ RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
! #define CAN_ELIMINATE(FROM, TO) \
! s390_can_eliminate ((FROM), (TO))
! #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
! (OFFSET) = s390_initial_elimination_offset ((FROM), (TO))
/* Stack arguments. */
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de