/* Save and restore call-clobbered registers which are live across a call.
- Copyright (C) 1989, 1992, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1992, 1994, 1995, 1997 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 "rtl.h"
#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
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)
{
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.
for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
if (regno_save_mem[i][j] != 0)
ok &= strict_memory_address_p (GET_MODE (regno_save_mem[i][j]),
- XEXP (eliminate_regs (regno_save_mem[i][j], 0, NULL_RTX), 0));
+ XEXP (eliminate_regs (regno_save_mem[i][j], 0, NULL_RTX, 1), 0));
return ok;
}
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)
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