/* Assign reload pseudos.
- Copyright (C) 2010-2014 Free Software Foundation, Inc.
+ Copyright (C) 2010-2015 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
#include "recog.h"
#include "output.h"
#include "regs.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "vec.h"
+#include "machmode.h"
+#include "input.h"
#include "function.h"
+#include "symtab.h"
+#include "flags.h"
+#include "statistics.h"
+#include "double-int.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
#include "basic-block.h"
#include "except.h"
#include "df.h"
#include "params.h"
#include "lra-int.h"
+/* Current iteration number of the pass and current iteration number
+ of the pass after the latest spill pass when any former reload
+ pseudo was spilled. */
+int lra_assignment_iter;
+int lra_assignment_iter_after_spill;
+
+/* Flag of spilling former reload pseudos on this pass. */
+static bool former_reload_pseudo_spill_p;
+
/* Array containing corresponding values of function
lra_get_allocno_class. It is used to speed up the code. */
static enum reg_class *regno_allocno_class_array;
pseudos in complicated situations where pseudo sizes are different.
If TRY_ONLY_HARD_REGNO >= 0, consider only that hard register,
- otherwise consider all hard registers in REGNO's class. */
+ otherwise consider all hard registers in REGNO's class.
+
+ If REGNO_SET is not empty, only hard registers from the set are
+ considered. */
static int
-find_hard_regno_for (int regno, int *cost, int try_only_hard_regno,
- bool first_p)
+find_hard_regno_for_1 (int regno, int *cost, int try_only_hard_regno,
+ bool first_p, HARD_REG_SET regno_set)
{
HARD_REG_SET conflict_set;
int best_cost = INT_MAX, best_priority = INT_MIN, best_usage = INT_MAX;
lra_live_range_t r;
int p, i, j, rclass_size, best_hard_regno, priority, hard_regno;
int hr, conflict_hr, nregs;
- enum machine_mode biggest_mode;
+ machine_mode biggest_mode;
unsigned int k, conflict_regno;
int offset, val, biggest_nregs, nregs_diff;
enum reg_class rclass;
bool *rclass_intersect_p;
HARD_REG_SET impossible_start_hard_regs, available_regs;
- COPY_HARD_REG_SET (conflict_set, lra_no_alloc_regs);
+ if (hard_reg_set_empty_p (regno_set))
+ COPY_HARD_REG_SET (conflict_set, lra_no_alloc_regs);
+ else
+ {
+ COMPL_HARD_REG_SET (conflict_set, regno_set);
+ IOR_HARD_REG_SET (conflict_set, lra_no_alloc_regs);
+ }
rclass = regno_allocno_class_array[regno];
rclass_intersect_p = ira_reg_classes_intersect_p[rclass];
curr_hard_regno_costs_check++;
return best_hard_regno;
}
+/* A wrapper for find_hard_regno_for_1 (see comments for that function
+ description). This function tries to find a hard register for
+ preferred class first if it is worth. */
+static int
+find_hard_regno_for (int regno, int *cost, int try_only_hard_regno, bool first_p)
+{
+ int hard_regno;
+ HARD_REG_SET regno_set;
+
+ /* Only original pseudos can have a different preferred class. */
+ if (try_only_hard_regno < 0 && regno < lra_new_regno_start)
+ {
+ enum reg_class pref_class = reg_preferred_class (regno);
+
+ if (regno_allocno_class_array[regno] != pref_class)
+ {
+ hard_regno = find_hard_regno_for_1 (regno, cost, -1, first_p,
+ reg_class_contents[pref_class]);
+ if (hard_regno >= 0)
+ return hard_regno;
+ }
+ }
+ CLEAR_HARD_REG_SET (regno_set);
+ return find_hard_regno_for_1 (regno, cost, try_only_hard_regno, first_p,
+ regno_set);
+}
+
/* Current value used for checking elements in
update_hard_regno_preference_check. */
static int curr_update_hard_regno_preference_check;
setup_try_hard_regno_pseudos (int p, enum reg_class rclass)
{
int i, hard_regno;
- enum machine_mode mode;
+ machine_mode mode;
unsigned int spill_regno;
bitmap_iterator bi;
{
int i, j, n, p, hard_regno, best_hard_regno, cost, best_cost, rclass_size;
int reload_hard_regno, reload_cost;
- enum machine_mode mode;
+ machine_mode mode;
enum reg_class rclass;
unsigned int spill_regno, reload_regno, uid;
int insn_pseudos_num, best_insn_pseudos_num;
+ int bad_spills_num, smallest_bad_spills_num;
lra_live_range_t r;
bitmap_iterator bi;
best_hard_regno = -1;
best_cost = INT_MAX;
best_insn_pseudos_num = INT_MAX;
+ smallest_bad_spills_num = INT_MAX;
rclass_size = ira_class_hard_regs_num[rclass];
mode = PSEUDO_REGNO_MODE (regno);
/* Invalidate try_hard_reg_pseudos elements. */
}
/* Spill pseudos. */
EXECUTE_IF_SET_IN_BITMAP (&spill_pseudos_bitmap, 0, spill_regno, bi)
- if ((int) spill_regno >= lra_constraint_new_regno_start
- && ! bitmap_bit_p (&lra_inheritance_pseudos, spill_regno)
- && ! bitmap_bit_p (&lra_split_regs, spill_regno)
- && ! bitmap_bit_p (&lra_subreg_reload_pseudos, spill_regno)
- && ! bitmap_bit_p (&lra_optional_reload_pseudos, spill_regno))
+ if ((pic_offset_table_rtx != NULL
+ && spill_regno == REGNO (pic_offset_table_rtx))
+ || ((int) spill_regno >= lra_constraint_new_regno_start
+ && ! bitmap_bit_p (&lra_inheritance_pseudos, spill_regno)
+ && ! bitmap_bit_p (&lra_split_regs, spill_regno)
+ && ! bitmap_bit_p (&lra_subreg_reload_pseudos, spill_regno)
+ && ! bitmap_bit_p (&lra_optional_reload_pseudos, spill_regno)))
goto fail;
insn_pseudos_num = 0;
+ bad_spills_num = 0;
if (lra_dump_file != NULL)
fprintf (lra_dump_file, " Trying %d:", hard_regno);
sparseset_clear (live_range_reload_inheritance_pseudos);
{
if (bitmap_bit_p (&insn_conflict_pseudos, spill_regno))
insn_pseudos_num++;
+ if (spill_regno >= (unsigned int) lra_bad_spill_regno_start)
+ bad_spills_num++;
for (r = lra_reg_info[spill_regno].live_ranges;
r != NULL;
r = r->next)
}
EXECUTE_IF_SET_IN_BITMAP (&spill_pseudos_bitmap, 0, spill_regno, bi)
{
- rtx x;
+ rtx_insn_list *x;
cost += lra_reg_info[spill_regno].freq;
if (ira_reg_equiv[spill_regno].memory != NULL
|| ira_reg_equiv[spill_regno].constant != NULL)
for (x = ira_reg_equiv[spill_regno].init_insns;
x != NULL;
- x = XEXP (x, 1))
- cost -= REG_FREQ_FROM_BB (BLOCK_FOR_INSN (XEXP (x, 0)));
+ x = x->next ())
+ cost -= REG_FREQ_FROM_BB (BLOCK_FOR_INSN (x->insn ()));
}
if (best_insn_pseudos_num > insn_pseudos_num
|| (best_insn_pseudos_num == insn_pseudos_num
- && best_cost > cost))
+ && (bad_spills_num < smallest_bad_spills_num
+ || (bad_spills_num == smallest_bad_spills_num
+ && best_cost > cost))))
{
best_insn_pseudos_num = insn_pseudos_num;
+ smallest_bad_spills_num = bad_spills_num;
best_cost = cost;
best_hard_regno = hard_regno;
bitmap_copy (&best_spill_pseudos_bitmap, &spill_pseudos_bitmap);
if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " Now best %d(cost=%d)\n",
- hard_regno, cost);
+ fprintf (lra_dump_file,
+ " Now best %d(cost=%d, bad_spills=%d, insn_pseudos=%d)\n",
+ hard_regno, cost, bad_spills_num, insn_pseudos_num);
}
assign_temporarily (regno, -1);
for (j = 0; j < n; j++)
/* Spill: */
EXECUTE_IF_SET_IN_BITMAP (&best_spill_pseudos_bitmap, 0, spill_regno, bi)
{
+ if ((int) spill_regno >= lra_constraint_new_regno_start)
+ former_reload_pseudo_spill_p = true;
if (lra_dump_file != NULL)
fprintf (lra_dump_file, " Spill %sr%d(hr=%d, freq=%d) for r%d\n",
pseudo_prefix_title (spill_regno),
unsigned int k, conflict_regno;
int val, offset;
HARD_REG_SET conflict_set;
- enum machine_mode mode;
+ machine_mode mode;
lra_live_range_t r;
bitmap_iterator bi;
int max_regno = max_reg_num ();
return;
}
for (n = 0, i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_renumber[i] >= 0 && lra_reg_info[i].nrefs > 0)
+ if ((pic_offset_table_rtx == NULL_RTX
+ || i != (int) REGNO (pic_offset_table_rtx))
+ && reg_renumber[i] >= 0 && lra_reg_info[i].nrefs > 0)
sorted_pseudos[n++] = i;
qsort (sorted_pseudos, n, sizeof (int), pseudo_compare_func);
+ if (pic_offset_table_rtx != NULL_RTX
+ && (regno = REGNO (pic_offset_table_rtx)) >= FIRST_PSEUDO_REGISTER
+ && reg_renumber[regno] >= 0 && lra_reg_info[regno].nrefs > 0)
+ sorted_pseudos[n++] = regno;
for (i = n - 1; i >= 0; i--)
{
regno = sorted_pseudos[i];
j++)
lra_hard_reg_usage[hard_regno + j] -= lra_reg_info[regno].freq;
reg_renumber[regno] = -1;
+ if (regno >= lra_constraint_new_regno_start)
+ former_reload_pseudo_spill_p = true;
if (lra_dump_file != NULL)
fprintf (lra_dump_file, " Spill r%d after risky transformations\n",
regno);
assign_by_spills (void)
{
int i, n, nfails, iter, regno, hard_regno, cost, restore_regno;
- rtx insn;
+ rtx_insn *insn;
bitmap_head changed_insns, do_not_assign_nonreload_pseudos;
unsigned int u, conflict_regno;
bitmap_iterator bi;
break;
if (iter > 0)
{
- /* We did not assign hard regs to reload pseudos after two
- iteration. It means something is wrong with asm insn
- constraints. Report it. */
+ /* We did not assign hard regs to reload pseudos after two iterations.
+ Either it's an asm and something is wrong with the constraints, or
+ we have run out of spill registers; error out in either case. */
bool asm_p = false;
bitmap_head failed_reload_insns;
bitmap_ior_into (&failed_reload_insns,
&lra_reg_info[regno].insn_bitmap);
/* Assign an arbitrary hard register of regno class to
- avoid further trouble with the asm insns. */
+ avoid further trouble with this insn. */
bitmap_clear_bit (&all_spilled_pseudos, regno);
assign_hard_regno
(ira_class_hard_regs[regno_allocno_class_array[regno]][0],
lra_set_insn_deleted (insn);
}
}
+ else if (!asm_p)
+ {
+ error ("unable to find a register to spill");
+ fatal_insn ("this is the insn:", insn);
+ }
}
- lra_assert (asm_p);
break;
}
/* This is a very rare event. We can not assign a hard register
EXECUTE_IF_SET_IN_SPARSESET (live_range_hard_reg_pseudos, conflict_regno)
{
if ((int) conflict_regno >= lra_constraint_new_regno_start)
- sorted_pseudos[nfails++] = conflict_regno;
+ {
+ sorted_pseudos[nfails++] = conflict_regno;
+ former_reload_pseudo_spill_p = true;
+ }
if (lra_dump_file != NULL)
fprintf (lra_dump_file, " Spill %s r%d(hr=%d, freq=%d)\n",
pseudo_prefix_title (conflict_regno), conflict_regno,
alternatives of insns containing the pseudo. */
bitmap_set_bit (&changed_pseudo_bitmap, regno);
}
+ else
+ {
+ enum reg_class rclass = lra_get_allocno_class (regno);
+ enum reg_class spill_class;
+
+ if (targetm.spill_class == NULL
+ || lra_reg_info[regno].restore_regno < 0
+ || ! bitmap_bit_p (&lra_inheritance_pseudos, regno)
+ || (spill_class
+ = ((enum reg_class)
+ targetm.spill_class
+ ((reg_class_t) rclass,
+ PSEUDO_REGNO_MODE (regno)))) == NO_REGS)
+ continue;
+ regno_allocno_class_array[regno] = spill_class;
+ hard_regno = find_hard_regno_for (regno, &cost, -1, false);
+ if (hard_regno < 0)
+ regno_allocno_class_array[regno] = rclass;
+ else
+ {
+ setup_reg_classes
+ (regno, spill_class, spill_class, spill_class);
+ assign_hard_regno (hard_regno, regno);
+ bitmap_set_bit (&changed_pseudo_bitmap, regno);
+ }
+ }
}
}
free (update_hard_regno_preference_check);
int max_regno = max_reg_num ();
timevar_push (TV_LRA_ASSIGN);
+ lra_assignment_iter++;
+ if (lra_dump_file != NULL)
+ fprintf (lra_dump_file, "\n********** Assignment #%d: **********\n\n",
+ lra_assignment_iter);
init_lives ();
sorted_pseudos = XNEWVEC (int, max_regno);
sorted_reload_pseudos = XNEWVEC (int, max_regno);
regno_allocno_class_array = XNEWVEC (enum reg_class, max_regno);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
regno_allocno_class_array[i] = lra_get_allocno_class (i);
+ former_reload_pseudo_spill_p = false;
init_regno_assign_info ();
bitmap_initialize (&all_spilled_pseudos, ®_obstack);
create_live_range_start_chains ();
setup_live_pseudos_and_spill_after_risky_transforms (&all_spilled_pseudos);
#ifdef ENABLE_CHECKING
- if (!flag_use_caller_save)
+ if (!flag_ipa_ra)
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
if (lra_reg_info[i].nrefs != 0 && reg_renumber[i] >= 0
&& lra_reg_info[i].call_p
free (sorted_reload_pseudos);
finish_lives ();
timevar_pop (TV_LRA_ASSIGN);
+ if (former_reload_pseudo_spill_p)
+ lra_assignment_iter_after_spill++;
+ if (lra_assignment_iter_after_spill > LRA_MAX_ASSIGNMENT_ITERATION_NUMBER)
+ internal_error
+ ("Maximum number of LRA assignment passes is achieved (%d)\n",
+ LRA_MAX_ASSIGNMENT_ITERATION_NUMBER);
return no_spills_p;
}