#include "tm_p.h"
#include "obstack.h"
#include "insn-config.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
static int num_labels;
\f
+static void replace_pseudos_in_call_usage PARAMS((rtx *,
+ enum machine_mode,
+ rtx));
static void maybe_fix_stack_asms PARAMS ((void));
static void copy_reloads PARAMS ((struct insn_chain *));
static void calculate_needs_all_insns PARAMS ((int));
static void spill_failure PARAMS ((rtx, enum reg_class));
static void count_spilled_pseudo PARAMS ((int, int, int));
static void delete_dead_insn PARAMS ((rtx));
-static void alter_reg PARAMS ((int, int));
+static void alter_reg PARAMS ((int, int));
static void set_label_offsets PARAMS ((rtx, rtx, int));
static void check_eliminable_occurrences PARAMS ((rtx));
static void elimination_effects PARAMS ((rtx, enum machine_mode));
enum machine_mode));
static int reload_reg_free_p PARAMS ((unsigned int, int,
enum reload_type));
-static int reload_reg_free_for_value_p PARAMS ((int, int, enum reload_type,
+static int reload_reg_free_for_value_p PARAMS ((int, int, int,
+ enum reload_type,
rtx, rtx, int, int));
static int free_for_value_p PARAMS ((int, enum machine_mode, int,
enum reload_type, rtx, rtx,
#ifdef AUTO_INC_DEC
static void add_auto_inc_notes PARAMS ((rtx, rtx));
#endif
-static rtx gen_mode_int PARAMS ((enum machine_mode,
+static void copy_eh_notes PARAMS ((rtx, rtx));
+static HOST_WIDE_INT sext_for_mode PARAMS ((enum machine_mode,
HOST_WIDE_INT));
static void failed_reload PARAMS ((rtx, int));
static int set_reload_reg PARAMS ((int, int));
}
});
}
+
+/* Replace all pseudos found in LOC with their corresponding
+ equivalences. */
+
+static void
+replace_pseudos_in_call_usage (loc, mem_mode, usage)
+ rtx *loc;
+ enum machine_mode mem_mode;
+ rtx usage;
+{
+ rtx x = *loc;
+ enum rtx_code code;
+ const char *fmt;
+ int i, j;
+
+ if (! x)
+ return;
+
+ code = GET_CODE (x);
+ if (code == REG)
+ {
+ int regno = REGNO (x);
+
+ if (regno < FIRST_PSEUDO_REGISTER)
+ return;
+
+ x = eliminate_regs (x, mem_mode, usage);
+ if (x != *loc)
+ {
+ *loc = x;
+ replace_pseudos_in_call_usage (loc, mem_mode, usage);
+ return;
+ }
+
+ if (reg_equiv_constant[regno])
+ *loc = reg_equiv_constant[regno];
+ else if (reg_equiv_mem[regno])
+ *loc = reg_equiv_mem[regno];
+ else if (reg_equiv_address[regno])
+ *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address[regno]);
+ else if (GET_CODE (regno_reg_rtx[regno]) != REG
+ || REGNO (regno_reg_rtx[regno]) != regno)
+ *loc = regno_reg_rtx[regno];
+ else
+ abort ();
+
+ return;
+ }
+ else if (code == MEM)
+ {
+ replace_pseudos_in_call_usage (& XEXP (x, 0), GET_MODE (x), usage);
+ return;
+ }
+
+ /* Process each of our operands recursively. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ if (*fmt == 'e')
+ replace_pseudos_in_call_usage (&XEXP (x, i), mem_mode, usage);
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ replace_pseudos_in_call_usage (& XVECEXP (x, i, j), mem_mode, usage);
+}
+
\f
/* Global variables used by reload and its subroutines. */
/* The two pointers used to track the true location of the memory used
for label offsets. */
- char *real_known_ptr = NULL_PTR;
+ char *real_known_ptr = NULL;
int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
/* Make sure even insns with volatile mem refs are recognizable. */
/* Make sure that the last insn in the chain
is not something that needs reloading. */
- emit_note (NULL_PTR, NOTE_INSN_DELETED);
+ emit_note (NULL, NOTE_INSN_DELETED);
/* Enable find_equiv_reg to distinguish insns made by reload. */
reload_first_uid = get_max_uid ();
{
rtx *pnote;
+ if (GET_CODE (insn) == CALL_INSN)
+ replace_pseudos_in_call_usage (& CALL_INSN_FUNCTION_USAGE (insn),
+ VOIDmode,
+ CALL_INSN_FUNCTION_USAGE (insn));
+
if ((GET_CODE (PATTERN (insn)) == USE
&& find_reg_note (insn, REG_EQUAL, NULL_RTX))
|| (GET_CODE (PATTERN (insn)) == CLOBBER
return x;
case SUBREG:
- /* Similar to above processing, but preserve SUBREG_WORD.
+ /* Similar to above processing, but preserve SUBREG_BYTE.
Convert (subreg (mem)) to (mem) if not paradoxical.
Also, if we have a non-paradoxical (subreg (pseudo)) and the
pseudo didn't get a hard reg, we must replace this with the
else
new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
- if (new != XEXP (x, 0))
+ if (new != SUBREG_REG (x))
{
int x_size = GET_MODE_SIZE (GET_MODE (x));
int new_size = GET_MODE_SIZE (GET_MODE (new));
|| (x_size == new_size))
)
{
- int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+ int offset = SUBREG_BYTE (x);
enum machine_mode mode = GET_MODE (x);
- if (BYTES_BIG_ENDIAN)
- offset += (MIN (UNITS_PER_WORD,
- GET_MODE_SIZE (GET_MODE (new)))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-
PUT_MODE (new, mode);
XEXP (new, 0) = plus_constant (XEXP (new, 0), offset);
return new;
}
else
- return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_WORD (x));
+ return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_BYTE (x));
}
return x;
return x;
case USE:
+ /* Handle insn_list USE that a call to a pure function may generate. */
+ new = eliminate_regs (XEXP (x, 0), 0, insn);
+ if (new != XEXP (x, 0))
+ return gen_rtx_USE (GET_MODE (x), new);
+ return x;
+
case CLOBBER:
case ASM_OPERANDS:
case SET:
currently support: a single set with the source being a PLUS of an
eliminable register and a constant. */
if (old_set
+ && GET_CODE (SET_DEST (old_set)) == REG
&& GET_CODE (SET_SRC (old_set)) == PLUS
&& GET_CODE (XEXP (SET_SRC (old_set), 0)) == REG
&& GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
into the insn's body (or perhaps into the bodies of other
load and store insn that we just made for reloading
and that we moved the structure into). */
- subst_reloads ();
+ subst_reloads (insn);
/* If this was an ASM, make sure that all the reload insns
we have generated are valid. If not, give an error
unsigned int nr;
int offset = 0;
- /* note_stores does give us subregs of hard regs. */
+ /* note_stores does give us subregs of hard regs,
+ subreg_regno_offset will abort if it is not a hard reg. */
while (GET_CODE (x) == SUBREG)
{
- offset += SUBREG_WORD (x);
+ offset += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x),
+ GET_MODE (x));
x = SUBREG_REG (x);
}
or -1 if we did not need a register for this reload. */
int reload_spill_index[MAX_RELOADS];
-/* Subroutine of free_for_value_p, used to check a single register. */
+/* Subroutine of free_for_value_p, used to check a single register.
+ START_REGNO is the starting regno of the full reload register
+ (possibly comprising multiple hard registers) that we are considering. */
static int
-reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
- ignore_address_reloads)
- int regno;
+reload_reg_free_for_value_p (start_regno, regno, opnum, type, value, out,
+ reloadnum, ignore_address_reloads)
+ int start_regno, regno;
int opnum;
enum reload_type type;
rtx value, out;
<= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned)1)
&& i != reloadnum)
{
- if (! rld[i].in || ! rtx_equal_p (rld[i].in, value)
+ rtx other_input = rld[i].in;
+
+ /* If the other reload loads the same input value, that
+ will not cause a conflict only if it's loading it into
+ the same register. */
+ if (true_regnum (reg) != start_regno)
+ other_input = NULL_RTX;
+ if (! other_input || ! rtx_equal_p (other_input, value)
|| rld[i].out || out)
{
int time2;
case RELOAD_OTHER:
/* If there is no conflict in the input part, handle this
like an output reload. */
- if (! rld[i].in || rtx_equal_p (rld[i].in, value))
+ if (! rld[i].in || rtx_equal_p (other_input, value))
{
time2 = MAX_RECOG_OPERANDS * 4 + 4;
/* Earlyclobbered outputs must conflict with inputs. */
}
if ((time1 >= time2
&& (! rld[i].in || rld[i].out
- || ! rtx_equal_p (rld[i].in, value)))
+ || ! rtx_equal_p (other_input, value)))
|| (out && rld[reloadnum].out_reg
&& time2 >= MAX_RECOG_OPERANDS * 4 + 3))
return 0;
{
int nregs = HARD_REGNO_NREGS (regno, mode);
while (nregs-- > 0)
- if (! reload_reg_free_for_value_p (regno + nregs, opnum, type, value, out,
- reloadnum, ignore_address_reloads))
+ if (! reload_reg_free_for_value_p (regno, regno + nregs, opnum, type,
+ value, out, reloadnum,
+ ignore_address_reloads))
return 0;
return 1;
}
if (inheritance)
{
- int word = 0;
+ int byte = 0;
register int regno = -1;
enum machine_mode mode = VOIDmode;
else if (GET_CODE (rld[r].in_reg) == SUBREG
&& GET_CODE (SUBREG_REG (rld[r].in_reg)) == REG)
{
- word = SUBREG_WORD (rld[r].in_reg);
+ byte = SUBREG_BYTE (rld[r].in_reg);
regno = REGNO (SUBREG_REG (rld[r].in_reg));
if (regno < FIRST_PSEUDO_REGISTER)
- regno += word;
+ regno = subreg_regno (rld[r].in_reg);
mode = GET_MODE (rld[r].in_reg);
}
#ifdef AUTO_INC_DEC
that can invalidate an inherited reload of part of a pseudoreg. */
else if (GET_CODE (rld[r].in) == SUBREG
&& GET_CODE (SUBREG_REG (rld[r].in)) == REG)
- regno = REGNO (SUBREG_REG (rld[r].in)) + SUBREG_WORD (rld[r].in);
+ regno = subreg_regno (rld[r].in);
#endif
if (regno >= 0 && reg_last_reload_reg[regno] != 0)
rtx last_reg = reg_last_reload_reg[regno];
enum machine_mode need_mode;
- i = REGNO (last_reg) + word;
+ i = REGNO (last_reg);
+ i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode);
last_class = REGNO_REG_CLASS (i);
- if (word == 0)
+ if (byte == 0)
need_mode = mode;
else
need_mode
- = smallest_mode_for_size (GET_MODE_SIZE (mode)
- + word * UNITS_PER_WORD,
+ = smallest_mode_for_size (GET_MODE_SIZE (mode) + byte,
GET_MODE_CLASS (mode));
if (
{
register rtx equiv
= find_equiv_reg (search_equiv, insn, rld[r].class,
- -1, NULL_PTR, 0, rld[r].mode);
+ -1, NULL, 0, rld[r].mode);
int regno = 0;
if (equiv != 0)
Make a new REG since this might be used in an
address and not all machines support SUBREGs
there. */
- regno = REGNO (SUBREG_REG (equiv)) + SUBREG_WORD (equiv);
+ regno = subreg_regno (equiv);
equiv = gen_rtx_REG (rld[r].mode, regno);
}
else
RELOAD_FOR_OUTPUT_ADDRESS reload. */
if (equiv != 0)
- {
+ {
if (regno_clobbered_p (regno, insn, rld[r].mode, 0))
switch (rld[r].when_needed)
{
oldequiv
= find_equiv_reg (old, insn,
rld[rl->secondary_in_reload].class,
- -1, NULL_PTR, 0, mode);
+ -1, NULL, 0, mode);
#endif
/* If reloading from memory, see if there is a register
|| (GET_CODE (old) == REG
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (old)] < 0)))
- oldequiv = find_equiv_reg (old, insn, ALL_REGS,
- -1, NULL_PTR, 0, mode);
+ oldequiv = find_equiv_reg (old, insn, ALL_REGS, -1, NULL, 0, mode);
if (oldequiv)
{
oldequiv = SUBREG_REG (oldequiv);
if (GET_MODE (oldequiv) != VOIDmode
&& mode != GET_MODE (oldequiv))
- oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
+ oldequiv = gen_lowpart_SUBREG (mode, oldequiv);
/* Switch to the right place to emit the reload insns. */
switch (rl->when_needed)
rl->when_needed);
}
+ if (flag_non_call_exceptions)
+ copy_eh_notes (insn, get_insns ());
+
/* End this sequence. */
*where = get_insns ();
end_sequence ();
-
+
/* Update reload_override_in so that delete_address_reloads_1
can see the actual register usage. */
if (oldequiv_reg)
/* Copy primary reload reg to secondary reload reg.
(Note that these have been swapped above, then
- secondary reload reg to OLD using our insn. */
+ secondary reload reg to OLD using our insn.) */
/* If REAL_OLD is a paradoxical SUBREG, remove it
and try to put the opposite SUBREG on
else
output_reload_insns[rl->opnum] = get_insns ();
+ if (flag_non_call_exceptions)
+ copy_eh_notes (insn, get_insns ());
+
end_sequence ();
}
if (GET_CODE (body) == SET)
{
int count = 0;
- if (reload_cse_noop_set_p (body))
+
+ /* Simplify even if we may think it is a no-op.
+ We may think a memory load of a value smaller than WORD_SIZE
+ is redundant because we haven't taken into account possible
+ implicit extension. reload_cse_simplify_set() will bring
+ this out, so it's safer to simplify before we delete. */
+ count += reload_cse_simplify_set (body, insn);
+
+ if (!count && reload_cse_noop_set_p (body))
{
rtx value = SET_DEST (body);
if (! REG_FUNCTION_VALUE_P (SET_DEST (body)))
return;
}
- /* It's not a no-op, but we can try to simplify it. */
- count += reload_cse_simplify_set (body, insn);
-
if (count > 0)
apply_change_group ();
else
int old_cost;
cselib_val *val;
struct elt_loc_list *l;
+#ifdef LOAD_EXTEND_OP
+ enum rtx_code extend_op = NIL;
+#endif
dreg = true_regnum (SET_DEST (set));
if (dreg < 0)
dclass = REGNO_REG_CLASS (dreg);
+#ifdef LOAD_EXTEND_OP
+ /* When replacing a memory with a register, we need to honor assumptions
+ 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
+ && GET_MODE_BITSIZE (GET_MODE (src)) < BITS_PER_WORD
+ && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != NIL
+ && GET_CODE (SET_DEST (set)) != REG)
+ return 0;
+#endif
+
/* 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);
return 0;
for (l = val->locs; l; l = l->next)
{
+ rtx this_rtx = l->loc;
int this_cost;
- if (CONSTANT_P (l->loc) && ! references_value_p (l->loc, 0))
- this_cost = rtx_cost (l->loc, SET);
- else if (GET_CODE (l->loc) == REG)
- this_cost = REGISTER_MOVE_COST (GET_MODE (l->loc),
- REGNO_REG_CLASS (REGNO (l->loc)),
- dclass);
+
+ if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
+ {
+#ifdef LOAD_EXTEND_OP
+ if (extend_op != NIL)
+ {
+ HOST_WIDE_INT this_val;
+
+ /* ??? I'm lazy and don't wish to handle CONST_DOUBLE. Other
+ constants, such as SYMBOL_REF, cannot be extended. */
+ if (GET_CODE (this_rtx) != CONST_INT)
+ continue;
+
+ this_val = INTVAL (this_rtx);
+ switch (extend_op)
+ {
+ case ZERO_EXTEND:
+ this_val &= GET_MODE_MASK (GET_MODE (src));
+ break;
+ case SIGN_EXTEND:
+ /* ??? In theory we're already extended. */
+ if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
+ break;
+ default:
+ abort ();
+ }
+ this_rtx = GEN_INT (this_val);
+ }
+#endif
+ this_cost = rtx_cost (this_rtx, SET);
+ }
+ else if (GET_CODE (this_rtx) == REG)
+ {
+#ifdef LOAD_EXTEND_OP
+ if (extend_op != NIL)
+ {
+ this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
+ this_cost = rtx_cost (this_rtx, SET);
+ }
+ else
+#endif
+ this_cost = REGISTER_MOVE_COST (GET_MODE (this_rtx),
+ REGNO_REG_CLASS (REGNO (this_rtx)),
+ dclass);
+ }
else
continue;
- /* If equal costs, prefer registers over anything else. That tends to
- lead to smaller instructions on some machines. */
- if ((this_cost < old_cost
- || (this_cost == old_cost
- && GET_CODE (l->loc) == REG
- && GET_CODE (SET_SRC (set)) != REG))
- && validate_change (insn, &SET_SRC (set), copy_rtx (l->loc), 1))
- old_cost = this_cost, did_change = 1;
+
+ /* If equal costs, prefer registers over anything else. That
+ 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))
+ {
+#ifdef LOAD_EXTEND_OP
+ if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
+ && extend_op != NIL)
+ {
+ rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
+ ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
+ validate_change (insn, &SET_DEST (set), wide_dest, 1);
+ }
+#endif
+
+ validate_change (insn, &SET_SRC (set), copy_rtx (this_rtx), 1);
+ old_cost = this_cost, did_change = 1;
+ }
}
return did_change;
if (GET_CODE (dst) == SUBREG)
{
- regno = SUBREG_WORD (dst);
+ regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
+ GET_MODE (SUBREG_REG (dst)),
+ SUBREG_BYTE (dst),
+ GET_MODE (dst));
dst = SUBREG_REG (dst);
}
if (GET_CODE (dst) != REG)
}
}
\f
-/* See if we can reduce the cost of a constant by replacing a move with
- an add. */
+/* See if we can reduce the cost of a constant by replacing a move
+ with an add. We track situations in which a register is set to a
+ constant or to a register plus a constant. */
/* We cannot do our optimization across labels. Invalidating all the
information about register contents we have would be costly, so we
- use last_label_luid (local variable of reload_cse_move2add) to note
- where the label is and then later disable any optimization that would
- cross it.
+ use move2add_last_label_luid to note where the label is and then
+ later disable any optimization that would cross it.
reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if
- reg_set_luid[n] is larger than last_label_luid[n] . */
+ reg_set_luid[n] is greater than last_label_luid[n] . */
static int reg_set_luid[FIRST_PSEUDO_REGISTER];
-/* reg_offset[n] has to be CONST_INT for it and reg_base_reg[n] /
- reg_mode[n] to be valid.
- If reg_offset[n] is a CONST_INT and reg_base_reg[n] is negative, register n
- has been set to reg_offset[n] in mode reg_mode[n] .
- If reg_offset[n] is a CONST_INT and reg_base_reg[n] is non-negative,
- register n has been set to the sum of reg_offset[n] and register
- reg_base_reg[n], calculated in mode reg_mode[n] . */
-static rtx reg_offset[FIRST_PSEUDO_REGISTER];
+/* If reg_base_reg[n] is negative, register n has been set to
+ reg_offset[n] in mode reg_mode[n] .
+ If reg_base_reg[n] is non-negative, register n has been set to the
+ sum of reg_offset[n] and the value of register reg_base_reg[n]
+ before reg_set_luid[n], calculated in mode reg_mode[n] . */
+static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
static int reg_base_reg[FIRST_PSEUDO_REGISTER];
static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
reload_cse_move2add and move2add_note_store. */
static int move2add_luid;
+/* move2add_last_label_luid is set whenever a label is found. Labels
+ invalidate all previously collected reg_offset data. */
+static int move2add_last_label_luid;
+
/* Generate a CONST_INT and force it in the range of MODE. */
-static rtx
-gen_mode_int (mode, value)
+static HOST_WIDE_INT
+sext_for_mode (mode, value)
enum machine_mode mode;
HOST_WIDE_INT value;
{
&& (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
cval |= (HOST_WIDE_INT) -1 << width;
- return GEN_INT (cval);
+ return cval;
}
+/* ??? We don't know how zero / sign extension is handled, hence we
+ can't go from a narrower to a wider mode. */
+#define MODES_OK_FOR_MOVE2ADD(OUTMODE, INMODE) \
+ (GET_MODE_SIZE (OUTMODE) == GET_MODE_SIZE (INMODE) \
+ || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \
+ GET_MODE_BITSIZE (INMODE))))
+
static void
reload_cse_move2add (first)
rtx first;
{
int i;
rtx insn;
- int last_label_luid;
for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
reg_set_luid[i] = 0;
- last_label_luid = 0;
- move2add_luid = 1;
+ move2add_last_label_luid = 0;
+ move2add_luid = 2;
for (insn = first; insn; insn = NEXT_INSN (insn), move2add_luid++)
{
rtx pat, note;
if (GET_CODE (insn) == CODE_LABEL)
- last_label_luid = move2add_luid;
+ {
+ move2add_last_label_luid = move2add_luid;
+ /* We're going to increment move2add_luid twice after a
+ label, so that we can use move2add_last_label_luid + 1 as
+ the luid for constants. */
+ move2add_luid++;
+ continue;
+ }
if (! INSN_P (insn))
continue;
pat = PATTERN (insn);
/* Check if we have valid information on the contents of this
register in the mode of REG. */
- /* ??? We don't know how zero / sign extension is handled, hence
- we can't go from a narrower to a wider mode. */
- if (reg_set_luid[regno] > last_label_luid
- && ((GET_MODE_SIZE (GET_MODE (reg))
- == GET_MODE_SIZE (reg_mode[regno]))
- || ((GET_MODE_SIZE (GET_MODE (reg))
- <= GET_MODE_SIZE (reg_mode[regno]))
- && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (reg)),
- GET_MODE_BITSIZE (reg_mode[regno]))))
- && GET_CODE (reg_offset[regno]) == CONST_INT)
+ if (reg_set_luid[regno] > move2add_last_label_luid
+ && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]))
{
/* Try to transform (set (REGX) (CONST_INT A))
...
if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
{
int success = 0;
- rtx new_src
- = gen_mode_int (GET_MODE (reg),
- INTVAL (src) - INTVAL (reg_offset[regno]));
+ rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
+ INTVAL (src)
+ - reg_offset[regno]));
/* (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
gen_add2_insn (reg, new_src), 0);
reg_set_luid[regno] = move2add_luid;
reg_mode[regno] = GET_MODE (reg);
- reg_offset[regno] = src;
+ reg_offset[regno] = INTVAL (src);
continue;
}
...
(set (REGX) (plus (REGX) (CONST_INT B-A))) */
else if (GET_CODE (src) == REG
- && reg_base_reg[regno] == (int) REGNO (src)
- && reg_set_luid[regno] > reg_set_luid[REGNO (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),
+ reg_mode[REGNO (src)]))
{
rtx next = next_nonnote_insn (insn);
rtx set = NULL_RTX;
if (next)
set = single_set (next);
- if (next
- && set
+ if (set
&& SET_DEST (set) == reg
&& GET_CODE (SET_SRC (set)) == PLUS
&& XEXP (SET_SRC (set), 0) == reg
&& GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
{
rtx src3 = XEXP (SET_SRC (set), 1);
- rtx new_src
- = gen_mode_int (GET_MODE (reg),
- INTVAL (src3)
- - INTVAL (reg_offset[regno]));
+ HOST_WIDE_INT added_offset = INTVAL (src3);
+ HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
+ HOST_WIDE_INT regno_offset = reg_offset[regno];
+ rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
+ added_offset
+ + base_offset
+ - regno_offset));
int success = 0;
if (new_src == const0_rtx)
NOTE_SOURCE_FILE (insn) = 0;
}
insn = next;
- reg_set_luid[regno] = move2add_luid;
reg_mode[regno] = GET_MODE (reg);
- reg_offset[regno] = src3;
+ reg_offset[regno] = sext_for_mode (GET_MODE (reg),
+ added_offset
+ + base_offset);
continue;
}
}
if (REG_NOTE_KIND (note) == REG_INC
&& GET_CODE (XEXP (note, 0)) == REG)
{
- /* Indicate that this register has been recently written to,
- but the exact contents are not available. */
+ /* Reset the information about this register. */
int regno = REGNO (XEXP (note, 0));
if (regno < FIRST_PSEUDO_REGISTER)
- {
- reg_set_luid[regno] = move2add_luid;
- reg_offset[regno] = note;
- }
+ reg_set_luid[regno] = 0;
}
}
note_stores (PATTERN (insn), move2add_note_store, NULL);
for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
{
if (call_used_regs[i])
- {
- reg_set_luid[i] = move2add_luid;
- reg_offset[i] = insn; /* Invalidate contents. */
- }
+ /* Reset the information about this register. */
+ reg_set_luid[i] = 0;
}
}
}
if (GET_CODE (dst) == SUBREG)
{
- regno = SUBREG_WORD (dst);
+ regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
+ GET_MODE (SUBREG_REG (dst)),
+ SUBREG_BYTE (dst),
+ GET_MODE (dst));
dst = SUBREG_REG (dst);
}
dst = XEXP (dst, 0);
if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_DEC
|| GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC)
- {
- regno = REGNO (XEXP (dst, 0));
- reg_set_luid[regno] = move2add_luid;
- reg_offset[regno] = dst;
- }
+ reg_set_luid[REGNO (XEXP (dst, 0))] = 0;
return;
- }
+ }
if (GET_CODE (dst) != REG)
return;
&& GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
{
rtx src = SET_SRC (set);
+ rtx base_reg;
+ HOST_WIDE_INT offset;
+ int base_regno;
+ /* This may be different from mode, if SET_DEST (set) is a
+ SUBREG. */
+ enum machine_mode dst_mode = GET_MODE (dst);
- reg_mode[regno] = mode;
switch (GET_CODE (src))
{
case PLUS:
- {
- rtx src0 = XEXP (src, 0);
-
- if (GET_CODE (src0) == REG)
- {
- if (REGNO (src0) != regno
- || reg_offset[regno] != const0_rtx)
- {
- reg_base_reg[regno] = REGNO (src0);
- reg_set_luid[regno] = move2add_luid;
- }
+ if (GET_CODE (XEXP (src, 0)) == REG)
+ {
+ 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
+ && (reg_set_luid[REGNO (XEXP (src, 1))]
+ > move2add_last_label_luid)
+ && (MODES_OK_FOR_MOVE2ADD
+ (dst_mode, reg_mode[REGNO (XEXP (src, 1))])))
+ {
+ if (reg_base_reg[REGNO (XEXP (src, 1))] < 0)
+ offset = reg_offset[REGNO (XEXP (src, 1))];
+ /* Maybe the first register is known to be a
+ constant. */
+ else if (reg_set_luid[REGNO (base_reg)]
+ > move2add_last_label_luid
+ && (MODES_OK_FOR_MOVE2ADD
+ (dst_mode, reg_mode[REGNO (XEXP (src, 1))]))
+ && reg_base_reg[REGNO (base_reg)] < 0)
+ {
+ offset = reg_offset[REGNO (base_reg)];
+ base_reg = XEXP (src, 1);
+ }
+ else
+ goto invalidate;
+ }
+ else
+ goto invalidate;
- reg_offset[regno] = XEXP (src, 1);
- break;
- }
+ break;
+ }
- reg_set_luid[regno] = move2add_luid;
- reg_offset[regno] = set; /* Invalidate contents. */
- break;
- }
+ goto invalidate;
case REG:
- reg_base_reg[regno] = REGNO (SET_SRC (set));
- reg_offset[regno] = const0_rtx;
- reg_set_luid[regno] = move2add_luid;
+ base_reg = src;
+ offset = 0;
break;
- default:
+ case CONST_INT:
+ /* Start tracking the register as a constant. */
reg_base_reg[regno] = -1;
- reg_offset[regno] = SET_SRC (set);
- reg_set_luid[regno] = move2add_luid;
- break;
+ reg_offset[regno] = INTVAL (SET_SRC (set));
+ /* We assign the same luid to all registers set to constants. */
+ reg_set_luid[regno] = move2add_last_label_luid + 1;
+ reg_mode[regno] = mode;
+ return;
+
+ default:
+ invalidate:
+ /* Invalidate the contents of the register. */
+ reg_set_luid[regno] = 0;
+ return;
+ }
+
+ base_regno = REGNO (base_reg);
+ /* If information about the base register is not valid, set it
+ up as a new base register, pretending its value is known
+ starting from the current insn. */
+ if (reg_set_luid[base_regno] <= move2add_last_label_luid)
+ {
+ reg_base_reg[base_regno] = base_regno;
+ reg_offset[base_regno] = 0;
+ reg_set_luid[base_regno] = move2add_luid;
+ reg_mode[base_regno] = mode;
}
+ else if (! MODES_OK_FOR_MOVE2ADD (dst_mode,
+ reg_mode[base_regno]))
+ goto invalidate;
+
+ reg_mode[regno] = mode;
+
+ /* Copy base information from our base register. */
+ reg_set_luid[regno] = reg_set_luid[base_regno];
+ reg_base_reg[regno] = reg_base_reg[base_regno];
+
+ /* Compute the sum of the offsets or constants. */
+ reg_offset[regno] = sext_for_mode (dst_mode,
+ offset
+ + reg_offset[base_regno]);
}
else
{
unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
for (i = regno; i < endregno; i++)
- {
- /* Indicate that this register has been recently written to,
- but the exact contents are not available. */
- reg_set_luid[i] = move2add_luid;
- reg_offset[i] = dst;
- }
+ /* Reset the information about this register. */
+ reg_set_luid[i] = 0;
}
}
}
}
#endif
+
+/* Copy EH notes from an insn to its reloads. */
+static void
+copy_eh_notes (insn, x)
+ rtx insn;
+ rtx x;
+{
+ rtx eh_note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+ if (eh_note)
+ {
+ for (; x != 0; x = NEXT_INSN (x))
+ {
+ if (may_trap_p (PATTERN (x)))
+ REG_NOTES (x)
+ = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (eh_note, 0),
+ REG_NOTES (x));
+ }
+ }
+}
+