/* Reload pseudo regs into hard regs for insns that require hard regs.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "machmode.h"
#include "hard-reg-set.h"
int from; /* Register number to be eliminated. */
int to; /* Register number used as replacement. */
int initial_offset; /* Initial difference between values. */
- int can_eliminate; /* Non-zero if this elimination can be done. */
+ int can_eliminate; /* Nonzero if this elimination can be done. */
int can_eliminate_previous; /* Value of CAN_ELIMINATE in previous scan over
insns made by reload. */
int offset; /* Current offset between the two regs. */
/* For each label, we record the offset of each elimination. If we reach
a label by more than one path and an offset differs, we cannot do the
- elimination. This information is indexed by the number of the label.
- The first table is an array of flags that records whether we have yet
- encountered a label and the second table is an array of arrays, one
- entry in the latter array for each elimination. */
-
+ elimination. This information is indexed by the difference of the
+ number of the label and the first label number. We can't offset the
+ pointer itself as this can cause problems on machines with segmented
+ memory. The first table is an array of flags that records whether we
+ have yet encountered a label and the second table is an array of arrays,
+ one entry in the latter array for each elimination. */
+
+static int first_label_num;
static char *offsets_known_at;
static int (*offsets_at)[NUM_ELIMINABLE_REGS];
struct elim_table *ep;
basic_block bb;
- /* The two pointers used to track the true location of the memory used
- for label offsets. */
- char *real_known_ptr = NULL;
- int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
-
/* Make sure even insns with volatile mem refs are recognizable. */
init_recog ();
else if (LEGITIMATE_CONSTANT_P (x))
reg_equiv_constant[i] = x;
else
- reg_equiv_memory_loc[i]
- = force_const_mem (GET_MODE (SET_DEST (set)), x);
+ {
+ reg_equiv_memory_loc[i]
+ = force_const_mem (GET_MODE (SET_DEST (set)), x);
+ if (!reg_equiv_memory_loc[i])
+ continue;
+ }
}
else
continue;
init_elim_table ();
- num_labels = max_label_num () - get_first_label_num ();
+ first_label_num = get_first_label_num ();
+ num_labels = max_label_num () - first_label_num;
/* Allocate the tables used to store offset information at labels. */
/* We used to use alloca here, but the size of what it would try to
allocate would occasionally cause it to exceed the stack limit and
cause a core dump. */
- real_known_ptr = xmalloc (num_labels);
- real_at_ptr
+ offsets_known_at = xmalloc (num_labels);
+ offsets_at
= (int (*)[NUM_ELIMINABLE_REGS])
xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
- offsets_known_at = real_known_ptr - get_first_label_num ();
- offsets_at
- = (int (*)[NUM_ELIMINABLE_REGS]) (real_at_ptr - get_first_label_num ());
-
/* Alter each pseudo-reg rtx to contain its hard reg number.
Assign stack slots to the pseudos that lack hard regs or equivalents.
Do not touch virtual registers. */
free (reg_equiv_memory_loc);
reg_equiv_memory_loc = 0;
- if (real_known_ptr)
- free (real_known_ptr);
- if (real_at_ptr)
- free (real_at_ptr);
+ if (offsets_known_at)
+ free (offsets_known_at);
+ if (offsets_at)
+ free (offsets_at);
free (reg_equiv_mem);
free (reg_equiv_init);
for (;;)
{
- char c = *p++;
+ char c = *p;
if (c == '\0' || c == ',' || c == '#')
{
class, and reset the class. */
IOR_HARD_REG_SET (allowed, reg_class_contents[cls]);
cls = NO_REGS;
+ p++;
if (c == '#')
do {
c = *p++;
break;
default:
- if (EXTRA_ADDRESS_CONSTRAINT (c))
+ if (EXTRA_ADDRESS_CONSTRAINT (c, p))
cls = (int) reg_class_subunion[cls]
[(int) MODE_BASE_REG_CLASS (VOIDmode)];
else
cls = (int) reg_class_subunion[cls]
- [(int) REG_CLASS_FROM_LETTER (c)];
+ [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
}
+ p += CONSTRAINT_LEN (c, p);
}
}
/* Those of the registers which are clobbered, but allowed by the
/* If we have a decl for the original register, set it for the
memory. If this is a shared MEM, make a copy. */
- if (REGNO_DECL (i))
+ if (REG_EXPR (regno_reg_rtx[i])
+ && TREE_CODE_CLASS (TREE_CODE (REG_EXPR (regno_reg_rtx[i]))) == 'd')
{
- rtx decl = DECL_RTL_IF_SET (REGNO_DECL (i));
+ rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i]));
/* We can do this only for the DECLs home pseudo, not for
any copies of it, since otherwise when the stack slot
if (from_reg != -1 && spill_stack_slot[from_reg] == x)
x = copy_rtx (x);
- set_mem_expr (x, REGNO_DECL (i));
+ set_mem_attrs_from_reg (x, regno_reg_rtx[i]);
}
}
we guessed wrong, we will suppress an elimination that might have
been possible had we been able to guess correctly. */
- if (! offsets_known_at[CODE_LABEL_NUMBER (x)])
+ if (! offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num])
{
for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
- offsets_at[CODE_LABEL_NUMBER (x)][i]
+ offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
= (initial_p ? reg_eliminate[i].initial_offset
: reg_eliminate[i].offset);
- offsets_known_at[CODE_LABEL_NUMBER (x)] = 1;
+ offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num] = 1;
}
/* Otherwise, if this is the definition of a label and it is
where the offsets disagree. */
for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
- if (offsets_at[CODE_LABEL_NUMBER (x)][i]
+ if (offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
!= (initial_p ? reg_eliminate[i].initial_offset
: reg_eliminate[i].offset))
reg_eliminate[i].can_eliminate = 0;
case ABS:
case SQRT:
case FFS:
+ case CLZ:
+ case CTZ:
+ case POPCOUNT:
+ case PARITY:
new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
if (new != XEXP (x, 0))
return gen_rtx_fmt_e (code, GET_MODE (x), new);
case ABS:
case SQRT:
case FFS:
+ case CLZ:
+ case CTZ:
+ case POPCOUNT:
+ case PARITY:
elimination_effects (XEXP (x, 0), mem_mode);
return;
rtx old_set = single_set (insn);
rtx new_body;
int val = 0;
- int i, any_changes;
+ int i;
rtx substed_operand[MAX_RECOG_OPERANDS];
rtx orig_operand[MAX_RECOG_OPERANDS];
struct elim_table *ep;
/* Eliminate all eliminable registers occurring in operands that
can be handled by reload. */
extract_insn (insn);
- any_changes = 0;
for (i = 0; i < recog_data.n_operands; i++)
{
orig_operand[i] = recog_data.operand[i];
substed_operand[i] = eliminate_regs (recog_data.operand[i], 0,
replace ? insn : NULL_RTX);
if (substed_operand[i] != orig_operand[i])
- val = any_changes = 1;
+ val = 1;
/* Terminate the search in check_eliminable_occurrences at
this point. */
*recog_data.operand_loc[i] = 0;
insn. The changes we make were determined by the earlier call to
elimination_effects.
- We also detect a cases where register elimination cannot be done,
+ We also detect cases where register elimination cannot be done,
namely, if a register would be both changed and referenced outside a MEM
in the resulting insn since such an insn is often undefined and, even if
not, we cannot know what meaning will be given to it. Note that it is
set_initial_label_offsets ()
{
rtx x;
- memset ((char *) &offsets_known_at[get_first_label_num ()], 0, num_labels);
+ memset (offsets_known_at, 0, num_labels);
for (x = forced_labels; x; x = XEXP (x, 1))
if (XEXP (x, 0))
num_not_at_initial_offset = 0;
for (i = 0, ep = reg_eliminate; i < NUM_ELIMINABLE_REGS; ep++, i++)
{
- ep->offset = ep->previous_offset = offsets_at[label_nr][i];
+ ep->offset = ep->previous_offset
+ = offsets_at[label_nr - first_label_num][i];
if (ep->can_eliminate && ep->offset != ep->initial_offset)
num_not_at_initial_offset++;
}
update_eliminables (pset)
HARD_REG_SET *pset;
{
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
int previous_frame_pointer_needed = frame_pointer_needed;
-#endif
struct elim_table *ep;
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
}
}
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
/* If we didn't need a frame pointer last time, but we do now, spill
the hard frame pointer. */
if (frame_pointer_needed && ! previous_frame_pointer_needed)
SET_HARD_REG_BIT (*pset, HARD_FRAME_POINTER_REGNUM);
-#endif
}
/* Initialize the table of registers to eliminate. */
for (chain = reload_insn_chain; chain; chain = chain->next)
{
- rtx prev;
+ rtx prev = 0;
rtx insn = chain->insn;
rtx old_next = NEXT_INSN (insn);
REGNO (rld[i].reg_rtx))
/* Make sure it is the inc/dec pseudo, and not
some other (e.g. output operand) pseudo. */
- && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+ && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
== REGNO (XEXP (in_reg, 0))))
{
REGNO (rld[i].reg_rtx))
/* Make sure it is the inc/dec pseudo, and not
some other (e.g. output operand) pseudo. */
- && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+ && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
== REGNO (XEXP (in_reg, 0))))
{
SET_HARD_REG_BIT (reg_is_output_reload,
GET_MODE_CLASS (mode));
if (
-#ifdef CLASS_CANNOT_CHANGE_MODE
- (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], i)
- ? ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (last_reg),
- need_mode)
- : (GET_MODE_SIZE (GET_MODE (last_reg))
- >= GET_MODE_SIZE (need_mode)))
-#else
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg),
+ need_mode)
+ ||
+#endif
(GET_MODE_SIZE (GET_MODE (last_reg))
>= GET_MODE_SIZE (need_mode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ )
#endif
&& reg_reloaded_contents[i] == regno
&& TEST_HARD_REG_BIT (reg_reloaded_valid, i)
if (reload_override_in[j])
rld[j].in = reload_override_in[j];
- /* If this reload won't be done because it has been cancelled or is
+ /* If this reload won't be done because it has been canceled or is
optional and not inherited, clear reload_reg_rtx so other
routines (such as subst_reloads) don't get confused. */
for (j = 0; j < n_reloads; j++)
or memory. */
if (oldequiv != 0
- && ((REGNO_REG_CLASS (regno) != rl->class
+ && (((enum reg_class) REGNO_REG_CLASS (regno) != rl->class
&& (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
rl->class)
>= MEMORY_MOVE_COST (mode, rl->class, 1)))
struct reload *rl;
int j;
{
- int expect_occurrences = 1;
rtx insn = chain->insn;
rtx old = (rl->in && GET_CODE (rl->in) == MEM
? rl->in_reg : rl->in);
&& GET_CODE (rl->in_reg) == MEM
&& reload_spill_index[j] >= 0
&& TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
- {
- expect_occurrences
- = count_occurrences (PATTERN (insn), rl->in, 0) == 1 ? 0 : -1;
- rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
- }
+ rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
/* If we are reloading a register that was recently stored in with an
output-reload, see if we can prove there was
rtx i1;
rtx substed;
+ /* It is possible that this reload has been only used to set another reload
+ we eliminated earlier and thus deleted this instruction too. */
+ if (INSN_DELETED_P (output_reload_insn))
+ return;
+
/* Get the raw pseudo-register referred to. */
while (GET_CODE (reg) == SUBREG)
/* The caller has already checked that REG dies or is set in INSN.
It has also checked that we are optimizing, and thus some
- inaccurancies in the debugging information are acceptable.
+ inaccuracies in the debugging information are acceptable.
So we could just delete output_reload_insn. But in some cases
we can improve the debugging information without sacrificing
optimization - maybe even improving the code: See if the pseudo
return;
/* ??? We can't finish the loop here, because dst might be
allocated to a pseudo in this block if no reload in this
- block needs any of the clsses containing DST - see
+ block needs any of the classes containing DST - see
spill_hard_reg. There is no easy way to tell this, so we
have to scan till the end of the basic block. */
}
{
#ifdef LOAD_EXTEND_OP
if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
- && extend_op != NIL)
+ && extend_op != NIL
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+ word_mode,
+ REGNO_REG_CLASS (REGNO (SET_DEST (set))))
+#endif
+ )
{
rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
p = constraints[i];
for (;;)
{
- char c = *p++;
+ char c = *p;
switch (c)
{
default:
class
- = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER ((unsigned char) c)];
+ = (reg_class_subunion
+ [(int) class]
+ [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
break;
case ',': case '\0':
j++;
break;
}
+ p += CONSTRAINT_LEN (c, p);
if (c == '\0')
break;
\f
/* If reload couldn't use reg+reg+offset addressing, try to use reg+reg
addressing now.
- This code might also be useful when reload gave up on reg+reg addresssing
+ This code might also be useful when reload gave up on reg+reg addressing
because of clashes between the return register and INDEX_REG_CLASS. */
/* The maximum number of uses of a register we can keep track of to
last, of these uses.
STORE_RUID is always meaningful if we only want to use a value in a
register in a different place: it denotes the next insn in the insn
- stream (i.e. the last ecountered) that sets or clobbers the register. */
+ stream (i.e. the last encountered) that sets or clobbers the register. */
static struct
{
struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
static int reg_base_reg[FIRST_PSEUDO_REGISTER];
static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
-/* move2add_luid is linearily increased while scanning the instructions
+/* move2add_luid is linearly increased while scanning the instructions
from first to last. It is used to set reg_set_luid in
reload_cse_move2add and move2add_note_store. */
static int move2add_luid;
use (set (reg) (reg)) instead.
We don't delete this insn, nor do we convert it into a
note, to avoid losing register notes or the return
- value flag. jump2 already knowns how to get rid of
+ value flag. jump2 already knows how to get rid of
no-op moves. */
if (new_src == const0_rtx)
success = validate_change (insn, &SET_SRC (pat), reg, 0);
{
edge e;
- /* Look for cases we are interested in - an calls or instructions causing
+ /* Look for cases we are interested in - calls or instructions causing
exceptions. */
for (e = bb->succ; e; e = e->succ_next)
{
If it's placed after a trapping call (i.e. that
call is the last insn anyway), we have no fallthru
edge. Simply delete this use and don't try to insert
- on the non-existant edge. */
+ on the non-existent edge. */
if (GET_CODE (PATTERN (insn)) != USE)
{
/* We're not deleting it, we're moving it. */
}
}
}
+ /* We've possibly turned single trapping insn into multiple ones. */
+ if (flag_non_call_exceptions)
+ {
+ sbitmap blocks;
+ blocks = sbitmap_alloc (last_basic_block);
+ sbitmap_ones (blocks);
+ find_many_sub_basic_blocks (blocks);
+ }
if (inserted)
commit_edge_insertions ();
}