/* Perform simple optimizations to clean up the result of reload.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#include "except.h"
#include "tree.h"
-static int reload_cse_noop_set_p PARAMS ((rtx));
-static void reload_cse_simplify PARAMS ((rtx, rtx));
-static void reload_cse_regs_1 PARAMS ((rtx));
-static int reload_cse_simplify_set PARAMS ((rtx, rtx));
-static int reload_cse_simplify_operands PARAMS ((rtx, rtx));
+static int reload_cse_noop_set_p (rtx);
+static void reload_cse_simplify (rtx, rtx);
+static void reload_cse_regs_1 (rtx);
+static int reload_cse_simplify_set (rtx, rtx);
+static int reload_cse_simplify_operands (rtx, rtx);
-static void reload_combine PARAMS ((void));
-static void reload_combine_note_use PARAMS ((rtx *, rtx));
-static void reload_combine_note_store PARAMS ((rtx, rtx, void *));
+static void reload_combine (void);
+static void reload_combine_note_use (rtx *, rtx);
+static void reload_combine_note_store (rtx, rtx, void *);
-static void reload_cse_move2add PARAMS ((rtx));
-static void move2add_note_store PARAMS ((rtx, rtx, void *));
+static void reload_cse_move2add (rtx);
+static void move2add_note_store (rtx, rtx, void *);
/* Call cse / combine like post-reload optimization phases.
FIRST is the first instruction. */
void
-reload_cse_regs (first)
- rtx first ATTRIBUTE_UNUSED;
+reload_cse_regs (rtx first ATTRIBUTE_UNUSED)
{
reload_cse_regs_1 (first);
reload_combine ();
/* See whether a single set SET is a noop. */
static int
-reload_cse_noop_set_p (set)
- rtx set;
+reload_cse_noop_set_p (rtx set)
{
if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
return 0;
/* Try to simplify INSN. */
static void
-reload_cse_simplify (insn, testreg)
- rtx insn;
- rtx testreg;
+reload_cse_simplify (rtx insn, rtx testreg)
{
rtx body = PATTERN (insn);
if possible, much like an optional reload would. */
static void
-reload_cse_regs_1 (first)
- rtx first;
+reload_cse_regs_1 (rtx first)
{
rtx insn;
rtx testreg = gen_rtx_REG (VOIDmode, -1);
and change the set into a register copy. */
static int
-reload_cse_simplify_set (set, insn)
- rtx set;
- rtx insn;
+reload_cse_simplify_set (rtx set, rtx insn)
{
int did_change = 0;
int dreg;
return 0;
#endif
+ val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+ if (! val)
+ return 0;
+
/* If memory loads are cheaper than register copies, don't change them. */
if (GET_CODE (src) == MEM)
old_cost = MEMORY_MOVE_COST (GET_MODE (src), dclass, 1);
- else if (CONSTANT_P (src))
- old_cost = rtx_cost (src, SET);
else if (GET_CODE (src) == REG)
old_cost = REGISTER_MOVE_COST (GET_MODE (src),
REGNO_REG_CLASS (REGNO (src)), dclass);
else
- /* ??? */
old_cost = rtx_cost (src, SET);
- val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
- if (! val)
- return 0;
for (l = val->locs; l; l = l->next)
{
rtx this_rtx = l->loc;
hard registers. */
static int
-reload_cse_simplify_operands (insn, testreg)
- rtx insn;
- rtx testreg;
+reload_cse_simplify_operands (rtx insn, rtx testreg)
{
int i, j;
if (! constrain_operands (1))
fatal_insn_not_found (insn);
- alternative_reject = (int *) alloca (recog_data.n_alternatives * sizeof (int));
- alternative_nregs = (int *) alloca (recog_data.n_alternatives * sizeof (int));
- alternative_order = (int *) alloca (recog_data.n_alternatives * sizeof (int));
- memset ((char *) alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
- memset ((char *) alternative_nregs, 0, recog_data.n_alternatives * sizeof (int));
+ alternative_reject = alloca (recog_data.n_alternatives * sizeof (int));
+ alternative_nregs = alloca (recog_data.n_alternatives * sizeof (int));
+ alternative_order = alloca (recog_data.n_alternatives * sizeof (int));
+ memset (alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
+ memset (alternative_nregs, 0, recog_data.n_alternatives * sizeof (int));
/* For each operand, find out which regs are equivalent. */
for (i = 0; i < recog_data.n_operands; i++)
{
cselib_val *v;
struct elt_loc_list *l;
+ rtx op;
+ enum machine_mode mode;
CLEAR_HARD_REG_SET (equiv_regs[i]);
&& recog_data.operand_mode[i] == VOIDmode))
continue;
- v = cselib_lookup (recog_data.operand[i], recog_data.operand_mode[i], 0);
+ op = recog_data.operand[i];
+ mode = GET_MODE (op);
+#ifdef LOAD_EXTEND_OP
+ if (GET_CODE (op) == MEM
+ && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
+ && LOAD_EXTEND_OP (mode) != NIL)
+ {
+ rtx set = single_set (insn);
+
+ /* We might have multiple sets, some of which do implicit
+ extension. Punt on this for now. */
+ if (! set)
+ continue;
+ /* If the destination is a also MEM or a STRICT_LOW_PART, no
+ extension applies.
+ Also, if there is an explicit extension, we don't have to
+ worry about an implicit one. */
+ else if (GET_CODE (SET_DEST (set)) == MEM
+ || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART
+ || GET_CODE (SET_SRC (set)) == ZERO_EXTEND
+ || GET_CODE (SET_SRC (set)) == SIGN_EXTEND)
+ ; /* Continue ordinary processing. */
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ /* If the register cannot change mode to word_mode, it follows that
+ it cannot have been used in word_mode. */
+ else if (GET_CODE (SET_DEST (set)) == REG
+ && CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+ word_mode,
+ REGNO_REG_CLASS (REGNO (SET_DEST (set)))))
+ ; /* Continue ordinary processing. */
+#endif
+ /* If this is a straight load, make the extension explicit. */
+ else if (GET_CODE (SET_DEST (set)) == REG
+ && recog_data.n_operands == 2
+ && SET_SRC (set) == op
+ && SET_DEST (set) == recog_data.operand[1-i])
+ {
+ validate_change (insn, recog_data.operand_loc[i],
+ gen_rtx_fmt_e (LOAD_EXTEND_OP (mode),
+ word_mode, op),
+ 1);
+ validate_change (insn, recog_data.operand_loc[1-i],
+ gen_rtx_REG (word_mode, REGNO (SET_DEST (set))),
+ 1);
+ if (! apply_change_group ())
+ return 0;
+ return reload_cse_simplify_operands (insn, testreg);
+ }
+ else
+ /* ??? There might be arithmetic operations with memory that are
+ safe to optimize, but is it worth the trouble? */
+ continue;
+ }
+#endif /* LOAD_EXTEND_OP */
+ v = cselib_lookup (op, recog_data.operand_mode[i], 0);
if (! v)
continue;
int regno;
const char *p;
- op_alt_regno[i] = (int *) alloca (recog_data.n_alternatives * sizeof (int));
+ op_alt_regno[i] = alloca (recog_data.n_alternatives * sizeof (int));
for (j = 0; j < recog_data.n_alternatives; j++)
op_alt_regno[i][j] = -1;
(label_live[CODE_LABEL_NUMBER (LABEL) - min_labelno])
static void
-reload_combine ()
+reload_combine (void)
{
rtx insn, set;
int first_index_reg = -1;
destination. */
min_labelno = get_first_label_num ();
n_labels = max_label_num () - min_labelno;
- label_live = (HARD_REG_SET *) xmalloc (n_labels * sizeof (HARD_REG_SET));
+ label_live = xmalloc (n_labels * sizeof (HARD_REG_SET));
CLEAR_HARD_REG_SET (ever_live_at_start);
FOR_EACH_BB_REVERSE (bb)
{
- insn = bb->head;
+ insn = BB_HEAD (bb);
if (GET_CODE (insn) == CODE_LABEL)
{
HARD_REG_SET live;
... (MEM (PLUS (REGZ) (REGY)))... .
First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
- and that we know all uses of REGX before it dies. */
+ and that we know all uses of REGX before it dies.
+ Also, explicitly check that REGX != REGY; our life information
+ does not yet show whether REGY changes in this insn. */
set = single_set (insn);
if (set != NULL_RTX
&& GET_CODE (SET_DEST (set)) == REG
- && (HARD_REGNO_NREGS (REGNO (SET_DEST (set)),
- GET_MODE (SET_DEST (set)))
+ && (hard_regno_nregs[REGNO (SET_DEST (set))]
+ [GET_MODE (SET_DEST (set))]
== 1)
&& GET_CODE (SET_SRC (set)) == PLUS
&& GET_CODE (XEXP (SET_SRC (set), 1)) == REG
&& rtx_equal_p (XEXP (SET_SRC (set), 0), SET_DEST (set))
+ && !rtx_equal_p (XEXP (SET_SRC (set), 1), SET_DEST (set))
&& last_label_ruid < reg_state[REGNO (SET_DEST (set))].use_ruid)
{
rtx reg = SET_DEST (set);
else
{
/* Otherwise, look for a free index register. Since we have
- checked above that neiter REG nor BASE are index registers,
+ checked above that neither REG nor BASE are index registers,
if we find anything at all, it will be different from these
two registers. */
for (i = first_index_reg; i <= last_index_reg; i++)
i)
&& reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
&& reg_state[i].store_ruid <= reg_state[regno].use_ruid
- && HARD_REGNO_NREGS (i, GET_MODE (reg)) == 1)
+ && hard_regno_nregs[i][GET_MODE (reg)] == 1)
{
rtx index_reg = gen_rtx_REG (GET_MODE (reg), i);
unsigned int i;
unsigned int start_reg = REGNO (usage_rtx);
unsigned int num_regs =
- HARD_REGNO_NREGS (start_reg, GET_MODE (usage_rtx));
+ hard_regno_nregs[start_reg][GET_MODE (usage_rtx)];
unsigned int end_reg = start_reg + num_regs - 1;
for (i = start_reg; i <= end_reg; i++)
if (GET_CODE (XEXP (link, 0)) == CLOBBER)
accordingly. Called via note_stores from reload_combine. */
static void
-reload_combine_note_store (dst, set, data)
- rtx dst, set;
- void *data ATTRIBUTE_UNUSED;
+reload_combine_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
{
int regno = 0;
int i;
|| GET_CODE (SET_DEST (set)) == SIGN_EXTRACT
|| GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
{
- for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
+ for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
{
reg_state[i].use_index = -1;
reg_state[i].store_ruid = reload_combine_ruid;
}
else
{
- for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
+ for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
{
reg_state[i].store_ruid = reload_combine_ruid;
reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
*XP is the pattern of INSN, or a part of it.
Called from reload_combine, and recursively by itself. */
static void
-reload_combine_note_use (xp, insn)
- rtx *xp, insn;
+reload_combine_note_use (rtx *xp, rtx insn)
{
rtx x = *xp;
enum rtx_code code = x->code;
/* Mark the return register as used in an unknown fashion. */
rtx reg = XEXP (x, 0);
int regno = REGNO (reg);
- int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ int nregs = hard_regno_nregs[regno][GET_MODE (reg)];
while (--nregs >= 0)
reg_state[regno + nregs].use_index = -1;
if (regno >= FIRST_PSEUDO_REGISTER)
abort ();
- nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ nregs = hard_regno_nregs[regno][GET_MODE (x)];
/* We can't substitute into multi-hard-reg uses. */
if (nregs > 1)
GET_MODE_BITSIZE (INMODE))))
static void
-reload_cse_move2add (first)
- rtx first;
+reload_cse_move2add (rtx first)
{
int i;
rtx insn;
else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
&& have_add2_insn (reg, new_src))
{
- rtx newpat = gen_add2_insn (reg, new_src);
- if (INSN_P (newpat) && NEXT_INSN (newpat) == NULL_RTX)
- newpat = PATTERN (newpat);
- /* If it was the first insn of a sequence or
- some other emitted insn, validate_change will
- reject it. */
- validate_change (insn, &PATTERN (insn),
- newpat, 0);
+ rtx newpat = gen_rtx_SET (VOIDmode,
+ reg,
+ gen_rtx_PLUS (GET_MODE (reg),
+ reg,
+ new_src));
+ validate_change (insn, &PATTERN (insn), newpat, 0);
}
else
{
< COSTS_N_INSNS (1) + rtx_cost (src3, SET))
&& have_add2_insn (reg, new_src))
{
- rtx newpat = gen_add2_insn (reg, new_src);
- if (INSN_P (newpat)
- && NEXT_INSN (newpat) == NULL_RTX)
- newpat = PATTERN (newpat);
+ rtx newpat = gen_rtx_SET (VOIDmode,
+ reg,
+ gen_rtx_PLUS (GET_MODE (reg),
+ reg,
+ new_src));
success
= validate_change (next, &PATTERN (next),
newpat, 0);
number of calls to gen_rtx_SET to avoid memory
allocation if possible. */
&& SCALAR_INT_MODE_P (GET_MODE (XEXP (cnd, 0)))
- && HARD_REGNO_NREGS (REGNO (XEXP (cnd, 0)), GET_MODE (XEXP (cnd, 0))) == 1
+ && hard_regno_nregs[REGNO (XEXP (cnd, 0))][GET_MODE (XEXP (cnd, 0))] == 1
&& GET_CODE (XEXP (cnd, 1)) == CONST_INT)
{
rtx implicit_set =
Called from reload_cse_move2add via note_stores. */
static void
-move2add_note_store (dst, set, data)
- rtx dst, set;
- void *data ATTRIBUTE_UNUSED;
+move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
{
unsigned int regno = 0;
unsigned int i;
regno += REGNO (dst);
if (SCALAR_INT_MODE_P (mode)
- && HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
+ && hard_regno_nregs[regno][mode] == 1 && GET_CODE (set) == SET
&& GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (set)) != SIGN_EXTRACT
&& GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
}
else
{
- unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
+ unsigned int endregno = regno + hard_regno_nregs[regno][mode];
for (i = regno; i < endregno; i++)
/* Reset the information about this register. */