/* 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, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GCC.
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
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-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. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "toplev.h"
#include "except.h"
#include "tree.h"
+#include "timevar.h"
+#include "tree-pass.h"
+#include "df.h"
+#include "dbgcnt.h"
static int reload_cse_noop_set_p (rtx);
static void reload_cse_simplify (rtx, rtx);
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_combine_note_store (rtx, const_rtx, void *);
static void reload_cse_move2add (rtx);
-static void move2add_note_store (rtx, rtx, void *);
+static void move2add_note_store (rtx, const_rtx, void *);
/* Call cse / combine like post-reload optimization phases.
FIRST is the first instruction. */
int count = 0;
rtx value = NULL_RTX;
+ /* Registers mentioned in the clobber list for an asm cannot be reused
+ within the body of the asm. Invalidate those registers now so that
+ we don't try to substitute values for them. */
+ if (asm_noperands (body) >= 0)
+ {
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ {
+ rtx part = XVECEXP (body, 0, i);
+ if (GET_CODE (part) == CLOBBER && REG_P (XEXP (part, 0)))
+ cselib_invalidate_rtx (XEXP (part, 0));
+ }
+ }
+
/* If every action in a PARALLEL is a noop, we can delete
the entire PARALLEL. */
for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
rtx insn;
rtx testreg = gen_rtx_REG (VOIDmode, -1);
- cselib_init ();
+ cselib_init (true);
init_alias_analysis ();
for (insn = first; insn; insn = NEXT_INSN (insn))
cselib_val *val;
struct elt_loc_list *l;
#ifdef LOAD_EXTEND_OP
- enum rtx_code extend_op = NIL;
+ enum rtx_code extend_op = UNKNOWN;
#endif
+ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
dreg = true_regnum (SET_DEST (set));
if (dreg < 0)
that combine made wrt the contents of sign bits. We'll do this by
generating an extend instruction instead of a reg->reg copy. Thus
the destination must be a register that we can widen. */
- if (GET_CODE (src) == MEM
+ if (MEM_P (src)
&& GET_MODE_BITSIZE (GET_MODE (src)) < BITS_PER_WORD
- && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != NIL
- && GET_CODE (SET_DEST (set)) != REG)
+ && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != UNKNOWN
+ && !REG_P (SET_DEST (set)))
return 0;
#endif
return 0;
/* If memory loads are cheaper than register copies, don't change them. */
- if (GET_CODE (src) == MEM)
+ if (MEM_P (src))
old_cost = MEMORY_MOVE_COST (GET_MODE (src), dclass, 1);
- else if (GET_CODE (src) == REG)
+ else if (REG_P (src))
old_cost = REGISTER_MOVE_COST (GET_MODE (src),
REGNO_REG_CLASS (REGNO (src)), dclass);
else
- old_cost = rtx_cost (src, SET);
+ old_cost = rtx_cost (src, SET, speed);
for (l = val->locs; l; l = l->next)
{
if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
{
#ifdef LOAD_EXTEND_OP
- if (extend_op != NIL)
+ if (extend_op != UNKNOWN)
{
HOST_WIDE_INT this_val;
if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
break;
default:
- abort ();
+ gcc_unreachable ();
}
this_rtx = GEN_INT (this_val);
}
#endif
- this_cost = rtx_cost (this_rtx, SET);
+ this_cost = rtx_cost (this_rtx, SET, speed);
}
- else if (GET_CODE (this_rtx) == REG)
+ else if (REG_P (this_rtx))
{
#ifdef LOAD_EXTEND_OP
- if (extend_op != NIL)
+ if (extend_op != UNKNOWN)
{
this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
- this_cost = rtx_cost (this_rtx, SET);
+ this_cost = rtx_cost (this_rtx, SET, speed);
}
else
#endif
tends to lead to smaller instructions on some machines. */
if (this_cost < old_cost
|| (this_cost == old_cost
- && GET_CODE (this_rtx) == REG
- && GET_CODE (SET_SRC (set)) != REG))
+ && REG_P (this_rtx)
+ && !REG_P (SET_SRC (set))))
{
#ifdef LOAD_EXTEND_OP
if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
- && extend_op != NIL
+ && extend_op != UNKNOWN
#ifdef CANNOT_CHANGE_MODE_CLASS
&& !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
word_mode,
}
#endif
- validate_change (insn, &SET_SRC (set), copy_rtx (this_rtx), 1);
+ validate_unshare_change (insn, &SET_SRC (set), this_rtx, 1);
old_cost = this_cost, did_change = 1;
}
}
if (! constrain_operands (1))
fatal_insn_not_found (insn);
- 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));
+ alternative_reject = XALLOCAVEC (int, recog_data.n_alternatives);
+ alternative_nregs = XALLOCAVEC (int, recog_data.n_alternatives);
+ alternative_order = XALLOCAVEC (int, recog_data.n_alternatives);
memset (alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
memset (alternative_nregs, 0, recog_data.n_alternatives * sizeof (int));
/* cselib blows up on CODE_LABELs. Trying to fix that doesn't seem
right, so avoid the problem here. Likewise if we have a constant
and the insn pattern doesn't tell us the mode we need. */
- if (GET_CODE (recog_data.operand[i]) == CODE_LABEL
+ if (LABEL_P (recog_data.operand[i])
|| (CONSTANT_P (recog_data.operand[i])
&& recog_data.operand_mode[i] == VOIDmode))
continue;
op = recog_data.operand[i];
mode = GET_MODE (op);
#ifdef LOAD_EXTEND_OP
- if (GET_CODE (op) == MEM
+ if (MEM_P (op)
&& GET_MODE_BITSIZE (mode) < BITS_PER_WORD
- && LOAD_EXTEND_OP (mode) != NIL)
+ && LOAD_EXTEND_OP (mode) != UNKNOWN)
{
rtx set = single_set (insn);
- /* We might have multiple sets, some of which do implict
+ /* 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
+ /* If the destination is also a 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
+ else if (MEM_P (SET_DEST (set))
|| 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 (REG_P (SET_DEST (set))
+ && 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
+ else if (REG_P (SET_DEST (set))
&& recog_data.n_operands == 2
&& SET_SRC (set) == op
&& SET_DEST (set) == recog_data.operand[1-i])
continue;
for (l = v->locs; l; l = l->next)
- if (GET_CODE (l->loc) == REG)
+ if (REG_P (l->loc))
SET_HARD_REG_BIT (equiv_regs[i], REGNO (l->loc));
}
int regno;
const char *p;
- op_alt_regno[i] = alloca (recog_data.n_alternatives * sizeof (int));
+ op_alt_regno[i] = XALLOCAVEC (int, recog_data.n_alternatives);
for (j = 0; j < recog_data.n_alternatives; j++)
op_alt_regno[i][j] = -1;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
{
- int class = (int) NO_REGS;
+ enum reg_class rclass = NO_REGS;
if (! TEST_HARD_REG_BIT (equiv_regs[i], regno))
continue;
- REGNO (testreg) = regno;
+ SET_REGNO (testreg, regno);
PUT_MODE (testreg, mode);
/* We found a register equal to this operand. Now look for all
case '*': case '%':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- case 'm': case '<': case '>': case 'V': case 'o':
+ case '<': case '>': case 'V': case 'o':
case 'E': case 'F': case 'G': case 'H':
case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
- case 'p': case 'X':
+ case 'p': case 'X': case TARGET_MEM_CONSTRAINT:
/* These don't say anything we care about. */
break;
case 'g': case 'r':
- class = reg_class_subunion[(int) class][(int) GENERAL_REGS];
+ rclass = reg_class_subunion[(int) rclass][(int) GENERAL_REGS];
break;
default:
- class
+ rclass
= (reg_class_subunion
- [(int) class]
+ [(int) rclass]
[(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
break;
alternative yet and the operand being replaced is not
a cheap CONST_INT. */
if (op_alt_regno[i][j] == -1
- && reg_fits_class_p (testreg, class, 0, mode)
+ && reg_fits_class_p (testreg, rclass, 0, mode)
&& (GET_CODE (recog_data.operand[i]) != CONST_INT
- || (rtx_cost (recog_data.operand[i], SET)
- > rtx_cost (testreg, SET))))
+ || (rtx_cost (recog_data.operand[i], SET,
+ optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)))
+ > rtx_cost (testreg, SET,
+ optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn))))))
{
alternative_nregs[j]++;
op_alt_regno[i][j] = regno;
}
j++;
+ rclass = NO_REGS;
break;
}
p += CONSTRAINT_LEN (c, p);
int this_nregs = alternative_nregs[alternative_order[j]];
if (this_reject < best_reject
- || (this_reject == best_reject && this_nregs < best_nregs))
+ || (this_reject == best_reject && this_nregs > best_nregs))
{
best = j;
best_reject = this_reject;
replace them with reg+reg addressing. */
#define RELOAD_COMBINE_MAX_USES 6
-/* INSN is the insn where a register has ben used, and USEP points to the
+/* INSN is the insn where a register has been used, and USEP points to the
location of the register within the rtl. */
struct reg_use { rtx insn, *usep; };
destination. */
min_labelno = get_first_label_num ();
n_labels = max_label_num () - min_labelno;
- label_live = xmalloc (n_labels * sizeof (HARD_REG_SET));
+ label_live = XNEWVEC (HARD_REG_SET, n_labels);
CLEAR_HARD_REG_SET (ever_live_at_start);
FOR_EACH_BB_REVERSE (bb)
{
insn = BB_HEAD (bb);
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
{
HARD_REG_SET live;
+ bitmap live_in = df_get_live_in (bb);
- REG_SET_TO_HARD_REG_SET (live,
- bb->global_live_at_start);
- compute_use_by_pseudos (&live,
- bb->global_live_at_start);
+ REG_SET_TO_HARD_REG_SET (live, live_in);
+ compute_use_by_pseudos (&live, live_in);
COPY_HARD_REG_SET (LABEL_LIVE (insn), live);
IOR_HARD_REG_SET (ever_live_at_start, live);
}
/* We cannot do our optimization across labels. Invalidating all the use
information we have would be costly, so we just note where the label
is and then later disable any optimization that would cross it. */
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
last_label_ruid = reload_combine_ruid;
- else if (GET_CODE (insn) == BARRIER)
+ else if (BARRIER_P (insn))
for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
if (! fixed_regs[r])
reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
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)))
+ && REG_P (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
+ && REG_P (XEXP (SET_SRC (set), 1))
&& 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)
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);
with REG_SUM. */
for (i = reg_state[regno].use_index;
i < RELOAD_COMBINE_MAX_USES; i++)
- validate_change (reg_state[regno].reg_use[i].insn,
- reg_state[regno].reg_use[i].usep,
- /* Each change must have its own
- replacement. */
- copy_rtx (reg_sum), 1);
+ validate_unshare_change (reg_state[regno].reg_use[i].insn,
+ reg_state[regno].reg_use[i].usep,
+ /* Each change must have its own
+ replacement. */
+ reg_sum, 1);
if (apply_change_group ())
{
- rtx *np;
-
/* Delete the reg-reg addition. */
delete_insn (insn);
if (reg_state[regno].offset != const0_rtx)
/* Previous REG_EQUIV / REG_EQUAL notes for PREV
are now invalid. */
- for (np = ®_NOTES (prev); *np;)
- {
- if (REG_NOTE_KIND (*np) == REG_EQUAL
- || REG_NOTE_KIND (*np) == REG_EQUIV)
- *np = XEXP (*np, 1);
- else
- np = &XEXP (*np, 1);
- }
+ remove_reg_equal_equiv_notes (prev);
reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
reg_state[REGNO (const_reg)].store_ruid
note_stores (PATTERN (insn), reload_combine_note_store, NULL);
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
rtx link;
link = XEXP (link, 1))
{
rtx usage_rtx = XEXP (XEXP (link, 0), 0);
- if (GET_CODE (usage_rtx) == REG)
+ if (REG_P (usage_rtx))
{
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)
}
}
- else if (GET_CODE (insn) == JUMP_INSN
+ else if (JUMP_P (insn)
&& GET_CODE (PATTERN (insn)) != RETURN)
{
/* Non-spill registers might be used at the call destination in
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_INC
- && GET_CODE (XEXP (note, 0)) == REG)
+ && REG_P (XEXP (note, 0)))
{
int regno = REGNO (XEXP (note, 0));
accordingly. Called via note_stores from reload_combine. */
static void
-reload_combine_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
+reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
{
int regno = 0;
int i;
GET_MODE (dst));
dst = SUBREG_REG (dst);
}
- if (GET_CODE (dst) != REG)
+ if (!REG_P (dst))
return;
regno += REGNO (dst);
/* note_stores might have stripped a STRICT_LOW_PART, so we have to be
careful with registers / register parts that are not full words.
-
- Similarly for ZERO_EXTRACT and SIGN_EXTRACT. */
+ Similarly for ZERO_EXTRACT. */
if (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)
{
- 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;
switch (code)
{
case SET:
- if (GET_CODE (SET_DEST (x)) == REG)
+ if (REG_P (SET_DEST (x)))
{
reload_combine_note_use (&SET_SRC (x), insn);
return;
case USE:
/* If this is the USE of a return value, we can't change it. */
- if (GET_CODE (XEXP (x, 0)) == REG && REG_FUNCTION_VALUE_P (XEXP (x, 0)))
+ if (REG_P (XEXP (x, 0)) && REG_FUNCTION_VALUE_P (XEXP (x, 0)))
{
/* 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;
break;
case CLOBBER:
- if (GET_CODE (SET_DEST (x)) == REG)
+ if (REG_P (SET_DEST (x)))
{
/* No spurious CLOBBERs of pseudo registers may remain. */
- if (REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER)
- abort ();
+ gcc_assert (REGNO (SET_DEST (x)) < FIRST_PSEUDO_REGISTER);
return;
}
break;
case PLUS:
/* We are interested in (plus (reg) (const_int)) . */
- if (GET_CODE (XEXP (x, 0)) != REG
+ if (!REG_P (XEXP (x, 0))
|| GET_CODE (XEXP (x, 1)) != CONST_INT)
break;
offset = XEXP (x, 1);
int nregs;
/* No spurious USEs of pseudo registers may remain. */
- if (regno >= FIRST_PSEUDO_REGISTER)
- abort ();
+ gcc_assert (regno < FIRST_PSEUDO_REGISTER);
- 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)
{
rtx pat, note;
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
{
move2add_last_label_luid = move2add_luid;
/* We're going to increment move2add_luid twice after a
/* For simplicity, we only perform this optimization on
straightforward SETs. */
if (GET_CODE (pat) == SET
- && GET_CODE (SET_DEST (pat)) == REG)
+ && REG_P (SET_DEST (pat)))
{
rtx reg = SET_DEST (pat);
int regno = REGNO (reg);
/* Check if we have valid information on the contents of this
register in the mode of REG. */
if (reg_set_luid[regno] > move2add_last_label_luid
- && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]))
+ && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno])
+ && dbg_cnt (cse2_move2add))
{
/* Try to transform (set (REGX) (CONST_INT A))
...
if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
{
- rtx new_src =
- GEN_INT (trunc_int_for_mode (INTVAL (src)
- - reg_offset[regno],
- GET_MODE (reg)));
+ rtx new_src = gen_int_mode (INTVAL (src) - reg_offset[regno],
+ GET_MODE (reg));
+ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
+
/* (set (reg) (plus (reg) (const_int 0))) is not canonical;
use (set (reg) (reg)) instead.
We don't delete this insn, nor do we convert it into a
if (INTVAL (src) == reg_offset [regno])
validate_change (insn, &SET_SRC (pat), reg, 0);
}
- else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
+ else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed)
&& have_add2_insn (reg, new_src))
{
- rtx newpat = gen_rtx_SET (VOIDmode,
- reg,
- gen_rtx_PLUS (GET_MODE (reg),
- reg,
- new_src));
- validate_change (insn, &PATTERN (insn), newpat, 0);
+ rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
+ validate_change (insn, &SET_SRC (pat), tem, 0);
}
- else
+ else if (GET_MODE (reg) != BImode)
{
enum machine_mode narrow_mode;
for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
- narrow_mode != GET_MODE (reg);
+ narrow_mode != VOIDmode
+ && narrow_mode != GET_MODE (reg);
narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
{
if (have_insn_for (STRICT_LOW_PART, narrow_mode)
{
rtx narrow_reg = gen_rtx_REG (narrow_mode,
REGNO (reg));
- rtx narrow_src =
- GEN_INT (trunc_int_for_mode (INTVAL (src),
- narrow_mode));
+ rtx narrow_src = gen_int_mode (INTVAL (src),
+ narrow_mode);
rtx new_set =
gen_rtx_SET (VOIDmode,
gen_rtx_STRICT_LOW_PART (VOIDmode,
(set (REGX) (PLUS (REGX) (CONST_INT A)))
...
(set (REGX) (plus (REGX) (CONST_INT B-A))) */
- else if (GET_CODE (src) == REG
+ else if (REG_P (src)
&& reg_set_luid[regno] == reg_set_luid[REGNO (src)]
&& reg_base_reg[regno] == reg_base_reg[REGNO (src)]
&& MODES_OK_FOR_MOVE2ADD (GET_MODE (reg),
HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
HOST_WIDE_INT regno_offset = reg_offset[regno];
rtx new_src =
- GEN_INT (trunc_int_for_mode (added_offset
- + base_offset
- - regno_offset,
- GET_MODE (reg)));
- int success = 0;
+ gen_int_mode (added_offset
+ + base_offset
+ - regno_offset,
+ GET_MODE (reg));
+ bool success = false;
+ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
if (new_src == const0_rtx)
/* See above why we create (set (reg) (reg)) here. */
success
= validate_change (next, &SET_SRC (set), reg, 0);
- else if ((rtx_cost (new_src, PLUS)
- < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
+ else if ((rtx_cost (new_src, PLUS, speed)
+ < COSTS_N_INSNS (1) + rtx_cost (src3, SET, speed))
&& have_add2_insn (reg, new_src))
{
rtx newpat = gen_rtx_SET (VOIDmode,
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_INC
- && GET_CODE (XEXP (note, 0)) == REG)
+ && REG_P (XEXP (note, 0)))
{
/* Reset the information about this register. */
int regno = REGNO (XEXP (note, 0));
/* If INSN is a conditional branch, we try to extract an
implicit set out of it. */
- if (any_condjump_p (insn) && onlyjump_p (insn))
+ if (any_condjump_p (insn))
{
rtx cnd = fis_get_condition (insn);
if (cnd != NULL_RTX
&& GET_CODE (cnd) == NE
- && GET_CODE (XEXP (cnd, 0)) == REG
+ && REG_P (XEXP (cnd, 0))
+ && !reg_set_p (XEXP (cnd, 0), insn)
/* The following two checks, which are also in
move2add_note_store, are intended to reduce the
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 =
/* If this is a CALL_INSN, all call used registers are stored with
unknown values. */
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
{
Called from reload_cse_move2add via note_stores. */
static void
-move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
+move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
{
unsigned int regno = 0;
+ unsigned int nregs = 0;
unsigned int i;
enum machine_mode mode = GET_MODE (dst);
GET_MODE (SUBREG_REG (dst)),
SUBREG_BYTE (dst),
GET_MODE (dst));
+ nregs = subreg_nregs (dst);
dst = SUBREG_REG (dst);
}
/* Some targets do argument pushes without adding REG_INC notes. */
- if (GET_CODE (dst) == MEM)
+ if (MEM_P (dst))
{
dst = XEXP (dst, 0);
if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC
reg_set_luid[REGNO (XEXP (dst, 0))] = 0;
return;
}
- if (GET_CODE (dst) != REG)
+ if (!REG_P (dst))
return;
regno += REGNO (dst);
+ if (!nregs)
+ nregs = hard_regno_nregs[regno][mode];
- if (SCALAR_INT_MODE_P (mode)
- && HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
+ if (SCALAR_INT_MODE_P (GET_MODE (dst))
+ && nregs == 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)
{
rtx src = SET_SRC (set);
switch (GET_CODE (src))
{
case PLUS:
- if (GET_CODE (XEXP (src, 0)) == REG)
+ if (REG_P (XEXP (src, 0)))
{
base_reg = XEXP (src, 0);
if (GET_CODE (XEXP (src, 1)) == CONST_INT)
offset = INTVAL (XEXP (src, 1));
- else if (GET_CODE (XEXP (src, 1)) == REG
+ else if (REG_P (XEXP (src, 1))
&& (reg_set_luid[REGNO (XEXP (src, 1))]
> move2add_last_label_luid)
&& (MODES_OK_FOR_MOVE2ADD
}
else
{
- unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
+ unsigned int endregno = regno + nregs;
for (i = regno; i < endregno; i++)
/* Reset the information about this register. */
reg_set_luid[i] = 0;
}
}
+\f
+static bool
+gate_handle_postreload (void)
+{
+ return (optimize > 0 && reload_completed);
+}
+
+
+static unsigned int
+rest_of_handle_postreload (void)
+{
+ if (!dbg_cnt (postreload_cse))
+ return 0;
+
+ /* Do a very simple CSE pass over just the hard registers. */
+ reload_cse_regs (get_insns ());
+ /* Reload_cse_regs can eliminate potentially-trapping MEMs.
+ Remove any EH edges associated with them. */
+ if (flag_non_call_exceptions)
+ purge_all_dead_edges ();
+
+ return 0;
+}
+
+struct rtl_opt_pass pass_postreload_cse =
+{
+ {
+ RTL_PASS,
+ "postreload", /* name */
+ gate_handle_postreload, /* gate */
+ rest_of_handle_postreload, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_RELOAD_CSE_REGS, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_df_finish | TODO_verify_rtl_sharing |
+ TODO_dump_func /* todo_flags_finish */
+ }
+};