summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-30 21:23:29 +0000
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-30 21:23:29 +0000
commit4fed3f99b034309e255c9f820b40788458d2da70 (patch)
tree81a32418ffd1c56b733fb0bb0b171fbf1dea4bed /gcc/config
parent772b9a4fbb783e82ff9ee2d0b67f9e33ed441f89 (diff)
downloadgcc-4fed3f99b034309e255c9f820b40788458d2da70.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@88357 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/s390/s390-protos.h4
-rw-r--r--gcc/config/s390/s390.c278
-rw-r--r--gcc/config/s390/s390.h25
3 files changed, 184 insertions, 123 deletions
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 359e20cd87b..d1407c19c5a 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -23,8 +23,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
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 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);
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index bb468fe510f..073d9dfedf0 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -254,6 +254,9 @@ struct machine_function GTY(())
/* 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;
};
@@ -289,11 +292,13 @@ static void find_constant_pool_ref (rtx, rtx *);
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 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, int);
-static void s390_frame_info (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);
@@ -4895,7 +4900,7 @@ s390_mainpool_start (void)
}
}
- if (!pool->pool_insn)
+ if (!pool->pool_insn && pool->size > 0)
abort ();
if (pool->size >= 4096)
@@ -4918,13 +4923,17 @@ s390_mainpool_start (void)
static void
s390_mainpool_finish (struct constant_pool *pool)
{
- rtx base_reg = SET_DEST (PATTERN (pool->pool_insn));
+ rtx base_reg = cfun->machine->base_reg;
rtx insn;
/* If the pool is empty, we're done. */
if (pool->size == 0)
{
- remove_insn (pool->pool_insn);
+ /* 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;
}
@@ -5437,20 +5446,16 @@ s390_output_pool_entry (rtx exp, enum machine_mode mode, unsigned int align)
/* Rework the prologue/epilogue to avoid saving/restoring
- registers unnecessarily. BASE_USED specifies whether
- the literal pool base register needs to be saved. */
+ registers unnecessarily. */
static void
-s390_optimize_prologue (bool base_used)
+s390_optimize_prologue (void)
{
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;
+ 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. */
@@ -5509,10 +5514,13 @@ s390_optimize_prologue (bool base_used)
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == REG
- && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGNUM
+ && (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);
@@ -5526,7 +5534,7 @@ s390_optimize_prologue (bool base_used)
{
new_insn = save_gprs (base,
off + (cfun_frame_layout.first_save_gpr
- - BASE_REGNUM) * UNITS_PER_WORD,
+ - first) * UNITS_PER_WORD,
cfun_frame_layout.first_save_gpr,
cfun_frame_layout.last_save_gpr);
new_insn = emit_insn_before (new_insn, insn);
@@ -5572,10 +5580,13 @@ s390_optimize_prologue (bool base_used)
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (insn))) == REG
- && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGNUM
+ && (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);
@@ -5589,7 +5600,7 @@ s390_optimize_prologue (bool base_used)
{
new_insn = restore_gprs (base,
off + (cfun_frame_layout.first_restore_gpr
- - BASE_REGNUM) * UNITS_PER_WORD,
+ - first) * UNITS_PER_WORD,
cfun_frame_layout.first_restore_gpr,
cfun_frame_layout.last_restore_gpr);
new_insn = emit_insn_before (new_insn, insn);
@@ -5607,7 +5618,6 @@ s390_optimize_prologue (bool base_used)
static void
s390_reorg (void)
{
- bool base_used = false;
bool pool_overflow = false;
/* Make sure all splits have been performed; splits after
@@ -5680,19 +5690,17 @@ s390_reorg (void)
/* 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);
+ /* We're done splitting branches. */
+ cfun->machine->split_branches_pending_p = false;
break;
}
- s390_optimize_prologue (base_used);
+ s390_optimize_prologue ();
}
@@ -5806,14 +5814,12 @@ s390_frame_area (int *area_bottom, int *area_top)
*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. */
+/* 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 base_used, int return_addr_used)
+s390_register_info (int live_regs[])
{
- int live_regs[16];
int i, j;
/* fprs 8 - 15 are call saved for 64 Bit ABI. */
@@ -5837,17 +5843,24 @@ s390_register_info (int base_used, int return_addr_used)
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);
+ 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])
@@ -5895,19 +5908,14 @@ s390_register_info (int base_used, int return_addr_used)
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. */
+/* Fill cfun->machine with info about frame of current function. */
static void
-s390_frame_info (int base_used, int return_addr_used)
+s390_frame_info (void)
{
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.");
@@ -6011,37 +6019,136 @@ s390_frame_info (int base_used, int return_addr_used)
}
}
-/* Return offset between argument pointer and frame pointer
- initially after prologue. */
+/* 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. */
-HOST_WIDE_INT
-s390_arg_frame_offset (void)
+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)
{
- /* 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;
+ 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);
- s390_frame_info (1, !TARGET_CPU_ZARCH || return_addr_used);
+ /* 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 cfun_frame_layout.frame_size + STACK_POINTER_OFFSET;
+ return true;
}
-/* Return offset between return address pointer (location of r14
- on the stack) and frame pointer initially after prologue. */
+/* Return offset between register FROM and TO initially after prolog. */
HOST_WIDE_INT
-s390_return_address_offset (void)
+s390_initial_elimination_offset (int from, int to)
{
- s390_frame_info (1, 1);
+ HOST_WIDE_INT offset;
+ int index;
- if (cfun_frame_layout.last_save_gpr < RETURN_REGNUM)
- abort ();
+ /* ??? 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;
- return (cfun_frame_layout.frame_size + cfun_frame_layout.gprs_offset
- + (RETURN_REGNUM - cfun_frame_layout.first_save_gpr) * UNITS_PER_WORD);
+ 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
@@ -6230,41 +6337,9 @@ s390_emit_prologue (void)
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. */
+ /* Complete frame layout. */
- 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;
+ s390_update_frame_layout ();
/* Annotate all constant pool references to let the scheduler know
they implicitly use the base register. */
@@ -6297,7 +6372,8 @@ s390_emit_prologue (void)
/* Dummy insn to mark literal pool slot. */
- emit_insn (gen_main_pool (cfun->machine->base_reg));
+ if (cfun->machine->base_reg)
+ emit_insn (gen_main_pool (cfun->machine->base_reg));
offset = cfun_frame_layout.f0_offset;
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 5b083aadbe6..9814561e052 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -652,26 +652,11 @@ extern int current_function_outgoing_args_size;
{ 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(); \
-}
+#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. */