/* Save and restore call-clobbered registers which are live across a call.
- Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1992, 94-95, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "insn-config.h"
#include "flags.h"
#include "basic-block.h"
#include "reload.h"
#include "expr.h"
+#include "toplev.h"
#ifndef MAX_MOVE_MAX
#define MAX_MOVE_MAX MOVE_MAX
#endif
-#ifndef MAX_UNITS_PER_WORD
-#define MAX_UNITS_PER_WORD UNITS_PER_WORD
+#ifndef MIN_UNITS_PER_WORD
+#define MIN_UNITS_PER_WORD UNITS_PER_WORD
#endif
/* Modes for each hard register that we can save. The smallest mode is wide
If that is not possible the save is done one register at a time. */
static enum machine_mode
- regno_save_mode[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
+ regno_save_mode[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
/* For each hard register, a place on the stack where it can be saved,
if needed. */
static rtx
- regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
+ regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
/* We will only make a register eligible for caller-save if it can be
saved in its widest mode with a simple SET insn as long as the memory
be recognized. */
static enum insn_code
- reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
+ reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
static enum insn_code
- reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
+ reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
/* Set of hard regs currently live (during scan of all insns). */
int n_regs_saved;
-static enum machine_mode choose_hard_reg_mode PROTO((int, int));
static void set_reg_live PROTO((rtx, rtx));
static void clear_reg_live PROTO((rtx));
static void restore_referenced_regs PROTO((rtx, rtx, enum machine_mode));
static int insert_save_restore PROTO((rtx, int, int,
enum machine_mode, int));
\f
-/* Return a machine mode that is legitimate for hard reg REGNO and large
- enough to save nregs. If we can't find one, return VOIDmode. */
-
-static enum machine_mode
-choose_hard_reg_mode (regno, nregs)
- int regno;
- int nregs;
-{
- enum machine_mode found_mode = VOIDmode, mode;
-
- /* We first look for the largest integer mode that can be validly
- held in REGNO. If none, we look for the largest floating-point mode.
- If we still didn't find a valid mode, try CCmode. */
-
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
- if (HARD_REGNO_NREGS (regno, mode) == nregs
- && HARD_REGNO_MODE_OK (regno, mode))
- found_mode = mode;
-
- if (found_mode != VOIDmode)
- return found_mode;
-
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
- if (HARD_REGNO_NREGS (regno, mode) == nregs
- && HARD_REGNO_MODE_OK (regno, mode))
- found_mode = mode;
-
- if (found_mode != VOIDmode)
- return found_mode;
-
- if (HARD_REGNO_NREGS (regno, CCmode) == nregs
- && HARD_REGNO_MODE_OK (regno, CCmode))
- return CCmode;
-
- /* We can't find a mode valid for this register. */
- return VOIDmode;
-}
-\f
/* Initialize for caller-save.
Look at all the hard registers that are used by a call and for which
if (i == FIRST_PSEUDO_REGISTER)
abort ();
- addr_reg = gen_rtx (REG, Pmode, i);
+ addr_reg = gen_rtx_REG (Pmode, i);
for (offset = 1 << (HOST_BITS_PER_INT / 2); offset; offset >>= 1)
{
- address = gen_rtx (PLUS, Pmode, addr_reg, GEN_INT (offset));
+ address = gen_rtx_PLUS (Pmode, addr_reg, GEN_INT (offset));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regno_save_mode[i][1] != VOIDmode
for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
if (regno_save_mode[i][j] != VOIDmode)
{
- rtx mem = gen_rtx (MEM, regno_save_mode[i][j], address);
- rtx reg = gen_rtx (REG, regno_save_mode[i][j], i);
- rtx savepat = gen_rtx (SET, VOIDmode, mem, reg);
- rtx restpat = gen_rtx (SET, VOIDmode, reg, mem);
+ rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address);
+ rtx reg = gen_rtx_REG (regno_save_mode[i][j], i);
+ rtx savepat = gen_rtx_SET (VOIDmode, mem, reg);
+ rtx restpat = gen_rtx_SET (VOIDmode, reg, mem);
rtx saveinsn = emit_insn (savepat);
rtx restinsn = emit_insn (restpat);
int ok;
reg_save_code[i][j] = recog_memoized (saveinsn);
reg_restore_code[i][j] = recog_memoized (restinsn);
- /* Now extract both insns and see if we can meet their constraints. */
+ /* Now extract both insns and see if we can meet their
+ constraints. */
ok = (reg_save_code[i][j] != -1 && reg_restore_code[i][j] != -1);
if (ok)
{
/* Find and record all call-used hard-registers in this function. */
CLEAR_HARD_REG_SET (hard_regs_used);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_renumber[i] >= 0 && reg_n_calls_crossed[i] > 0)
+ if (reg_renumber[i] >= 0 && REG_N_CALLS_CROSSED (i) > 0)
{
int regno = reg_renumber[i];
int endregno
ok &= (TEST_HARD_REG_BIT (hard_regs_used, regno) != 0);
}
- /* We have found an acceptable mode to store in. */
+ /* We have found an acceptable mode to store in. */
if (ok)
{
= assign_stack_local (regno_save_mode[i][j],
GET_MODE_SIZE (regno_save_mode[i][j]), 0);
- /* Setup single word save area just in case... */
+ /* Setup single word save area just in case... */
for (k = 0; k < j; k++)
{
/* This should not depend on WORDS_BIG_ENDIAN.
The order of words in regs is the same as in memory. */
- rtx temp = gen_rtx (MEM, regno_save_mode[i+k][1],
- XEXP (regno_save_mem[i][j], 0));
+ rtx temp = gen_rtx_MEM (regno_save_mode[i+k][1],
+ XEXP (regno_save_mem[i][j], 0));
regno_save_mem[i+k][1]
= adj_offsettable_operand (temp, k * UNITS_PER_WORD);
{
regset regs_live = basic_block_live_at_start[b];
rtx prev_block_last = PREV_INSN (basic_block_head[b]);
- REGSET_ELT_TYPE bit;
- int offset, i, j;
+ int i, j;
int regno;
/* Compute hard regs live at start of block -- this is the
saved because we restore all of them before the end of the basic
block. */
-#ifdef HARD_REG_SET
- hard_regs_live = *regs_live;
-#else
- COPY_HARD_REG_SET (hard_regs_live, regs_live);
-#endif
-
+ REG_SET_TO_HARD_REG_SET (hard_regs_live, regs_live);
CLEAR_HARD_REG_SET (hard_regs_saved);
CLEAR_HARD_REG_SET (hard_regs_need_restore);
n_regs_saved = 0;
- for (offset = 0, i = 0; offset < regset_size; offset++)
- {
- if (regs_live[offset] == 0)
- i += REGSET_ELT_BITS;
- else
- for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
- if ((regs_live[offset] & bit)
- && (regno = reg_renumber[i]) >= 0)
- for (j = regno;
- j < regno + HARD_REGNO_NREGS (regno,
- PSEUDO_REGNO_MODE (i));
- j++)
- SET_HARD_REG_BIT (hard_regs_live, j);
-
- }
+ EXECUTE_IF_SET_IN_REG_SET (regs_live, 0, i,
+ {
+ if ((regno = reg_renumber[i]) >= 0)
+ for (j = regno;
+ j < regno + HARD_REGNO_NREGS (regno,
+ PSEUDO_REGNO_MODE (i));
+ j++)
+ SET_HARD_REG_BIT (hard_regs_live, j);
+ });
/* Now scan the insns in the block, keeping track of what hard
regs are live as we go. When we see a call, save the live
live, call-used, not fixed, and not already saved. We must
test at this point because registers that die in a CALL_INSN
are not live across the call and likewise for registers that
- are born in the CALL_INSN. */
+ are born in the CALL_INSN.
+
+ If registers are filled with parameters for this function,
+ and some of these are also being set by this function, then
+ they will not appear to die (no REG_DEAD note for them),
+ to check if in fact they do, collect the set registers in
+ hard_regs_live first. */
if (code == CALL_INSN)
{
+ HARD_REG_SET this_call_sets;
+ {
+ HARD_REG_SET old_hard_regs_live;
+
+ /* Save the hard_regs_live information. */
+ COPY_HARD_REG_SET (old_hard_regs_live, hard_regs_live);
+
+ /* Now calculate hard_regs_live for this CALL_INSN
+ only. */
+ CLEAR_HARD_REG_SET (hard_regs_live);
+ note_stores (PATTERN (insn), set_reg_live);
+ COPY_HARD_REG_SET (this_call_sets, hard_regs_live);
+
+ /* Restore the hard_regs_live information. */
+ COPY_HARD_REG_SET (hard_regs_live, old_hard_regs_live);
+ }
+
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (call_used_regs[regno] && ! call_fixed_regs[regno]
&& TEST_HARD_REG_BIT (hard_regs_live, regno)
+ /* It must not be set by this instruction. */
+ && ! TEST_HARD_REG_BIT (this_call_sets, regno)
&& ! TEST_HARD_REG_BIT (hard_regs_saved, regno))
regno += insert_save_restore (insn, 1, regno,
insn_mode, 0);
-#ifdef HARD_REG_SET
- hard_regs_need_restore = hard_regs_saved;
-#else
- COPY_HARD_REG_SET (hard_regs_need_restore,
- hard_regs_saved);
-#endif
+
+ /* Put the information for this CALL_INSN on top of what
+ we already had. */
+ IOR_HARD_REG_SET (hard_regs_live, this_call_sets);
+ COPY_HARD_REG_SET (hard_regs_need_restore, hard_regs_saved);
/* Must recompute n_regs_saved. */
n_regs_saved = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
n_regs_saved++;
-
}
-
- note_stores (PATTERN (insn), set_reg_live);
+ else
+ {
+ note_stores (PATTERN (insn), set_reg_live);
+#ifdef AUTO_INC_DEC
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_INC)
+ set_reg_live (XEXP (link, 0), NULL_RTX);
+#endif
+ }
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_UNUSED)
static void
set_reg_live (reg, setter)
- rtx reg, setter;
+ rtx reg;
+ rtx setter ATTRIBUTE_UNUSED;
{
register int regno, endregno, i;
enum machine_mode mode = GET_MODE (reg);
enum machine_mode insn_mode;
int maxrestore;
{
- rtx pat;
- enum insn_code code;
- int i, numregs;
+ rtx pat = NULL_RTX;
+ enum insn_code code = CODE_FOR_nothing;
+ int numregs = 0;
/* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to
if (regno_save_mem[regno][1] == 0)
abort ();
- /* If INSN is a CALL_INSN, we must insert our insns before any
- USE insns in front of the CALL_INSN. */
-
- if (GET_CODE (insn) == CALL_INSN)
- while (GET_CODE (PREV_INSN (insn)) == INSN
- && GET_CODE (PATTERN (PREV_INSN (insn))) == USE)
- insn = PREV_INSN (insn);
-
#ifdef HAVE_cc0
/* If INSN references CC0, put our insns in front of the insn that sets
CC0. This is always safe, since the only way we could be passed an
if (! ok)
continue;
- pat = gen_rtx (SET, VOIDmode, regno_save_mem[regno][i],
- gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]), regno));
+ pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i],
+ gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
+ regno));
code = reg_save_code[regno][i];
/* Set hard_regs_saved for all the registers we saved. */
if (! ok)
continue;
- pat = gen_rtx (SET, VOIDmode,
- gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]),
- regno),
+ pat = gen_rtx_SET (VOIDmode,
+ gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
+ regno),
regno_save_mem[regno][i]);
code = reg_restore_code[regno][i];