/* Save and restore call-clobbered registers which are live across a call.
Copyright (C) 1989, 1992, 1994, 1995, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "insn-config.h"
#include "flags.h"
when we emit them, the addresses might not be valid, so they might not
be recognized. */
-static enum insn_code
+static int
reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
-static enum insn_code
+static int
reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
/* Set of hard regs currently residing in save area (during insn scan). */
static int insert_restore PARAMS ((struct insn_chain *, int, int,
int, enum machine_mode *));
static struct insn_chain *insert_one_insn PARAMS ((struct insn_chain *, int,
- enum insn_code, rtx));
+ int, rtx));
static void add_stored_regs PARAMS ((rtx, rtx, void *));
\f
/* Initialize for caller-save.
rtx address;
int i, j;
enum machine_mode mode;
+ rtx savepat, restpat;
+ rtx test_reg, test_mem;
+ rtx saveinsn, restinsn;
/* First find all the registers that we need to deal with and all
the modes that they can have. If we can't find a mode to use,
that register in every mode we will use to save registers. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (reg_class_contents[(int) BASE_REG_CLASS], i))
+ if (TEST_HARD_REG_BIT
+ (reg_class_contents
+ [(int) MODE_BASE_REG_CLASS (regno_save_mode [i][1])], i))
break;
if (i == FIRST_PSEUDO_REGISTER)
address = addr_reg;
/* Next we try to form an insn to save and restore the register. We
- see if such an insn is recognized and meets its constraints. */
+ see if such an insn is recognized and meets its constraints.
+
+ To avoid lots of unnecessary RTL allocation, we construct all the RTL
+ once, then modify the memory and register operands in-place. */
- start_sequence ();
+ test_reg = gen_rtx_REG (VOIDmode, 0);
+ test_mem = gen_rtx_MEM (VOIDmode, address);
+ savepat = gen_rtx_SET (VOIDmode, test_mem, test_reg);
+ restpat = gen_rtx_SET (VOIDmode, test_reg, test_mem);
+
+ saveinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, 0, 0, savepat, -1, 0, 0);
+ restinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, 0, 0, restpat, -1, 0, 0);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (mode = 0 ; mode < MAX_MACHINE_MODE; mode++)
if (HARD_REGNO_MODE_OK (i, mode))
{
- rtx mem = gen_rtx_MEM (mode, address);
- rtx reg = gen_rtx_REG (mode, 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;
+ /* Update the register number and modes of the register
+ and memory operand. */
+ REGNO (test_reg) = i;
+ PUT_MODE (test_reg, mode);
+ PUT_MODE (test_mem, mode);
+
+ /* Force re-recognition of the modified insns. */
+ INSN_CODE (saveinsn) = -1;
+ INSN_CODE (restinsn) = -1;
+
reg_save_code[i][mode] = recog_memoized (saveinsn);
reg_restore_code[i][mode] = recog_memoized (restinsn);
/* Now extract both insns and see if we can meet their
constraints. */
- ok = (reg_save_code[i][mode] != (enum insn_code)-1
- && reg_restore_code[i][mode] != (enum insn_code)-1);
+ ok = (reg_save_code[i][mode] != -1
+ && reg_restore_code[i][mode] != -1);
if (ok)
{
extract_insn (saveinsn);
if (! ok)
{
- reg_save_code[i][mode] = (enum insn_code) -1;
- reg_restore_code[i][mode] = (enum insn_code) -1;
+ reg_save_code[i][mode] = -1;
+ reg_restore_code[i][mode] = -1;
}
}
else
{
- reg_save_code[i][mode] = (enum insn_code) -1;
- reg_restore_code[i][mode] = (enum insn_code) -1;
+ reg_save_code[i][mode] = -1;
+ reg_restore_code[i][mode] = -1;
}
+
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = 1; j <= MOVE_MAX_WORDS; j++)
- if (reg_save_code [i][regno_save_mode[i][j]] == (enum insn_code) -1)
+ if (reg_save_code [i][regno_save_mode[i][j]] == -1)
{
regno_save_mode[i][j] = VOIDmode;
if (j == 1)
SET_HARD_REG_BIT (call_fixed_reg_set, i);
}
}
-
- end_sequence ();
}
\f
/* Initialize save areas by showing that we haven't allocated any yet. */
/* 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));
-
- regno_save_mem[i + k][1]
- = adj_offsettable_operand (temp, k * UNITS_PER_WORD);
- }
+ /* This should not depend on WORDS_BIG_ENDIAN.
+ The order of words in regs is the same as in memory. */
+ regno_save_mem[i + k][1]
+ = adjust_address_nv (regno_save_mem[i][j],
+ regno_save_mode[i + k][1],
+ k * UNITS_PER_WORD);
}
/* Now loop again and set the alias set of any save areas we made to
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = MOVE_MAX_WORDS; j > 0; j--)
if (regno_save_mem[i][j] != 0)
- MEM_ALIAS_SET (regno_save_mem[i][j]) = get_frame_alias_set ();
+ set_mem_alias_set (regno_save_mem[i][j], get_frame_alias_set ());
}
\f
/* Find the places where hard regs are live across calls and save them. */
regs are live during the call. */
REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
&chain->live_throughout);
- /* Save hard registers always in the widest mode availble. */
+ /* Save hard registers always in the widest mode available. */
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
save_mode [regno] = regno_save_mode [regno][1];
else
save_mode [regno] = VOIDmode;
- /* Look trought all live pseudos, mark their hard registers
+ /* Look through all live pseudos, mark their hard registers
and choose proper mode for saving. */
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno,
rtx setter ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
- register int regno, endregno, i;
+ int regno, endregno, i;
enum machine_mode mode = GET_MODE (reg);
if (GET_CODE (reg) == SUBREG)
rtx setter;
void *data;
{
- register int regno, endregno, i;
+ int regno, endregno, i;
enum machine_mode mode = GET_MODE (reg);
int offset = 0;
{
int i, k;
rtx pat = NULL_RTX;
- enum insn_code code = CODE_FOR_nothing;
+ int code;
unsigned int numregs = 0;
struct insn_chain *new;
rtx mem;
mem = regno_save_mem [regno][numregs];
if (save_mode [regno] != VOIDmode
&& save_mode [regno] != GET_MODE (mem)
- && numregs == HARD_REGNO_NREGS (regno, save_mode [regno]))
+ && numregs == (unsigned int) HARD_REGNO_NREGS (regno, save_mode [regno]))
mem = adjust_address (mem, save_mode[regno], 0);
pat = gen_rtx_SET (VOIDmode,
gen_rtx_REG (GET_MODE (mem),
n_regs_saved--;
}
-
-
/* Tell our callers how many extra registers we saved/restored */
return numregs - 1;
}
/* Like insert_restore above, but save registers instead. */
+
static int
insert_save (chain, before_p, regno, to_save, save_mode)
struct insn_chain *chain;
int i;
unsigned int k;
rtx pat = NULL_RTX;
- enum insn_code code = CODE_FOR_nothing;
+ int code;
unsigned int numregs = 0;
struct insn_chain *new;
rtx mem;
mem = regno_save_mem [regno][numregs];
if (save_mode [regno] != VOIDmode
&& save_mode [regno] != GET_MODE (mem)
- && numregs == HARD_REGNO_NREGS (regno, save_mode [regno]))
+ && numregs == (unsigned int) HARD_REGNO_NREGS (regno, save_mode [regno]))
mem = adjust_address (mem, save_mode[regno], 0);
pat = gen_rtx_SET (VOIDmode, mem,
gen_rtx_REG (GET_MODE (mem),
insert_one_insn (chain, before_p, code, pat)
struct insn_chain *chain;
int before_p;
- enum insn_code code;
+ int code;
rtx pat;
{
rtx insn = chain->insn;