aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog-ira-reload128
-rw-r--r--gcc/Makefile.in7
-rw-r--r--gcc/NOTES47
-rw-r--r--gcc/ira-build.c47
-rw-r--r--gcc/ira-color.c4
-rw-r--r--gcc/ira-conflicts.c104
-rw-r--r--gcc/ira-costs.c27
-rw-r--r--gcc/ira-int.h10
-rw-r--r--gcc/ira-reload.c982
-rw-r--r--gcc/ira.c19
-rw-r--r--gcc/ira.h1
-rw-r--r--gcc/regs.h1
-rw-r--r--gcc/regstat.c10
-rw-r--r--gcc/reload.h8
-rw-r--r--gcc/reload1.c273
15 files changed, 1482 insertions, 186 deletions
diff --git a/gcc/ChangeLog-ira-reload b/gcc/ChangeLog-ira-reload
new file mode 100644
index 00000000000..1354c4335ff
--- /dev/null
+++ b/gcc/ChangeLog-ira-reload
@@ -0,0 +1,128 @@
+2009-10-22 Jeff Law <law@redhat.com>
+
+ * reload1.c (finish_spills): Also try to re-allocate pseudos
+ currently on the stack.
+
+ * ira-lives.c (process_single_reg_class_operands): Update the
+ hard reg costs for all the hard registers desired by the single
+ reg class operand.
+
+2009-10-15 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (ira_bad_reload_regno): New function.
+ (ira_bad_reload_regno_1): Likewise.
+ * ira.h (ira_bad_reload_regno): Declare.
+ * reload1.c (allocate_reload_reg): Use ira_bad_reload_regno.
+
+2009-10-13 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (no_uses_after_last_set): New bitmap.
+ (identify_singleton_sets): Set it appropriately.
+ (emit_localizing_stores): More aggressively replace a pseudo
+ with its equivalent memory location. Indicate that INSN
+ should be deleted in certain cases.
+ (localize_pseudos): Allocate and free no_uses_after_last_set.
+ Fix SET/USE processing order for no_uses_after_last_set.
+ If emit_localizing_stores requests an insn be deleted, do it.
+
+2009-09-31 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (emit_localizing_loads): Attempt to replace the
+ pseudo with its equivalent memory when safe and profitable.
+
+2009-09-30 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (uses_before_set): Remove bitmap.
+ (identify_singleton_uses): Corresponding changes.
+ (localize_pseudos): Likewise.
+
+ * ira-reload.c (emit_localizing_stores): Return whether or not the
+ current insn needs to be rescanned by DF analyzer.
+ Attempt to replace the pseudo with its equivalent memory.
+ (localize_pseudos): Rescan as needed after emit_localizing_stores.
+
+2009-09-25 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (identify_singleton_uses): Twiddles for using DF rather
+ than note_stores/note_uses.
+ (identify_singleton_sets, collect_loads): Likewise.
+ (identify_singleton_uses_1): Remove.
+ (collect_loads_1, emit_localizing_loads_1): Likewise.
+ (emit_localizing_loads): Twiddles for using DF rather than
+ note_stores/note_uses. Return whether or not rescanning is needed.
+ (rename_sets, emit_localizing_stores): Likewise.
+ (localize_pseudos): Iterate over DF structures rather than using
+ note_stores/note_uses. Defer rescanning until we're finished with
+ the current insn.
+
+2009-09-24 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (emit_localizing_loads_1): Incrementally update DF.
+ (emit_localizing_stores): Likewise.
+ (create_new_allocno_for_spilling): Clear the hard register conflicts
+ for the new allocno.
+ (maybe_add_conflict): Handle hard register conflicts.
+ (mark_conflicts): Renamed from mark_conflict. Simplify slightly.
+ (mark_uses): New.
+ (live_uses, live_uses_1): Remove.
+ (build_conflicts_for_new_allocnos): Simplify and use DF.
+
+2009-09-22 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (build_conflicts_for_new_allocnos): Ignore debug
+ insns.
+ (localize_pseudos): Likewise.
+
+2009-09-21 Jeff Law <law@redhat.com>
+
+ * ira-reload.c (localize_pseudos): Add new argument to call to
+ setup_reg_classes.
+ (emit_localizing_stores): Remove unused variable.
+ * reload1.c (reload): Pass in the right peudo register number
+ to alter_reg. Restore incorrectly removed initialization of
+ tmp_pseudo_reg_arr.
+
+ * NOTES: New file.
+
+ * ira-reload.c: New file.
+ * ira-int.h (reload_reload): Declare.
+ * ira-color.c (sorted_allocnos): No longer static.
+ * ira.c (ira): Call ira_reload.
+ * Makefile.in (OBJS-common): Add ira-reload.o
+ (ira-reload.o): Add dependencies
+
+ * ira-color.c (setup_allocno_priorities): No longer static.
+ * ira-int.h (setup_allocno_priorities): Declare
+
+ * reload1.c (reg_max_ref_width): No longer static.
+ (alter_reg): Likewise.
+ (record_equivalences_for_reload): New function extracted from reload.
+ (reload): Don't sort registers prior to calling alter_reg anymore.
+ * reload.h (reg_max_ref_width): Declare.
+ (alter_reg): Likewise.
+ (record_equivalences_for_reload): Likewise.
+
+2009-09-18 Jeff Law <law@redhat.com>
+
+ * ira.c (expand_reg_info): No longer static.
+ * ira-int.h (expand_reg_info): Declare.
+
+ * ira-build.c (remove_from_all_conflicts): New function.
+ (remove_allocno_conflicts): New function.
+ * ira-int.h (remove_from_all_conflicts): Declare.
+
+ 2009-09-14 Vladimir Makarov <vmakarov@redhat.com>
+ * ira.c (ira_non_ordered_class_hard_regs): Define.
+ (setup_class_hard_regs): Initialize ira_non_ordered_class_hard_regs.
+ * ira-int.h (ira_non_ordered_class_hard_regs): Declare.
+ * ira-costs.c (ira_tune_allocno_costs_and_cover_classes): Increase
+ cost of unaligned hard regs when allocating multi-reg pseudos.
+
+ * regstat.c (regstat_reallocate_ri): New function.
+ * regs.h (regstat_reallocate_ri): Declare
+
+ * ira-conflicts.c (print_allocno_conflicts): New function to print
+ conflicts for a single allocno.
+ (print_conflicts): Use print_allocno_conflicts.
+
+
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 934c4ed1b3a..ea57af4db53 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1211,6 +1211,7 @@ OBJS-common = \
intl.o \
ira.o \
ira-build.o \
+ ira-reload.o \
ira-costs.o \
ira-conflicts.o \
ira-color.o \
@@ -3189,6 +3190,12 @@ ira.o: ira.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(BITMAP_H) hard-reg-set.h $(BASIC_BLOCK_H) \
$(EXPR_H) $(RECOG_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) output.h \
$(EXCEPT_H) reload.h errors.h $(INTEGRATE_H) $(DF_H) $(GGC_H) $(IRA_INT_H)
+ira-reload.o: ira-reload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+ $(TARGET_H) $(TM_H) $(RTL_H) $(RECOG_H) \
+ $(REGS_H) hard-reg-set.h $(FLAGS_H) $(OBSTACK_H) \
+ $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) \
+ $(DF_H) $(IRA_INT_H) $(PARAMS_H) $(TIMEVAR_H) $(INTEGRATE_H) \
+ $(TREE_PASS_H) output.h
regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
insn-config.h $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H)\
$(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \
diff --git a/gcc/NOTES b/gcc/NOTES
new file mode 100644
index 00000000000..7da5cf391ac
--- /dev/null
+++ b/gcc/NOTES
@@ -0,0 +1,47 @@
+ * Need to use process_bb_node_lives rather than our own conflict
+ building routines. Our current approach is slow (not using DF) and
+ naive/inaccurate. Our current approach also doesn't get hard register
+ conflicts which are copied from the original pseudo (which is
+ horribly conservative and the cause of most of our regressions).
+
+ * In general, we need to be using DF rather than note_{stores,uses}.
+
+ * Need to rewrite the local allocator/spiller.
+
+ * How to tune when we're choosing between replacing an operand with a
+ MEM or emitting distinct load/store insns.
+
+ * Should we be working with EBBs and reverse EBBs?
+
+ * Is it really necessary to remove the conflicts when we localize a
+ pseudo? We might get away with just ignoring it. However, we're
+ probably still going to need the conflict removal bits so we can
+ "spill" by clearing key conflicts and calling back into IRA.
+
+ * ira-costs.c has a twiddle to slightly prefer aligned groups of hard
+ regs. This should generally help, but needs serious benchmarking.
+
+ * Put all the reg_XXX bits into a structure and expand the structure
+ rather than expanding each array individually. Also helps as we can
+ dump everything we know about a reg with a single gdb statement rather
+ than a dozen of them.
+
+ * Break ira_reassign_pseudos into two parts, once which just assigns
+ the given pseudo array the other which does that plus reassignment of
+ conflicting pseudos. The former is all we care about for ira-reload.c.
+
+ * SUBREG handling is probably not correct and certainly not efficient
+ yet. We want to be able to track which subregs are live and emit code
+ appropriately. We also want to narrow operands when opportunities
+ present themselves. Also would like to identify these at kill the
+ first statement and avoid unncessary conflicts
+
+ (set (reg) (whatever))
+ (set (subreg (reg 0)) (something))
+ (set (subreg (reg 4)) (something else))
+
+ * Need to find an efficient way to determine range transparency.
+
+ * Need to find a way to update ranges for newly created pseudos so
+ that slots can be shared more effectively.
+
diff --git a/gcc/ira-build.c b/gcc/ira-build.c
index edb761b0d71..5f2ca4023fd 100644
--- a/gcc/ira-build.c
+++ b/gcc/ira-build.c
@@ -565,6 +565,53 @@ ira_allocate_allocno_conflicts (ira_allocno_t a, int num)
allocate_allocno_conflict_bit_vec (a);
}
+/* Remove A2 from the conflicts of A1. */
+static void
+remove_allocno_conflicts (ira_allocno_t a1, ira_allocno_t a2)
+{
+ int num, i;
+
+ if (ALLOCNO_CONFLICT_VEC_P (a1))
+ {
+ ira_allocno_t *vec
+ = (ira_allocno_t *) ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a1);
+ num = ALLOCNO_CONFLICT_ALLOCNOS_NUM (a1) + 2;
+
+ for (i = 0; i < num; i++)
+ if (vec[i] == a2)
+ {
+ num--;
+ if (i != num - 2)
+ vec[i] = vec[num - 2];
+ vec[num - 2] = NULL;
+ ALLOCNO_CONFLICT_ALLOCNOS_NUM (a1)--;
+ }
+ }
+ else
+ {
+ int id = ALLOCNO_CONFLICT_ID (a2);
+ IRA_INT_TYPE *vec;
+
+ if (id < ALLOCNO_MIN (a1) || id > ALLOCNO_MAX (a1))
+ return;
+
+ vec = (IRA_INT_TYPE *) ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a1);
+ CLEAR_ALLOCNO_SET_BIT (vec, id, ALLOCNO_MIN (a1), ALLOCNO_MAX (a1));
+ }
+}
+
+/* Remove A from all conflicts. */
+void
+remove_from_all_conflicts (ira_allocno_t to_remove)
+{
+ ira_allocno_conflict_iterator aci;
+ ira_allocno_t a;
+
+ FOR_EACH_ALLOCNO_CONFLICT (to_remove, a, aci)
+ remove_allocno_conflicts (a, to_remove);
+}
+
+
/* Add A2 to the conflicts of A1. */
static void
add_to_allocno_conflicts (ira_allocno_t a1, ira_allocno_t a2)
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index 743ec3cd835..d5e98f4f5b9 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -63,7 +63,7 @@ static bool allocno_coalesced_p;
static bitmap processed_coalesced_allocno_bitmap;
/* All allocnos sorted according their priorities. */
-static ira_allocno_t *sorted_allocnos;
+ira_allocno_t *sorted_allocnos;
/* Vec representing the stack of allocnos used during coloring. */
static VEC(ira_allocno_t,heap) *allocno_stack_vec;
@@ -1692,7 +1692,7 @@ static int *allocno_priorities;
/* Set up priorities for N allocnos in array
CONSIDERATION_ALLOCNOS. */
-static void
+void
setup_allocno_priorities (ira_allocno_t *consideration_allocnos, int n)
{
int i, length, nrefs, priority, max_priority, mult;
diff --git a/gcc/ira-conflicts.c b/gcc/ira-conflicts.c
index 6d84e5643b5..ae5d8de998c 100644
--- a/gcc/ira-conflicts.c
+++ b/gcc/ira-conflicts.c
@@ -685,68 +685,72 @@ print_hard_reg_set (FILE *file, const char *title, HARD_REG_SET set)
putc ('\n', file);
}
-/* Print information about allocno or only regno (if REG_P) conflicts
- to FILE. */
static void
-print_conflicts (FILE *file, bool reg_p)
+print_allocno_conflicts (FILE * file, bool reg_p, ira_allocno_t a)
{
- ira_allocno_t a;
- ira_allocno_iterator ai;
HARD_REG_SET conflicting_hard_regs;
+ ira_allocno_t conflict_a;
+ ira_allocno_conflict_iterator aci;
+ basic_block bb;
- FOR_EACH_ALLOCNO (a, ai)
+ if (reg_p)
+ fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
+ else
{
- ira_allocno_t conflict_a;
- ira_allocno_conflict_iterator aci;
- basic_block bb;
-
- if (reg_p)
- fprintf (file, ";; r%d", ALLOCNO_REGNO (a));
+ fprintf (file, ";; a%d(r%d,", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
+ if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
+ fprintf (file, "b%d", bb->index);
else
- {
- fprintf (file, ";; a%d(r%d,", ALLOCNO_NUM (a), ALLOCNO_REGNO (a));
- if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
- fprintf (file, "b%d", bb->index);
- else
- fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
- putc (')', file);
- }
- fputs (" conflicts:", file);
- if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) != NULL)
- FOR_EACH_ALLOCNO_CONFLICT (a, conflict_a, aci)
- {
- if (reg_p)
- fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
+ fprintf (file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
+ putc (')', file);
+ }
+ fputs (" conflicts:", file);
+ if (ALLOCNO_CONFLICT_ALLOCNO_ARRAY (a) != NULL)
+ FOR_EACH_ALLOCNO_CONFLICT (a, conflict_a, aci)
+ {
+ if (reg_p)
+ fprintf (file, " r%d,", ALLOCNO_REGNO (conflict_a));
+ else
+ {
+ fprintf (file, " a%d(r%d,", ALLOCNO_NUM (conflict_a),
+ ALLOCNO_REGNO (conflict_a));
+ if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
+ fprintf (file, "b%d)", bb->index);
else
- {
- fprintf (file, " a%d(r%d,", ALLOCNO_NUM (conflict_a),
- ALLOCNO_REGNO (conflict_a));
- if ((bb = ALLOCNO_LOOP_TREE_NODE (conflict_a)->bb) != NULL)
- fprintf (file, "b%d)", bb->index);
- else
- fprintf (file, "l%d)",
- ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
- }
+ fprintf (file, "l%d)",
+ ALLOCNO_LOOP_TREE_NODE (conflict_a)->loop->num);
}
- COPY_HARD_REG_SET (conflicting_hard_regs,
- ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
- AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
- AND_HARD_REG_SET (conflicting_hard_regs,
- reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
- print_hard_reg_set (file, "\n;; total conflict hard regs:",
- conflicting_hard_regs);
- COPY_HARD_REG_SET (conflicting_hard_regs,
- ALLOCNO_CONFLICT_HARD_REGS (a));
- AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
- AND_HARD_REG_SET (conflicting_hard_regs,
- reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
- print_hard_reg_set (file, ";; conflict hard regs:",
- conflicting_hard_regs);
- }
+ }
+ COPY_HARD_REG_SET (conflicting_hard_regs,
+ ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a));
+ AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+ AND_HARD_REG_SET (conflicting_hard_regs,
+ reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
+ print_hard_reg_set (file, "\n;; total conflict hard regs:",
+ conflicting_hard_regs);
+ COPY_HARD_REG_SET (conflicting_hard_regs,
+ ALLOCNO_CONFLICT_HARD_REGS (a));
+ AND_COMPL_HARD_REG_SET (conflicting_hard_regs, ira_no_alloc_regs);
+ AND_HARD_REG_SET (conflicting_hard_regs,
+ reg_class_contents[ALLOCNO_COVER_CLASS (a)]);
+ print_hard_reg_set (file, ";; conflict hard regs:",
+ conflicting_hard_regs);
putc ('\n', file);
}
/* Print information about allocno or only regno (if REG_P) conflicts
+ to FILE. */
+static void
+print_conflicts (FILE *file, bool reg_p)
+{
+ ira_allocno_t a;
+ ira_allocno_iterator ai;
+
+ FOR_EACH_ALLOCNO (a, ai)
+ print_allocno_conflicts (file, reg_p, a);
+}
+
+/* Print information about allocno or only regno (if REG_P) conflicts
to stderr. */
void
ira_debug_conflicts (bool reg_p)
diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index 4b9d29f1db1..7916cb27bf1 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -1767,5 +1767,32 @@ ira_tune_allocno_costs_and_cover_classes (void)
}
if (min_cost != INT_MAX)
ALLOCNO_COVER_CLASS_COST (a) = min_cost;
+
+ /* Some targets allow pseudos to be allocated to unaligned
+ sequences of hard registers. However, selecting an unaligned
+ sequence can unnecessarily restrict later allocations. So
+ increase the cost of unaligned hard regs to encourage the use
+ of aligned hard regs. */
+ {
+ int nregs, index;
+
+ if ((nregs = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)]) > 1)
+ {
+ ira_allocate_and_set_costs
+ (&ALLOCNO_HARD_REG_COSTS (a), cover_class,
+ ALLOCNO_COVER_CLASS_COST (a));
+ reg_costs = ALLOCNO_HARD_REG_COSTS (a);
+ for (j = n - 1; j >= 0; j--)
+ {
+ if (j % nregs != 0)
+ {
+ regno = ira_non_ordered_class_hard_regs[cover_class][j];
+ index = ira_class_hard_reg_index[cover_class][regno];
+ ira_assert (index != 0);
+ reg_costs[index] += ALLOCNO_FREQ (a);
+ }
+ }
+ }
+ }
}
}
diff --git a/gcc/ira-int.h b/gcc/ira-int.h
index 1327f945149..a4b1ac7a758 100644
--- a/gcc/ira-int.h
+++ b/gcc/ira-int.h
@@ -743,6 +743,11 @@ extern move_table *ira_may_move_out_cost[MAX_MACHINE_MODE];
allocation. */
extern int ira_class_subset_p[N_REG_CLASSES][N_REG_CLASSES];
+/* Array of the number of hard registers of given class which are
+ available for allocation. The order is defined by the the hard
+ register numbers. */
+extern short ira_non_ordered_class_hard_regs[N_REG_CLASSES][FIRST_PSEUDO_REGISTER];
+
/* Index (in ira_class_hard_regs) for given register class and hard
register (in general case a hard register can belong to several
register classes). The index is negative for hard registers
@@ -808,6 +813,7 @@ extern void ira_print_disposition (FILE *);
extern void ira_debug_disposition (void);
extern void ira_debug_class_cover (void);
extern void ira_init_register_move_cost (enum machine_mode);
+extern void expand_reg_info (int);
/* The length of the two following arrays. */
extern int ira_reg_equiv_len;
@@ -865,6 +871,7 @@ extern void ira_free_cost_vector (int *, enum reg_class);
extern void ira_flattening (int, int);
extern bool ira_build (bool);
extern void ira_destroy (void);
+extern void remove_from_all_conflicts (ira_allocno_t to_remove);
/* ira-costs.c */
extern void ira_init_costs_once (void);
@@ -894,10 +901,13 @@ extern void ira_reassign_conflict_allocnos (int);
extern void ira_initiate_assign (void);
extern void ira_finish_assign (void);
extern void ira_color (void);
+extern void setup_allocno_priorities (ira_allocno_t *, int);
/* ira-emit.c */
extern void ira_emit (bool);
+/* ira-reload.c */
+extern void ira_reload (void);
/* Return cost of moving value of MODE from register of class FROM to
diff --git a/gcc/ira-reload.c b/gcc/ira-reload.c
new file mode 100644
index 00000000000..80bcb26b918
--- /dev/null
+++ b/gcc/ira-reload.c
@@ -0,0 +1,982 @@
+/* Integrated Register Allocator (IRA) reloading .
+ Copyright (C) 2009
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "regs.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "target.h"
+#include "flags.h"
+#include "obstack.h"
+#include "bitmap.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "expr.h"
+#include "recog.h"
+#include "params.h"
+#include "timevar.h"
+#include "tree-pass.h"
+#include "output.h"
+#include "except.h"
+#include "reload.h"
+#include "errors.h"
+#include "integrate.h"
+#include "df.h"
+#include "ggc.h"
+#include "ira-int.h"
+
+
+static bitmap pseudos_to_localize;
+static bitmap regs_to_load;
+static bitmap regs_to_store;
+static bitmap no_uses_after_last_set;
+static int *pseudo_nuses;
+static int *pseudo_nsets;
+static rtx *reg_map;
+
+/* Return true if REG is a pseudo which should be localized, return false
+ otherwise. */
+
+static bool
+localize_pseudo_p (unsigned int regno)
+{
+ /* If this pseudo got a hard register, then we obviously do not want to
+ localize it. */
+ if (reg_renumber [regno] != -1)
+ return false;
+
+ /* Avoid localizing a pseudo which can be rematerialized.
+ ?!? I think this is a holdover from ancient code and may no longer
+ be necessary. */
+ if ((reg_equiv_constant && reg_equiv_constant[regno])
+ || (reg_equiv_invariant && reg_equiv_invariant[regno]))
+ return false;
+
+ /* If we don't know what register class to use for the psuedo, then
+ we don't try to localize it.
+ ?!? ISTM we should go ahead and localize as the localized pseudo
+ should be easier for reload to handle. */
+ if (reg_preferred_class (regno) == NO_REGS)
+ return false;
+
+ /* If the pseudo is already local to a block, then there's no point
+ in localizing it. */
+ if (REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL
+ && REG_BASIC_BLOCK (regno) != REG_BLOCK_UNKNOWN)
+ return false;
+
+ return true;
+}
+
+
+/* Alter each pseudo-reg rtx to contain its hard reg number. Assign
+ stack slots to the pseudos that lack hard regs or equivalents.
+ Do not touch virtual registers.
+
+ ?!? This assigns for local pseudos too, which might be wasteful
+ as we get another chance to allocate those. */
+static void
+assign_stack_slots (void)
+{
+ unsigned i, n, max_regno = max_reg_num ();
+ int *temp_pseudo_reg_arr;
+
+ /* ?!? This should be cleaned up or go away. */
+ ira_spilled_reg_stack_slots_num = 0;
+
+
+ temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1);
+ n = 0;
+ for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
+ temp_pseudo_reg_arr[n++] = i;
+
+ /* Ask IRA to order pseudo-registers for better stack slot
+ sharing. */
+ ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_width);
+
+ for (i = 0; i < n; i++)
+ alter_reg (temp_pseudo_reg_arr[i], -1, false);
+
+ free (temp_pseudo_reg_arr);
+}
+
+
+/* Count uses of USE (into pseudo_nuses) if USE is a register marked for
+ localization. */
+
+static void
+identify_singleton_uses (rtx use)
+{
+ if (GET_CODE (use) == SUBREG)
+ use = SUBREG_REG (use);
+
+ if (GET_CODE (use) != REG)
+ return;
+
+ if (bitmap_bit_p (pseudos_to_localize, REGNO (use)))
+ pseudo_nuses[REGNO (use)]++;
+}
+
+/* Count assignments to DEST (into pseudo_nsets) if DEST is a register marked
+ for localization. */
+
+static void
+identify_singleton_sets (rtx dest)
+{
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
+ if (GET_CODE (dest) != REG)
+ return;
+
+ /* If DEST isn't maked for spilling, then there is nothing to do. */
+ if (bitmap_bit_p (pseudos_to_localize, REGNO (dest)))
+ {
+ if (pseudo_nuses[REGNO (dest)] == 0 && pseudo_nsets[REGNO (dest)] == 0)
+ bitmap_set_bit (no_uses_after_last_set, REGNO (dest));
+ pseudo_nsets[REGNO (dest)]++;
+ }
+}
+
+/* Collect (into REGS_TO_LOAD) USE if it is a pseudo marked for
+ localization. */
+
+static void
+collect_loads (rtx use)
+{
+ if (GET_CODE (use) == SUBREG)
+ use = SUBREG_REG (use);
+
+ if (GET_CODE (use) != REG)
+ return;
+
+ if (bitmap_bit_p (pseudos_to_localize, REGNO (use)))
+ bitmap_set_bit (regs_to_load, REGNO (use));
+
+ return;
+}
+
+/* If USE refers to a pseudo marked in REGS_TO_LOAD, emit a load of
+ the pseudo before INSN. */
+
+static int
+emit_localizing_loads (rtx use, rtx insn)
+{
+ if (GET_CODE (use) == SUBREG)
+ use = SUBREG_REG (use);
+
+ if (GET_CODE (use) != REG)
+ return 0 ;
+
+ if (bitmap_bit_p (pseudos_to_localize, REGNO (use)))
+ {
+ /* Create a new pseudo and record it in our map. */
+ if (reg_map [(REGNO (use))] == NULL)
+ reg_map [REGNO (use)] = gen_reg_rtx (GET_MODE (use));
+
+
+ /* If this pseudo still needs a load, emit it. */
+ if (bitmap_bit_p (regs_to_load, REGNO (use)))
+ {
+ rtx insns, temp;
+ rtx mem = copy_rtx (reg_equiv_memory_loc[REGNO (use)]);
+ int nuses = pseudo_nuses[REGNO (use)];
+ int nsets = pseudo_nsets[REGNO (use)];
+ int occurrences = count_occurrences (PATTERN (insn), use, 0);
+
+ /* validate_replace_rtx internally calls df_insn_rescan, which is
+ unsafe as our caller is iterating over the existing DF info. So
+ we have to turn off insn rescanning temporarily. */
+ df_set_flags (DF_NO_INSN_RESCAN);
+
+ /* If this insn has all the uses of a pseudo we want to localize
+ and the pseudo is never set, then try to replace the pseudo
+ with its equivalent memory location. */
+ if (nsets == 0
+ && (occurrences == nuses || nuses == 2)
+ && validate_replace_rtx (use, mem, insn))
+ {
+ df_clear_flags (DF_NO_INSN_RESCAN);
+ }
+ else
+ {
+ df_clear_flags (DF_NO_INSN_RESCAN);
+ start_sequence ();
+ emit_move_insn (reg_map [REGNO (use)], mem);
+ insns = get_insns();
+ end_sequence ();
+ emit_insn_before (insns, insn);
+
+ /* Inform the DF framework about the new insns. */
+ for (temp = insns; temp != insn; temp = NEXT_INSN (insns))
+ df_insn_rescan (temp);
+
+ /* Note it is no longer necessary to load this pseudo. */
+ bitmap_clear_bit (regs_to_load, REGNO (use));
+ }
+ }
+
+ /* Replace the original pseudo with the new one. */
+ replace_rtx (insn, use, reg_map [REGNO (use)]);
+ return 1;
+ }
+ return 0;
+}
+
+/* DEST is an output for INSN (passed in DATA). If the output is marked
+ for localizing, then we need to rename it to the new block-local
+ pseudo. This finishes the localization of unallocated globals. */
+
+static int
+rename_sets (rtx dest, rtx insn)
+{
+ rtx orig = dest;
+
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
+ if (GET_CODE (dest) != REG)
+ return 0;
+
+ /* If DEST isn't maked for spilling, then there is nothing to do. */
+ if (! bitmap_bit_p (pseudos_to_localize, REGNO (dest)))
+ return 0;
+
+ /* A store can be viewed as a store followed by a load, so we can clear DEST
+ from REGS_TO_LOAD, but not if this was a partial store. */
+ if (GET_CODE (orig) == STRICT_LOW_PART)
+ {
+ /* This must be treated as a USE too.
+ ?!? Does this need to integrated with the use processing? */
+ emit_localizing_loads (dest, insn);
+ }
+ else if (GET_CODE (orig) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (orig)))
+ < GET_MODE_SIZE (GET_MODE (dest)))
+ {
+ /* This must be treated as a USE too.
+ ?!? Does this need to integrated with the use processing? */
+ emit_localizing_loads (dest, insn);
+ }
+
+ /* ?!? I'm not entirely sure this can still happen. */
+ if (reg_map [(REGNO (dest))] == NULL)
+ reg_map [REGNO (dest)] = gen_reg_rtx (GET_MODE (dest));
+
+
+ replace_rtx (insn, dest, reg_map [REGNO (dest)]);
+ return 1;
+}
+
+/* Store each pseudo set by the current insn (passed in DATA) that is
+ marked for localizing into memory after INSN.
+
+ Return 0 if INSN does not need rescanning.
+
+ Return 1 if INSN needs rescanning.
+
+ Return -1 if INSN should be deleted. */
+
+static int
+emit_localizing_stores (rtx dest, rtx insn)
+{
+ unsigned int regno;
+ int retval = 0;
+ rtx insns;
+ rtx orig = dest;
+
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
+ /* If the output isn't a register, then there's nothing to do. */
+ if (GET_CODE (dest) != REG)
+ return retval;
+
+ regno = REGNO (dest);
+
+ /* If the register isn't marked for localization, then there's nothing
+ to do. */
+ if (! bitmap_bit_p (pseudos_to_localize, regno))
+ return retval;
+
+ /* DEST is marked for spilling, if we have not emitted a spill store yet for
+ DEST, then do so now. Note we do not change INSN at this time. */
+ if (bitmap_bit_p (regs_to_store, regno))
+ {
+ int nuses = pseudo_nuses[REGNO (dest)];
+ int nsets = pseudo_nsets[REGNO (dest)];
+ int occurrences = count_occurrences (PATTERN (insn), dest, 0);
+
+ /* We must copy the memory location to avoid incorrect RTL sharing. */
+ rtx mem = copy_rtx (reg_equiv_memory_loc[regno]);
+
+ /* Note that we have stored this register so that we don't try to
+ store it again. */
+ bitmap_clear_bit (regs_to_store, regno);
+
+ /* validate_replace_rtx internally calls df_insn_rescan, which is
+ unsafe as our caller is iterating over the existing DF info. So
+ we have to turn off insn rescanning temporarily. */
+ df_set_flags (DF_NO_INSN_RESCAN);
+ /* If this insn both uses and sets a pseudo we want to localize and
+ contains all the uses and sets, then try to replace the pseudo
+ with its equivalent memory location. */
+ if (nuses
+ && nsets == 1
+ && occurrences == nuses
+ && validate_replace_rtx (dest, mem, insn))
+ {
+ df_clear_flags (DF_NO_INSN_RESCAN);
+ retval = 1;
+ }
+ /* Similarly if this insn sets a pseudo we want to localize and
+ there are no uses after this set, then try to replace the pseudo
+ with its equivalent memory location. */
+ else if (bitmap_bit_p (no_uses_after_last_set, (REGNO (dest)))
+ && nsets == 1
+ && validate_replace_rtx (dest, mem, insn))
+ {
+ df_clear_flags (DF_NO_INSN_RESCAN);
+ retval = 1;
+ }
+ else
+ {
+ df_clear_flags (DF_NO_INSN_RESCAN);
+ start_sequence ();
+ emit_move_insn (mem, dest);
+ insns = get_insns();
+ end_sequence ();
+
+ /* If the pseudo is being set from its equivalent memory location
+ and is unused from this point until the end of this block, then
+ we don't need to store the pseudo back to memory back, we
+ actually want to delete INSN. */
+ if (NEXT_INSN (insns) == 0
+ && single_set (insns)
+ && single_set (insn)
+ && rtx_equal_p (SET_SRC (single_set (insn)),
+ SET_DEST (single_set (insns))))
+ {
+ if (bitmap_bit_p (no_uses_after_last_set, REGNO (dest)))
+ retval = -1;
+ }
+ else
+ {
+ rtx temp;
+ /* Inform the DF framework about the new insns. */
+ for (temp = insns; temp; temp = NEXT_INSN (temp))
+ df_insn_rescan (temp);
+
+ emit_insn_after_noloc (insns, insn, NULL);
+ }
+ }
+ }
+
+ /* A store can be viewed as a store followed by a load, so we can clear DEST
+ from REGS_TO_LOAD, but not if this was a partial store. */
+ if (GET_CODE (orig) == STRICT_LOW_PART)
+ bitmap_set_bit (regs_to_load, regno);
+ else if (GET_CODE (orig) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (orig))
+ < GET_MODE_SIZE (GET_MODE (dest))))
+ bitmap_set_bit (regs_to_load, regno);
+ else
+ bitmap_clear_bit (regs_to_load, REGNO (dest));
+ return retval;
+}
+
+static void
+create_new_allocno_for_spilling (int nreg, int oreg)
+{
+ ira_allocno_t to, from, a;
+ ira_allocno_iterator ai;
+ ira_allocno_conflict_iterator aci;
+ unsigned int conflicts;
+ allocno_live_range_t prev, range, r;
+
+ /* Update IRA's datastructures. */
+
+ /* First create the allocno. */
+ to = ira_create_allocno (nreg, true, ira_curr_loop_tree_node);
+ ALLOCNO_REG (to) = regno_reg_rtx[nreg];
+
+ /* Now lengthen the regno->allocno map. */
+ ira_free (ira_regno_allocno_map);
+ ira_regno_allocno_map
+ = (ira_allocno_t *) ira_allocate (max_reg_num () * sizeof (ira_allocno_t));
+ memset (ira_regno_allocno_map, 0, max_reg_num () * sizeof (ira_allocno_t));
+ FOR_EACH_ALLOCNO (a, ai)
+ {
+ unsigned int regno = ALLOCNO_REGNO (a);
+ ira_regno_allocno_map[regno] = a;
+ }
+
+
+ /* Copy various fields from the original allocno to the new one. */
+ from = ira_regno_allocno_map [oreg];
+#ifdef STACK_REGS
+ ALLOCNO_NO_STACK_REG_P (to) = ALLOCNO_NO_STACK_REG_P (from);
+ ALLOCNO_TOTAL_NO_STACK_REG_P (to) = ALLOCNO_TOTAL_NO_STACK_REG_P (from);
+#endif
+ ALLOCNO_NREFS (to) = ALLOCNO_NREFS (from);
+ ALLOCNO_FREQ (to) = ALLOCNO_FREQ (from);
+ ALLOCNO_CALL_FREQ (to) = ALLOCNO_CALL_FREQ (from);
+ ALLOCNO_CALLS_CROSSED_NUM (to) = ALLOCNO_CALLS_CROSSED_NUM (from);
+ ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (to)
+ = ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (from);
+ ALLOCNO_BAD_SPILL_P (to) = ALLOCNO_BAD_SPILL_P (from);
+
+ ALLOCNO_COVER_CLASS (to) = ALLOCNO_COVER_CLASS (from);
+ ALLOCNO_COVER_CLASS_COST (to) = ALLOCNO_COVER_CLASS_COST (from);
+ ALLOCNO_MEMORY_COST (to) = ALLOCNO_MEMORY_COST (from);
+#if 0
+ ira_allocate_and_accumulate_costs (&ALLOCNO_HARD_REG_COSTS (to),
+ ALLOCNO_COVER_CLASS (to),
+ ALLOCNO_HARD_REG_COSTS (from));
+ ira_allocate_and_accumulate_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (to),
+ ALLOCNO_COVER_CLASS (to),
+ ALLOCNO_CONFLICT_HARD_REG_COSTS (from));
+#endif
+
+ /* We recompute these fields after we have localized an entire block. */
+ CLEAR_HARD_REG_SET (ALLOCNO_CONFLICT_HARD_REGS (to));
+ CLEAR_HARD_REG_SET (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (to));
+
+ /* Count the number of conflicts on the original allocno. We use that count
+ as an estimate for the number of conflicts in the new allocno. The new
+ allocno should have fewer conflicts than the original as the new allocno
+ is only live in BB and thus only conflicts with objects live in BB. */
+ conflicts = 0;
+ FOR_EACH_ALLOCNO_CONFLICT (from, a, aci)
+ conflicts++;
+
+ ALLOCNO_MIN (to) = ALLOCNO_MIN (from);
+ ALLOCNO_MAX (to) = ALLOCNO_MAX (from);
+ ira_allocate_allocno_conflicts (to, conflicts);
+
+ /* For now we copy the live range from the original allocno to the new
+ allocno. This is very suboptimal. Consider if we have some allocno A
+ which gets split into A0..A100. A0..A100 will not be able to share
+ stack slots because the live ranges conflict (they were copied from A
+ verbatim) -- however, in reality each new allocno A0..A100 has a
+ distinct, non-conflicting live range. */
+ for (prev = NULL, r = ALLOCNO_LIVE_RANGES (from);
+ r != NULL;
+ r = r->next, prev = range)
+ {
+ range = ira_create_allocno_live_range (to, r->start, r->finish, NULL);
+ /* ?!? This may not be necessary. */
+ range->start_next = NULL;
+ range->finish_next = NULL;
+ if (prev)
+ prev->next = range;
+ else
+ ALLOCNO_LIVE_RANGES (to) = range;
+ }
+}
+
+static bitmap live;
+
+static void
+maybe_add_conflict (int reg1, int reg2, int limit)
+{
+ if (reg1 < FIRST_PSEUDO_REGISTER
+ && reg2 < FIRST_PSEUDO_REGISTER)
+ return;
+
+ /* If neither register was created by localization, then ignore this
+ conflict. */
+ if (reg1 < limit && reg2 < limit)
+ return;
+
+ if (reg1 < FIRST_PSEUDO_REGISTER)
+ {
+ ira_allocno_t a = ira_regno_allocno_map[reg2];
+ SET_HARD_REG_BIT (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), reg1);
+ SET_HARD_REG_BIT (ALLOCNO_CONFLICT_HARD_REGS (a), reg1);
+ return;
+ }
+
+ if (reg2 < FIRST_PSEUDO_REGISTER)
+ {
+ ira_allocno_t a = ira_regno_allocno_map[reg1];
+ SET_HARD_REG_BIT (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), reg2);
+ SET_HARD_REG_BIT (ALLOCNO_CONFLICT_HARD_REGS (a), reg2);
+ return;
+ }
+
+ /* If the registers are in different cover classes, then ignore this
+ conflict. */
+ if (ira_class_translate[reg_preferred_class (reg1)]
+ != ira_class_translate[reg_preferred_class (reg2)])
+ return;
+
+ ira_add_allocno_conflict (ira_regno_allocno_map[reg1],
+ ira_regno_allocno_map[reg2]);
+}
+
+static void
+mark_conflicts (rtx reg, unsigned int limit)
+{
+ bitmap_iterator bi;
+ unsigned int i;
+ unsigned int j, nregs;
+ unsigned int non_killing_store = 0;
+
+ if (GET_CODE (reg) == SUBREG
+ && GET_CODE (SUBREG_REG (reg)) == REG)
+ {
+ if (GET_MODE_SIZE (GET_MODE (reg))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (reg))))
+ non_killing_store = 1;
+
+ reg = SUBREG_REG (reg);
+ }
+
+ if (GET_CODE (reg) != REG)
+ return;
+
+ if (REGNO (reg) >= FIRST_PSEUDO_REGISTER)
+ nregs = 1;
+ else
+ nregs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
+
+ for (j = 0; j < nregs; j++)
+ {
+ if (!non_killing_store)
+ {
+ bitmap_clear_bit (live, REGNO (reg) + j);
+ }
+ EXECUTE_IF_SET_IN_BITMAP (live, 0, i, bi)
+ maybe_add_conflict (i, REGNO (reg) + j, limit);
+ }
+}
+
+static void
+mark_live (rtx reg)
+{
+ int i, nregs;
+
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+ if (REGNO (reg) > FIRST_PSEUDO_REGISTER)
+ nregs = 1;
+ else
+ nregs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
+
+ for (i = 0; i < nregs; i++)
+ bitmap_set_bit (live, REGNO (reg));
+}
+
+static void
+build_conflicts_for_new_allocnos (basic_block bb,
+ bitmap pseudos_to_localize,
+ int orig_max_reg_num)
+{
+ rtx insn;
+
+
+ live = BITMAP_ALLOC (NULL);
+
+ /* Starting state is the live-out pseudos - pseudos we're localizing. */
+ bitmap_and_compl (live, DF_LIVE_OUT (bb), pseudos_to_localize);
+
+ FOR_BB_INSNS_REVERSE (bb, insn)
+ {
+ df_ref *def_rec, *use_rec;
+ int call_p;
+
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ call_p = CALL_P (insn);
+ /* Mark conflicts for any values defined in this insn. */
+ for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
+ if (!call_p || !DF_REF_FLAGS_IS_SET (*def_rec, DF_REF_MAY_CLOBBER))
+ mark_conflicts (DF_REF_REG (*def_rec), orig_max_reg_num);
+
+ /* Mark each used value as live. */
+ for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+ mark_live (DF_REF_REG (*use_rec));
+ }
+
+ BITMAP_FREE (live);
+}
+
+/* Emit trivial spill code for unallocated pseudos which are live at one or
+ more basic block boundaries appearing in BB.
+
+ Effectively we're splitting the range of these pseudos in such a way as
+ the new pseudos are live within a single basic block by adding a store
+ after the last assignment to the pseudo and a load before the first use
+ within BB.
+
+ ?!? We might be able to use extended basic blocks to avoid additional loads
+ and stores. Definitely worth some experimentation. */
+
+static void
+localize_pseudos (basic_block bb, bitmap pseudos_to_localize)
+{
+ int orig_max_reg_num = max_reg_num ();
+ int i;
+ rtx insn;
+
+ regs_to_store = BITMAP_ALLOC (NULL);
+ regs_to_load = BITMAP_ALLOC (NULL);
+ no_uses_after_last_set = BITMAP_ALLOC (NULL);
+ pseudo_nuses = (int *) xmalloc (max_reg_num () * sizeof (int));
+ memset (pseudo_nuses, 0, max_reg_num () * sizeof (int));
+ pseudo_nsets = (int *) xmalloc (max_reg_num () * sizeof (int));
+ memset (pseudo_nsets, 0, max_reg_num () * sizeof (int));
+
+ reg_map = (rtx *) xmalloc (sizeof (rtx) * orig_max_reg_num);
+ memset (reg_map, 0, sizeof (rtx) * orig_max_reg_num);
+
+ bitmap_copy (regs_to_store, pseudos_to_localize);
+
+ /* First walk over the insns in this region and identify singleton
+ uses of registers in PSEUDOS_TO_LOCALIZE. We want to know if a
+ use is a singleton so that we can change the use to a MEM. We
+ need this information prior to emitting localizing stores so that
+ we can change both the use and set in a single insn to a MEM. */
+ FOR_BB_INSNS_REVERSE (bb, insn)
+ {
+ df_ref *def_rec, *use_rec;
+
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
+ identify_singleton_sets (DF_REF_REG (*def_rec));
+
+ for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+ identify_singleton_uses (DF_REF_REG (*use_rec));
+ }
+
+ /* Next emit a store after the last assignment of each pseudo in
+ PSEUDOS_TO_LOCALIZE within the region. Collect list of pseudos
+ we'll need to load as well. */
+ FOR_BB_INSNS_REVERSE (bb, insn)
+ {
+ df_ref *def_rec, *use_rec;
+ int status;
+
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ status = 0;
+ for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
+ status |= emit_localizing_stores (DF_REF_REG (*def_rec), insn);
+
+ /* A return status of -1 indicates INSN should be removed. */
+ if (status == -1 && single_set (insn))
+ {
+ set_insn_deleted (insn);
+ continue;
+ }
+
+ /* It is not safe to defer scanning any further as emit_localizing_stores
+ can change uses and defs. */
+ if (status)
+ df_insn_rescan (insn);
+
+ for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+ collect_loads (DF_REF_REG (*use_rec));
+ }
+
+ /* Now walk forward through the region emitting loads before
+ the first use of each pseudo that we're localizing and change
+ each reference from an unallocated pseudo to a new block local
+ spill register. */
+ FOR_BB_INSNS (bb, insn)
+ {
+ df_ref *def_rec, *use_rec;
+ int need_rescan;
+
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+
+ need_rescan = 0;
+ for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
+ need_rescan |= emit_localizing_loads (DF_REF_REG (*use_rec), insn);
+
+ for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
+ need_rescan |= rename_sets (DF_REF_REG (*def_rec), insn);
+
+ if (need_rescan)
+ df_insn_rescan (insn);
+
+ }
+
+ /* If we allocated new pseudos, then we need to expand various arrays and
+ update IRA's data structures. */
+ if (orig_max_reg_num != max_reg_num ())
+ {
+ unsigned int max_regno = max_reg_num ();
+ unsigned int nregs = max_regno - orig_max_reg_num;
+
+ /* First expand various data structures. */
+ regstat_reallocate_ri (max_regno);
+ expand_reg_info (max_regno - 1);
+ reg_equiv_invariant = (rtx *) xrealloc (reg_equiv_invariant,
+ max_regno * sizeof (rtx));
+ memset (&reg_equiv_invariant[orig_max_reg_num], 0, nregs * sizeof (rtx));
+ reg_equiv_constant = (rtx *) xrealloc (reg_equiv_constant,
+ max_regno * sizeof (rtx));
+ memset (&reg_equiv_constant[orig_max_reg_num], 0, nregs * sizeof (rtx));
+ reg_equiv_mem = (rtx *) xrealloc (reg_equiv_mem, max_regno * sizeof (rtx));
+ memset (&reg_equiv_mem[orig_max_reg_num], 0, nregs * sizeof (rtx));
+ reg_equiv_alt_mem_list = (rtx *) xrealloc (reg_equiv_alt_mem_list,
+ max_regno * sizeof (rtx));
+ memset (&reg_equiv_alt_mem_list[orig_max_reg_num], 0, nregs * sizeof (rtx));
+ reg_equiv_address = (rtx *) xrealloc (reg_equiv_address,
+ max_regno * sizeof (rtx));
+ memset (&reg_equiv_address[orig_max_reg_num], 0, nregs * sizeof (rtx));
+ VEC_safe_grow_cleared (rtx, gc, reg_equiv_memory_loc_vec, max_regno);
+ reg_equiv_memory_loc = VEC_address (rtx, reg_equiv_memory_loc_vec);
+ reg_equiv_init
+ = (rtx *) ggc_realloc (reg_equiv_init, max_regno * sizeof (rtx));
+ memset (&reg_equiv_init[orig_max_reg_num], 0, nregs * sizeof (rtx));
+ regstat_n_sets_and_refs
+ = ((struct regstat_n_sets_and_refs_t *)
+ xrealloc (regstat_n_sets_and_refs,
+ (max_regno * sizeof (struct regstat_n_sets_and_refs_t))));
+ memset (&regstat_n_sets_and_refs[orig_max_reg_num], 0,
+ nregs * sizeof (struct regstat_n_sets_and_refs_t));
+ reg_max_ref_width = (unsigned int *) xrealloc (reg_max_ref_width,
+ max_regno * sizeof (unsigned int));
+ memset (&reg_max_ref_width[orig_max_reg_num], 0,
+ nregs * sizeof (unsigned int));
+
+ /* Now copy data from the original register to the new register. */
+ for (i = 0; i < orig_max_reg_num; i++)
+ {
+ int nregno;
+
+ if (reg_map[i] == 0)
+ continue;
+
+ nregno = REGNO (reg_map[i]);
+ setup_reg_classes (nregno, reg_preferred_class (i), reg_alternate_class (i), ira_class_translate [reg_preferred_class (i)]);
+ reg_equiv_invariant[nregno] = reg_equiv_invariant[i];
+ reg_equiv_constant[nregno] = reg_equiv_constant[i];
+ reg_equiv_mem[nregno] = reg_equiv_mem[i];
+ reg_equiv_alt_mem_list[nregno] = reg_equiv_alt_mem_list[i];
+ reg_equiv_address[nregno] = reg_equiv_address[i];
+ reg_equiv_memory_loc[nregno] = reg_equiv_memory_loc[i];
+ /* ?!? I don't recall why this was originally necessary. Definitely need
+ to retest and understand or make it go away. */
+ reg_equiv_init[i] = NULL;
+ reg_equiv_init[nregno] = reg_equiv_init[i];
+ reg_max_ref_width[nregno] = reg_max_ref_width[i];
+ reg_renumber[nregno] = reg_renumber[i];
+ REG_N_CALLS_CROSSED (nregno) = REG_N_CALLS_CROSSED (i);
+
+ /* We don't really care other than to be sure there's a set and ref. */
+ SET_REG_N_SETS (nregno, 1);
+ SET_REG_N_REFS (nregno, 1);
+
+ /* The new register is always local to this block. */
+ REG_BASIC_BLOCK (nregno) = REG_BLOCK_GLOBAL;
+
+ /* Create a new allocno for the new register. */
+ create_new_allocno_for_spilling (nregno, i);
+ }
+
+ /* Now reallocate a few IRA arrays. */
+ ira_finish_assign ();
+ ira_initiate_assign ();
+
+ /* Fill in the sorted_allocnos and priority arrays. */
+ {
+ ira_allocno_t a;
+ ira_allocno_iterator ai;
+ unsigned int num = 0;
+ extern ira_allocno_t *sorted_allocnos;
+
+ FOR_EACH_ALLOCNO (a, ai)
+ sorted_allocnos[num++] = a;
+ setup_allocno_priorities (sorted_allocnos, num);
+ }
+
+ /* We didn't copy the conflicts from the old allocno to the new allocno
+ as typically the new allocno will have fewer conflicts.
+
+ We wait until after we've created all the new allocnos for this block
+ so that we can update the conflict graph with a single backwards walk
+ through this block. */
+ build_conflicts_for_new_allocnos (bb, pseudos_to_localize, orig_max_reg_num);
+
+ /* We added new live-range objects, so rebuild the chains. */
+ ira_rebuild_start_finish_chains ();
+ }
+
+ free (reg_map);
+ reg_map = NULL;
+ BITMAP_FREE (regs_to_store);
+ regs_to_store = NULL;
+ BITMAP_FREE (regs_to_load);
+ regs_to_load = NULL;
+ BITMAP_FREE (no_uses_after_last_set);
+ no_uses_after_last_set = NULL;
+ free (pseudo_nuses);
+ pseudo_nuses = NULL;
+ free (pseudo_nsets);
+ pseudo_nsets = NULL;
+}
+
+void
+ira_reload (void)
+{
+ /* We need to build the various equivalences prior to assigning stack
+ slots for unallocated global pseudos. */
+ record_equivalences_for_reload ();
+
+ if (ira_conflicts_p)
+ {
+ unsigned int i, j;
+ bitmap_iterator bi;
+ basic_block bb;
+
+ pseudos_to_localize = BITMAP_ALLOC (NULL);
+ max_regno = max_reg_num ();
+ /* Collect all the registers we want to localize into a bitmap. */
+ for (j = FIRST_PSEUDO_REGISTER; j < (unsigned) max_regno; j++)
+ if (localize_pseudo_p (j))
+ bitmap_set_bit (pseudos_to_localize, j);
+
+ /* Assign stack slots for pseudos live at block boundaries which did not
+ get hard regs. This unfortunately turns pseudos into hard regs which
+ we will need to undo later. */
+ assign_stack_slots ();
+
+ for (i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++)
+ if (regno_reg_rtx[i])
+ SET_REGNO (regno_reg_rtx[i], i);
+
+ if (!bitmap_empty_p (pseudos_to_localize))
+ {
+ FOR_EACH_BB (bb)
+ localize_pseudos (bb, pseudos_to_localize);
+ }
+
+ /* Now we want to remove each allocnos associated with the pseudos we
+ localized from the conflicts of every other allocno. Do this once
+ after localizing in all blocks rather than in each block. */
+ EXECUTE_IF_SET_IN_BITMAP (pseudos_to_localize,
+ FIRST_PSEUDO_REGISTER, i, bi)
+ remove_from_all_conflicts (ira_regno_allocno_map[i]);
+
+ /* We may have allocated additional pseudos during spilling, so update
+ max_regno. ?!? Updating max_regno should really occur when we
+ allocate new regs. Or better yet, max it go away completely. */
+ max_regno = max_reg_num ();
+
+ /* Try to assign hard regs to pseudos that didn't get them the
+ first time through the allocator. */
+ {
+ unsigned int i, n;
+ int *x = (int *) xmalloc (max_regno * sizeof (int));
+ HARD_REG_SET bad_spill_regs ;
+ HARD_REG_SET *p = XNEWVEC (HARD_REG_SET, max_regno);
+ regset_head z;
+
+
+ if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+ fprintf (ira_dump_file, "Reassigning after localization\n");
+
+ INIT_REG_SET (&z);
+ CLEAR_REG_SET (&z);
+ COPY_HARD_REG_SET (bad_spill_regs, fixed_reg_set);
+ memset (x, 0, max_regno * sizeof (int));
+ for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < (unsigned) max_regno; i++)
+ {
+ CLEAR_HARD_REG_SET (p[i]);
+ if (reg_renumber[i] == -1 && ira_regno_allocno_map[i] && !bitmap_bit_p (pseudos_to_localize, i))
+ x[n++] = i;
+ }
+
+ ira_reassign_pseudos (x, n, bad_spill_regs, p, p, &z);
+
+ if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+ fprintf (ira_dump_file, "Done reassigning after localization\n");
+ }
+
+ BITMAP_FREE (pseudos_to_localize);
+
+
+ /* Spill code insertion can force creation of new basic blocks. */
+ fixup_abnormal_edges ();
+
+ for (i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++)
+ if (regno_reg_rtx[i])
+ SET_REGNO (regno_reg_rtx[i], i);
+
+ /* Finally, reset the DF analyzer as we have added new blocks, new
+ insns, modified existing insns, etc etc. */
+ df_scan_alloc (NULL);
+ df_scan_blocks ();
+ df_analyze ();
+ }
+}
+
+/* Return nonzero if REGNO is a particularly bad choice for reloading X. */
+static int
+ira_bad_reload_regno_1 (int regno, rtx x)
+{
+ int x_regno;
+ ira_allocno_t a;
+ enum reg_class pref;
+
+ /* We only deal with pseudo regs. */
+ if (! x || GET_CODE (x) != REG)
+ return 0;
+
+ x_regno = REGNO (x);
+ if (x_regno < FIRST_PSEUDO_REGISTER)
+ return 0;
+
+ /* If the pseudo prefers REGNO explicitly, then do not consider
+ REGNO a bad spill choice. */
+ pref = reg_preferred_class (x_regno);
+ if (reg_class_size[pref] == 1
+ && TEST_HARD_REG_BIT (reg_class_contents[pref], regno))
+ return 0;
+
+ /* If the pseudo conflicts with REGNO, then we consider REGNO a
+ poor choice for a reload regno. */
+ a = ira_regno_allocno_map[x_regno];
+ if (TEST_HARD_REG_BIT (ALLOCNO_TOTAL_CONFLICT_HARD_REGS (a), regno))
+ return 1;
+
+ return 0;
+}
+
+/* Return nonzero if REGNO is a particularly bad choice for reloading
+ IN or OUT. */
+int
+ira_bad_reload_regno (int regno, rtx in, rtx out)
+{
+ return (ira_bad_reload_regno_1 (regno, in)
+ || ira_bad_reload_regno_1 (regno, out));
+}
diff --git a/gcc/ira.c b/gcc/ira.c
index 962d0994c36..cf389a4f5a6 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -413,6 +413,11 @@ static HARD_REG_SET no_unit_alloc_regs;
allocation order. */
short ira_class_hard_regs[N_REG_CLASSES][FIRST_PSEUDO_REGISTER];
+/* Array of the number of hard registers of given class which are
+ available for allocation. The order is defined by the
+ the hard register numbers. */
+short ira_non_ordered_class_hard_regs[N_REG_CLASSES][FIRST_PSEUDO_REGISTER];
+
/* The number of elements of the above array for given register
class. */
int ira_class_hard_regs_num[N_REG_CLASSES];
@@ -440,7 +445,10 @@ setup_class_hard_regs (void)
AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
CLEAR_HARD_REG_SET (processed_hard_reg_set);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- ira_class_hard_reg_index[cl][0] = -1;
+ {
+ ira_non_ordered_class_hard_regs[cl][0] = -1;
+ ira_class_hard_reg_index[cl][0] = -1;
+ }
for (n = 0, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
#ifdef REG_ALLOC_ORDER
@@ -460,6 +468,10 @@ setup_class_hard_regs (void)
}
}
ira_class_hard_regs_num[cl] = n;
+ for (n = 0, i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (temp_hard_regset, i))
+ ira_non_ordered_class_hard_regs[cl][n++] = i;
+ ira_assert (ira_class_hard_regs_num[cl] == n);
}
}
@@ -1841,7 +1853,7 @@ setup_preferred_alternate_classes_for_new_pseudos (int start)
/* Regional allocation can create new pseudo-registers. This function
expands some arrays for pseudo-registers. */
-static void
+void
expand_reg_info (int old_size)
{
int i;
@@ -3269,6 +3281,9 @@ ira (FILE *f)
timevar_pop (TV_IRA);
timevar_push (TV_RELOAD);
+
+ ira_reload ();
+
df_set_flags (DF_NO_INSN_RESCAN);
build_insn_chain ();
diff --git a/gcc/ira.h b/gcc/ira.h
index 9688f7485dc..3c4ce593246 100644
--- a/gcc/ira.h
+++ b/gcc/ira.h
@@ -87,3 +87,4 @@ extern rtx ira_reuse_stack_slot (int, unsigned int, unsigned int);
extern void ira_mark_new_stack_slot (rtx, int, unsigned int);
extern bool ira_better_spill_reload_regno_p (int *, int *, rtx, rtx, rtx);
+extern int ira_bad_reload_regno (int, rtx, rtx);
diff --git a/gcc/regs.h b/gcc/regs.h
index 00be997695f..b9b7fa80ae8 100644
--- a/gcc/regs.h
+++ b/gcc/regs.h
@@ -105,6 +105,7 @@ extern void regstat_free_ri (void);
extern bitmap regstat_get_setjmp_crosses (void);
extern void regstat_compute_calls_crossed (void);
extern void regstat_free_calls_crossed (void);
+extern void regstat_reallocate_ri (unsigned int);
/* Register information indexed by register number. This structure is
diff --git a/gcc/regstat.c b/gcc/regstat.c
index 70ddfa4d84f..6f96c631ee9 100644
--- a/gcc/regstat.c
+++ b/gcc/regstat.c
@@ -337,6 +337,16 @@ regstat_bb_compute_ri (unsigned int bb_index,
bitmap_clear (local_live);
}
+/* Reallocate the register info structure, ensuring the new entries are
+ properly cleared. */
+void
+regstat_reallocate_ri (unsigned int max_regno)
+{
+ reg_info_p = XRESIZEVEC (struct reg_info_t, reg_info_p, max_regno);
+ memset (&reg_info_p[reg_info_p_size], 0,
+ (max_regno - reg_info_p_size) * sizeof (struct reg_info_t));
+ reg_info_p_size = max_regno;
+}
/* Compute register info: lifetime, bb, and number of defs and uses. */
void
diff --git a/gcc/reload.h b/gcc/reload.h
index 3789680f7ca..a526d60442d 100644
--- a/gcc/reload.h
+++ b/gcc/reload.h
@@ -161,6 +161,7 @@ extern rtx *reg_equiv_memory_loc;
extern rtx *reg_equiv_address;
extern rtx *reg_equiv_mem;
extern rtx *reg_equiv_alt_mem_list;
+extern unsigned int *reg_max_ref_width;
/* Element N is the list of insns that initialized reg N from its equivalent
constant or memory slot. */
@@ -373,3 +374,10 @@ extern void debug_reload (void);
/* Compute the actual register we should reload to, in case we're
reloading to/from a register that is wider than a word. */
extern rtx reload_adjust_reg_for_mode (rtx, enum machine_mode);
+
+/* Modify the home of a pseudo register. */
+extern void alter_reg (int, int, bool);
+
+/* Record memory and constant equivalences for pseudos which did not get hard
+ registers. */
+extern void record_equivalences_for_reload (void);
diff --git a/gcc/reload1.c b/gcc/reload1.c
index e9a0aba83bc..5a1839944dc 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -130,7 +130,7 @@ rtx *reg_equiv_mem;
rtx *reg_equiv_alt_mem_list;
/* Widest width in which each pseudo reg is referred to (via subreg). */
-static unsigned int *reg_max_ref_width;
+unsigned int *reg_max_ref_width;
/* Element N is the list of insns that initialized reg N from its equivalent
constant or memory slot. */
@@ -394,7 +394,6 @@ static void delete_caller_save_insns (void);
static void spill_failure (rtx, enum reg_class);
static void count_spilled_pseudo (int, int, int);
static void delete_dead_insn (rtx);
-static void alter_reg (int, int, bool);
static void set_label_offsets (rtx, rtx, int);
static void check_eliminable_occurrences (rtx);
static void elimination_effects (rtx, enum machine_mode);
@@ -761,126 +760,12 @@ reload (rtx first, int global)
if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
df_set_regs_ever_live (i, true);
- /* Find all the pseudo registers that didn't get hard regs
- but do have known equivalent constants or memory slots.
- These include parameters (known equivalent to parameter slots)
- and cse'd or loop-moved constant memory addresses.
-
- Record constant equivalents in reg_equiv_constant
- so they will be substituted by find_reloads.
- Record memory equivalents in reg_mem_equiv so they can
- be substituted eventually by altering the REG-rtx's. */
-
- reg_equiv_constant = XCNEWVEC (rtx, max_regno);
- reg_equiv_invariant = XCNEWVEC (rtx, max_regno);
- reg_equiv_mem = XCNEWVEC (rtx, max_regno);
- reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno);
- reg_equiv_address = XCNEWVEC (rtx, max_regno);
- reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
reg_old_renumber = XCNEWVEC (short, max_regno);
memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short));
pseudo_forbidden_regs = XNEWVEC (HARD_REG_SET, max_regno);
pseudo_previous_regs = XCNEWVEC (HARD_REG_SET, max_regno);
-
CLEAR_HARD_REG_SET (bad_spill_regs_global);
- /* Look for REG_EQUIV notes; record what each pseudo is equivalent
- to. Also find all paradoxical subregs and find largest such for
- each pseudo. */
-
- num_eliminable_invariants = 0;
- for (insn = first; insn; insn = NEXT_INSN (insn))
- {
- rtx set = single_set (insn);
-
- /* We may introduce USEs that we want to remove at the end, so
- we'll mark them with QImode. Make sure there are no
- previously-marked insns left by say regmove. */
- if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE
- && GET_MODE (insn) != VOIDmode)
- PUT_MODE (insn, VOIDmode);
-
- if (NONDEBUG_INSN_P (insn))
- scan_paradoxical_subregs (PATTERN (insn));
-
- if (set != 0 && REG_P (SET_DEST (set)))
- {
- rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
- rtx x;
-
- if (! note)
- continue;
-
- i = REGNO (SET_DEST (set));
- x = XEXP (note, 0);
-
- if (i <= LAST_VIRTUAL_REGISTER)
- continue;
-
- if (! function_invariant_p (x)
- || ! flag_pic
- /* A function invariant is often CONSTANT_P but may
- include a register. We promise to only pass
- CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
- || (CONSTANT_P (x)
- && LEGITIMATE_PIC_OPERAND_P (x)))
- {
- /* It can happen that a REG_EQUIV note contains a MEM
- that is not a legitimate memory operand. As later
- stages of reload assume that all addresses found
- in the reg_equiv_* arrays were originally legitimate,
- we ignore such REG_EQUIV notes. */
- if (memory_operand (x, VOIDmode))
- {
- /* Always unshare the equivalence, so we can
- substitute into this insn without touching the
- equivalence. */
- reg_equiv_memory_loc[i] = copy_rtx (x);
- }
- else if (function_invariant_p (x))
- {
- if (GET_CODE (x) == PLUS)
- {
- /* This is PLUS of frame pointer and a constant,
- and might be shared. Unshare it. */
- reg_equiv_invariant[i] = copy_rtx (x);
- num_eliminable_invariants++;
- }
- else if (x == frame_pointer_rtx || x == arg_pointer_rtx)
- {
- reg_equiv_invariant[i] = x;
- num_eliminable_invariants++;
- }
- else if (LEGITIMATE_CONSTANT_P (x))
- reg_equiv_constant[i] = x;
- else
- {
- reg_equiv_memory_loc[i]
- = force_const_mem (GET_MODE (SET_DEST (set)), x);
- if (! reg_equiv_memory_loc[i])
- reg_equiv_init[i] = NULL_RTX;
- }
- }
- else
- {
- reg_equiv_init[i] = NULL_RTX;
- continue;
- }
- }
- else
- reg_equiv_init[i] = NULL_RTX;
- }
- }
-
- if (dump_file)
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_equiv_init[i])
- {
- fprintf (dump_file, "init_insns for %u: ", i);
- print_inline_rtx (dump_file, reg_equiv_init[i], 20);
- fprintf (dump_file, "\n");
- }
-
init_elim_table ();
first_label_num = get_first_label_num ();
@@ -893,22 +778,16 @@ reload (rtx first, int global)
offsets_known_at = XNEWVEC (char, num_labels);
offsets_at = (HOST_WIDE_INT (*)[NUM_ELIMINABLE_REGS]) xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT));
- /* Alter each pseudo-reg rtx to contain its hard reg number. Assign
- stack slots to the pseudos that lack hard regs or equivalents.
- Do not touch virtual registers. */
-
+ /* Other hunks of code still use this array. Ugh. */
temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1);
- for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
- temp_pseudo_reg_arr[n++] = i;
-
- if (ira_conflicts_p)
- /* Ask IRA to order pseudo-registers for better stack slot
- sharing. */
- ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_width);
- for (i = 0; i < n; i++)
- alter_reg (temp_pseudo_reg_arr[i], -1, false);
+ /* ira-reload may have created new pseudos which didn't get hard registers
+ or stack slots. Assign them stack slots now. Also alter each pseudo
+ to contain its hard reg number. */
+ for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
+ alter_reg (i, -1, false);
+
/* 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
@@ -1450,6 +1329,130 @@ reload (rtx first, int global)
return failure;
}
+/* Find all the pseudo registers that didn't get hard regs
+ but do have known equivalent constants or memory slots.
+ These include parameters (known equivalent to parameter slots)
+ and cse'd or loop-moved constant memory addresses.
+
+ Record constant equivalents in reg_equiv_constant
+ so they will be substituted by find_reloads.
+ Record memory equivalents in reg_mem_equiv so they can
+ be substituted eventually by altering the REG-rtx's. */
+
+void
+record_equivalences_for_reload (void)
+{
+ rtx insn, first;
+ int i;
+ int max_regno = max_reg_num ();
+
+ first = get_insns ();
+ reg_equiv_constant = XCNEWVEC (rtx, max_regno);
+ reg_equiv_invariant = XCNEWVEC (rtx, max_regno);
+ reg_equiv_mem = XCNEWVEC (rtx, max_regno);
+ reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno);
+ reg_equiv_address = XCNEWVEC (rtx, max_regno);
+ reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
+
+ /* Look for REG_EQUIV notes; record what each pseudo is equivalent
+ to. Also find all paradoxical subregs and find largest such for
+ each pseudo. */
+
+ num_eliminable_invariants = 0;
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ rtx set = single_set (insn);
+
+ /* We may introduce USEs that we want to remove at the end, so
+ we'll mark them with QImode. Make sure there are no
+ previously-marked insns left by say regmove. */
+ if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE
+ && GET_MODE (insn) != VOIDmode)
+ PUT_MODE (insn, VOIDmode);
+
+ if (NONDEBUG_INSN_P (insn))
+ scan_paradoxical_subregs (PATTERN (insn));
+
+ if (set != 0 && REG_P (SET_DEST (set)))
+ {
+ rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
+ rtx x;
+
+ if (! note)
+ continue;
+
+ i = REGNO (SET_DEST (set));
+ x = XEXP (note, 0);
+
+ if (i <= LAST_VIRTUAL_REGISTER)
+ continue;
+
+ if (! function_invariant_p (x)
+ || ! flag_pic
+ /* A function invariant is often CONSTANT_P but may
+ include a register. We promise to only pass
+ CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
+ || (CONSTANT_P (x)
+ && LEGITIMATE_PIC_OPERAND_P (x)))
+ {
+ /* It can happen that a REG_EQUIV note contains a MEM
+ that is not a legitimate memory operand. As later
+ stages of reload assume that all addresses found
+ in the reg_equiv_* arrays were originally legitimate,
+ we ignore such REG_EQUIV notes. */
+ if (memory_operand (x, VOIDmode))
+ {
+ /* Always unshare the equivalence, so we can
+ substitute into this insn without touching the
+ equivalence. */
+ reg_equiv_memory_loc[i] = copy_rtx (x);
+ }
+ else if (function_invariant_p (x))
+ {
+ if (GET_CODE (x) == PLUS)
+ {
+ /* This is PLUS of frame pointer and a constant,
+ and might be shared. Unshare it. */
+ reg_equiv_invariant[i] = copy_rtx (x);
+ num_eliminable_invariants++;
+ }
+ else if (x == frame_pointer_rtx || x == arg_pointer_rtx)
+ {
+ reg_equiv_invariant[i] = x;
+ num_eliminable_invariants++;
+ }
+ else if (LEGITIMATE_CONSTANT_P (x))
+ reg_equiv_constant[i] = x;
+ else
+ {
+ reg_equiv_memory_loc[i]
+ = force_const_mem (GET_MODE (SET_DEST (set)), x);
+ if (! reg_equiv_memory_loc[i])
+ reg_equiv_init[i] = NULL_RTX;
+ }
+ }
+ else
+ {
+ reg_equiv_init[i] = NULL_RTX;
+ continue;
+ }
+ }
+ else
+ reg_equiv_init[i] = NULL_RTX;
+ }
+ }
+
+ if (dump_file)
+ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ if (reg_equiv_init[i])
+ {
+ fprintf (dump_file, "init_insns for %u: ", i);
+ print_inline_rtx (dump_file, reg_equiv_init[i], 20);
+ fprintf (dump_file, "\n");
+ }
+}
+
+
/* Yet another special case. Unfortunately, reg-stack forces people to
write incorrect clobbers in asm statements. These clobbers must not
cause the register to appear in bad_spill_regs, otherwise we'll call
@@ -2170,7 +2173,7 @@ delete_dead_insn (rtx insn)
This is used so that all pseudos spilled from a given hard reg
can share one stack slot. */
-static void
+void
alter_reg (int i, int from_reg, bool dont_share_p)
{
/* When outputting an inline function, this can happen
@@ -4000,7 +4003,8 @@ finish_spills (int global)
indicate which hard regs can't be used, and call
ira_reassign_pseudos. */
for (n = 0, i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++)
- if (reg_old_renumber[i] != reg_renumber[i])
+ if ((reg_renumber[i] == -1 && REG_N_REFS(i) != 0)
+ || reg_old_renumber[i] != reg_renumber[i])
{
if (reg_renumber[i] < 0)
temp_pseudo_reg_arr[n++] = i;
@@ -5761,7 +5765,7 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r,
reloads A and B can share regs. These need two regs.
Suppose A and B are given different regs.
That leaves none for C. */
- for (pass = 0; pass < 2; pass++)
+ for (pass = 0; pass < 3; pass++)
{
/* I is the index in spill_regs.
We advance it round-robin between insns to use all spill regs
@@ -5801,6 +5805,11 @@ allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r,
regnum))))
{
int nr = hard_regno_nregs[regnum][rld[r].mode];
+
+ if (pass == 1
+ && ira_bad_reload_regno (regnum, rld[r].in, rld[r].out))
+ continue;
+
/* Avoid the problem where spilling a GENERAL_OR_FP_REG
(on 68000) got us two FP regs. If NR is 1,
we would reject both of them. */