diff options
-rw-r--r-- | gcc/ChangeLog-ira-reload | 128 | ||||
-rw-r--r-- | gcc/Makefile.in | 7 | ||||
-rw-r--r-- | gcc/NOTES | 47 | ||||
-rw-r--r-- | gcc/ira-build.c | 47 | ||||
-rw-r--r-- | gcc/ira-color.c | 4 | ||||
-rw-r--r-- | gcc/ira-conflicts.c | 104 | ||||
-rw-r--r-- | gcc/ira-costs.c | 27 | ||||
-rw-r--r-- | gcc/ira-int.h | 10 | ||||
-rw-r--r-- | gcc/ira-reload.c | 982 | ||||
-rw-r--r-- | gcc/ira.c | 19 | ||||
-rw-r--r-- | gcc/ira.h | 1 | ||||
-rw-r--r-- | gcc/regs.h | 1 | ||||
-rw-r--r-- | gcc/regstat.c | 10 | ||||
-rw-r--r-- | gcc/reload.h | 8 | ||||
-rw-r--r-- | gcc/reload1.c | 273 |
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 (®_equiv_invariant[orig_max_reg_num], 0, nregs * sizeof (rtx)); + reg_equiv_constant = (rtx *) xrealloc (reg_equiv_constant, + max_regno * sizeof (rtx)); + memset (®_equiv_constant[orig_max_reg_num], 0, nregs * sizeof (rtx)); + reg_equiv_mem = (rtx *) xrealloc (reg_equiv_mem, max_regno * sizeof (rtx)); + memset (®_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 (®_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 (®_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 (®_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 (®stat_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 (®_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 (®_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. */ |