summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/reload1.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1999-08-26 09:30:50 +0000
committerobrien <obrien@FreeBSD.org>1999-08-26 09:30:50 +0000
commit0bedf4fb30066e5e1d4342a1d3914dae7d37cba7 (patch)
tree68d8110b41afd0ebbf39167b1a4918eea667a7c5 /contrib/gcc/reload1.c
parentd4db5fb866b7ad5216abd5047774a3973b9901a9 (diff)
downloadFreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.zip
FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.tar.gz
Virgin import of gcc from EGCS 1.1.2
Diffstat (limited to 'contrib/gcc/reload1.c')
-rw-r--r--contrib/gcc/reload1.c3002
1 files changed, 2415 insertions, 587 deletions
diff --git a/contrib/gcc/reload1.c b/contrib/gcc/reload1.c
index 33c77e4..c2987bb 100644
--- a/contrib/gcc/reload1.c
+++ b/contrib/gcc/reload1.c
@@ -1,5 +1,5 @@
/* Reload pseudo regs into hard regs for insns that require hard regs.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,8 +19,11 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
+
+#include "machmode.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "obstack.h"
#include "insn-config.h"
@@ -29,12 +32,12 @@ Boston, MA 02111-1307, USA. */
#include "flags.h"
#include "expr.h"
#include "regs.h"
-#include "hard-reg-set.h"
#include "reload.h"
#include "recog.h"
#include "basic-block.h"
#include "output.h"
#include "real.h"
+#include "toplev.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
@@ -73,13 +76,9 @@ Boston, MA 02111-1307, USA. */
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
#endif
-
-#ifndef MEMORY_MOVE_COST
-#define MEMORY_MOVE_COST(x) 4
-#endif
/* During reload_as_needed, element N contains a REG rtx for the hard reg
- into which reg N has been reloaded (perhaps for a previous insn). */
+ into which reg N has been reloaded (perhaps for a previous insn). */
static rtx *reg_last_reload_reg;
/* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn
@@ -118,19 +117,23 @@ static int *reg_max_ref_width;
constant or memory slot. */
static rtx *reg_equiv_init;
-/* During reload_as_needed, element N contains the last pseudo regno
- reloaded into the Nth reload register. This vector is in parallel
- with spill_regs. If that pseudo reg occupied more than one register,
+/* During reload_as_needed, element N contains the last pseudo regno reloaded
+ into hard register N. If that pseudo reg occupied more than one register,
reg_reloaded_contents points to that pseudo for each spill register in
use; all of these must remain set for an inheritance to occur. */
static int reg_reloaded_contents[FIRST_PSEUDO_REGISTER];
/* During reload_as_needed, element N contains the insn for which
- the Nth reload register was last used. This vector is in parallel
- with spill_regs, and its contents are significant only when
- reg_reloaded_contents is significant. */
+ hard register N was last used. Its contents are significant only
+ when reg_reloaded_valid is set for this register. */
static rtx reg_reloaded_insn[FIRST_PSEUDO_REGISTER];
+/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
+static HARD_REG_SET reg_reloaded_valid;
+/* Indicate if the register was dead at the end of the reload.
+ This is only valid if reg_reloaded_contents is set and valid. */
+static HARD_REG_SET reg_reloaded_dead;
+
/* Number of spill-regs so far; number of valid elements of spill_regs. */
static int n_spills;
@@ -159,7 +162,7 @@ HARD_REG_SET forbidden_regs;
/* This reg set indicates registers that are not good for spill registers.
They will not be used to complete groups of spill registers. This includes
all fixed registers, registers that may be eliminated, and, if
- SMALL_REGISTER_CLASSES is not defined, registers explicitly used in the rtl.
+ SMALL_REGISTER_CLASSES is zero, registers explicitly used in the rtl.
(spill_reg_order prevents these registers from being used to start a
group.) */
@@ -170,6 +173,13 @@ static HARD_REG_SET bad_spill_regs;
elements that are actually valid; new ones are added at the end. */
static short spill_regs[FIRST_PSEUDO_REGISTER];
+/* This reg set indicates those registers that have been used a spill
+ registers. This information is used in reorg.c, to help figure out
+ what registers are live at any point. It is assumed that all spill_regs
+ are dead at every CODE_LABEL. */
+
+HARD_REG_SET used_spill_regs;
+
/* Index of last register assigned as a spill register. We allocate in
a round-robin fashion. */
@@ -197,12 +207,6 @@ static HARD_REG_SET counted_for_groups;
as part of a group, even if it seems to be otherwise ok. */
static HARD_REG_SET counted_for_nongroups;
-/* Indexed by pseudo reg number N,
- says may not delete stores into the real (memory) home of pseudo N.
- This is set if we already substituted a memory equivalent in some uses,
- which happens when we have to eliminate the fp from it. */
-static char *cannot_omit_stores;
-
/* Nonzero if indirect addressing is supported on the machine; this means
that spilling (REG n) does not require reloading it into a register in
order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))). The
@@ -246,6 +250,18 @@ int reload_first_uid;
int caller_save_needed;
+/* The register class to use for a base register when reloading an
+ address. This is normally BASE_REG_CLASS, but it may be different
+ when using SMALL_REGISTER_CLASSES and passing parameters in
+ registers. */
+enum reg_class reload_address_base_reg_class;
+
+/* The register class to use for an index register when reloading an
+ address. This is normally INDEX_REG_CLASS, but it may be different
+ when using SMALL_REGISTER_CLASSES and passing parameters in
+ registers. */
+enum reg_class reload_address_index_reg_class;
+
/* Set to 1 while reload_as_needed is operating.
Required by some machines to handle any generated moves differently. */
@@ -270,6 +286,9 @@ char *reload_firstobj;
/* List of labels that must never be deleted. */
extern rtx forced_labels;
+
+/* Allocation number table from global register allocation. */
+extern int *reg_allocno;
/* This structure is used to record information about register eliminations.
Each array entry describes one possible way of eliminating a register
@@ -278,22 +297,22 @@ extern rtx forced_labels;
static struct elim_table
{
- 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 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_previous; /* Value of CAN_ELIMINATE in previous scan over
- insns made by reload. */
- int offset; /* Current offset between the two regs. */
- int max_offset; /* Maximum offset between the two regs. */
- int previous_offset; /* Offset at end of previous insn. */
- int ref_outside_mem; /* "to" has been referenced outside a MEM. */
+ insns made by reload. */
+ int offset; /* Current offset between the two regs. */
+ int max_offset; /* Maximum offset between the two regs. */
+ int previous_offset; /* Offset at end of previous insn. */
+ int ref_outside_mem; /* "to" has been referenced outside a MEM. */
rtx from_rtx; /* REG rtx for the register to be eliminated.
We cannot simply compare the number since
we might then spuriously replace a hard
register corresponding to a pseudo
- assigned to the reg to be eliminated. */
- rtx to_rtx; /* REG rtx for the replacement. */
+ assigned to the reg to be eliminated. */
+ rtx to_rtx; /* REG rtx for the replacement. */
} reg_eliminate[] =
/* If a set of eliminable registers was specified, define the table from it.
@@ -349,21 +368,20 @@ static int eliminate_regs_in_insn PROTO((rtx, int));
static void mark_not_eliminable PROTO((rtx, rtx));
static int spill_hard_reg PROTO((int, int, FILE *, int));
static void scan_paradoxical_subregs PROTO((rtx));
-static int hard_reg_use_compare PROTO((struct hard_reg_n_uses *,
- struct hard_reg_n_uses *));
-static void order_regs_for_reload PROTO((void));
-static int compare_spill_regs PROTO((short *, short *));
+static int hard_reg_use_compare PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void order_regs_for_reload PROTO((int));
+static int compare_spill_regs PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void reload_as_needed PROTO((rtx, int));
static void forget_old_reloads_1 PROTO((rtx, rtx));
-static int reload_reg_class_lower PROTO((short *, short *));
+static int reload_reg_class_lower PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void mark_reload_reg_in_use PROTO((int, int, enum reload_type,
enum machine_mode));
static void clear_reload_reg_in_use PROTO((int, int, enum reload_type,
enum machine_mode));
static int reload_reg_free_p PROTO((int, int, enum reload_type));
static int reload_reg_free_before_p PROTO((int, int, enum reload_type));
+static int reload_reg_free_for_value_p PROTO((int, int, enum reload_type, rtx, rtx, int));
static int reload_reg_reaches_end_p PROTO((int, int, enum reload_type));
-static int reloads_conflict PROTO((int, int));
static int allocate_reload_reg PROTO((int, rtx, int, int));
static void choose_reload_regs PROTO((rtx, rtx));
static void merge_assigned_reloads PROTO((rtx));
@@ -371,7 +389,18 @@ static void emit_reload_insns PROTO((rtx));
static void delete_output_reload PROTO((rtx, int, rtx));
static void inc_for_reload PROTO((rtx, rtx, int));
static int constraint_accepts_reg_p PROTO((char *, rtx));
-static int count_occurrences PROTO((rtx, rtx));
+static void reload_cse_invalidate_regno PROTO((int, enum machine_mode, int));
+static int reload_cse_mem_conflict_p PROTO((rtx, rtx));
+static void reload_cse_invalidate_mem PROTO((rtx));
+static void reload_cse_invalidate_rtx PROTO((rtx, rtx));
+static int reload_cse_regno_equal_p PROTO((int, rtx, enum machine_mode));
+static int reload_cse_noop_set_p PROTO((rtx, rtx));
+static int reload_cse_simplify_set PROTO((rtx, rtx));
+static int reload_cse_simplify_operands PROTO((rtx));
+static void reload_cse_check_clobber PROTO((rtx, rtx));
+static void reload_cse_record_set PROTO((rtx, rtx));
+static void reload_cse_delete_death_notes PROTO((rtx));
+static void reload_cse_no_longer_dead PROTO((int, enum machine_mode));
/* Initialize the reload pass once per compilation. */
@@ -385,30 +414,30 @@ init_reload ()
permitted, zero if it is not permitted at all. */
register rtx tem
- = gen_rtx (MEM, Pmode,
- gen_rtx (PLUS, Pmode,
- gen_rtx (REG, Pmode, LAST_VIRTUAL_REGISTER + 1),
- GEN_INT (4)));
+ = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ gen_rtx_REG (Pmode, LAST_VIRTUAL_REGISTER + 1),
+ GEN_INT (4)));
spill_indirect_levels = 0;
while (memory_address_p (QImode, tem))
{
spill_indirect_levels++;
- tem = gen_rtx (MEM, Pmode, tem);
+ tem = gen_rtx_MEM (Pmode, tem);
}
/* See if indirect addressing is valid for (MEM (SYMBOL_REF ...)). */
- tem = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, Pmode, "foo"));
+ tem = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (Pmode, "foo"));
indirect_symref_ok = memory_address_p (QImode, tem);
/* See if reg+reg is a valid (and offsettable) address. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
- tem = gen_rtx (PLUS, Pmode,
- gen_rtx (REG, Pmode, HARD_FRAME_POINTER_REGNUM),
- gen_rtx (REG, Pmode, i));
+ tem = gen_rtx_PLUS (Pmode,
+ gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),
+ gen_rtx_REG (Pmode, i));
/* This way, we make sure that reg+reg is an offsettable address. */
tem = plus_constant (tem, 4);
@@ -419,9 +448,67 @@ init_reload ()
}
}
- /* Initialize obstack for our rtl allocation. */
+ /* Initialize obstack for our rtl allocation. */
gcc_obstack_init (&reload_obstack);
reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+ /* Decide which register class should be used when reloading
+ addresses. If we are using SMALL_REGISTER_CLASSES, and any
+ parameters are passed in registers, then we do not want to use
+ those registers when reloading an address. Otherwise, if a
+ function argument needs a reload, we may wind up clobbering
+ another argument to the function which was already computed. If
+ we find a subset class which simply avoids those registers, we
+ use it instead. ??? It would be better to only use the
+ restricted class when we actually are loading function arguments,
+ but that is hard to determine. */
+ reload_address_base_reg_class = BASE_REG_CLASS;
+ reload_address_index_reg_class = INDEX_REG_CLASS;
+ if (SMALL_REGISTER_CLASSES)
+ {
+ int regno;
+ HARD_REG_SET base, index;
+ enum reg_class *p;
+
+ COPY_HARD_REG_SET (base, reg_class_contents[BASE_REG_CLASS]);
+ COPY_HARD_REG_SET (index, reg_class_contents[INDEX_REG_CLASS]);
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (FUNCTION_ARG_REGNO_P (regno))
+ {
+ CLEAR_HARD_REG_BIT (base, regno);
+ CLEAR_HARD_REG_BIT (index, regno);
+ }
+ }
+
+ GO_IF_HARD_REG_EQUAL (base, reg_class_contents[BASE_REG_CLASS],
+ baseok);
+ for (p = reg_class_subclasses[BASE_REG_CLASS];
+ *p != LIM_REG_CLASSES;
+ p++)
+ {
+ GO_IF_HARD_REG_EQUAL (base, reg_class_contents[*p], usebase);
+ continue;
+ usebase:
+ reload_address_base_reg_class = *p;
+ break;
+ }
+ baseok:;
+
+ GO_IF_HARD_REG_EQUAL (index, reg_class_contents[INDEX_REG_CLASS],
+ indexok);
+ for (p = reg_class_subclasses[INDEX_REG_CLASS];
+ *p != LIM_REG_CLASSES;
+ p++)
+ {
+ GO_IF_HARD_REG_EQUAL (index, reg_class_contents[*p], useindex);
+ continue;
+ useindex:
+ reload_address_index_reg_class = *p;
+ break;
+ }
+ indexok:;
+ }
}
/* Main entry point for the reload pass.
@@ -453,6 +540,11 @@ reload (first, global, dumpfile)
register rtx insn;
register struct elim_table *ep;
+ /* The two pointers used to track the true location of the memory used
+ for label offsets. */
+ char *real_known_ptr = NULL_PTR;
+ int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
+
int something_changed;
int something_needs_reloads;
int something_needs_elimination;
@@ -497,10 +589,18 @@ reload (first, global, dumpfile)
as homes for pseudo registers.
This is done here rather than (eg) in global_alloc
because this point is reached even if not optimizing. */
-
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
mark_home_live (i);
+ /* A function that receives a nonlocal goto must save all call-saved
+ registers. */
+ if (current_function_has_nonlocal_label)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (! call_used_regs[i] && ! fixed_regs[i])
+ regs_ever_live[i] = 1;
+ }
+
for (i = 0; i < scratch_list_length; i++)
if (scratch_list[i])
mark_scratch_live (scratch_list[i]);
@@ -531,22 +631,27 @@ reload (first, global, dumpfile)
bzero ((char *) reg_equiv_address, max_regno * sizeof (rtx));
reg_max_ref_width = (int *) alloca (max_regno * sizeof (int));
bzero ((char *) reg_max_ref_width, max_regno * sizeof (int));
- cannot_omit_stores = (char *) alloca (max_regno);
- bzero (cannot_omit_stores, max_regno);
-#ifdef SMALL_REGISTER_CLASSES
- CLEAR_HARD_REG_SET (forbidden_regs);
-#endif
+ if (SMALL_REGISTER_CLASSES)
+ CLEAR_HARD_REG_SET (forbidden_regs);
/* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
Also find all paradoxical subregs and find largest such for each pseudo.
On machines with small register classes, record hard registers that
- are used for user variables. These can never be used for spills. */
+ are used for user variables. These can never be used for spills.
+ Also look for a "constant" NOTE_INSN_SETJMP. This means that all
+ caller-saved registers must be marked live. */
for (insn = first; insn; insn = NEXT_INSN (insn))
{
rtx set = single_set (insn);
+ if (GET_CODE (insn) == NOTE && CONST_CALL_P (insn)
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! call_used_regs[i])
+ regs_ever_live[i] = 1;
+
if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
{
rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
@@ -562,7 +667,14 @@ reload (first, global, dumpfile)
if (i > LAST_VIRTUAL_REGISTER)
{
if (GET_CODE (x) == MEM)
- reg_equiv_memory_loc[i] = x;
+ {
+ /* If the operand is a PLUS, the MEM may be shared,
+ so make sure we have an unshared copy here. */
+ if (GET_CODE (XEXP (x, 0)) == PLUS)
+ x = copy_rtx (x);
+
+ reg_equiv_memory_loc[i] = x;
+ }
else if (CONSTANT_P (x))
{
if (LEGITIMATE_CONSTANT_P (x))
@@ -635,20 +747,24 @@ reload (first, global, dumpfile)
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
{
num_eliminable += ep->can_eliminate;
- ep->from_rtx = gen_rtx (REG, Pmode, ep->from);
- ep->to_rtx = gen_rtx (REG, Pmode, ep->to);
+ ep->from_rtx = gen_rtx_REG (Pmode, ep->from);
+ ep->to_rtx = gen_rtx_REG (Pmode, ep->to);
}
num_labels = max_label_num () - get_first_label_num ();
/* Allocate the tables used to store offset information at labels. */
- offsets_known_at = (char *) alloca (num_labels);
- offsets_at
+ /* 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
= (int (*)[NUM_ELIMINABLE_REGS])
- alloca (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
+ xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
- offsets_known_at -= get_first_label_num ();
- offsets_at -= get_first_label_num ();
+ 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.
@@ -657,11 +773,6 @@ reload (first, global, dumpfile)
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
alter_reg (i, -1);
- /* Round size of stack frame to BIGGEST_ALIGNMENT. This must be done here
- because the stack size may be a part of the offset computation for
- register elimination. */
- assign_stack_local (BLKmode, 0, 0);
-
/* If we have some registers we think can be eliminated, scan all insns to
see if there is an insn that sets one of these registers to something
other than itself plus a constant. If so, the register cannot be
@@ -681,17 +792,21 @@ reload (first, global, dumpfile)
in that case some pseudos might be in the wrong kind of hard reg. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_renumber[i] == -1 && reg_n_refs[i] != 0)
+ if (reg_renumber[i] == -1 && REG_N_REFS (i) != 0)
break;
if (i == max_regno && num_eliminable == 0 && ! caller_save_needed)
- return;
+ {
+ free (real_known_ptr);
+ free (real_at_ptr);
+ return;
+ }
#endif
/* Compute the order of preference for hard registers to spill.
Store them by decreasing preference in potential_reload_regs. */
- order_regs_for_reload ();
+ order_regs_for_reload (global);
/* So far, no hard regs have been spilled. */
n_spills = 0;
@@ -705,9 +820,8 @@ reload (first, global, dumpfile)
rtl as a spill register. But on some, we have to. Those will have
taken care to keep the life of hard regs as short as possible. */
-#ifndef SMALL_REGISTER_CLASSES
- COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
-#endif
+ if (! SMALL_REGISTER_CLASSES)
+ COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
/* Spill any hard regs that we know we can't eliminate. */
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -770,8 +884,10 @@ reload (first, global, dumpfile)
rtx max_groups_insn[N_REG_CLASSES];
rtx max_nongroups_insn[N_REG_CLASSES];
rtx x;
- int starting_frame_size = get_frame_size ();
+ HOST_WIDE_INT starting_frame_size;
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
int previous_frame_pointer_needed = frame_pointer_needed;
+#endif
static char *reg_class_names[] = REG_CLASS_NAMES;
something_changed = 0;
@@ -792,6 +908,14 @@ reload (first, global, dumpfile)
changes from 0 to 1 in this pass. */
new_basic_block_needs = 0;
+ /* Round size of stack frame to BIGGEST_ALIGNMENT. This must be done
+ here because the stack size may be a part of the offset computation
+ for register elimination, and there might have been new stack slots
+ created in the last iteration of this loop. */
+ assign_stack_local (BLKmode, 0, 0);
+
+ starting_frame_size = get_frame_size ();
+
/* Reset all offsets on eliminable registers to their initial values. */
#ifdef ELIMINABLE_REGS
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -959,17 +1083,18 @@ reload (first, global, dumpfile)
struct needs op_addr;
struct needs op_addr_reload;
struct needs in_addr[MAX_RECOG_OPERANDS];
+ struct needs in_addr_addr[MAX_RECOG_OPERANDS];
struct needs out_addr[MAX_RECOG_OPERANDS];
+ struct needs out_addr_addr[MAX_RECOG_OPERANDS];
} insn_needs;
/* If needed, eliminate any eliminable registers. */
if (num_eliminable)
did_elimination = eliminate_regs_in_insn (insn, 0);
-#ifdef SMALL_REGISTER_CLASSES
/* Set avoid_return_reg if this is an insn
that might use the value of a function call. */
- if (GET_CODE (insn) == CALL_INSN)
+ if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
{
if (GET_CODE (PATTERN (insn)) == SET)
after_call = SET_DEST (PATTERN (insn));
@@ -979,15 +1104,15 @@ reload (first, global, dumpfile)
else
after_call = 0;
}
- else if (after_call != 0
+ else if (SMALL_REGISTER_CLASSES && after_call != 0
&& !(GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
+ && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
+ && GET_CODE (PATTERN (insn)) != USE)
{
if (reg_referenced_p (after_call, PATTERN (insn)))
avoid_return_reg = after_call;
after_call = 0;
}
-#endif /* SMALL_REGISTER_CLASSES */
/* Analyze the instruction. */
find_reloads (insn, 0, spill_indirect_levels, global,
@@ -1043,7 +1168,6 @@ reload (first, global, dumpfile)
enum reg_class class = reload_reg_class[i];
int size;
enum machine_mode mode;
- int nongroup_need;
struct needs *this_needs;
/* Don't count the dummy reloads, for which one of the
@@ -1066,37 +1190,11 @@ reload (first, global, dumpfile)
new_basic_block_needs = 1;
}
-
mode = reload_inmode[i];
if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
mode = reload_outmode[i];
size = CLASS_MAX_NREGS (class, mode);
- /* If this class doesn't want a group, determine if we have
- a nongroup need or a regular need. We have a nongroup
- need if this reload conflicts with a group reload whose
- class intersects with this reload's class. */
-
- nongroup_need = 0;
- if (size == 1)
- for (j = 0; j < n_reloads; j++)
- if ((CLASS_MAX_NREGS (reload_reg_class[j],
- (GET_MODE_SIZE (reload_outmode[j])
- > GET_MODE_SIZE (reload_inmode[j]))
- ? reload_outmode[j]
- : reload_inmode[j])
- > 1)
- && (!reload_optional[j])
- && (reload_in[j] != 0 || reload_out[j] != 0
- || reload_secondary_p[j])
- && reloads_conflict (i, j)
- && reg_classes_intersect_p (class,
- reload_reg_class[j]))
- {
- nongroup_need = 1;
- break;
- }
-
/* Decide which time-of-use to count this reload for. */
switch (reload_when_needed[i])
{
@@ -1118,9 +1216,15 @@ reload (first, global, dumpfile)
case RELOAD_FOR_INPUT_ADDRESS:
this_needs = &insn_needs.in_addr[reload_opnum[i]];
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ this_needs = &insn_needs.in_addr_addr[reload_opnum[i]];
+ break;
case RELOAD_FOR_OUTPUT_ADDRESS:
this_needs = &insn_needs.out_addr[reload_opnum[i]];
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ this_needs = &insn_needs.out_addr_addr[reload_opnum[i]];
+ break;
case RELOAD_FOR_OPERAND_ADDRESS:
this_needs = &insn_needs.op_addr;
break;
@@ -1168,10 +1272,10 @@ reload (first, global, dumpfile)
}
else if (size == 1)
{
- this_needs->regs[nongroup_need][(int) class] += 1;
+ this_needs->regs[reload_nongroup[i]][(int) class] += 1;
p = reg_class_superclasses[(int) class];
while (*p != LIM_REG_CLASSES)
- this_needs->regs[nongroup_need][(int) *p++] += 1;
+ this_needs->regs[reload_nongroup[i]][(int) *p++] += 1;
}
else
abort ();
@@ -1193,16 +1297,21 @@ reload (first, global, dumpfile)
k < reload_n_operands; k++)
{
in_max
- = MAX (in_max, insn_needs.in_addr[k].regs[j][i]);
+ = MAX (in_max,
+ (insn_needs.in_addr[k].regs[j][i]
+ + insn_needs.in_addr_addr[k].regs[j][i]));
out_max
= MAX (out_max, insn_needs.out_addr[k].regs[j][i]);
+ out_max
+ = MAX (out_max,
+ insn_needs.out_addr_addr[k].regs[j][i]);
}
/* RELOAD_FOR_INSN reloads conflict with inputs, outputs,
and operand addresses but not things used to reload
them. Similarly, RELOAD_FOR_OPERAND_ADDRESS reloads
don't conflict with things needed to reload inputs or
- outputs. */
+ outputs. */
in_max = MAX (MAX (insn_needs.op_addr.regs[j][i],
insn_needs.op_addr_reload.regs[j][i]),
@@ -1229,8 +1338,12 @@ reload (first, global, dumpfile)
j < reload_n_operands; j++)
{
in_max = MAX (in_max, insn_needs.in_addr[j].groups[i]);
+ in_max = MAX (in_max,
+ insn_needs.in_addr_addr[j].groups[i]);
out_max
= MAX (out_max, insn_needs.out_addr[j].groups[i]);
+ out_max
+ = MAX (out_max, insn_needs.out_addr_addr[j].groups[i]);
}
in_max = MAX (MAX (insn_needs.op_addr.groups[i],
@@ -1270,20 +1383,21 @@ reload (first, global, dumpfile)
if (GET_CODE (insn) == CALL_INSN
&& caller_save_spill_class != NO_REGS)
{
- /* See if this register would conflict with any reload
- that needs a group. */
+ /* See if this register would conflict with any reload that
+ needs a group or any reload that needs a nongroup. */
int nongroup_need = 0;
int *caller_save_needs;
for (j = 0; j < n_reloads; j++)
- if ((CLASS_MAX_NREGS (reload_reg_class[j],
- (GET_MODE_SIZE (reload_outmode[j])
- > GET_MODE_SIZE (reload_inmode[j]))
- ? reload_outmode[j]
- : reload_inmode[j])
- > 1)
- && reg_classes_intersect_p (caller_save_spill_class,
- reload_reg_class[j]))
+ if (reg_classes_intersect_p (caller_save_spill_class,
+ reload_reg_class[j])
+ && ((CLASS_MAX_NREGS
+ (reload_reg_class[j],
+ (GET_MODE_SIZE (reload_outmode[j])
+ > GET_MODE_SIZE (reload_inmode[j]))
+ ? reload_outmode[j] : reload_inmode[j])
+ > 1)
+ || reload_nongroup[j]))
{
nongroup_need = 1;
break;
@@ -1318,16 +1432,15 @@ reload (first, global, dumpfile)
}
}
-#ifdef SMALL_REGISTER_CLASSES
/* If this insn stores the value of a function call,
and that value is in a register that has been spilled,
and if the insn needs a reload in a class
that might use that register as the reload register,
- then add add an extra need in that class.
+ then add an extra need in that class.
This makes sure we have a register available that does
not overlap the return value. */
- if (avoid_return_reg)
+ if (SMALL_REGISTER_CLASSES && avoid_return_reg)
{
int regno = REGNO (avoid_return_reg);
int nregs
@@ -1360,7 +1473,7 @@ reload (first, global, dumpfile)
}
/* Now count extra regs if there might be a conflict with
- the return value register. */
+ the return value register. */
for (r = regno; r < regno + nregs; r++)
if (spill_reg_order[r] >= 0)
@@ -1387,7 +1500,6 @@ reload (first, global, dumpfile)
}
}
}
-#endif /* SMALL_REGISTER_CLASSES */
/* For each class, collect maximum need of any insn. */
@@ -1442,19 +1554,26 @@ reload (first, global, dumpfile)
/* If we have caller-saves, set up the save areas and see if caller-save
will need a spill register. */
- if (caller_save_needed
- && ! setup_save_areas (&something_changed)
- && caller_save_spill_class == NO_REGS)
+ if (caller_save_needed)
{
- /* The class we will need depends on whether the machine
- supports the sum of two registers for an address; see
- find_address_reloads for details. */
-
- caller_save_spill_class
- = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
- caller_save_group_size
- = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
- something_changed = 1;
+ /* Set the offsets for setup_save_areas. */
+ for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+ ep++)
+ ep->previous_offset = ep->max_offset;
+
+ if ( ! setup_save_areas (&something_changed)
+ && caller_save_spill_class == NO_REGS)
+ {
+ /* The class we will need depends on whether the machine
+ supports the sum of two registers for an address; see
+ find_address_reloads for details. */
+
+ caller_save_spill_class
+ = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
+ caller_save_group_size
+ = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
+ something_changed = 1;
+ }
}
/* See if anything that happened changes which eliminations are valid.
@@ -1676,9 +1795,8 @@ reload (first, global, dumpfile)
}
}
/* We can't complete a group, so start one. */
-#ifdef SMALL_REGISTER_CLASSES
/* Look for a pair neither of which is explicitly used. */
- if (i == FIRST_PSEUDO_REGISTER)
+ if (SMALL_REGISTER_CLASSES && i == FIRST_PSEUDO_REGISTER)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int k;
@@ -1701,7 +1819,6 @@ reload (first, global, dumpfile)
&& ! regs_explicitly_used[j + 1])
break;
}
-#endif
/* Now try any group at all
whose registers are not in bad_spill_regs. */
if (i == FIRST_PSEUDO_REGISTER)
@@ -1808,10 +1925,6 @@ reload (first, global, dumpfile)
while (max_needs[class] > 0 || max_nongroups[class] > 0)
{
-#ifdef SMALL_REGISTER_CLASSES
- /* This should be right for all machines, but only the 386
- is known to need it, so this conditional plays safe.
- ??? For 2.5, try making this unconditional. */
/* If we spilled enough regs, but they weren't counted
against the non-group need, see if we can count them now.
If so, we can avoid some actual spilling. */
@@ -1835,7 +1948,6 @@ reload (first, global, dumpfile)
}
if (max_needs[class] <= 0 && max_nongroups[class] <= 0)
break;
-#endif
/* Consider the potential reload regs that aren't
yet in use as reload regs, in order of preference.
@@ -1945,9 +2057,8 @@ reload (first, global, dumpfile)
if (! frame_pointer_needed)
for (i = 0; i < n_basic_blocks; i++)
- basic_block_live_at_start[i][HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- &= ~ ((REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
- % REGSET_ELT_BITS));
+ CLEAR_REGNO_REG_SET (basic_block_live_at_start[i],
+ HARD_FRAME_POINTER_REGNUM);
/* Come here (with failure set nonzero) if we can't get enough spill regs
and we decide not to abort about it. */
@@ -1969,13 +2080,20 @@ reload (first, global, dumpfile)
{
rtx addr = 0;
int in_struct = 0;
- if (reg_equiv_mem[i])
+ int is_readonly = 0;
+
+ if (reg_equiv_memory_loc[i])
{
- addr = XEXP (reg_equiv_mem[i], 0);
- in_struct = MEM_IN_STRUCT_P (reg_equiv_mem[i]);
+ in_struct = MEM_IN_STRUCT_P (reg_equiv_memory_loc[i]);
+ is_readonly = RTX_UNCHANGING_P (reg_equiv_memory_loc[i]);
}
+
+ if (reg_equiv_mem[i])
+ addr = XEXP (reg_equiv_mem[i], 0);
+
if (reg_equiv_address[i])
addr = reg_equiv_address[i];
+
if (addr)
{
if (reg_renumber[i] < 0)
@@ -1983,7 +2101,11 @@ reload (first, global, dumpfile)
rtx reg = regno_reg_rtx[i];
XEXP (reg, 0) = addr;
REG_USERVAR_P (reg) = 0;
+ RTX_UNCHANGING_P (reg) = is_readonly;
MEM_IN_STRUCT_P (reg) = in_struct;
+ /* We have no alias information about this newly created
+ MEM. */
+ MEM_ALIAS_SET (reg) = 0;
PUT_CODE (reg, MEM);
}
else if (reg_equiv_mem[i])
@@ -1991,16 +2113,28 @@ reload (first, global, dumpfile)
}
}
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- /* Make a pass over all the insns and remove death notes for things that
- are no longer registers or no longer die in the insn (e.g., an input
- and output pseudo being tied). */
+ /* Make a pass over all the insns and delete all USEs which we inserted
+ only to tag a REG_EQUAL note on them; if PRESERVE_DEATH_INFO_REGNO_P
+ is defined, also remove death notes for things that are no longer
+ registers or no longer die in the insn (e.g., an input and output
+ pseudo being tied). */
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
rtx note, next;
+#endif
+ if (GET_CODE (PATTERN (insn)) == USE
+ && find_reg_note (insn, REG_EQUAL, NULL_RTX))
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_SOURCE_FILE (insn) = 0;
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ continue;
+ }
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
for (note = REG_NOTES (insn); note; note = next)
{
next = XEXP (note, 1);
@@ -2009,13 +2143,32 @@ reload (first, global, dumpfile)
|| reg_set_p (XEXP (note, 0), PATTERN (insn))))
remove_note (insn, note);
}
- }
#endif
+ }
+
+ /* If we are doing stack checking, give a warning if this function's
+ frame size is larger than we expect. */
+ if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+ {
+ HOST_WIDE_INT size = get_frame_size () + STACK_CHECK_FIXED_FRAME_SIZE;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (regs_ever_live[i] && ! fixed_regs[i] && call_used_regs[i])
+ size += UNITS_PER_WORD;
+ if (size > STACK_CHECK_MAX_FRAME_SIZE)
+ warning ("frame size too large for reliable stack checking");
+ }
+
/* Indicate that we no longer have known memory locations or constants. */
reg_equiv_constant = 0;
reg_equiv_memory_loc = 0;
+ if (real_known_ptr)
+ free (real_known_ptr);
+ if (real_at_ptr)
+ free (real_at_ptr);
+
if (scratch_list)
free (scratch_list);
scratch_list = 0;
@@ -2023,6 +2176,10 @@ reload (first, global, dumpfile)
free (scratch_block);
scratch_block = 0;
+ CLEAR_HARD_REG_SET (used_spill_regs);
+ for (i = 0; i < n_spills; i++)
+ SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]);
+
return failure;
}
@@ -2219,9 +2376,12 @@ new_spill_reg (i, class, max_needs, max_nongroups, global, dumpfile)
abort (); /* Caller failed to find any register. */
if (fixed_regs[regno] || TEST_HARD_REG_BIT (forbidden_regs, regno))
- fatal ("fixed or forbidden register was spilled.\n\
+ {
+ static char *reg_class_names[] = REG_CLASS_NAMES;
+ fatal ("fixed or forbidden register %d (%s) was spilled for class %s.\n\
This may be due to a compiler bug or to impossible asm\n\
-statements or clauses.");
+statements or clauses.", regno, reg_names[regno], reg_class_names[class]);
+ }
/* Make reg REGNO an additional reload reg. */
@@ -2289,7 +2449,8 @@ delete_dead_insn (insn)
if (prev && GET_CODE (PATTERN (prev)) == SET
&& (prev_dest = SET_DEST (PATTERN (prev)), GET_CODE (prev_dest) == REG)
&& reg_mentioned_p (prev_dest, PATTERN (insn))
- && find_regno_note (insn, REG_DEAD, REGNO (prev_dest)))
+ && find_regno_note (insn, REG_DEAD, REGNO (prev_dest))
+ && ! side_effects_p (SET_SRC (PATTERN (prev))))
delete_dead_insn (prev);
PUT_CODE (insn, NOTE);
@@ -2329,7 +2490,7 @@ alter_reg (i, from_reg)
allocate a stack slot for it. */
if (reg_renumber[i] < 0
- && reg_n_refs[i] > 0
+ && REG_N_REFS (i) > 0
&& reg_equiv_constant[i] == 0
&& reg_equiv_memory_loc[i] == 0)
{
@@ -2349,7 +2510,8 @@ alter_reg (i, from_reg)
if (from_reg == -1)
{
/* No known place to spill from => no slot to reuse. */
- x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, -1);
+ x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
+ inherent_size == total_size ? 0 : -1);
if (BYTES_BIG_ENDIAN)
/* Cancel the big-endian correction done in assign_stack_local.
Get the address of the beginning of the slot.
@@ -2381,7 +2543,8 @@ alter_reg (i, from_reg)
total_size = spill_stack_slot_width[from_reg];
}
/* Make a slot with that size. */
- x = assign_stack_local (mode, total_size, -1);
+ x = assign_stack_local (mode, total_size,
+ inherent_size == total_size ? 0 : -1);
stack_slot = x;
if (BYTES_BIG_ENDIAN)
{
@@ -2391,9 +2554,9 @@ alter_reg (i, from_reg)
below. */
adjust = GET_MODE_SIZE (mode) - total_size;
if (adjust)
- stack_slot = gen_rtx (MEM, mode_for_size (total_size
- * BITS_PER_UNIT,
- MODE_INT, 1),
+ stack_slot = gen_rtx_MEM (mode_for_size (total_size
+ * BITS_PER_UNIT,
+ MODE_INT, 1),
plus_constant (XEXP (x, 0), adjust));
}
spill_stack_slot[from_reg] = stack_slot;
@@ -2409,9 +2572,16 @@ alter_reg (i, from_reg)
wrong mode, make a new stack slot. */
if (adjust != 0 || GET_MODE (x) != GET_MODE (regno_reg_rtx[i]))
{
- x = gen_rtx (MEM, GET_MODE (regno_reg_rtx[i]),
+ x = gen_rtx_MEM (GET_MODE (regno_reg_rtx[i]),
plus_constant (XEXP (x, 0), adjust));
- RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
+
+ /* If this was shared among registers, must ensure we never
+ set it readonly since that can cause scheduling
+ problems. Note we would only have in this adjustment
+ case in any event, since the code above doesn't set it. */
+
+ if (from_reg == -1)
+ RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
}
/* Save the stack slot for later. */
@@ -2478,7 +2648,7 @@ set_label_offsets (x, insn, initial_p)
x = XEXP (x, 0);
- /* ... fall through ... */
+ /* ... fall through ... */
case CODE_LABEL:
/* If we know nothing about this label, set the desired offsets. Note
@@ -2533,7 +2703,7 @@ set_label_offsets (x, insn, initial_p)
case JUMP_INSN:
set_label_offsets (PATTERN (insn), insn, initial_p);
- /* ... fall through ... */
+ /* ... fall through ... */
case INSN:
case CALL_INSN:
@@ -2547,7 +2717,7 @@ set_label_offsets (x, insn, initial_p)
case ADDR_VEC:
case ADDR_DIFF_VEC:
/* Each of the labels in the address vector must be at their initial
- offsets. We want the first first for ADDR_VEC and the second
+ offsets. We want the first field for ADDR_VEC and the second
field for ADDR_DIFF_VEC. */
for (i = 0; i < XVECLEN (x, code == ADDR_DIFF_VEC); i++)
@@ -2594,6 +2764,9 @@ set_label_offsets (x, insn, initial_p)
else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN)
break;
return;
+
+ default:
+ break;
}
/* If we reach here, all eliminations must be at their initial
@@ -2601,6 +2774,10 @@ set_label_offsets (x, insn, initial_p)
for (p = reg_eliminate; p < &reg_eliminate[NUM_ELIMINABLE_REGS]; p++)
if (p->offset != p->initial_offset)
p->can_eliminate = 0;
+ break;
+
+ default:
+ break;
}
}
@@ -2621,7 +2798,7 @@ static struct rtvec_def *old_asm_operands_vec, *new_asm_operands_vec;
If INSN is an insn, it is the insn containing X. If we replace a REG
in a SET_DEST with an equivalent MEM and INSN is non-zero, write a
CLOBBER of the pseudo after INSN so find_equiv_regs will know that
- that the REG is being modified.
+ the REG is being modified.
Alternatively, INSN may be a note (an EXPR_LIST or INSN_LIST).
That's used when we eliminate in expressions stored in notes.
@@ -2666,6 +2843,15 @@ eliminate_regs (x, mem_mode, insn)
case RETURN:
return x;
+ case ADDRESSOF:
+ /* This is only for the benefit of the debugging backends, which call
+ eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
+ removed after CSE. */
+ new = eliminate_regs (XEXP (x, 0), 0, insn);
+ if (GET_CODE (new) == MEM)
+ return XEXP (new, 0);
+ return x;
+
case REG:
regno = REGNO (x);
@@ -2697,11 +2883,13 @@ eliminate_regs (x, mem_mode, insn)
elimination) and ignore the fact that this is actually a
reference to the pseudo. Ensure we make a copy of the
address in case it is shared. */
- new = eliminate_regs (reg_equiv_memory_loc[regno],
- mem_mode, insn);
+ new = eliminate_regs (reg_equiv_memory_loc[regno], mem_mode, insn);
if (new != reg_equiv_memory_loc[regno])
{
- cannot_omit_stores[regno] = 1;
+ if (insn != 0 && GET_CODE (insn) != EXPR_LIST
+ && GET_CODE (insn) != INSN_LIST)
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, x), insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL, new, NULL_RTX);
return copy_rtx (new);
}
}
@@ -2736,9 +2924,9 @@ eliminate_regs (x, mem_mode, insn)
&& INTVAL (XEXP (x, 1)) == - ep->previous_offset)
return ep->to_rtx;
else
- return gen_rtx (PLUS, Pmode, ep->to_rtx,
- plus_constant (XEXP (x, 1),
- ep->previous_offset));
+ return gen_rtx_PLUS (Pmode, ep->to_rtx,
+ plus_constant (XEXP (x, 1),
+ ep->previous_offset));
}
/* If the register is not eliminable, we are done since the other
@@ -2787,7 +2975,7 @@ eliminate_regs (x, mem_mode, insn)
turn a PLUS into something else. We might try to do so here
for an addition of 0 if we aren't optimizing. */
if (! mem_mode && GET_CODE (new) != PLUS)
- return gen_rtx (PLUS, GET_MODE (x), new, const0_rtx);
+ return gen_rtx_PLUS (GET_MODE (x), new, const0_rtx);
else
return new;
}
@@ -2814,11 +3002,11 @@ eliminate_regs (x, mem_mode, insn)
ep->ref_outside_mem = 1;
return
- plus_constant (gen_rtx (MULT, Pmode, ep->to_rtx, XEXP (x, 1)),
+ plus_constant (gen_rtx_MULT (Pmode, ep->to_rtx, XEXP (x, 1)),
ep->previous_offset * INTVAL (XEXP (x, 1)));
}
- /* ... fall through ... */
+ /* ... fall through ... */
case CALL:
case COMPARE:
@@ -2837,7 +3025,7 @@ eliminate_regs (x, mem_mode, insn)
= XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn) : 0;
if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
- return gen_rtx (code, GET_MODE (x), new0, new1);
+ return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1);
}
return x;
@@ -2847,10 +3035,10 @@ eliminate_regs (x, mem_mode, insn)
{
new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
if (new != XEXP (x, 0))
- x = gen_rtx (EXPR_LIST, REG_NOTE_KIND (x), new, XEXP (x, 1));
+ x = gen_rtx_EXPR_LIST (REG_NOTE_KIND (x), new, XEXP (x, 1));
}
- /* ... fall through ... */
+ /* ... fall through ... */
case INSN_LIST:
/* Now do eliminations in the rest of the chain. If this was
@@ -2860,7 +3048,7 @@ eliminate_regs (x, mem_mode, insn)
{
new = eliminate_regs (XEXP (x, 1), mem_mode, insn);
if (new != XEXP (x, 1))
- return gen_rtx (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
+ return gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
}
return x;
@@ -2885,7 +3073,6 @@ eliminate_regs (x, mem_mode, insn)
}
/* Fall through to generic unary operation case. */
- case USE:
case STRICT_LOW_PART:
case NEG: case NOT:
case SIGN_EXTEND: case ZERO_EXTEND:
@@ -2897,7 +3084,7 @@ eliminate_regs (x, mem_mode, insn)
case FFS:
new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
if (new != XEXP (x, 0))
- return gen_rtx (code, GET_MODE (x), new);
+ return gen_rtx_fmt_e (code, GET_MODE (x), new);
return x;
case SUBREG:
@@ -2921,16 +3108,17 @@ eliminate_regs (x, mem_mode, insn)
new = SUBREG_REG (x);
else
{
- /* Otherwise, ensure NEW isn't shared in case we have to reload
- it. */
- new = copy_rtx (new);
-
/* In this case, we must show that the pseudo is used in this
insn so that delete_output_reload will do the right thing. */
if (insn != 0 && GET_CODE (insn) != EXPR_LIST
&& GET_CODE (insn) != INSN_LIST)
- emit_insn_before (gen_rtx (USE, VOIDmode, SUBREG_REG (x)),
- insn);
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
+ SUBREG_REG (x)),
+ insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL, new, NULL_RTX);
+
+ /* Ensure NEW isn't shared in case we have to reload it. */
+ new = copy_rtx (new);
}
}
else
@@ -2938,22 +3126,23 @@ eliminate_regs (x, mem_mode, insn)
if (new != XEXP (x, 0))
{
+ int x_size = GET_MODE_SIZE (GET_MODE (x));
+ int new_size = GET_MODE_SIZE (GET_MODE (new));
+
if (GET_CODE (new) == MEM
- && (GET_MODE_SIZE (GET_MODE (x))
- <= GET_MODE_SIZE (GET_MODE (new)))
-#ifdef LOAD_EXTEND_OP
- /* On these machines we will be reloading what is
- inside the SUBREG if it originally was a pseudo and
- the inner and outer modes are both a word or
- smaller. So leave the SUBREG then. */
- && ! (GET_CODE (SUBREG_REG (x)) == REG
- && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (x))
- > GET_MODE_SIZE (GET_MODE (new)))
- && INTEGRAL_MODE_P (GET_MODE (new))
- && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
+ && ((x_size < new_size
+#ifdef WORD_REGISTER_OPERATIONS
+ /* On these machines, combine can create rtl of the form
+ (set (subreg:m1 (reg:m2 R) 0) ...)
+ where m1 < m2, and expects something interesting to
+ happen to the entire word. Moreover, it will use the
+ (reg:m2 R) later, expecting all bits to be preserved.
+ So if the number of words is the same, preserve the
+ subreg so that push_reloads can see it. */
+ && ! ((x_size-1)/UNITS_PER_WORD == (new_size-1)/UNITS_PER_WORD)
#endif
+ )
+ || (x_size == new_size))
)
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
@@ -2969,11 +3158,24 @@ eliminate_regs (x, mem_mode, insn)
return new;
}
else
- return gen_rtx (SUBREG, GET_MODE (x), new, SUBREG_WORD (x));
+ return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_WORD (x));
}
return x;
+ case USE:
+ /* If using a register that is the source of an eliminate we still
+ think can be performed, note it cannot be performed since we don't
+ know how this register is used. */
+ for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ if (ep->from_rtx == XEXP (x, 0))
+ ep->can_eliminate = 0;
+
+ new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+ if (new != XEXP (x, 0))
+ return gen_rtx_fmt_e (code, GET_MODE (x), new);
+ return x;
+
case CLOBBER:
/* If clobbering a register that is the replacement register for an
elimination we still think can be performed, note that it cannot
@@ -2984,7 +3186,7 @@ eliminate_regs (x, mem_mode, insn)
new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
if (new != XEXP (x, 0))
- return gen_rtx (code, GET_MODE (x), new);
+ return gen_rtx_fmt_e (code, GET_MODE (x), new);
return x;
case ASM_OPERANDS:
@@ -3017,12 +3219,13 @@ eliminate_regs (x, mem_mode, insn)
if (new_asm_operands_vec == old_asm_operands_vec)
return x;
- new = gen_rtx (ASM_OPERANDS, VOIDmode, ASM_OPERANDS_TEMPLATE (x),
- ASM_OPERANDS_OUTPUT_CONSTRAINT (x),
- ASM_OPERANDS_OUTPUT_IDX (x), new_asm_operands_vec,
- ASM_OPERANDS_INPUT_CONSTRAINT_VEC (x),
- ASM_OPERANDS_SOURCE_FILE (x),
- ASM_OPERANDS_SOURCE_LINE (x));
+ new = gen_rtx_ASM_OPERANDS (VOIDmode, ASM_OPERANDS_TEMPLATE (x),
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (x),
+ ASM_OPERANDS_OUTPUT_IDX (x),
+ new_asm_operands_vec,
+ ASM_OPERANDS_INPUT_CONSTRAINT_VEC (x),
+ ASM_OPERANDS_SOURCE_FILE (x),
+ ASM_OPERANDS_SOURCE_LINE (x));
new->volatil = x->volatil;
return new;
}
@@ -3079,22 +3282,28 @@ eliminate_regs (x, mem_mode, insn)
if (GET_CODE (SET_DEST (x)) == REG && GET_CODE (new0) == MEM
&& insn != 0 && GET_CODE (insn) != EXPR_LIST
&& GET_CODE (insn) != INSN_LIST)
- emit_insn_after (gen_rtx (CLOBBER, VOIDmode, SET_DEST (x)), insn);
+ emit_insn_after (gen_rtx_CLOBBER (VOIDmode, SET_DEST (x)), insn);
if (new0 != SET_DEST (x) || new1 != SET_SRC (x))
- return gen_rtx (SET, VOIDmode, new0, new1);
+ return gen_rtx_SET (VOIDmode, new0, new1);
}
return x;
case MEM:
+ /* This is only for the benefit of the debugging backends, which call
+ eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
+ removed after CSE. */
+ if (GET_CODE (XEXP (x, 0)) == ADDRESSOF)
+ return eliminate_regs (XEXP (XEXP (x, 0), 0), 0, insn);
+
/* Our only special processing is to pass the mode of the MEM to our
recursive call and copy the flags. While we are here, handle this
case more efficiently. */
new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn);
if (new != XEXP (x, 0))
{
- new = gen_rtx (MEM, GET_MODE (x), new);
+ new = gen_rtx_MEM (GET_MODE (x), new);
new->volatil = x->volatil;
new->unchanging = x->unchanging;
new->in_struct = x->in_struct;
@@ -3102,6 +3311,9 @@ eliminate_regs (x, mem_mode, insn)
}
else
return x;
+
+ default:
+ break;
}
/* Process each of our operands recursively. If any have changed, make a
@@ -3131,8 +3343,8 @@ eliminate_regs (x, mem_mode, insn)
new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn);
if (new != XVECEXP (x, i, j) && ! copied_vec)
{
- rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
- &XVECEXP (x, i, 0));
+ rtvec new_v = gen_rtvec_vv (XVECLEN (x, i),
+ XVEC (x, i)->elem);
if (! copied)
{
rtx new_x = rtx_alloc (code);
@@ -3199,12 +3411,34 @@ eliminate_regs_in_insn (insn, replace)
{
rtx src = SET_SRC (old_set);
int offset, ok = 0;
+ rtx prev_insn, prev_set;
if (src == ep->to_rtx)
offset = 0, ok = 1;
else if (GET_CODE (src) == PLUS
- && GET_CODE (XEXP (src, 0)) == CONST_INT)
+ && GET_CODE (XEXP (src, 0)) == CONST_INT
+ && XEXP (src, 1) == ep->to_rtx)
offset = INTVAL (XEXP (src, 0)), ok = 1;
+ else if (GET_CODE (src) == PLUS
+ && GET_CODE (XEXP (src, 1)) == CONST_INT
+ && XEXP (src, 0) == ep->to_rtx)
+ offset = INTVAL (XEXP (src, 1)), ok = 1;
+ else if ((prev_insn = prev_nonnote_insn (insn)) != 0
+ && (prev_set = single_set (prev_insn)) != 0
+ && rtx_equal_p (SET_DEST (prev_set), src))
+ {
+ src = SET_SRC (prev_set);
+ if (src == ep->to_rtx)
+ offset = 0, ok = 1;
+ else if (GET_CODE (src) == PLUS
+ && GET_CODE (XEXP (src, 0)) == CONST_INT
+ && XEXP (src, 1) == ep->to_rtx)
+ offset = INTVAL (XEXP (src, 0)), ok = 1;
+ else if (GET_CODE (src) == PLUS
+ && GET_CODE (XEXP (src, 1)) == CONST_INT
+ && XEXP (src, 0) == ep->to_rtx)
+ offset = INTVAL (XEXP (src, 1)), ok = 1;
+ }
if (ok)
{
@@ -3268,8 +3502,9 @@ eliminate_regs_in_insn (insn, replace)
/* We assume here that we don't need a PARALLEL of
any CLOBBERs for this assignment. There's not
much we can do if we do need it. */
- PATTERN (insn) = gen_rtx (SET, VOIDmode,
- SET_DEST (old_set), ep->to_rtx);
+ PATTERN (insn) = gen_rtx_SET (VOIDmode,
+ SET_DEST (old_set),
+ ep->to_rtx);
INSN_CODE (insn) = -1;
val = 1;
goto done;
@@ -3287,7 +3522,7 @@ eliminate_regs_in_insn (insn, replace)
If we are replacing a body that was a (set X (plus Y Z)), try to
re-recognize the insn. We do this in case we had a simple addition
but now can do this as a load-address. This saves an insn in this
- common case. */
+ common case. */
new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX);
if (new_body != old_body)
@@ -3295,7 +3530,7 @@ eliminate_regs_in_insn (insn, replace)
/* If we aren't replacing things permanently and we changed something,
make another copy to ensure that all the RTL is new. Otherwise
things can go wrong if find_reload swaps commutative operands
- and one is inside RTL that has been copied while the other is not. */
+ and one is inside RTL that has been copied while the other is not. */
/* Don't copy an asm_operands because (1) there's no need and (2)
copy_rtx can't do it properly when there are multiple outputs. */
@@ -3475,14 +3710,14 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
if (! cant_eliminate
&& basic_block_needs[0]
- && reg_basic_block[i] >= 0
- && basic_block_needs[(int) class][reg_basic_block[i]] == 0)
+ && REG_BASIC_BLOCK (i) >= 0
+ && basic_block_needs[(int) class][REG_BASIC_BLOCK (i)] == 0)
{
enum reg_class *p;
for (p = reg_class_superclasses[(int) class];
*p != LIM_REG_CLASSES; p++)
- if (basic_block_needs[(int) *p][reg_basic_block[i]] > 0)
+ if (basic_block_needs[(int) *p][REG_BASIC_BLOCK (i)] > 0)
break;
if (*p == LIM_REG_CLASSES)
@@ -3494,7 +3729,7 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
/* We will need to scan everything again. */
something_changed = 1;
if (global)
- retry_global_alloc (i, forbidden_regs);
+ retry_global_alloc (i, forbidden_regs);
alter_reg (i, regno);
if (dumpfile)
@@ -3508,7 +3743,11 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
}
for (i = 0; i < scratch_list_length; i++)
{
- if (scratch_list[i] && REGNO (scratch_list[i]) == regno)
+ if (scratch_list[i]
+ && regno >= REGNO (scratch_list[i])
+ && regno < REGNO (scratch_list[i])
+ + HARD_REGNO_NREGS (REGNO (scratch_list[i]),
+ GET_MODE (scratch_list[i])))
{
if (! cant_eliminate && basic_block_needs[0]
&& ! basic_block_needs[(int) class][scratch_block[i]])
@@ -3548,10 +3787,9 @@ scan_paradoxical_subregs (x)
switch (code)
{
case REG:
-#ifdef SMALL_REGISTER_CLASSES
- if (REGNO (x) < FIRST_PSEUDO_REGISTER && REG_USERVAR_P (x))
+ if (SMALL_REGISTER_CLASSES && REGNO (x) < FIRST_PSEUDO_REGISTER
+ && REG_USERVAR_P (x))
SET_HARD_REG_BIT (forbidden_regs, REGNO (x));
-#endif
return;
case CONST_INT:
@@ -3571,6 +3809,9 @@ scan_paradoxical_subregs (x)
reg_max_ref_width[REGNO (SUBREG_REG (x))]
= GET_MODE_SIZE (GET_MODE (x));
return;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -3588,9 +3829,12 @@ scan_paradoxical_subregs (x)
}
static int
-hard_reg_use_compare (p1, p2)
- struct hard_reg_n_uses *p1, *p2;
+hard_reg_use_compare (p1p, p2p)
+ const GENERIC_PTR p1p;
+ const GENERIC_PTR p2p;
{
+ struct hard_reg_n_uses *p1 = (struct hard_reg_n_uses *)p1p,
+ *p2 = (struct hard_reg_n_uses *)p2p;
int tem = p1->uses - p2->uses;
if (tem != 0) return tem;
/* If regs are equally good, sort by regno,
@@ -3603,7 +3847,8 @@ hard_reg_use_compare (p1, p2)
Store them in order of decreasing preference in potential_reload_regs. */
static void
-order_regs_for_reload ()
+order_regs_for_reload (global)
+ int global;
{
register int i;
register int o = 0;
@@ -3632,9 +3877,17 @@ order_regs_for_reload ()
{
int lim = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (i));
while (regno < lim)
- hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+ {
+ /* If allocated by local-alloc, show more uses since
+ we're not going to be able to reallocate it, but
+ we might if allocated by global alloc. */
+ if (global && reg_allocno[i] < 0)
+ hard_reg_n_uses[regno].uses += (REG_N_REFS (i) + 1) / 2;
+
+ hard_reg_n_uses[regno++].uses += REG_N_REFS (i);
+ }
}
- large += reg_n_refs[i];
+ large += REG_N_REFS (i);
}
/* Now fixed registers (which cannot safely be used for reloading)
@@ -3651,14 +3904,13 @@ order_regs_for_reload ()
else if (regs_explicitly_used[i])
{
hard_reg_n_uses[i].uses += large + 1;
-#ifndef SMALL_REGISTER_CLASSES
- /* ??? We are doing this here because of the potential that
- bad code may be generated if a register explicitly used in
- an insn was used as a spill register for that insn. But
- not using these are spill registers may lose on some machine.
- We'll have to see how this works out. */
- SET_HARD_REG_BIT (bad_spill_regs, i);
-#endif
+ if (! SMALL_REGISTER_CLASSES)
+ /* ??? We are doing this here because of the potential
+ that bad code may be generated if a register explicitly
+ used in an insn was used as a spill register for that
+ insn. But not using these are spill registers may lose
+ on some machine. We'll have to see how this works out. */
+ SET_HARD_REG_BIT (bad_spill_regs, i);
}
}
hard_reg_n_uses[HARD_FRAME_POINTER_REGNUM].uses += 2 * large + 2;
@@ -3714,10 +3966,12 @@ order_regs_for_reload ()
/* Used in reload_as_needed to sort the spilled regs. */
static int
-compare_spill_regs (r1, r2)
- short *r1, *r2;
+compare_spill_regs (r1p, r2p)
+ const GENERIC_PTR r1p;
+ const GENERIC_PTR r2p;
{
- return *r1 - *r2;
+ short r1 = *(short *)r1p, r2 = *(short *)r2p;
+ return r1 - r2;
}
/* Reload pseudo-registers into hard regs around each insn as needed.
@@ -3745,11 +3999,7 @@ reload_as_needed (first, live_known)
reg_last_reload_reg = (rtx *) alloca (max_regno * sizeof (rtx));
bzero ((char *) reg_last_reload_reg, max_regno * sizeof (rtx));
reg_has_output_reload = (char *) alloca (max_regno);
- for (i = 0; i < n_spills; i++)
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ CLEAR_HARD_REG_SET (reg_reloaded_valid);
/* Reset all offsets on eliminable registers to their initial values. */
#ifdef ELIMINABLE_REGS
@@ -3807,10 +4057,9 @@ reload_as_needed (first, live_known)
rtx avoid_return_reg = 0;
rtx oldpat = PATTERN (insn);
-#ifdef SMALL_REGISTER_CLASSES
/* Set avoid_return_reg if this is an insn
that might use the value of a function call. */
- if (GET_CODE (insn) == CALL_INSN)
+ if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
{
if (GET_CODE (PATTERN (insn)) == SET)
after_call = SET_DEST (PATTERN (insn));
@@ -3820,15 +4069,15 @@ reload_as_needed (first, live_known)
else
after_call = 0;
}
- else if (after_call != 0
+ else if (SMALL_REGISTER_CLASSES && after_call != 0
&& !(GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
+ && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
+ && GET_CODE (PATTERN (insn)) != USE)
{
if (reg_referenced_p (after_call, PATTERN (insn)))
avoid_return_reg = after_call;
after_call = 0;
}
-#endif /* SMALL_REGISTER_CLASSES */
/* If this is a USE and CLOBBER of a MEM, ensure that any
references to eliminable registers have been removed. */
@@ -3838,7 +4087,8 @@ reload_as_needed (first, live_known)
&& GET_CODE (XEXP (PATTERN (insn), 0)) == MEM)
XEXP (XEXP (PATTERN (insn), 0), 0)
= eliminate_regs (XEXP (XEXP (PATTERN (insn), 0), 0),
- GET_MODE (XEXP (PATTERN (insn), 0)), NULL_RTX);
+ GET_MODE (XEXP (PATTERN (insn), 0)),
+ NULL_RTX);
/* If we need to do register elimination processing, do so.
This might delete the insn, in which case we are done. */
@@ -3894,12 +4144,11 @@ reload_as_needed (first, live_known)
Record the choices of reload reg in reload_reg_rtx. */
choose_reload_regs (insn, avoid_return_reg);
-#ifdef SMALL_REGISTER_CLASSES
/* Merge any reloads that we didn't combine for fear of
increasing the number of spill registers needed but now
discover can be safely merged. */
- merge_assigned_reloads (insn);
-#endif
+ if (SMALL_REGISTER_CLASSES)
+ merge_assigned_reloads (insn);
/* Generate the insns to reload operands into or out of
their reload regs. */
@@ -3964,32 +4213,21 @@ reload_as_needed (first, live_known)
}
/* A reload reg's contents are unknown after a label. */
if (GET_CODE (insn) == CODE_LABEL)
- for (i = 0; i < n_spills; i++)
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ CLEAR_HARD_REG_SET (reg_reloaded_valid);
/* Don't assume a reload reg is still good after a call insn
if it is a call-used reg. */
else if (GET_CODE (insn) == CALL_INSN)
- for (i = 0; i < n_spills; i++)
- if (call_used_regs[spill_regs[i]])
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ AND_COMPL_HARD_REG_SET(reg_reloaded_valid, call_used_reg_set);
/* In case registers overlap, allow certain insns to invalidate
particular hard registers. */
#ifdef INSN_CLOBBERS_REGNO_P
- for (i = 0 ; i < n_spills ; i++)
- if (INSN_CLOBBERS_REGNO_P (insn, spill_regs[i]))
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ for (i = 0 ; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (reg_reloaded_valid, i)
+ && INSN_CLOBBERS_REGNO_P (insn, i))
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, i);
#endif
insn = next;
@@ -4010,44 +4248,56 @@ reload_as_needed (first, live_known)
static void
forget_old_reloads_1 (x, ignored)
rtx x;
- rtx ignored;
+ rtx ignored ATTRIBUTE_UNUSED;
{
register int regno;
+ enum machine_mode mode = GET_MODE (x);
int nr;
- int offset = 0;
- /* note_stores does give us subregs of hard regs. */
+ /* note_stores does give us subregs of hard regs.
+
+ This is a egcs-1.1 tree hack only. A better solution is being
+ developed for mainline sources. Do not import this back to the
+ mainline tree.
+
+ We want to strip all the SUBREGs, but also keep track of the
+ largest mode we encounter so that we can invalidate all the
+ hard regs which are needed to hold the widest mode.
+
+ This avoids a bug in choose_reload_regs (which is where the real
+ fix for the mainline tree will be). */
+
while (GET_CODE (x) == SUBREG)
{
- offset += SUBREG_WORD (x);
+ if (GET_MODE_BITSIZE (GET_MODE (x)) > GET_MODE_BITSIZE (mode))
+ mode = GET_MODE (x);
x = SUBREG_REG (x);
}
+ if (GET_MODE_BITSIZE (GET_MODE (x)) > GET_MODE_BITSIZE (mode))
+ mode = GET_MODE (x);
+
if (GET_CODE (x) != REG)
return;
- regno = REGNO (x) + offset;
+ regno = REGNO (x);
if (regno >= FIRST_PSEUDO_REGISTER)
nr = 1;
else
{
int i;
- nr = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ nr = HARD_REGNO_NREGS (regno, mode);
/* Storing into a spilled-reg invalidates its contents.
This can happen if a block-local pseudo is allocated to that reg
and it wasn't spilled because this block's total need is 0.
Then some insn might have an optional reload and use this reg. */
for (i = 0; i < nr; i++)
- if (spill_reg_order[regno + i] >= 0
- /* But don't do this if the reg actually serves as an output
- reload reg in the current instruction. */
- && (n_reloads == 0
- || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i)))
- {
- reg_reloaded_contents[spill_reg_order[regno + i]] = -1;
- reg_reloaded_insn[spill_reg_order[regno + i]] = 0;
- }
+ /* But don't do this if the reg actually serves as an output
+ reload reg in the current instruction. */
+ if (n_reloads == 0
+ || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
}
/* Since value of X has changed,
@@ -4070,10 +4320,11 @@ static int reload_nregs[MAX_RELOADS];
should be handled first. *P1 and *P2 are the reload numbers. */
static int
-reload_reg_class_lower (p1, p2)
- short *p1, *p2;
+reload_reg_class_lower (r1p, r2p)
+ const GENERIC_PTR r1p;
+ const GENERIC_PTR r2p;
{
- register int r1 = *p1, r2 = *p2;
+ register int r1 = *(short *)r1p, r2 = *(short *)r2p;
register int t;
/* Consider required reloads before optional ones. */
@@ -4109,8 +4360,12 @@ reload_reg_class_lower (p1, p2)
static HARD_REG_SET reload_reg_used;
/* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I. */
static HARD_REG_SET reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_INPADDR_ADDRESS reload for operand I. */
+static HARD_REG_SET reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS];
/* If reg is in use for a RELOAD_FOR_OUTPUT_ADDRESS reload for operand I. */
static HARD_REG_SET reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_OUTADDR_ADDRESS reload for operand I. */
+static HARD_REG_SET reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS];
/* If reg is in use for a RELOAD_FOR_INPUT reload for operand I. */
static HARD_REG_SET reload_reg_used_in_input[MAX_RECOG_OPERANDS];
/* If reg is in use for a RELOAD_FOR_OUTPUT reload for operand I. */
@@ -4157,10 +4412,18 @@ mark_reload_reg_in_use (regno, opnum, type, mode)
SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ SET_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OUTPUT_ADDRESS:
SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ SET_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OPERAND_ADDRESS:
SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
break;
@@ -4214,10 +4477,18 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OUTPUT_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OPERAND_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
break;
@@ -4256,27 +4527,24 @@ reload_reg_free_p (regno, opnum, type)
{
int i;
- /* In use for a RELOAD_OTHER means it's not available for anything except
- RELOAD_FOR_OTHER_ADDRESS. Recall that RELOAD_FOR_OTHER_ADDRESS is known
- to be used only for inputs. */
-
- if (type != RELOAD_FOR_OTHER_ADDRESS
- && TEST_HARD_REG_BIT (reload_reg_used, regno))
+ /* In use for a RELOAD_OTHER means it's not available for anything. */
+ if (TEST_HARD_REG_BIT (reload_reg_used, regno))
return 0;
switch (type)
{
case RELOAD_OTHER:
- /* In use for anything except RELOAD_FOR_OTHER_ADDRESS means
- we can't use it for RELOAD_OTHER. */
- if (TEST_HARD_REG_BIT (reload_reg_used, regno)
+ /* In use for anything means we can't use it for RELOAD_OTHER. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
return 0;
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4298,7 +4566,8 @@ reload_reg_free_p (regno, opnum, type)
/* If it is used in a later operand's address, can't use it. */
for (i = opnum + 1; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return 1;
@@ -4306,7 +4575,21 @@ reload_reg_free_p (regno, opnum, type)
case RELOAD_FOR_INPUT_ADDRESS:
/* Can't use a register if it is used for an input address for this
operand or used as an input in an earlier one. */
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
+ return 0;
+
+ for (i = 0; i < opnum; i++)
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+ return 0;
+
+ return 1;
+
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ /* Can't use a register if it is used for an input address
+ for this operand or used as an input in an earlier
+ one. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
return 0;
for (i = 0; i < opnum; i++)
@@ -4327,6 +4610,19 @@ reload_reg_free_p (regno, opnum, type)
return 1;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ /* Can't use a register if it is used for an output address
+ for this operand or used as an output in this or a
+ later operand. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
+ return 0;
+
+ for (i = opnum; i < reload_n_operands; i++)
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+ return 0;
+
+ return 1;
+
case RELOAD_FOR_OPERAND_ADDRESS:
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
@@ -4353,7 +4649,8 @@ reload_reg_free_p (regno, opnum, type)
return 0;
for (i = 0; i <= opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
return 0;
return 1;
@@ -4407,12 +4704,18 @@ reload_reg_free_before_p (regno, opnum, type)
the first place, since we know that it was allocated. */
case RELOAD_FOR_OUTPUT_ADDRESS:
+ /* Earlier reloads include RELOAD_FOR_OUTADDR_ADDRESS reloads. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
+ return 0;
+ /* ... fall through ... */
+ case RELOAD_FOR_OUTADDR_ADDRESS:
/* Earlier reloads are for earlier outputs or their addresses,
any RELOAD_FOR_INSN reloads, any inputs or their addresses, or any
RELOAD_FOR_OTHER_ADDRESS reloads (we know it can't conflict with
RELOAD_OTHER).. */
for (i = 0; i < opnum; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4421,42 +4724,35 @@ reload_reg_free_before_p (regno, opnum, type)
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
return 0;
return (! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+ && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
case RELOAD_FOR_OUTPUT:
- /* This can't be used in the output address for this operand and
- anything that can't be used for it, except that we've already
- tested for RELOAD_FOR_INSN objects. */
+ /* There is no reason to call this function for output reloads, thus
+ anything we'd put here wouldn't be tested. So just abort. */
+ abort ();
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno))
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ /* Earlier reloads include RELOAD_FOR_OPADDR_ADDR reloads. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
return 0;
- for (i = 0; i < opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
- return 0;
-
- for (i = 0; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
- return 0;
-
- return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
+ /* ... fall through ... */
- case RELOAD_FOR_OPERAND_ADDRESS:
case RELOAD_FOR_OPADDR_ADDR:
case RELOAD_FOR_INSN:
/* These can't conflict with inputs, or each other, so all we have to
test is input addresses and the addresses of OTHER items. */
for (i = 0; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4467,16 +4763,23 @@ reload_reg_free_before_p (regno, opnum, type)
with), and addresses of RELOAD_OTHER objects. */
for (i = 0; i <= opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
case RELOAD_FOR_INPUT_ADDRESS:
+ /* Earlier reloads include RELOAD_FOR_INPADDR_ADDRESS reloads. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
+ return 0;
+ /* ... fall through ... */
+ case RELOAD_FOR_INPADDR_ADDRESS:
/* Similarly, all we have to check is for use in earlier inputs'
addresses. */
for (i = 0; i < opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4518,8 +4821,10 @@ reload_reg_reaches_end_p (regno, opnum, type)
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
return 0;
@@ -4528,6 +4833,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
&& ! TEST_HARD_REG_BIT (reload_reg_used, regno));
case RELOAD_FOR_INPUT_ADDRESS:
+ case RELOAD_FOR_INPADDR_ADDRESS:
/* Similar, except that we check only for this and subsequent inputs
and the address of only subsequent inputs and we do not need
to check for RELOAD_OTHER objects since they are known not to
@@ -4538,11 +4844,13 @@ reload_reg_reaches_end_p (regno, opnum, type)
return 0;
for (i = opnum + 1; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4560,16 +4868,18 @@ reload_reg_reaches_end_p (regno, opnum, type)
for (i = opnum + 1; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
return 0;
- /* ... fall through ... */
+ /* ... fall through ... */
case RELOAD_FOR_OPERAND_ADDRESS:
/* Check outputs and their addresses. */
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4578,6 +4888,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
case RELOAD_FOR_OPADDR_ADDR:
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4590,14 +4901,16 @@ reload_reg_reaches_end_p (regno, opnum, type)
opnum = -1;
- /* ... fall through ... */
+ /* ... fall through ... */
case RELOAD_FOR_OUTPUT:
case RELOAD_FOR_OUTPUT_ADDRESS:
+ case RELOAD_FOR_OUTADDR_ADDRESS:
/* We already know these can't conflict with a later output. So the
only thing to check are later output addresses. */
for (i = opnum + 1; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
return 0;
return 1;
@@ -4611,7 +4924,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
This function uses the same algorithm as reload_reg_free_p above. */
-static int
+int
reloads_conflict (r1, r2)
int r1, r2;
{
@@ -4620,9 +4933,8 @@ reloads_conflict (r1, r2)
int r1_opnum = reload_opnum[r1];
int r2_opnum = reload_opnum[r2];
- /* RELOAD_OTHER conflicts with everything except RELOAD_FOR_OTHER_ADDRESS. */
-
- if (r2_type == RELOAD_OTHER && r1_type != RELOAD_FOR_OTHER_ADDRESS)
+ /* RELOAD_OTHER conflicts with everything. */
+ if (r2_type == RELOAD_OTHER)
return 1;
/* Otherwise, check conflicts differently for each type. */
@@ -4634,16 +4946,26 @@ reloads_conflict (r1, r2)
|| r2_type == RELOAD_FOR_OPERAND_ADDRESS
|| r2_type == RELOAD_FOR_OPADDR_ADDR
|| r2_type == RELOAD_FOR_INPUT
- || (r2_type == RELOAD_FOR_INPUT_ADDRESS && r2_opnum > r1_opnum));
+ || ((r2_type == RELOAD_FOR_INPUT_ADDRESS
+ || r2_type == RELOAD_FOR_INPADDR_ADDRESS)
+ && r2_opnum > r1_opnum));
case RELOAD_FOR_INPUT_ADDRESS:
return ((r2_type == RELOAD_FOR_INPUT_ADDRESS && r1_opnum == r2_opnum)
|| (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ return ((r2_type == RELOAD_FOR_INPADDR_ADDRESS && r1_opnum == r2_opnum)
+ || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
+
case RELOAD_FOR_OUTPUT_ADDRESS:
return ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS && r2_opnum == r1_opnum)
|| (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ return ((r2_type == RELOAD_FOR_OUTADDR_ADDRESS && r2_opnum == r1_opnum)
+ || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+
case RELOAD_FOR_OPERAND_ADDRESS:
return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
|| r2_type == RELOAD_FOR_OPERAND_ADDRESS);
@@ -4654,7 +4976,8 @@ reloads_conflict (r1, r2)
case RELOAD_FOR_OUTPUT:
return (r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OUTPUT
- || (r2_type == RELOAD_FOR_OUTPUT_ADDRESS
+ || ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS
+ || r2_type == RELOAD_FOR_OUTADDR_ADDRESS)
&& r2_opnum >= r1_opnum));
case RELOAD_FOR_INSN:
@@ -4666,7 +4989,7 @@ reloads_conflict (r1, r2)
return r2_type == RELOAD_FOR_OTHER_ADDRESS;
case RELOAD_OTHER:
- return r2_type != RELOAD_FOR_OTHER_ADDRESS;
+ return 1;
default:
abort ();
@@ -4689,10 +5012,138 @@ rtx reload_inheritance_insn[MAX_RELOADS];
rather than using reload_in. */
rtx reload_override_in[MAX_RELOADS];
-/* For each reload, the index in spill_regs of the spill register used,
- or -1 if we did not need one of the spill registers for this reload. */
+/* For each reload, the hard register number of the register used,
+ or -1 if we did not need a register for this reload. */
int reload_spill_index[MAX_RELOADS];
+/* Return 1 if the value in reload reg REGNO, as used by a reload
+ needed for the part of the insn specified by OPNUM and TYPE,
+ may be used to load VALUE into it.
+
+ Other read-only reloads with the same value do not conflict
+ unless OUT is non-zero and these other reloads have to live while
+ output reloads live.
+
+ RELOADNUM is the number of the reload we want to load this value for;
+ a reload does not conflict with itself.
+
+ The caller has to make sure that there is no conflict with the return
+ register. */
+static int
+reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
+ int regno;
+ int opnum;
+ enum reload_type type;
+ rtx value, out;
+ int reloadnum;
+{
+ int time1;
+ int i;
+
+ /* We use some pseudo 'time' value to check if the lifetimes of the
+ new register use would overlap with the one of a previous reload
+ that is not read-only or uses a different value.
+ The 'time' used doesn't have to be linear in any shape or form, just
+ monotonic.
+ Some reload types use different 'buckets' for each operand.
+ So there are MAX_RECOG_OPERANDS different time values for each
+ such reload type.
+ We compute TIME1 as the time when the register for the prospective
+ new reload ceases to be live, and TIME2 for each existing
+ reload as the time when that the reload register of that reload
+ becomes live.
+ Where there is little to be gained by exact lifetime calculations,
+ we just make conservative assumptions, i.e. a longer lifetime;
+ this is done in the 'default:' cases. */
+ switch (type)
+ {
+ case RELOAD_FOR_OTHER_ADDRESS:
+ time1 = 0;
+ break;
+ /* For each input, we might have a sequence of RELOAD_FOR_INPADDR_ADDRESS,
+ RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT. By adding 0 / 1 / 2 ,
+ respectively, to the time values for these, we get distinct time
+ values. To get distinct time values for each operand, we have to
+ multiply opnum by at least three. We round that up to four because
+ multiply by four is often cheaper. */
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ time1 = opnum * 4 + 1;
+ break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ time1 = opnum * 4 + 2;
+ break;
+ case RELOAD_FOR_INPUT:
+ /* All RELOAD_FOR_INPUT reloads remain live till just before the
+ instruction is executed. */
+ time1 = (MAX_RECOG_OPERANDS - 1) * 4 + 3;
+ break;
+ /* opnum * 4 + 3 < opnum * 4 + 4
+ <= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ time1 = MAX_RECOG_OPERANDS * 4 + opnum;
+ break;
+ default:
+ time1 = MAX_RECOG_OPERANDS * 5;
+ }
+
+ for (i = 0; i < n_reloads; i++)
+ {
+ rtx reg = reload_reg_rtx[i];
+ if (reg && GET_CODE (reg) == REG
+ && ((unsigned) regno - true_regnum (reg)
+ <= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned)1)
+ && i != reloadnum)
+ {
+ if (out
+ && reload_when_needed[i] != RELOAD_FOR_INPUT
+ && reload_when_needed[i] != RELOAD_FOR_INPUT_ADDRESS
+ && reload_when_needed[i] != RELOAD_FOR_INPADDR_ADDRESS)
+ return 0;
+ if (! reload_in[i] || ! rtx_equal_p (reload_in[i], value)
+ || reload_out[i])
+ {
+ int time2;
+ switch (reload_when_needed[i])
+ {
+ case RELOAD_FOR_OTHER_ADDRESS:
+ time2 = 0;
+ break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ time2 = reload_opnum[i] * 4 + 1;
+ break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ time2 = reload_opnum[i] * 4 + 2;
+ break;
+ case RELOAD_FOR_INPUT:
+ time2 = reload_opnum[i] * 4 + 3;
+ break;
+ case RELOAD_FOR_OUTPUT:
+ /* All RELOAD_FOR_OUTPUT reloads become live just after the
+ instruction is executed. */
+ time2 = MAX_RECOG_OPERANDS * 4;
+ break;
+ /* The first RELOAD_FOR_OUTPUT_ADDRESS reload conflicts with the
+ RELOAD_FOR_OUTPUT reloads, so assign it the same time value. */
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ time2 = MAX_RECOG_OPERANDS * 4 + reload_opnum[i];
+ break;
+ case RELOAD_OTHER:
+ if (! reload_in[i] || rtx_equal_p (reload_in[i], value))
+ {
+ time2 = MAX_RECOG_OPERANDS * 4;
+ break;
+ }
+ default:
+ time2 = 0;
+ }
+ if (time1 >= time2)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
/* Find a spill register to use as a reload register for reload R.
LAST_RELOAD is non-zero if this is the last reload for the insn being
processed.
@@ -4765,8 +5216,17 @@ allocate_reload_reg (r, insn, last_reload, noerror)
i = (i + 1) % n_spills;
- if (reload_reg_free_p (spill_regs[i], reload_opnum[r],
- reload_when_needed[r])
+ if ((reload_reg_free_p (spill_regs[i], reload_opnum[r],
+ reload_when_needed[r])
+ || (reload_in[r]
+ /* We check reload_reg_used to make sure we
+ don't clobber the return register. */
+ && ! TEST_HARD_REG_BIT (reload_reg_used, spill_regs[i])
+ && reload_reg_free_for_value_p (spill_regs[i],
+ reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
&& TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
&& HARD_REGNO_MODE_OK (spill_regs[i], reload_mode[r])
/* Look first for regs to share, then for unshared. But
@@ -4834,7 +5294,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
if (new == 0 || GET_MODE (new) != reload_mode[r])
spill_reg_rtx[i] = new
- = gen_rtx (REG, reload_mode[r], spill_regs[i]);
+ = gen_rtx_REG (reload_mode[r], spill_regs[i]);
regno = true_regnum (new);
@@ -4865,7 +5325,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
reload_when_needed[r], reload_mode[r]);
reload_reg_rtx[r] = new;
- reload_spill_index[r] = i;
+ reload_spill_index[r] = spill_regs[i];
return 1;
}
}
@@ -4916,7 +5376,9 @@ choose_reload_regs (insn, avoid_return_reg)
int save_reload_spill_index[MAX_RELOADS];
HARD_REG_SET save_reload_reg_used;
HARD_REG_SET save_reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+ HARD_REG_SET save_reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+ HARD_REG_SET save_reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_input[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_output[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_op_addr;
@@ -4941,13 +5403,14 @@ choose_reload_regs (insn, avoid_return_reg)
CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
CLEAR_HARD_REG_SET (reload_reg_used_in_input[i]);
CLEAR_HARD_REG_SET (reload_reg_used_in_input_addr[i]);
+ CLEAR_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i]);
CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr[i]);
+ CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
}
-#ifdef SMALL_REGISTER_CLASSES
/* Don't bother with avoiding the return reg
if we have no mandatory reload that could use it. */
- if (avoid_return_reg)
+ if (SMALL_REGISTER_CLASSES && avoid_return_reg)
{
int do_avoid = 0;
int regno = REGNO (avoid_return_reg);
@@ -4967,7 +5430,6 @@ choose_reload_regs (insn, avoid_return_reg)
if (!do_avoid)
avoid_return_reg = 0;
}
-#endif /* SMALL_REGISTER_CLASSES */
#if 0 /* Not needed, now that we can always retry without inheritance. */
/* See if we have more mandatory reloads than spill regs.
@@ -4978,10 +5440,7 @@ choose_reload_regs (insn, avoid_return_reg)
unless it is equal to reload_in or reload_out, count such reloads. */
{
- int tem = 0;
-#ifdef SMALL_REGISTER_CLASSES
- int tem = (avoid_return_reg != 0);
-#endif
+ int tem = SMALL_REGISTER_CLASSES? (avoid_return_reg != 0): 0;
for (j = 0; j < n_reloads; j++)
if (! reload_optional[j]
&& (reload_in[j] != 0 || reload_out[j] != 0 || reload_secondary_p[j])
@@ -4994,10 +5453,9 @@ choose_reload_regs (insn, avoid_return_reg)
}
#endif
-#ifdef SMALL_REGISTER_CLASSES
/* Don't use the subroutine call return reg for a reload
if we are supposed to avoid it. */
- if (avoid_return_reg)
+ if (SMALL_REGISTER_CLASSES && avoid_return_reg)
{
int regno = REGNO (avoid_return_reg);
int nregs
@@ -5008,7 +5466,6 @@ choose_reload_regs (insn, avoid_return_reg)
if (spill_reg_order[r] >= 0)
SET_HARD_REG_BIT (reload_reg_used, r);
}
-#endif /* SMALL_REGISTER_CLASSES */
/* In order to be certain of getting the registers we need,
we must sort the reloads into order of increasing register class.
@@ -5079,8 +5536,12 @@ choose_reload_regs (insn, avoid_return_reg)
reload_reg_used_in_input[i]);
COPY_HARD_REG_SET (save_reload_reg_used_in_input_addr[i],
reload_reg_used_in_input_addr[i]);
+ COPY_HARD_REG_SET (save_reload_reg_used_in_inpaddr_addr[i],
+ reload_reg_used_in_inpaddr_addr[i]);
COPY_HARD_REG_SET (save_reload_reg_used_in_output_addr[i],
reload_reg_used_in_output_addr[i]);
+ COPY_HARD_REG_SET (save_reload_reg_used_in_outaddr_addr[i],
+ reload_reg_used_in_outaddr_addr[i]);
}
/* If -O, try first with inheritance, then turning it off.
@@ -5116,12 +5577,14 @@ choose_reload_regs (insn, avoid_return_reg)
register int r = reload_order[j];
/* Ignore reloads that got marked inoperative. */
- if (reload_out[r] == 0 && reload_in[r] == 0 && ! reload_secondary_p[r])
+ if (reload_out[r] == 0 && reload_in[r] == 0
+ && ! reload_secondary_p[r])
continue;
/* If find_reloads chose a to use reload_in or reload_out as a reload
- register, we don't need to chose one. Otherwise, try even if it found
- one since we might save an insn if we find the value lying around. */
+ register, we don't need to chose one. Otherwise, try even if it
+ found one since we might save an insn if we find the value lying
+ around. */
if (reload_in[r] != 0 && reload_reg_rtx[r] != 0
&& (rtx_equal_p (reload_in[r], reload_reg_rtx[r])
|| rtx_equal_p (reload_out[r], reload_reg_rtx[r])))
@@ -5153,9 +5616,9 @@ choose_reload_regs (insn, avoid_return_reg)
an object that is already in a register of the desired class.
This would avoid the need for the secondary reload register.
But this is complex because we can't easily determine what
- objects might want to be loaded via this reload. So let a register
- be allocated here. In `emit_reload_insns' we suppress one of the
- loads in the case described above. */
+ objects might want to be loaded via this reload. So let a
+ register be allocated here. In `emit_reload_insns' we suppress
+ one of the loads in the case described above. */
if (inheritance)
{
@@ -5174,6 +5637,33 @@ choose_reload_regs (insn, avoid_return_reg)
regno = REGNO (reload_in_reg[r]);
mode = GET_MODE (reload_in_reg[r]);
}
+ else if (GET_CODE (reload_in[r]) == MEM)
+ {
+ rtx prev = prev_nonnote_insn (insn), note;
+
+ if (prev && GET_CODE (prev) == INSN
+ && GET_CODE (PATTERN (prev)) == USE
+ && GET_CODE (XEXP (PATTERN (prev), 0)) == REG
+ && (REGNO (XEXP (PATTERN (prev), 0))
+ >= FIRST_PSEUDO_REGISTER)
+ && (note = find_reg_note (prev, REG_EQUAL, NULL_RTX))
+ && GET_CODE (XEXP (note, 0)) == MEM)
+ {
+ rtx addr = XEXP (XEXP (note, 0), 0);
+ int size_diff
+ = (GET_MODE_SIZE (GET_MODE (addr))
+ - GET_MODE_SIZE (GET_MODE (reload_in[r])));
+ if (size_diff >= 0
+ && rtx_equal_p ((BYTES_BIG_ENDIAN
+ ? plus_constant (addr, size_diff)
+ : addr),
+ XEXP (reload_in[r], 0)))
+ {
+ regno = REGNO (XEXP (PATTERN (prev), 0));
+ mode = GET_MODE (reload_in[r]);
+ }
+ }
+ }
#if 0
/* This won't work, since REGNO can be a pseudo reg number.
Also, it takes much more hair to keep track of all the things
@@ -5185,32 +5675,36 @@ choose_reload_regs (insn, avoid_return_reg)
if (regno >= 0 && reg_last_reload_reg[regno] != 0)
{
- i = spill_reg_order[REGNO (reg_last_reload_reg[regno])];
+ i = REGNO (reg_last_reload_reg[regno]);
if (reg_reloaded_contents[i] == regno
+ && TEST_HARD_REG_BIT (reg_reloaded_valid, i)
&& (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
>= GET_MODE_SIZE (mode))
- && HARD_REGNO_MODE_OK (spill_regs[i], reload_mode[r])
+ && HARD_REGNO_MODE_OK (i, reload_mode[r])
&& TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
- spill_regs[i])
+ i)
&& (reload_nregs[r] == max_group_size
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class],
- spill_regs[i]))
- && reload_reg_free_p (spill_regs[i], reload_opnum[r],
- reload_when_needed[r])
- && reload_reg_free_before_p (spill_regs[i],
- reload_opnum[r],
- reload_when_needed[r]))
+ i))
+ && ((reload_reg_free_p (i, reload_opnum[r],
+ reload_when_needed[r])
+ && reload_reg_free_before_p (i, reload_opnum[r],
+ reload_when_needed[r]))
+ || reload_reg_free_for_value_p (i, reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
{
/* If a group is needed, verify that all the subsequent
- registers still have their values intact. */
+ registers still have their values intact. */
int nr
- = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
+ = HARD_REGNO_NREGS (i, reload_mode[r]);
int k;
for (k = 1; k < nr; k++)
- if (reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- != regno)
+ if (reg_reloaded_contents[i + k] != regno
+ || ! TEST_HARD_REG_BIT (reg_reloaded_valid, i + k))
break;
if (k == nr)
@@ -5231,6 +5725,10 @@ choose_reload_regs (insn, avoid_return_reg)
break;
if (i1 != n_earlyclobbers
+ /* Don't use it if we'd clobber a pseudo reg. */
+ || (spill_reg_order[i] < 0
+ && reload_out[r]
+ && ! TEST_HARD_REG_BIT (reg_reloaded_dead, i))
/* Don't really use the inherited spill reg
if we need it wider than we've got it. */
|| (GET_MODE_SIZE (reload_mode[r])
@@ -5242,7 +5740,7 @@ choose_reload_regs (insn, avoid_return_reg)
/* We can use this as a reload reg. */
/* Mark the register as in use for this part of
the insn. */
- mark_reload_reg_in_use (spill_regs[i],
+ mark_reload_reg_in_use (i,
reload_opnum[r],
reload_when_needed[r],
reload_mode[r]);
@@ -5253,7 +5751,7 @@ choose_reload_regs (insn, avoid_return_reg)
reload_spill_index[r] = i;
for (k = 0; k < nr; k++)
SET_HARD_REG_BIT (reload_reg_used_for_inherit,
- spill_regs[i + k]);
+ i + k);
}
}
}
@@ -5288,7 +5786,7 @@ choose_reload_regs (insn, avoid_return_reg)
address and not all machines support SUBREGs
there. */
regno = REGNO (SUBREG_REG (equiv)) + SUBREG_WORD (equiv);
- equiv = gen_rtx (REG, reload_mode[r], regno);
+ equiv = gen_rtx_REG (reload_mode[r], regno);
}
else
abort ();
@@ -5298,8 +5796,13 @@ choose_reload_regs (insn, avoid_return_reg)
and of the desired class. */
if (equiv != 0
&& ((spill_reg_order[regno] >= 0
- && ! reload_reg_free_before_p (regno, reload_opnum[r],
- reload_when_needed[r]))
+ && ! (reload_reg_free_before_p (regno, reload_opnum[r],
+ reload_when_needed[r])
+ || reload_reg_free_for_value_p (regno,
+ reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
regno)))
equiv = 0;
@@ -5325,33 +5828,60 @@ choose_reload_regs (insn, avoid_return_reg)
break;
}
- /* JRV: If the equiv register we have found is explicitly
- clobbered in the current insn, mark but don't use, as above. */
+ /* If the equiv register we have found is explicitly clobbered
+ in the current insn, it depends on the reload type if we
+ can use it, use it for reload_override_in, or not at all.
+ In particular, we then can't use EQUIV for a
+ RELOAD_FOR_OUTPUT_ADDRESS reload. */
if (equiv != 0 && regno_clobbered_p (regno, insn))
{
- reload_override_in[r] = equiv;
- equiv = 0;
+ switch (reload_when_needed[r])
+ {
+ case RELOAD_FOR_OTHER_ADDRESS:
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ case RELOAD_FOR_INPUT_ADDRESS:
+ case RELOAD_FOR_OPADDR_ADDR:
+ break;
+ case RELOAD_OTHER:
+ case RELOAD_FOR_INPUT:
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ reload_override_in[r] = equiv;
+ /* Fall through. */
+ default:
+ equiv = 0;
+ break;
+ }
}
/* If we found an equivalent reg, say no code need be generated
to load it, and use it as our reload reg. */
if (equiv != 0 && regno != HARD_FRAME_POINTER_REGNUM)
{
+ int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
+ int k;
reload_reg_rtx[r] = equiv;
reload_inherited[r] = 1;
- /* If it is a spill reg,
- mark the spill reg as in use for this insn. */
- i = spill_reg_order[regno];
- if (i >= 0)
+
+ /* If reg_reloaded_valid is not set for this register,
+ there might be a stale spill_reg_store lying around.
+ We must clear it, since otherwise emit_reload_insns
+ might delete the store. */
+ if (! TEST_HARD_REG_BIT (reg_reloaded_valid, regno))
+ spill_reg_store[regno] = NULL_RTX;
+ /* If any of the hard registers in EQUIV are spill
+ registers, mark them as in use for this insn. */
+ for (k = 0; k < nr; k++)
{
- int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
- int k;
- mark_reload_reg_in_use (regno, reload_opnum[r],
- reload_when_needed[r],
- reload_mode[r]);
- for (k = 0; k < nr; k++)
- SET_HARD_REG_BIT (reload_reg_used_for_inherit, regno + k);
+ i = spill_reg_order[regno + k];
+ if (i >= 0)
+ {
+ mark_reload_reg_in_use (regno, reload_opnum[r],
+ reload_when_needed[r],
+ reload_mode[r]);
+ SET_HARD_REG_BIT (reload_reg_used_for_inherit,
+ regno + k);
+ }
}
}
}
@@ -5407,7 +5937,7 @@ choose_reload_regs (insn, avoid_return_reg)
continue;
/* Skip reloads that already have a register allocated or are
- optional. */
+ optional. */
if (reload_reg_rtx[r] != 0 || reload_optional[r])
continue;
@@ -5453,8 +5983,12 @@ choose_reload_regs (insn, avoid_return_reg)
save_reload_reg_used_in_output[i]);
COPY_HARD_REG_SET (reload_reg_used_in_input_addr[i],
save_reload_reg_used_in_input_addr[i]);
+ COPY_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i],
+ save_reload_reg_used_in_inpaddr_addr[i]);
COPY_HARD_REG_SET (reload_reg_used_in_output_addr[i],
save_reload_reg_used_in_output_addr[i]);
+ COPY_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i],
+ save_reload_reg_used_in_outaddr_addr[i]);
}
}
@@ -5467,10 +6001,56 @@ choose_reload_regs (insn, avoid_return_reg)
register int r = reload_order[j];
if (reload_inherited[r] && reload_reg_rtx[r] != 0
- && ! reload_reg_free_before_p (true_regnum (reload_reg_rtx[r]),
- reload_opnum[r],
- reload_when_needed[r]))
+ && ! (reload_reg_free_before_p (true_regnum (reload_reg_rtx[r]),
+ reload_opnum[r],
+ reload_when_needed[r])
+ || reload_reg_free_for_value_p (true_regnum (reload_reg_rtx[r]),
+ reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
reload_inherited[r] = 0;
+ /* If we can inherit a RELOAD_FOR_INPUT, then we do not need its related
+ RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS reloads.
+ ??? This could be extended to other reload types, but these are
+ more tricky to handle:
+ RELOAD_FOR_OTHER_ADDRESS reloads might have been merged, so we
+ can't eliminate them without a check that *all* references are
+ now unused due to inheritance.
+ While RELOAD_FOR_INPADDR_ADDRESS and RELOAD_FOR_OUTADDR_ADDRESS are
+ not merged, we can't be sure that we have eliminated the use of
+ that particular reload if we have seen just one
+ RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS being inherited,
+ since there might be multiple of the latter two reloads for a single
+ operand.
+ RELOAD_FOR_OPADDR_ADDR reloads for different operands are not
+ merged, but might share the same register by courtesy of
+ reload_reg_free_for_value_p. reload_reg_used_in_op_addr_reload
+ does not differentiate by opnum, thus calling clear_reload_reg_in_use
+ for one of these reloads would mark the register as free even though
+ another RELOAD_FOR_OPADDR_ADDR reload might still use it. */
+ else if (reload_inherited[r] && reload_when_needed[r] == RELOAD_FOR_INPUT)
+ {
+ for (i = 0; i < n_reloads; i++)
+ {
+ if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
+ && reload_opnum[i] == reload_opnum[r]
+ && reload_in[i] && reload_reg_rtx[i])
+ {
+ int regno = true_regnum (reload_reg_rtx[i]);
+
+ reload_in[i] = 0;
+ if (spill_reg_order[regno] >= 0)
+ clear_reload_reg_in_use (regno, reload_opnum[i],
+ reload_when_needed[i],
+ reload_mode[i]);
+ reload_reg_rtx[i] = 0;
+ reload_spill_index[i] = -1;
+ remove_replacements (i);
+ }
+ }
+ }
/* If we found a better place to reload from,
validate it in the same fashion, if it is a reload reg. */
@@ -5516,7 +6096,7 @@ choose_reload_regs (insn, avoid_return_reg)
i = reload_spill_index[r];
- /* I is nonneg if this reload used one of the spill regs.
+ /* I is nonneg if this reload uses a register.
If reload_reg_rtx[r] is 0, this is an optional reload
that we opted to ignore. */
if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG
@@ -5533,9 +6113,9 @@ choose_reload_regs (insn, avoid_return_reg)
if (i >= 0)
{
- nr = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
+ nr = HARD_REGNO_NREGS (i, reload_mode[r]);
while (--nr >= 0)
- SET_HARD_REG_BIT (reg_is_output_reload, spill_regs[i] + nr);
+ SET_HARD_REG_BIT (reg_is_output_reload, i + nr);
}
if (reload_when_needed[r] != RELOAD_OTHER
@@ -5546,7 +6126,7 @@ choose_reload_regs (insn, avoid_return_reg)
}
}
-/* If SMALL_REGISTER_CLASSES are defined, we may not have merged two
+/* If SMALL_REGISTER_CLASSES is non-zero, we may not have merged two
reloads of the same item for fear that we might not have enough reload
registers. However, normally they will get the same reload register
and hence actually need not be loaded twice.
@@ -5559,8 +6139,6 @@ choose_reload_regs (insn, avoid_return_reg)
This will not increase the number of spill registers needed and will
prevent redundant code. */
-#ifdef SMALL_REGISTER_CLASSES
-
static void
merge_assigned_reloads (insn)
rtx insn;
@@ -5573,6 +6151,10 @@ merge_assigned_reloads (insn)
for (i = 0; i < n_reloads; i++)
{
+ int conflicting_input = 0;
+ int max_input_address_opnum = -1;
+ int min_conflicting_input_opnum = MAX_RECOG_OPERANDS;
+
if (reload_in[i] == 0 || reload_when_needed[i] == RELOAD_OTHER
|| reload_out[i] != 0 || reload_reg_rtx[i] == 0
|| reg_set_p (reload_reg_rtx[i], insn))
@@ -5591,27 +6173,46 @@ merge_assigned_reloads (insn)
reload_reg_rtx[i]))
continue;
+ if (reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
+ && reload_opnum[j] > max_input_address_opnum)
+ max_input_address_opnum = reload_opnum[j];
+
/* If the reload regs aren't exactly the same (e.g, different modes)
- or if the values are different, we can't merge anything with this
- reload register. */
+ or if the values are different, we can't merge this reload.
+ But if it is an input reload, we might still merge
+ RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_OTHER_ADDRESS reloads. */
if (! rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j])
|| reload_out[j] != 0 || reload_in[j] == 0
|| ! rtx_equal_p (reload_in[i], reload_in[j]))
- break;
+ {
+ if (reload_when_needed[j] != RELOAD_FOR_INPUT
+ || ((reload_when_needed[i] != RELOAD_FOR_INPUT_ADDRESS
+ || reload_opnum[i] > reload_opnum[j])
+ && reload_when_needed[i] != RELOAD_FOR_OTHER_ADDRESS))
+ break;
+ conflicting_input = 1;
+ if (min_conflicting_input_opnum > reload_opnum[j])
+ min_conflicting_input_opnum = reload_opnum[j];
+ }
}
/* If all is OK, merge the reloads. Only set this to RELOAD_OTHER if
we, in fact, found any matching reloads. */
- if (j == n_reloads)
+ if (j == n_reloads
+ && max_input_address_opnum <= min_conflicting_input_opnum)
{
for (j = 0; j < n_reloads; j++)
if (i != j && reload_reg_rtx[j] != 0
- && rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j]))
+ && rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j])
+ && (! conflicting_input
+ || reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[j] == RELOAD_FOR_OTHER_ADDRESS))
{
reload_when_needed[i] = RELOAD_OTHER;
reload_in[j] = 0;
+ reload_spill_index[j] = -1;
transfer_replacements (i, j);
}
@@ -5628,12 +6229,13 @@ merge_assigned_reloads (insn)
&& reg_overlap_mentioned_for_reload_p (reload_in[j],
reload_in[i]))
reload_when_needed[j]
- = reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER;
+ = ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
+ ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
}
}
}
-#endif /* SMALL_RELOAD_CLASSES */
+
/* Output insns to reload values in and out of the chosen reload regs. */
@@ -5646,20 +6248,28 @@ emit_reload_insns (insn)
rtx other_input_address_reload_insns = 0;
rtx other_input_reload_insns = 0;
rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
+ rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
rtx output_reload_insns[MAX_RECOG_OPERANDS];
rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
+ rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
rtx operand_reload_insns = 0;
rtx other_operand_reload_insns = 0;
- rtx other_output_reload_insns = 0;
+ rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
rtx following_insn = NEXT_INSN (insn);
rtx before_insn = insn;
int special;
/* Values to be put in spill_reg_store are put here first. */
rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
+ HARD_REG_SET reg_reloaded_died;
+
+ CLEAR_HARD_REG_SET (reg_reloaded_died);
for (j = 0; j < reload_n_operands; j++)
input_reload_insns[j] = input_address_reload_insns[j]
- = output_reload_insns[j] = output_address_reload_insns[j] = 0;
+ = inpaddr_address_reload_insns[j]
+ = output_reload_insns[j] = output_address_reload_insns[j]
+ = outaddr_address_reload_insns[j]
+ = other_output_reload_insns[j] = 0;
/* Now output the instructions to copy the data into and out of the
reload registers. Do these in the order that the reloads were reported,
@@ -5670,6 +6280,8 @@ emit_reload_insns (insn)
{
register rtx old;
rtx oldequiv_reg = 0;
+ rtx this_reload_insn = 0;
+ int expect_occurrences = 1;
if (reload_spill_index[j] >= 0)
new_spill_reg_store[reload_spill_index[j]] = 0;
@@ -5789,15 +6401,15 @@ emit_reload_insns (insn)
&& ((REGNO_REG_CLASS (regno) != reload_reg_class[j]
&& (REGISTER_MOVE_COST (REGNO_REG_CLASS (regno),
reload_reg_class[j])
- >= MEMORY_MOVE_COST (mode)))
+ >= MEMORY_MOVE_COST (mode, reload_reg_class[j], 1)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (reload_reg_class[j],
mode, oldequiv)
!= NO_REGS)
#endif
#ifdef SECONDARY_MEMORY_NEEDED
- || SECONDARY_MEMORY_NEEDED (reload_reg_class[j],
- REGNO_REG_CLASS (regno),
+ || SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
+ reload_reg_class[j],
mode)
#endif
))
@@ -5817,14 +6429,12 @@ emit_reload_insns (insn)
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
- && spill_reg_order[REGNO (oldequiv)] >= 0
- && spill_reg_store[spill_reg_order[REGNO (oldequiv)]] != 0
- && find_reg_note (insn, REG_DEAD, reload_in[j])
+ && spill_reg_store[REGNO (oldequiv)]
+ && GET_CODE (old) == REG && dead_or_set_p (insn, old)
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences weren't reloaded. */
- && count_occurrences (PATTERN (insn), reload_in[j]) == 1)
- delete_output_reload
- (insn, j, spill_reg_store[spill_reg_order[REGNO (oldequiv)]]);
+ && count_occurrences (PATTERN (insn), old) == 1)
+ delete_output_reload (insn, j, spill_reg_store[REGNO (oldequiv)]);
/* Encapsulate both RELOADREG and OLDEQUIV into that mode,
then load RELOADREG from OLDEQUIV. Note that we cannot use
@@ -5833,12 +6443,12 @@ emit_reload_insns (insn)
must always be a REG here. */
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
oldequiv = SUBREG_REG (oldequiv);
if (GET_MODE (oldequiv) != VOIDmode
&& mode != GET_MODE (oldequiv))
- oldequiv = gen_rtx (SUBREG, mode, oldequiv, 0);
+ oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
/* Switch to the right place to emit the reload insns. */
switch (reload_when_needed[j])
@@ -5852,9 +6462,15 @@ emit_reload_insns (insn)
case RELOAD_FOR_INPUT_ADDRESS:
where = &input_address_reload_insns[reload_opnum[j]];
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ where = &inpaddr_address_reload_insns[reload_opnum[j]];
+ break;
case RELOAD_FOR_OUTPUT_ADDRESS:
where = &output_address_reload_insns[reload_opnum[j]];
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ where = &outaddr_address_reload_insns[reload_opnum[j]];
+ break;
case RELOAD_FOR_OPERAND_ADDRESS:
where = &operand_reload_insns;
break;
@@ -5923,8 +6539,8 @@ emit_reload_insns (insn)
SET_DEST (PATTERN (temp)) = reloadreg;
/* If these are the only uses of the pseudo reg,
pretend for GDB it lives in the reload reg we used. */
- if (reg_n_deaths[REGNO (old)] == 1
- && reg_n_sets[REGNO (old)] == 1)
+ if (REG_N_DEATHS (REGNO (old)) == 1
+ && REG_N_SETS (REGNO (old)) == 1)
{
reg_renumber[REGNO (old)] = REGNO (reload_reg_rtx[j]);
alter_reg (REGNO (old), -1);
@@ -6015,8 +6631,8 @@ emit_reload_insns (insn)
oldequiv = old, real_oldequiv = real_old;
else
second_reload_reg
- = gen_rtx (REG, new_mode,
- REGNO (second_reload_reg));
+ = gen_rtx_REG (new_mode,
+ REGNO (second_reload_reg));
}
}
}
@@ -6083,20 +6699,34 @@ emit_reload_insns (insn)
&& reg_overlap_mentioned_for_reload_p (second_reload_reg,
PATTERN (prev)))
{
- REG_NOTES (prev) = gen_rtx (EXPR_LIST, REG_DEAD,
- second_reload_reg,
- REG_NOTES (prev));
+ REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_DEAD,
+ second_reload_reg,
+ REG_NOTES (prev));
break;
}
}
#endif
}
+ this_reload_insn = get_last_insn ();
/* End this sequence. */
*where = get_insns ();
end_sequence ();
}
+ /* When inheriting a wider reload, we have a MEM in reload_in[j],
+ e.g. inheriting a SImode output reload for
+ (mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */
+ if (optimize && reload_inherited[j] && reload_in[j]
+ && GET_CODE (reload_in[j]) == MEM
+ && reload_spill_index[j] >= 0
+ && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
+ {
+ expect_occurrences
+ = count_occurrences (PATTERN (insn), reload_in[j]) == 1 ? 0 : -1;
+ reload_in[j]
+ = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
+ }
/* Add a note saying the input reload reg
dies in this insn, if anyone cares. */
#ifdef PRESERVE_DEATH_INFO_REGNO_P
@@ -6125,8 +6755,8 @@ emit_reload_insns (insn)
|| reload_when_needed[j] == RELOAD_FOR_INPUT)
&& ! dead_or_set_p (insn, reloadreg))
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_DEAD,
- reloadreg, REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_DEAD,
+ reloadreg, REG_NOTES (insn));
}
/* When we inherit a reload, the last marked death of the reload reg
@@ -6198,9 +6828,9 @@ emit_reload_insns (insn)
&& reg_overlap_mentioned_for_reload_p (oldequiv_reg,
PATTERN (prev1)))
{
- REG_NOTES (prev1) = gen_rtx (EXPR_LIST, REG_DEAD,
- oldequiv_reg,
- REG_NOTES (prev1));
+ REG_NOTES (prev1) = gen_rtx_EXPR_LIST (REG_DEAD,
+ oldequiv_reg,
+ REG_NOTES (prev1));
break;
}
remove_death (REGNO (oldequiv_reg), prev);
@@ -6225,12 +6855,13 @@ emit_reload_insns (insn)
#endif
&& spill_reg_store[reload_spill_index[j]] != 0
/* This is unsafe if some other reload uses the same reg first. */
- && reload_reg_free_before_p (spill_regs[reload_spill_index[j]],
+ && reload_reg_free_before_p (reload_spill_index[j],
reload_opnum[j], reload_when_needed[j])
&& dead_or_set_p (insn, reload_in[j])
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences weren't reloaded. */
- && count_occurrences (PATTERN (insn), reload_in[j]) == 1)
+ && (count_occurrences (PATTERN (insn), reload_in[j])
+ == expect_occurrences))
delete_output_reload (insn, j,
spill_reg_store[reload_spill_index[j]]);
@@ -6246,7 +6877,9 @@ emit_reload_insns (insn)
&& reload_reg_rtx[j] != 0)
{
register rtx reloadreg = reload_reg_rtx[j];
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
register rtx second_reloadreg = 0;
+#endif
rtx note, p;
enum machine_mode mode;
int special = 0;
@@ -6307,11 +6940,11 @@ emit_reload_insns (insn)
error_for_asm (insn, "output operand is constant in `asm'");
/* Prevent crash--use something we know is valid. */
mode = word_mode;
- old = gen_rtx (REG, mode, REGNO (reloadreg));
+ old = gen_rtx_REG (mode, REGNO (reloadreg));
}
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
@@ -6352,7 +6985,7 @@ emit_reload_insns (insn)
= reload_secondary_out_icode[secondary_reload];
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
if (tertiary_icode != CODE_FOR_nothing)
{
@@ -6395,8 +7028,20 @@ emit_reload_insns (insn)
/* Output the last reload insn. */
if (! special)
- gen_reload (old, reloadreg, reload_opnum[j],
- reload_when_needed[j]);
+ {
+ rtx set;
+
+ /* Don't output the last reload if OLD is not the dest of
+ INSN and is in the src and is clobbered by INSN. */
+ if (! flag_expensive_optimizations
+ || GET_CODE (old) != REG
+ || !(set = single_set (insn))
+ || rtx_equal_p (old, SET_DEST (set))
+ || !reg_mentioned_p (old, SET_SRC (set))
+ || !regno_clobbered_p (REGNO (old), insn))
+ gen_reload (old, reloadreg, reload_opnum[j],
+ reload_when_needed[j]);
+ }
#ifdef PRESERVE_DEATH_INFO_REGNO_P
/* If final will look at death notes for this reg,
@@ -6407,40 +7052,83 @@ emit_reload_insns (insn)
if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& reg_overlap_mentioned_for_reload_p (reloadreg,
PATTERN (p)))
- REG_NOTES (p) = gen_rtx (EXPR_LIST, REG_DEAD,
- reloadreg, REG_NOTES (p));
+ REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_DEAD,
+ reloadreg, REG_NOTES (p));
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
- if (! special
+ if (! special && second_reloadreg
&& PRESERVE_DEATH_INFO_REGNO_P (REGNO (second_reloadreg)))
for (p = get_last_insn (); p; p = PREV_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& reg_overlap_mentioned_for_reload_p (second_reloadreg,
PATTERN (p)))
- REG_NOTES (p) = gen_rtx (EXPR_LIST, REG_DEAD,
- second_reloadreg, REG_NOTES (p));
+ REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_DEAD,
+ second_reloadreg,
+ REG_NOTES (p));
#endif
#endif
/* Look at all insns we emitted, just to be safe. */
for (p = get_insns (); p; p = NEXT_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
+ rtx pat = PATTERN (p);
+
/* If this output reload doesn't come from a spill reg,
clear any memory of reloaded copies of the pseudo reg.
If this output reload comes from a spill reg,
reg_has_output_reload will make this do nothing. */
- note_stores (PATTERN (p), forget_old_reloads_1);
+ note_stores (pat, forget_old_reloads_1);
+
+ if (reg_mentioned_p (reload_reg_rtx[j], pat))
+ {
+ if (reload_spill_index[j] < 0
+ && GET_CODE (pat) == SET
+ && SET_SRC (pat) == reload_reg_rtx[j])
+ {
+ int src = REGNO (SET_SRC (pat));
- if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p))
- && reload_spill_index[j] >= 0)
- new_spill_reg_store[reload_spill_index[j]] = p;
+ reload_spill_index[j] = src;
+ SET_HARD_REG_BIT (reg_is_output_reload, src);
+ if (find_regno_note (insn, REG_DEAD, src))
+ SET_HARD_REG_BIT (reg_reloaded_died, src);
+ }
+ if (reload_spill_index[j] >= 0)
+ {
+ int s = reload_secondary_out_reload[j];
+ rtx set = single_set (p);
+ /* If this reload copies only to the secondary reload
+ register, the secondary reload does the actual
+ store. */
+ if (s >= 0 && set == NULL_RTX)
+ ; /* We can't tell what function the secondary reload
+ has and where the actual store to the pseudo is
+ made; leave new_spill_reg_store alone. */
+ else if (s >= 0
+ && SET_SRC (set) == reload_reg_rtx[j]
+ && SET_DEST (set) == reload_reg_rtx[s])
+ {
+ /* Usually the next instruction will be the
+ secondary reload insn; if we can confirm
+ that it is, setting new_spill_reg_store to
+ that insn will allow an extra optimization. */
+ rtx s_reg = reload_reg_rtx[s];
+ rtx next = NEXT_INSN (p);
+ reload_out[s] = reload_out[j];
+ set = single_set (next);
+ if (set && SET_SRC (set) == s_reg
+ && ! new_spill_reg_store[REGNO (s_reg)])
+ new_spill_reg_store[REGNO (s_reg)] = next;
+ }
+ else
+ new_spill_reg_store[reload_spill_index[j]] = p;
+ }
+ }
}
if (reload_when_needed[j] == RELOAD_OTHER)
{
- if (other_output_reload_insns)
- emit_insns (other_output_reload_insns);
- other_output_reload_insns = get_insns ();
+ emit_insns (other_output_reload_insns[reload_opnum[j]]);
+ other_output_reload_insns[reload_opnum[j]] = get_insns ();
}
else
output_reload_insns[reload_opnum[j]] = get_insns ();
@@ -6455,10 +7143,11 @@ emit_reload_insns (insn)
RELOAD_FOR_OTHER_ADDRESS reloads for input addresses.
- RELOAD_OTHER reloads, output in ascending order by reload number.
+ RELOAD_OTHER reloads.
- For each operand, any RELOAD_FOR_INPUT_ADDRESS reloads followed by
- the RELOAD_FOR_INPUT reload for the operand.
+ For each operand, any RELOAD_FOR_INPADDR_ADDRESS reloads followed
+ by any RELOAD_FOR_INPUT_ADDRESS reloads followed by the
+ RELOAD_FOR_INPUT reload for the operand.
RELOAD_FOR_OPADDR_ADDRS reloads.
@@ -6466,17 +7155,18 @@ emit_reload_insns (insn)
After the insn being reloaded, we write the following:
- For each operand, any RELOAD_FOR_OUTPUT_ADDRESS reload followed by
- the RELOAD_FOR_OUTPUT reload for that operand.
-
- Any RELOAD_OTHER output reloads, output in descending order by
- reload number. */
+ For each operand, any RELOAD_FOR_OUTADDR_ADDRESS reloads followed
+ by any RELOAD_FOR_OUTPUT_ADDRESS reload followed by the
+ RELOAD_FOR_OUTPUT reload, followed by any RELOAD_OTHER output
+ reloads for the operand. The RELOAD_OTHER output reloads are
+ output in descending order by reload number. */
emit_insns_before (other_input_address_reload_insns, before_insn);
emit_insns_before (other_input_reload_insns, before_insn);
for (j = 0; j < reload_n_operands; j++)
{
+ emit_insns_before (inpaddr_address_reload_insns[j], before_insn);
emit_insns_before (input_address_reload_insns[j], before_insn);
emit_insns_before (input_reload_insns[j], before_insn);
}
@@ -6486,12 +7176,12 @@ emit_reload_insns (insn)
for (j = 0; j < reload_n_operands; j++)
{
+ emit_insns_before (outaddr_address_reload_insns[j], following_insn);
emit_insns_before (output_address_reload_insns[j], following_insn);
emit_insns_before (output_reload_insns[j], following_insn);
+ emit_insns_before (other_output_reload_insns[j], following_insn);
}
- emit_insns_before (other_output_reload_insns, following_insn);
-
/* Move death notes from INSN
to output-operand-address and output reload insns. */
#ifdef PRESERVE_DEATH_INFO_REGNO_P
@@ -6548,109 +7238,137 @@ emit_reload_insns (insn)
register int r = reload_order[j];
register int i = reload_spill_index[r];
- /* I is nonneg if this reload used one of the spill regs.
+ /* I is nonneg if this reload used a register.
If reload_reg_rtx[r] is 0, this is an optional reload
- that we opted to ignore.
-
- Also ignore reloads that don't reach the end of the insn,
- since we will eventually see the one that does. */
+ that we opted to ignore. */
- if (i >= 0 && reload_reg_rtx[r] != 0
- && reload_reg_reaches_end_p (spill_regs[i], reload_opnum[r],
- reload_when_needed[r]))
+ if (i >= 0 && reload_reg_rtx[r] != 0)
{
- /* First, clear out memory of what used to be in this spill reg.
- If consecutive registers are used, clear them all. */
int nr
- = HARD_REGNO_NREGS (spill_regs[i], GET_MODE (reload_reg_rtx[r]));
+ = HARD_REGNO_NREGS (i, GET_MODE (reload_reg_rtx[r]));
int k;
+ int part_reaches_end = 0;
+ int all_reaches_end = 1;
+ /* For a multi register reload, we need to check if all or part
+ of the value lives to the end. */
for (k = 0; k < nr; k++)
{
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+ if (reload_reg_reaches_end_p (i + k, reload_opnum[r],
+ reload_when_needed[r]))
+ part_reaches_end = 1;
+ else
+ all_reaches_end = 0;
}
- /* Maybe the spill reg contains a copy of reload_out. */
- if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+ /* Ignore reloads that don't reach the end of the insn in
+ entirety. */
+ if (all_reaches_end)
{
- register int nregno = REGNO (reload_out[r]);
- int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (reload_reg_rtx[r])));
-
- spill_reg_store[i] = new_spill_reg_store[i];
- reg_last_reload_reg[nregno] = reload_reg_rtx[r];
-
- /* If NREGNO is a hard register, it may occupy more than
- one register. If it does, say what is in the
- rest of the registers assuming that both registers
- agree on how many words the object takes. If not,
- invalidate the subsequent registers. */
-
- if (nregno < FIRST_PSEUDO_REGISTER)
- for (k = 1; k < nnr; k++)
- reg_last_reload_reg[nregno + k]
- = (nr == nnr ? gen_rtx (REG,
- reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
- REGNO (reload_reg_rtx[r]) + k)
- : 0);
+ /* First, clear out memory of what used to be in this spill reg.
+ If consecutive registers are used, clear them all. */
- /* Now do the inverse operation. */
for (k = 0; k < nr; k++)
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
+
+ /* Maybe the spill reg contains a copy of reload_out. */
+ if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
{
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
- : nregno + k);
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+ register int nregno = REGNO (reload_out[r]);
+ int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
+
+ spill_reg_store[i] = new_spill_reg_store[i];
+ reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+ /* If NREGNO is a hard register, it may occupy more than
+ one register. If it does, say what is in the
+ rest of the registers assuming that both registers
+ agree on how many words the object takes. If not,
+ invalidate the subsequent registers. */
+
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+ ? gen_rtx_REG (reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
+ /* Now do the inverse operation. */
+ for (k = 0; k < nr; k++)
+ {
+ CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
+ reg_reloaded_contents[i + k]
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ ? nregno
+ : nregno + k);
+ reg_reloaded_insn[i + k] = insn;
+ SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ }
}
- }
-
- /* Maybe the spill reg contains a copy of reload_in. Only do
- something if there will not be an output reload for
- the register being reloaded. */
- else if (reload_out[r] == 0
- && reload_in[r] != 0
- && ((GET_CODE (reload_in[r]) == REG
- && ! reg_has_output_reload[REGNO (reload_in[r])]
- || (GET_CODE (reload_in_reg[r]) == REG
- && ! reg_has_output_reload[REGNO (reload_in_reg[r])]))))
- {
- register int nregno;
- int nnr;
-
- if (GET_CODE (reload_in[r]) == REG)
- nregno = REGNO (reload_in[r]);
- else
- nregno = REGNO (reload_in_reg[r]);
-
- nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (reload_reg_rtx[r])));
- reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+ /* Maybe the spill reg contains a copy of reload_in. Only do
+ something if there will not be an output reload for
+ the register being reloaded. */
+ else if (reload_out[r] == 0
+ && reload_in[r] != 0
+ && spill_reg_order[i] >= 0
+ && ((GET_CODE (reload_in[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in[r])])
+ || (GET_CODE (reload_in_reg[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in_reg[r])])))
+ {
+ register int nregno;
+ int nnr;
- if (nregno < FIRST_PSEUDO_REGISTER)
- for (k = 1; k < nnr; k++)
- reg_last_reload_reg[nregno + k]
- = (nr == nnr ? gen_rtx (REG,
- reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
- REGNO (reload_reg_rtx[r]) + k)
- : 0);
+ if (GET_CODE (reload_in[r]) == REG)
+ nregno = REGNO (reload_in[r]);
+ else
+ nregno = REGNO (reload_in_reg[r]);
- /* Unless we inherited this reload, show we haven't
- recently done a store. */
- if (! reload_inherited[r])
- spill_reg_store[i] = 0;
+ nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
+
+ reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+ ? gen_rtx_REG (reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
+ /* Unless we inherited this reload, show we haven't
+ recently done a store. */
+ if (! reload_inherited[r])
+ spill_reg_store[i] = 0;
+
+ for (k = 0; k < nr; k++)
+ {
+ CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
+ reg_reloaded_contents[i + k]
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ ? nregno
+ : nregno + k);
+ reg_reloaded_insn[i + k] = insn;
+ SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ }
+ }
+ }
+ /* However, if part of the reload reaches the end, then we must
+ invalidate the old info for the part that survives to the end. */
+ else if (part_reaches_end)
+ {
for (k = 0; k < nr; k++)
- {
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
- : nregno + k);
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
- = insn;
- }
+ if (reload_reg_reaches_end_p (i + k,
+ reload_opnum[r],
+ reload_when_needed[r]))
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
}
}
@@ -6676,6 +7394,7 @@ emit_reload_insns (insn)
}
}
}
+ IOR_HARD_REG_SET (reg_reloaded_dead, reg_reloaded_died);
}
/* Emit code to perform a reload from IN (which may be a reload register) to
@@ -6735,8 +7454,10 @@ gen_reload (out, in, opnum, type)
if (GET_CODE (in) == PLUS
&& (GET_CODE (XEXP (in, 0)) == REG
+ || GET_CODE (XEXP (in, 0)) == SUBREG
|| GET_CODE (XEXP (in, 0)) == MEM)
&& (GET_CODE (XEXP (in, 1)) == REG
+ || GET_CODE (XEXP (in, 1)) == SUBREG
|| CONSTANT_P (XEXP (in, 1))
|| GET_CODE (XEXP (in, 1)) == MEM))
{
@@ -6764,16 +7485,16 @@ gen_reload (out, in, opnum, type)
if the add instruction is two-address and the second operand
of the add is the same as the reload reg, which is frequently
the case. If the insn would be A = B + A, rearrange it so
- it will be A = A + B as constrain_operands expects. */
+ it will be A = A + B as constrain_operands expects. */
if (GET_CODE (XEXP (in, 1)) == REG
&& REGNO (out) == REGNO (XEXP (in, 1)))
tem = op0, op0 = op1, op1 = tem;
if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
- in = gen_rtx (PLUS, GET_MODE (in), op0, op1);
+ in = gen_rtx_PLUS (GET_MODE (in), op0, op1);
- insn = emit_insn (gen_rtx (SET, VOIDmode, out, in));
+ insn = emit_insn (gen_rtx_SET (VOIDmode, out, in));
code = recog_memoized (insn);
if (code >= 0)
@@ -6797,12 +7518,12 @@ gen_reload (out, in, opnum, type)
DEFINE_PEEPHOLE should be specified that recognizes the sequence
we emit below. */
- if (CONSTANT_P (op1) || GET_CODE (op1) == MEM
+ if (CONSTANT_P (op1) || GET_CODE (op1) == MEM || GET_CODE (op1) == SUBREG
|| (GET_CODE (op1) == REG
&& REGNO (op1) >= FIRST_PSEUDO_REGISTER))
tem = op0, op0 = op1, op1 = tem;
- emit_insn (gen_move_insn (out, op0));
+ gen_reload (out, op0, opnum, type);
/* If OP0 and OP1 are the same, we can use OUT for OP1.
This fixes a problem on the 32K where the stack pointer cannot
@@ -6814,7 +7535,7 @@ gen_reload (out, in, opnum, type)
insn = emit_insn (gen_add2_insn (out, op1));
/* If that failed, copy the address register to the reload register.
- Then add the constant to the reload register. */
+ Then add the constant to the reload register. */
code = recog_memoized (insn);
@@ -6825,13 +7546,19 @@ gen_reload (out, in, opnum, type)
its validity determination, i.e., the way it would after reload
has completed. */
if (constrain_operands (code, 1))
- return insn;
+ {
+ /* Add a REG_EQUIV note so that find_equiv_reg can find it. */
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
+ return insn;
+ }
}
delete_insns_since (last);
- emit_insn (gen_move_insn (out, op1));
- emit_insn (gen_add2_insn (out, op0));
+ gen_reload (out, op1, opnum, type);
+ insn = emit_insn (gen_add2_insn (out, op0));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
}
#ifdef SECONDARY_MEMORY_NEEDED
@@ -6846,13 +7573,13 @@ gen_reload (out, in, opnum, type)
rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type);
if (GET_MODE (loc) != GET_MODE (out))
- out = gen_rtx (REG, GET_MODE (loc), REGNO (out));
+ out = gen_rtx_REG (GET_MODE (loc), REGNO (out));
if (GET_MODE (loc) != GET_MODE (in))
- in = gen_rtx (REG, GET_MODE (loc), REGNO (in));
+ in = gen_rtx_REG (GET_MODE (loc), REGNO (in));
- emit_insn (gen_move_insn (loc, in));
- emit_insn (gen_move_insn (out, loc));
+ gen_reload (loc, in, opnum, type);
+ gen_reload (out, loc, opnum, type);
}
#endif
@@ -6867,7 +7594,7 @@ gen_reload (out, in, opnum, type)
/* Otherwise, just write (set OUT IN) and hope for the best. */
else
- emit_insn (gen_rtx (SET, VOIDmode, out, in));
+ emit_insn (gen_rtx_SET (VOIDmode, out, in));
/* Return the first insn emitted.
We can not just return get_last_insn, because there may have
@@ -6912,23 +7639,40 @@ delete_output_reload (insn, j, output_reload_insn)
return;
if ((GET_CODE (i1) == INSN || GET_CODE (i1) == CALL_INSN)
&& reg_mentioned_p (reg, PATTERN (i1)))
- return;
+ {
+ /* If this is just a single USE with an REG_EQUAL note in front
+ of INSN, this is no problem, because this mentions just the
+ address that we are using here.
+ But if there is more than one such USE, the insn might use
+ the operand directly, or another reload might do that.
+ This is analogous to the count_occurences check in the callers. */
+ int num_occurences = 0;
+
+ while (GET_CODE (i1) == INSN && GET_CODE (PATTERN (i1)) == USE
+ && find_reg_note (i1, REG_EQUAL, NULL_RTX))
+ {
+ num_occurences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0;
+ i1 = NEXT_INSN (i1);
+ }
+ if (num_occurences == 1 && i1 == insn)
+ break;
+ return;
+ }
}
- if (cannot_omit_stores[REGNO (reg)])
- return;
-
- /* If this insn will store in the pseudo again,
- the previous store can be removed. */
- if (reload_out[j] == reload_in[j])
- delete_insn (output_reload_insn);
-
- /* See if the pseudo reg has been completely replaced
+ /* 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.
+ 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 reg has been completely replaced
with reload regs. If so, delete the store insn
and forget we had a stack slot for the pseudo. */
- else if (reg_n_deaths[REGNO (reg)] == 1
- && reg_basic_block[REGNO (reg)] >= 0
- && find_regno_note (insn, REG_DEAD, REGNO (reg)))
+ if (reload_out[j] != reload_in[j]
+ && REG_N_DEATHS (REGNO (reg)) == 1
+ && REG_BASIC_BLOCK (REGNO (reg)) >= 0
+ && find_regno_note (insn, REG_DEAD, REGNO (reg)))
{
rtx i2;
@@ -6950,9 +7694,12 @@ delete_output_reload (insn, j, output_reload_insn)
break;
if ((GET_CODE (i2) == INSN || GET_CODE (i2) == CALL_INSN)
&& reg_mentioned_p (reg, PATTERN (i2)))
- /* Some other ref remains;
- we can't do anything. */
- return;
+ {
+ /* Some other ref remains; just delete the output reload we
+ know to be dead. */
+ delete_insn (output_reload_insn);
+ return;
+ }
}
/* Delete the now-dead stores into this pseudo. */
@@ -6961,7 +7708,13 @@ delete_output_reload (insn, j, output_reload_insn)
rtx set = single_set (i2);
if (set != 0 && SET_DEST (set) == reg)
- delete_insn (i2);
+ {
+ /* This might be a basic block head,
+ thus don't use delete_insn. */
+ PUT_CODE (i2, NOTE);
+ NOTE_SOURCE_FILE (i2) = 0;
+ NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
+ }
if (GET_CODE (i2) == CODE_LABEL
|| GET_CODE (i2) == JUMP_INSN)
break;
@@ -6972,6 +7725,8 @@ delete_output_reload (insn, j, output_reload_insn)
reg_renumber[REGNO (reg)] = REGNO (reload_reg_rtx[j]);
alter_reg (REGNO (reg), -1);
}
+ delete_insn (output_reload_insn);
+
}
/* Output reload-insns to reload VALUE into RELOADREG.
@@ -7017,9 +7772,9 @@ inc_for_reload (reloadreg, value, inc_amount)
in gen_reload. */
last = get_last_insn ();
- add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc,
- gen_rtx (PLUS, GET_MODE (incloc),
- incloc, inc)));
+ add_insn = emit_insn (gen_rtx_SET (VOIDmode, incloc,
+ gen_rtx_PLUS (GET_MODE (incloc),
+ incloc, inc)));
code = recog_memoized (add_insn);
if (code >= 0)
@@ -7118,7 +7873,7 @@ constraint_accepts_reg_p (string, reg)
/* Return the number of places FIND appears within X, but don't count
an occurrence if some SET_DEST is FIND. */
-static int
+int
count_occurrences (x, find)
register rtx x, find;
{
@@ -7150,6 +7905,9 @@ count_occurrences (x, find)
if (SET_DEST (x) == find)
return count_occurrences (SET_SRC (x), find);
break;
+
+ default:
+ break;
}
format_ptr = GET_RTX_FORMAT (code);
@@ -7174,3 +7932,1073 @@ count_occurrences (x, find)
}
return count;
}
+
+/* This array holds values which are equivalent to a hard register
+ during reload_cse_regs. Each array element is an EXPR_LIST of
+ values. Each time a hard register is set, we set the corresponding
+ array element to the value. Each time a hard register is copied
+ into memory, we add the memory location to the corresponding array
+ element. We don't store values or memory addresses with side
+ effects in this array.
+
+ If the value is a CONST_INT, then the mode of the containing
+ EXPR_LIST is the mode in which that CONST_INT was referenced.
+
+ We sometimes clobber a specific entry in a list. In that case, we
+ just set XEXP (list-entry, 0) to 0. */
+
+static rtx *reg_values;
+
+/* This is a preallocated REG rtx which we use as a temporary in
+ reload_cse_invalidate_regno, so that we don't need to allocate a
+ new one each time through a loop in that function. */
+
+static rtx invalidate_regno_rtx;
+
+/* This is a set of registers for which we must remove REG_DEAD notes in
+ previous insns, because our modifications made them invalid. That can
+ happen if we introduced the register into the current insn, or we deleted
+ the current insn which used to set the register. */
+
+static HARD_REG_SET no_longer_dead_regs;
+
+/* Invalidate any entries in reg_values which depend on REGNO,
+ including those for REGNO itself. This is called if REGNO is
+ changing. If CLOBBER is true, then always forget anything we
+ currently know about REGNO. MODE is the mode of the assignment to
+ REGNO, which is used to determine how many hard registers are being
+ changed. If MODE is VOIDmode, then only REGNO is being changed;
+ this is used when invalidating call clobbered registers across a
+ call. */
+
+static void
+reload_cse_invalidate_regno (regno, mode, clobber)
+ int regno;
+ enum machine_mode mode;
+ int clobber;
+{
+ int endregno;
+ register int i;
+
+ /* Our callers don't always go through true_regnum; we may see a
+ pseudo-register here from a CLOBBER or the like. We probably
+ won't ever see a pseudo-register that has a real register number,
+ for we check anyhow for safety. */
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ regno = reg_renumber[regno];
+ if (regno < 0)
+ return;
+
+ if (mode == VOIDmode)
+ endregno = regno + 1;
+ else
+ endregno = regno + HARD_REGNO_NREGS (regno, mode);
+
+ if (clobber)
+ for (i = regno; i < endregno; i++)
+ reg_values[i] = 0;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ rtx x;
+
+ for (x = reg_values[i]; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) != 0
+ && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR))
+ {
+ /* If this is the only entry on the list, clear
+ reg_values[i]. Otherwise, just clear this entry on
+ the list. */
+ if (XEXP (x, 1) == 0 && x == reg_values[i])
+ {
+ reg_values[i] = 0;
+ break;
+ }
+ XEXP (x, 0) = 0;
+ }
+ }
+ }
+
+ /* We must look at earlier registers, in case REGNO is part of a
+ multi word value but is not the first register. If an earlier
+ register has a value in a mode which overlaps REGNO, then we must
+ invalidate that earlier register. Note that we do not need to
+ check REGNO or later registers (we must not check REGNO itself,
+ because we would incorrectly conclude that there was a conflict). */
+
+ for (i = 0; i < regno; i++)
+ {
+ rtx x;
+
+ for (x = reg_values[i]; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) != 0)
+ {
+ PUT_MODE (invalidate_regno_rtx, GET_MODE (x));
+ REGNO (invalidate_regno_rtx) = i;
+ if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
+ NULL_PTR))
+ {
+ reload_cse_invalidate_regno (i, VOIDmode, 1);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* The memory at address MEM_BASE is being changed.
+ Return whether this change will invalidate VAL. */
+
+static int
+reload_cse_mem_conflict_p (mem_base, val)
+ rtx mem_base;
+ rtx val;
+{
+ enum rtx_code code;
+ char *fmt;
+ int i;
+
+ code = GET_CODE (val);
+ switch (code)
+ {
+ /* Get rid of a few simple cases quickly. */
+ case REG:
+ case PC:
+ case CC0:
+ case SCRATCH:
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 0;
+
+ case MEM:
+ if (GET_MODE (mem_base) == BLKmode
+ || GET_MODE (val) == BLKmode)
+ return 1;
+ if (anti_dependence (val, mem_base))
+ return 1;
+ /* The address may contain nested MEMs. */
+ break;
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (reload_cse_mem_conflict_p (mem_base, XEXP (val, i)))
+ return 1;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = 0; j < XVECLEN (val, i); j++)
+ if (reload_cse_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Invalidate any entries in reg_values which are changed because of a
+ store to MEM_RTX. If this is called because of a non-const call
+ instruction, MEM_RTX is (mem:BLK const0_rtx). */
+
+static void
+reload_cse_invalidate_mem (mem_rtx)
+ rtx mem_rtx;
+{
+ register int i;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ rtx x;
+
+ for (x = reg_values[i]; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) != 0
+ && reload_cse_mem_conflict_p (mem_rtx, XEXP (x, 0)))
+ {
+ /* If this is the only entry on the list, clear
+ reg_values[i]. Otherwise, just clear this entry on
+ the list. */
+ if (XEXP (x, 1) == 0 && x == reg_values[i])
+ {
+ reg_values[i] = 0;
+ break;
+ }
+ XEXP (x, 0) = 0;
+ }
+ }
+ }
+}
+
+/* Invalidate DEST, which is being assigned to or clobbered. The
+ second parameter exists so that this function can be passed to
+ note_stores; it is ignored. */
+
+static void
+reload_cse_invalidate_rtx (dest, ignore)
+ rtx dest;
+ rtx ignore ATTRIBUTE_UNUSED;
+{
+ while (GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == SIGN_EXTRACT
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == SUBREG)
+ dest = XEXP (dest, 0);
+
+ if (GET_CODE (dest) == REG)
+ reload_cse_invalidate_regno (REGNO (dest), GET_MODE (dest), 1);
+ else if (GET_CODE (dest) == MEM)
+ reload_cse_invalidate_mem (dest);
+}
+
+/* Possibly delete death notes on the insns before INSN if modifying INSN
+ extended the lifespan of the registers. */
+
+static void
+reload_cse_delete_death_notes (insn)
+ rtx insn;
+{
+ int dreg;
+
+ for (dreg = 0; dreg < FIRST_PSEUDO_REGISTER; dreg++)
+ {
+ rtx trial;
+
+ if (! TEST_HARD_REG_BIT (no_longer_dead_regs, dreg))
+ continue;
+
+ for (trial = prev_nonnote_insn (insn);
+ (trial
+ && GET_CODE (trial) != CODE_LABEL
+ && GET_CODE (trial) != BARRIER);
+ trial = prev_nonnote_insn (trial))
+ {
+ if (find_regno_note (trial, REG_DEAD, dreg))
+ {
+ remove_death (dreg, trial);
+ break;
+ }
+ }
+ }
+}
+
+/* Record that the current insn uses hard reg REGNO in mode MODE. This
+ will be used in reload_cse_delete_death_notes to delete prior REG_DEAD
+ notes for this register. */
+
+static void
+reload_cse_no_longer_dead (regno, mode)
+ int regno;
+ enum machine_mode mode;
+{
+ int nregs = HARD_REGNO_NREGS (regno, mode);
+ while (nregs-- > 0)
+ {
+ SET_HARD_REG_BIT (no_longer_dead_regs, regno);
+ regno++;
+ }
+}
+
+
+/* Do a very simple CSE pass over the hard registers.
+
+ This function detects no-op moves where we happened to assign two
+ different pseudo-registers to the same hard register, and then
+ copied one to the other. Reload will generate a useless
+ instruction copying a register to itself.
+
+ This function also detects cases where we load a value from memory
+ into two different registers, and (if memory is more expensive than
+ registers) changes it to simply copy the first register into the
+ second register.
+
+ Another optimization is performed that scans the operands of each
+ instruction to see whether the value is already available in a
+ hard register. It then replaces the operand with the hard register
+ if possible, much like an optional reload would. */
+
+void
+reload_cse_regs (first)
+ rtx first;
+{
+ char *firstobj;
+ rtx callmem;
+ register int i;
+ rtx insn;
+
+ init_alias_analysis ();
+
+ reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
+ bzero ((char *)reg_values, FIRST_PSEUDO_REGISTER * sizeof (rtx));
+
+ /* Create our EXPR_LIST structures on reload_obstack, so that we can
+ free them when we are done. */
+ push_obstacks (&reload_obstack, &reload_obstack);
+ firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+ /* We pass this to reload_cse_invalidate_mem to invalidate all of
+ memory for a non-const call instruction. */
+ callmem = gen_rtx_MEM (BLKmode, const0_rtx);
+
+ /* This is used in reload_cse_invalidate_regno to avoid consing a
+ new REG in a loop in that function. */
+ invalidate_regno_rtx = gen_rtx_REG (VOIDmode, 0);
+
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ rtx body;
+
+ if (GET_CODE (insn) == CODE_LABEL)
+ {
+ /* Forget all the register values at a code label. We don't
+ try to do anything clever around jumps. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ reg_values[i] = 0;
+
+ continue;
+ }
+
+#ifdef NON_SAVING_SETJMP
+ if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ reg_values[i] = 0;
+
+ continue;
+ }
+#endif
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+
+ /* If this is a call instruction, forget anything stored in a
+ call clobbered register, or, if this is not a const call, in
+ memory. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (call_used_regs[i])
+ reload_cse_invalidate_regno (i, VOIDmode, 1);
+
+ if (! CONST_CALL_P (insn))
+ reload_cse_invalidate_mem (callmem);
+ }
+
+ body = PATTERN (insn);
+ if (GET_CODE (body) == SET)
+ {
+ int count = 0;
+ if (reload_cse_noop_set_p (body, insn))
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ reload_cse_delete_death_notes (insn);
+
+ /* We're done with this insn. */
+ continue;
+ }
+
+ /* It's not a no-op, but we can try to simplify it. */
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+ count += reload_cse_simplify_set (body, insn);
+
+ if (count > 0 && apply_change_group ())
+ reload_cse_delete_death_notes (insn);
+ else if (reload_cse_simplify_operands (insn))
+ reload_cse_delete_death_notes (insn);
+
+ reload_cse_record_set (body, body);
+ }
+ else if (GET_CODE (body) == PARALLEL)
+ {
+ int count = 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)
+ if ((GET_CODE (XVECEXP (body, 0, i)) != SET
+ || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn))
+ && GET_CODE (XVECEXP (body, 0, i)) != CLOBBER)
+ break;
+ if (i < 0)
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ reload_cse_delete_death_notes (insn);
+
+ /* We're done with this insn. */
+ continue;
+ }
+
+ /* It's not a no-op, but we can try to simplify it. */
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ if (GET_CODE (XVECEXP (body, 0, i)) == SET)
+ count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
+
+ if (count > 0 && apply_change_group ())
+ reload_cse_delete_death_notes (insn);
+ else if (reload_cse_simplify_operands (insn))
+ reload_cse_delete_death_notes (insn);
+
+ /* Look through the PARALLEL and record the values being
+ set, if possible. Also handle any CLOBBERs. */
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ {
+ rtx x = XVECEXP (body, 0, i);
+
+ if (GET_CODE (x) == SET)
+ reload_cse_record_set (x, body);
+ else
+ note_stores (x, reload_cse_invalidate_rtx);
+ }
+ }
+ else
+ note_stores (body, reload_cse_invalidate_rtx);
+
+#ifdef AUTO_INC_DEC
+ /* Clobber any registers which appear in REG_INC notes. We
+ could keep track of the changes to their values, but it is
+ unlikely to help. */
+ {
+ rtx x;
+
+ for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
+ if (REG_NOTE_KIND (x) == REG_INC)
+ reload_cse_invalidate_rtx (XEXP (x, 0), NULL_RTX);
+ }
+#endif
+
+ /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
+ after we have processed the insn. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ rtx x;
+
+ for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
+ if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+ reload_cse_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX);
+ }
+ }
+
+ /* Free all the temporary structures we created, and go back to the
+ regular obstacks. */
+ obstack_free (&reload_obstack, firstobj);
+ pop_obstacks ();
+}
+
+/* Return whether the values known for REGNO are equal to VAL. MODE
+ is the mode of the object that VAL is being copied to; this matters
+ if VAL is a CONST_INT. */
+
+static int
+reload_cse_regno_equal_p (regno, val, mode)
+ int regno;
+ rtx val;
+ enum machine_mode mode;
+{
+ rtx x;
+
+ if (val == 0)
+ return 0;
+
+ for (x = reg_values[regno]; x; x = XEXP (x, 1))
+ if (XEXP (x, 0) != 0
+ && rtx_equal_p (XEXP (x, 0), val)
+ && (! flag_float_store || GET_CODE (XEXP (x, 0)) != MEM
+ || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
+ && (GET_CODE (val) != CONST_INT
+ || mode == GET_MODE (x)
+ || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+ /* On a big endian machine if the value spans more than
+ one register then this register holds the high part of
+ it and we can't use it.
+
+ ??? We should also compare with the high part of the
+ value. */
+ && !(WORDS_BIG_ENDIAN
+ && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (x))))))
+ return 1;
+
+ return 0;
+}
+
+/* See whether a single set is a noop. SET is the set instruction we
+ are should check, and INSN is the instruction from which it came. */
+
+static int
+reload_cse_noop_set_p (set, insn)
+ rtx set;
+ rtx insn;
+{
+ rtx src, dest;
+ enum machine_mode dest_mode;
+ int dreg, sreg;
+ int ret;
+
+ src = SET_SRC (set);
+ dest = SET_DEST (set);
+ dest_mode = GET_MODE (dest);
+
+ if (side_effects_p (src))
+ return 0;
+
+ dreg = true_regnum (dest);
+ sreg = true_regnum (src);
+
+ /* Check for setting a register to itself. In this case, we don't
+ have to worry about REG_DEAD notes. */
+ if (dreg >= 0 && dreg == sreg)
+ return 1;
+
+ ret = 0;
+ if (dreg >= 0)
+ {
+ /* Check for setting a register to itself. */
+ if (dreg == sreg)
+ ret = 1;
+
+ /* Check for setting a register to a value which we already know
+ is in the register. */
+ else if (reload_cse_regno_equal_p (dreg, src, dest_mode))
+ ret = 1;
+
+ /* Check for setting a register DREG to another register SREG
+ where SREG is equal to a value which is already in DREG. */
+ else if (sreg >= 0)
+ {
+ rtx x;
+
+ for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+ {
+ rtx tmp;
+
+ if (XEXP (x, 0) == 0)
+ continue;
+
+ if (dest_mode == GET_MODE (x))
+ tmp = XEXP (x, 0);
+ else if (GET_MODE_BITSIZE (dest_mode)
+ < GET_MODE_BITSIZE (GET_MODE (x)))
+ tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+ else
+ continue;
+
+ if (tmp
+ && reload_cse_regno_equal_p (dreg, tmp, dest_mode))
+ {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ else if (GET_CODE (dest) == MEM)
+ {
+ /* Check for storing a register to memory when we know that the
+ register is equivalent to the memory location. */
+ if (sreg >= 0
+ && reload_cse_regno_equal_p (sreg, dest, dest_mode)
+ && ! side_effects_p (dest))
+ ret = 1;
+ }
+
+ /* If we can delete this SET, then we need to look for an earlier
+ REG_DEAD note on DREG, and remove it if it exists. */
+ if (ret && dreg >= 0)
+ {
+ if (! find_regno_note (insn, REG_UNUSED, dreg))
+ reload_cse_no_longer_dead (dreg, dest_mode);
+ }
+
+ return ret;
+}
+
+/* Try to simplify a single SET instruction. SET is the set pattern.
+ INSN is the instruction it came from.
+ This function only handles one case: if we set a register to a value
+ which is not a register, we try to find that value in some other register
+ and change the set into a register copy. */
+
+static int
+reload_cse_simplify_set (set, insn)
+ rtx set;
+ rtx insn;
+{
+ int dreg;
+ rtx src;
+ enum machine_mode dest_mode;
+ enum reg_class dclass;
+ register int i;
+
+ dreg = true_regnum (SET_DEST (set));
+ if (dreg < 0)
+ return 0;
+
+ src = SET_SRC (set);
+ if (side_effects_p (src) || true_regnum (src) >= 0)
+ return 0;
+
+ dclass = REGNO_REG_CLASS (dreg);
+
+ /* If memory loads are cheaper than register copies, don't change them. */
+ if (GET_CODE (src) == MEM
+ && MEMORY_MOVE_COST (GET_MODE (src), dclass, 1) < 2)
+ return 0;
+
+ /* If the constant is cheaper than a register, don't change it. */
+ if (CONSTANT_P (src)
+ && rtx_cost (src, SET) < 2)
+ return 0;
+
+ dest_mode = GET_MODE (SET_DEST (set));
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (i != dreg
+ && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2
+ && reload_cse_regno_equal_p (i, src, dest_mode))
+ {
+ int validated;
+
+ /* Pop back to the real obstacks while changing the insn. */
+ pop_obstacks ();
+
+ validated = validate_change (insn, &SET_SRC (set),
+ gen_rtx_REG (dest_mode, i), 1);
+
+ /* Go back to the obstack we are using for temporary
+ storage. */
+ push_obstacks (&reload_obstack, &reload_obstack);
+
+ if (validated && ! find_regno_note (insn, REG_UNUSED, i))
+ {
+ reload_cse_no_longer_dead (i, dest_mode);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Try to replace operands in INSN with equivalent values that are already
+ in registers. This can be viewed as optional reloading.
+
+ For each non-register operand in the insn, see if any hard regs are
+ known to be equivalent to that operand. Record the alternatives which
+ can accept these hard registers. Among all alternatives, select the
+ ones which are better or equal to the one currently matching, where
+ "better" is in terms of '?' and '!' constraints. Among the remaining
+ alternatives, select the one which replaces most operands with
+ hard registers. */
+
+static int
+reload_cse_simplify_operands (insn)
+ rtx insn;
+{
+#ifdef REGISTER_CONSTRAINTS
+ int insn_code_number, n_operands, n_alternatives;
+ int i,j;
+
+ char *constraints[MAX_RECOG_OPERANDS];
+
+ /* Vector recording how bad an alternative is. */
+ int *alternative_reject;
+ /* Vector recording how many registers can be introduced by choosing
+ this alternative. */
+ int *alternative_nregs;
+ /* Array of vectors recording, for each operand and each alternative,
+ which hard register to substitute, or -1 if the operand should be
+ left as it is. */
+ int *op_alt_regno[MAX_RECOG_OPERANDS];
+ /* Array of alternatives, sorted in order of decreasing desirability. */
+ int *alternative_order;
+ rtx reg = gen_rtx_REG (VOIDmode, -1);
+
+ /* Find out some information about this insn. */
+ insn_code_number = recog_memoized (insn);
+ /* We don't modify asm instructions. */
+ if (insn_code_number < 0)
+ return 0;
+
+ n_operands = insn_n_operands[insn_code_number];
+ n_alternatives = insn_n_alternatives[insn_code_number];
+
+ if (n_alternatives == 0 || n_operands == 0)
+ return 0;
+ insn_extract (insn);
+
+ /* Figure out which alternative currently matches. */
+ if (! constrain_operands (insn_code_number, 1))
+ fatal_insn_not_found (insn);
+
+ alternative_reject = (int *) alloca (n_alternatives * sizeof (int));
+ alternative_nregs = (int *) alloca (n_alternatives * sizeof (int));
+ alternative_order = (int *) alloca (n_alternatives * sizeof (int));
+ bzero ((char *)alternative_reject, n_alternatives * sizeof (int));
+ bzero ((char *)alternative_nregs, n_alternatives * sizeof (int));
+
+ for (i = 0; i < n_operands; i++)
+ {
+ enum machine_mode mode;
+ int regno;
+ char *p;
+
+ op_alt_regno[i] = (int *) alloca (n_alternatives * sizeof (int));
+ for (j = 0; j < n_alternatives; j++)
+ op_alt_regno[i][j] = -1;
+
+ p = constraints[i] = insn_operand_constraint[insn_code_number][i];
+ mode = insn_operand_mode[insn_code_number][i];
+
+ /* Add the reject values for each alternative given by the constraints
+ for this operand. */
+ j = 0;
+ while (*p != '\0')
+ {
+ char c = *p++;
+ if (c == ',')
+ j++;
+ else if (c == '?')
+ alternative_reject[j] += 3;
+ else if (c == '!')
+ alternative_reject[j] += 300;
+ }
+
+ /* We won't change operands which are already registers. We
+ also don't want to modify output operands. */
+ regno = true_regnum (recog_operand[i]);
+ if (regno >= 0
+ || constraints[i][0] == '='
+ || constraints[i][0] == '+')
+ continue;
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ int class = (int) NO_REGS;
+
+ if (! reload_cse_regno_equal_p (regno, recog_operand[i], mode))
+ continue;
+
+ REGNO (reg) = regno;
+ PUT_MODE (reg, mode);
+
+ /* We found a register equal to this operand. Now look for all
+ alternatives that can accept this register and have not been
+ assigned a register they can use yet. */
+ j = 0;
+ p = constraints[i];
+ for (;;)
+ {
+ char c = *p++;
+
+ switch (c)
+ {
+ case '=': case '+': case '?':
+ case '#': case '&': case '!':
+ case '*': case '%':
+ case '0': case '1': case '2': case '3': case '4':
+ case 'm': 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':
+#ifdef EXTRA_CONSTRAINT
+ case 'Q': case 'R': case 'S': case 'T': case 'U':
+#endif
+ case 'p': case 'X':
+ /* These don't say anything we care about. */
+ break;
+
+ case 'g': case 'r':
+ class = reg_class_subunion[(int) class][(int) GENERAL_REGS];
+ break;
+
+ default:
+ class
+ = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER (c)];
+ break;
+
+ case ',': case '\0':
+ /* See if REGNO fits this alternative, and set it up as the
+ replacement register if we don't have one for this
+ alternative yet and the operand being replaced is not
+ a cheap CONST_INT. */
+ if (op_alt_regno[i][j] == -1
+ && reg_fits_class_p (reg, class, 0, mode)
+ && (GET_CODE (recog_operand[i]) != CONST_INT
+ || rtx_cost (recog_operand[i], SET) > rtx_cost (reg, SET)))
+ {
+ alternative_nregs[j]++;
+ op_alt_regno[i][j] = regno;
+ }
+ j++;
+ break;
+ }
+
+ if (c == '\0')
+ break;
+ }
+ }
+ }
+
+ /* Record all alternatives which are better or equal to the currently
+ matching one in the alternative_order array. */
+ for (i = j = 0; i < n_alternatives; i++)
+ if (alternative_reject[i] <= alternative_reject[which_alternative])
+ alternative_order[j++] = i;
+ n_alternatives = j;
+
+ /* Sort it. Given a small number of alternatives, a dumb algorithm
+ won't hurt too much. */
+ for (i = 0; i < n_alternatives - 1; i++)
+ {
+ int best = i;
+ int best_reject = alternative_reject[alternative_order[i]];
+ int best_nregs = alternative_nregs[alternative_order[i]];
+ int tmp;
+
+ for (j = i + 1; j < n_alternatives; j++)
+ {
+ int this_reject = alternative_reject[alternative_order[j]];
+ int this_nregs = alternative_nregs[alternative_order[j]];
+
+ if (this_reject < best_reject
+ || (this_reject == best_reject && this_nregs < best_nregs))
+ {
+ best = j;
+ best_reject = this_reject;
+ best_nregs = this_nregs;
+ }
+ }
+
+ tmp = alternative_order[best];
+ alternative_order[best] = alternative_order[i];
+ alternative_order[i] = tmp;
+ }
+
+ /* Substitute the operands as determined by op_alt_regno for the best
+ alternative. */
+ j = alternative_order[0];
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+
+ /* Pop back to the real obstacks while changing the insn. */
+ pop_obstacks ();
+
+ for (i = 0; i < n_operands; i++)
+ {
+ enum machine_mode mode = insn_operand_mode[insn_code_number][i];
+ if (op_alt_regno[i][j] == -1)
+ continue;
+
+ reload_cse_no_longer_dead (op_alt_regno[i][j], mode);
+ validate_change (insn, recog_operand_loc[i],
+ gen_rtx_REG (mode, op_alt_regno[i][j]), 1);
+ }
+
+ for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
+ {
+ int op = recog_dup_num[i];
+ enum machine_mode mode = insn_operand_mode[insn_code_number][op];
+
+ if (op_alt_regno[op][j] == -1)
+ continue;
+
+ reload_cse_no_longer_dead (op_alt_regno[op][j], mode);
+ validate_change (insn, recog_dup_loc[i],
+ gen_rtx_REG (mode, op_alt_regno[op][j]), 1);
+ }
+
+ /* Go back to the obstack we are using for temporary
+ storage. */
+ push_obstacks (&reload_obstack, &reload_obstack);
+
+ return apply_change_group ();
+#else
+ return 0;
+#endif
+}
+
+/* These two variables are used to pass information from
+ reload_cse_record_set to reload_cse_check_clobber. */
+
+static int reload_cse_check_clobbered;
+static rtx reload_cse_check_src;
+
+/* See if DEST overlaps with RELOAD_CSE_CHECK_SRC. If it does, set
+ RELOAD_CSE_CHECK_CLOBBERED. This is called via note_stores. The
+ second argument, which is passed by note_stores, is ignored. */
+
+static void
+reload_cse_check_clobber (dest, ignore)
+ rtx dest;
+ rtx ignore ATTRIBUTE_UNUSED;
+{
+ if (reg_overlap_mentioned_p (dest, reload_cse_check_src))
+ reload_cse_check_clobbered = 1;
+}
+
+/* Record the result of a SET instruction. SET is the set pattern.
+ BODY is the pattern of the insn that it came from. */
+
+static void
+reload_cse_record_set (set, body)
+ rtx set;
+ rtx body;
+{
+ rtx dest, src, x;
+ int dreg, sreg;
+ enum machine_mode dest_mode;
+
+ dest = SET_DEST (set);
+ src = SET_SRC (set);
+ dreg = true_regnum (dest);
+ sreg = true_regnum (src);
+ dest_mode = GET_MODE (dest);
+
+ /* Some machines don't define AUTO_INC_DEC, but they still use push
+ instructions. We need to catch that case here in order to
+ invalidate the stack pointer correctly. Note that invalidating
+ the stack pointer is different from invalidating DEST. */
+ x = dest;
+ while (GET_CODE (x) == SUBREG
+ || GET_CODE (x) == ZERO_EXTRACT
+ || GET_CODE (x) == SIGN_EXTRACT
+ || GET_CODE (x) == STRICT_LOW_PART)
+ x = XEXP (x, 0);
+ if (push_operand (x, GET_MODE (x)))
+ {
+ reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX);
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+
+ /* We can only handle an assignment to a register, or a store of a
+ register to a memory location. For other cases, we just clobber
+ the destination. We also have to just clobber if there are side
+ effects in SRC or DEST. */
+ if ((dreg < 0 && GET_CODE (dest) != MEM)
+ || side_effects_p (src)
+ || side_effects_p (dest))
+ {
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+
+#ifdef HAVE_cc0
+ /* We don't try to handle values involving CC, because it's a pain
+ to keep track of when they have to be invalidated. */
+ if (reg_mentioned_p (cc0_rtx, src)
+ || reg_mentioned_p (cc0_rtx, dest))
+ {
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+#endif
+
+ /* If BODY is a PARALLEL, then we need to see whether the source of
+ SET is clobbered by some other instruction in the PARALLEL. */
+ if (GET_CODE (body) == PARALLEL)
+ {
+ int i;
+
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ {
+ rtx x;
+
+ x = XVECEXP (body, 0, i);
+ if (x == set)
+ continue;
+
+ reload_cse_check_clobbered = 0;
+ reload_cse_check_src = src;
+ note_stores (x, reload_cse_check_clobber);
+ if (reload_cse_check_clobbered)
+ {
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+ }
+ }
+
+ if (dreg >= 0)
+ {
+ int i;
+
+ /* This is an assignment to a register. Update the value we
+ have stored for the register. */
+ if (sreg >= 0)
+ {
+ rtx x;
+
+ /* This is a copy from one register to another. Any values
+ which were valid for SREG are now valid for DREG. If the
+ mode changes, we use gen_lowpart_common to extract only
+ the part of the value that is copied. */
+ reg_values[dreg] = 0;
+ for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+ {
+ rtx tmp;
+
+ if (XEXP (x, 0) == 0)
+ continue;
+ if (dest_mode == GET_MODE (XEXP (x, 0)))
+ tmp = XEXP (x, 0);
+ else if (GET_MODE_BITSIZE (dest_mode)
+ > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
+ continue;
+ else
+ tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+ if (tmp)
+ reg_values[dreg] = gen_rtx_EXPR_LIST (dest_mode, tmp,
+ reg_values[dreg]);
+ }
+ }
+ else
+ reg_values[dreg] = gen_rtx_EXPR_LIST (dest_mode, src, NULL_RTX);
+
+ /* We've changed DREG, so invalidate any values held by other
+ registers that depend upon it. */
+ reload_cse_invalidate_regno (dreg, dest_mode, 0);
+
+ /* If this assignment changes more than one hard register,
+ forget anything we know about the others. */
+ for (i = 1; i < HARD_REGNO_NREGS (dreg, dest_mode); i++)
+ reg_values[dreg + i] = 0;
+ }
+ else if (GET_CODE (dest) == MEM)
+ {
+ /* Invalidate conflicting memory locations. */
+ reload_cse_invalidate_mem (dest);
+
+ /* If we're storing a register to memory, add DEST to the list
+ in REG_VALUES. */
+ if (sreg >= 0 && ! side_effects_p (dest))
+ reg_values[sreg] = gen_rtx_EXPR_LIST (dest_mode, dest,
+ reg_values[sreg]);
+ }
+ else
+ {
+ /* We should have bailed out earlier. */
+ abort ();
+ }
+}
OpenPOWER on IntegriCloud