===================================================================
@@ -795,11 +795,6 @@ struct target_ira_int {
/* Map class->true if class is a pressure class, false otherwise. */
bool x_ira_reg_pressure_class_p[N_REG_CLASSES];
- /* Register class subset relation: TRUE if the first class is a subset
- of the second one considering only hard registers available for the
- allocation. */
- int x_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 hard
register numbers. */
@@ -838,13 +833,8 @@ struct target_ira_int {
taking all hard-registers including fixed ones into account. */
enum reg_class x_ira_reg_class_intersect[N_REG_CLASSES][N_REG_CLASSES];
- /* True if the two classes (that is calculated taking only hard
- registers available for allocation into account; are
- intersected. */
- bool x_ira_reg_classes_intersect_p[N_REG_CLASSES][N_REG_CLASSES];
-
/* Classes with end marker LIM_REG_CLASSES which are intersected with
- given class (the first index;. That includes given class itself.
+ given class (the first index). That includes given class itself.
This is calculated taking only hard registers available for
allocation into account. */
enum reg_class x_ira_reg_class_super_classes[N_REG_CLASSES][N_REG_CLASSES];
@@ -861,7 +851,7 @@ struct target_ira_int {
/* For each reg class, table listing all the classes contained in it
(excluding the class itself. Non-allocatable registers are
- excluded from the consideration;. */
+ excluded from the consideration). */
enum reg_class x_alloc_reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES];
/* Array whose values are hard regset of hard registers for which
@@ -894,8 +884,6 @@ extern struct target_ira_int *this_targe
(this_target_ira_int->x_ira_reg_allocno_class_p)
#define ira_reg_pressure_class_p \
(this_target_ira_int->x_ira_reg_pressure_class_p)
-#define ira_class_subset_p \
- (this_target_ira_int->x_ira_class_subset_p)
#define ira_non_ordered_class_hard_regs \
(this_target_ira_int->x_ira_non_ordered_class_hard_regs)
#define ira_class_hard_reg_index \
@@ -912,8 +900,6 @@ extern struct target_ira_int *this_targe
(this_target_ira_int->x_ira_uniform_class_p)
#define ira_reg_class_intersect \
(this_target_ira_int->x_ira_reg_class_intersect)
-#define ira_reg_classes_intersect_p \
- (this_target_ira_int->x_ira_reg_classes_intersect_p)
#define ira_reg_class_super_classes \
(this_target_ira_int->x_ira_reg_class_super_classes)
#define ira_reg_class_subunion \
@@ -934,17 +920,6 @@ extern void ira_debug_disposition (void)
extern void ira_debug_allocno_classes (void);
extern void ira_init_register_move_cost (enum machine_mode);
-/* The length of the two following arrays. */
-extern int ira_reg_equiv_len;
-
-/* The element value is TRUE if the corresponding regno value is
- invariant. */
-extern bool *ira_reg_equiv_invariant_p;
-
-/* The element value is equiv constant of given pseudo-register or
- NULL_RTX. */
-extern rtx *ira_reg_equiv_const;
-
/* ira-build.c */
/* The current loop tree node and its regno allocno map. */
@@ -1028,6 +1003,20 @@ extern void ira_emit (bool);
+/* Return true if equivalence of pseudo REGNO is not a lvalue. */
+static inline bool
+ira_equiv_no_lvalue_p (int regno)
+{
+ if (regno >= ira_reg_equiv_len)
+ return false;
+ return (ira_reg_equiv[regno].constant != NULL_RTX
+ || ira_reg_equiv[regno].invariant != NULL_RTX
+ || (ira_reg_equiv[regno].memory != NULL_RTX
+ && MEM_READONLY_P (ira_reg_equiv[regno].memory)));
+}
+
+
+
/* Initialize register costs for MODE if necessary. */
static inline void
ira_init_register_move_cost_if_necessary (enum machine_mode mode)
===================================================================
@@ -1201,6 +1201,7 @@ setup_reg_class_relations (void)
{
ira_reg_classes_intersect_p[cl1][cl2] = false;
ira_reg_class_intersect[cl1][cl2] = NO_REGS;
+ ira_reg_class_subset[cl1][cl2] = NO_REGS;
COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl1]);
AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
COPY_HARD_REG_SET (temp_set2, reg_class_contents[cl2]);
@@ -1248,9 +1249,8 @@ setup_reg_class_relations (void)
COPY_HARD_REG_SET (union_set, reg_class_contents[cl1]);
IOR_HARD_REG_SET (union_set, reg_class_contents[cl2]);
AND_COMPL_HARD_REG_SET (union_set, no_unit_alloc_regs);
- for (i = 0; i < ira_important_classes_num; i++)
+ for (cl3 = 0; cl3 < N_REG_CLASSES; cl3++)
{
- cl3 = ira_important_classes[i];
COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl3]);
AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
if (hard_reg_set_subset_p (temp_hard_regset, intersection_set))
@@ -1258,25 +1258,45 @@ setup_reg_class_relations (void)
/* CL3 allocatable hard register set is inside of
intersection of allocatable hard register sets
of CL1 and CL2. */
+ if (important_class_p[cl3])
+ {
+ COPY_HARD_REG_SET
+ (temp_set2,
+ reg_class_contents
+ [(int) ira_reg_class_intersect[cl1][cl2]]);
+ AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs);
+ if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2)
+ /* If the allocatable hard register sets are
+ the same, prefer GENERAL_REGS or the
+ smallest class for debugging
+ purposes. */
+ || (hard_reg_set_equal_p (temp_hard_regset, temp_set2)
+ && (cl3 == GENERAL_REGS
+ || ((ira_reg_class_intersect[cl1][cl2]
+ != GENERAL_REGS)
+ && hard_reg_set_subset_p
+ (reg_class_contents[cl3],
+ reg_class_contents
+ [(int)
+ ira_reg_class_intersect[cl1][cl2]])))))
+ ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3;
+ }
COPY_HARD_REG_SET
(temp_set2,
- reg_class_contents[(int)
- ira_reg_class_intersect[cl1][cl2]]);
+ reg_class_contents[(int) ira_reg_class_subset[cl1][cl2]]);
AND_COMPL_HARD_REG_SET (temp_set2, no_unit_alloc_regs);
- if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2)
- /* If the allocatable hard register sets are the
- same, prefer GENERAL_REGS or the smallest
- class for debugging purposes. */
+ if (! hard_reg_set_subset_p (temp_hard_regset, temp_set2)
+ /* Ignore unavailable hard registers and prefer
+ smallest class for debugging purposes. */
|| (hard_reg_set_equal_p (temp_hard_regset, temp_set2)
- && (cl3 == GENERAL_REGS
- || (ira_reg_class_intersect[cl1][cl2] != GENERAL_REGS
- && hard_reg_set_subset_p
- (reg_class_contents[cl3],
- reg_class_contents
- [(int) ira_reg_class_intersect[cl1][cl2]])))))
- ira_reg_class_intersect[cl1][cl2] = (enum reg_class) cl3;
+ && hard_reg_set_subset_p
+ (reg_class_contents[cl3],
+ reg_class_contents
+ [(int) ira_reg_class_subset[cl1][cl2]])))
+ ira_reg_class_subset[cl1][cl2] = (enum reg_class) cl3;
}
- if (hard_reg_set_subset_p (temp_hard_regset, union_set))
+ if (important_class_p[cl3]
+ && hard_reg_set_subset_p (temp_hard_regset, union_set))
{
/* CL3 allocatbale hard register set is inside of
union of allocatable hard register sets of CL1
@@ -1885,66 +1905,6 @@ ira_setup_eliminable_regset (void)
-/* The length of the following two arrays. */
-int ira_reg_equiv_len;
-
-/* The element value is TRUE if the corresponding regno value is
- invariant. */
-bool *ira_reg_equiv_invariant_p;
-
-/* The element value is equiv constant of given pseudo-register or
- NULL_RTX. */
-rtx *ira_reg_equiv_const;
-
-/* Set up the two arrays declared above. */
-static void
-find_reg_equiv_invariant_const (void)
-{
- unsigned int i;
- bool invariant_p;
- rtx list, insn, note, constant, x;
-
- for (i = FIRST_PSEUDO_REGISTER; i < VEC_length (reg_equivs_t, reg_equivs); i++)
- {
- constant = NULL_RTX;
- invariant_p = false;
- for (list = reg_equiv_init (i); list != NULL_RTX; list = XEXP (list, 1))
- {
- insn = XEXP (list, 0);
- note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
-
- if (note == NULL_RTX)
- continue;
-
- x = XEXP (note, 0);
-
- if (! CONSTANT_P (x)
- || ! flag_pic || 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 the 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))
- invariant_p = MEM_READONLY_P (x);
- else if (function_invariant_p (x))
- {
- if (GET_CODE (x) == PLUS
- || x == frame_pointer_rtx || x == arg_pointer_rtx)
- invariant_p = true;
- else
- constant = x;
- }
- }
- }
- ira_reg_equiv_invariant_p[i] = invariant_p;
- ira_reg_equiv_const[i] = constant;
- }
-}
-
-
-
/* Vector of substitutions of register numbers,
used to map pseudo regs into hardware regs.
This is set up as a result of register allocation.
@@ -1965,6 +1925,8 @@ setup_reg_renumber (void)
caller_save_needed = 0;
FOR_EACH_ALLOCNO (a, ai)
{
+ if (ira_use_lra_p && ALLOCNO_CAP_MEMBER (a) != NULL)
+ continue;
/* There are no caps at this point. */
ira_assert (ALLOCNO_CAP_MEMBER (a) == NULL);
if (! ALLOCNO_ASSIGNED_P (a))
@@ -1996,9 +1958,7 @@ setup_reg_renumber (void)
ira_assert (!optimize || flag_caller_saves
|| (ALLOCNO_CALLS_CROSSED_NUM (a)
== ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a))
- || regno >= ira_reg_equiv_len
- || ira_reg_equiv_const[regno]
- || ira_reg_equiv_invariant_p[regno]);
+ || ira_equiv_no_lvalue_p (regno));
caller_save_needed = 1;
}
}
@@ -2165,6 +2125,109 @@ check_allocation (void)
}
#endif
+/* Allocate REG_EQUIV_INIT. Set up it from IRA_REG_EQUIV which should
+ be already calculated. */
+static void
+setup_reg_equiv_init (void)
+{
+ int i;
+ int max_regno = max_reg_num ();
+
+ for (i = 0; i < max_regno; i++)
+ reg_equiv_init (i) = ira_reg_equiv[i].init_insns;
+}
+
+/* Update equiv regno from movement of FROM_REGNO to TO_REGNO. INSNS
+ are insns which were generated for such movement. It is assumed
+ that FROM_REGNO and TO_REGNO always have the same value at the
+ point of any move containing such registers. This function is used
+ to update equiv info for register shuffles on the region borders
+ and for caller save/restore insns. */
+void
+ira_update_equiv_info_by_shuffle_insn (int to_regno, int from_regno, rtx insns)
+{
+ rtx insn, x, note;
+
+ if (! ira_reg_equiv[from_regno].defined_p
+ && (! ira_reg_equiv[to_regno].defined_p
+ || ((x = ira_reg_equiv[to_regno].memory) != NULL_RTX
+ && ! MEM_READONLY_P (x))))
+ return;
+ insn = insns;
+ if (NEXT_INSN (insn) != NULL_RTX)
+ {
+ if (! ira_reg_equiv[to_regno].defined_p)
+ {
+ ira_assert (ira_reg_equiv[to_regno].init_insns == NULL_RTX);
+ return;
+ }
+ ira_reg_equiv[to_regno].defined_p = false;
+ ira_reg_equiv[to_regno].memory
+ = ira_reg_equiv[to_regno].constant
+ = ira_reg_equiv[to_regno].invariant
+ = ira_reg_equiv[to_regno].init_insns = NULL_RTX;
+ if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+ fprintf (ira_dump_file,
+ " Invalidating equiv info for reg %d\n", to_regno);
+ return;
+ }
+ /* It is possible that FROM_REGNO still has no equivalence because
+ in shuffles to_regno<-from_regno and from_regno<-to_regno the 2nd
+ insn was not processed yet. */
+ if (ira_reg_equiv[from_regno].defined_p)
+ {
+ ira_reg_equiv[to_regno].defined_p = true;
+ if ((x = ira_reg_equiv[from_regno].memory) != NULL_RTX)
+ {
+ ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX
+ && ira_reg_equiv[from_regno].constant == NULL_RTX);
+ ira_assert (ira_reg_equiv[to_regno].memory == NULL_RTX
+ || rtx_equal_p (ira_reg_equiv[to_regno].memory, x));
+ ira_reg_equiv[to_regno].memory = x;
+ if (! MEM_READONLY_P (x))
+ /* We don't add the insn to insn init list because memory
+ equivalence is just to say what memory is better to use
+ when the pseudo is spilled. */
+ return;
+ }
+ else if ((x = ira_reg_equiv[from_regno].constant) != NULL_RTX)
+ {
+ ira_assert (ira_reg_equiv[from_regno].invariant == NULL_RTX);
+ ira_assert (ira_reg_equiv[to_regno].constant == NULL_RTX
+ || rtx_equal_p (ira_reg_equiv[to_regno].constant, x));
+ ira_reg_equiv[to_regno].constant = x;
+ }
+ else
+ {
+ x = ira_reg_equiv[from_regno].invariant;
+ ira_assert (x != NULL_RTX);
+ ira_assert (ira_reg_equiv[to_regno].invariant == NULL_RTX
+ || rtx_equal_p (ira_reg_equiv[to_regno].invariant, x));
+ ira_reg_equiv[to_regno].invariant = x;
+ }
+ if (find_reg_note (insn, REG_EQUIV, x) == NULL_RTX)
+ {
+ note = set_unique_reg_note (insn, REG_EQUIV, x);
+ gcc_assert (note != NULL_RTX);
+ if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+ {
+ fprintf (ira_dump_file,
+ " Adding equiv note to insn %u for reg %d ",
+ INSN_UID (insn), to_regno);
+ print_value_slim (ira_dump_file, x, 1);
+ fprintf (ira_dump_file, "\n");
+ }
+ }
+ }
+ ira_reg_equiv[to_regno].init_insns
+ = gen_rtx_INSN_LIST (VOIDmode, insn,
+ ira_reg_equiv[to_regno].init_insns);
+ if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
+ fprintf (ira_dump_file,
+ " Adding equiv init move insn %u to reg %d\n",
+ INSN_UID (insn), to_regno);
+}
+
/* Fix values of array REG_EQUIV_INIT after live range splitting done
by IRA. */
static void
@@ -2202,6 +2265,7 @@ fix_reg_equiv_init (void)
prev = x;
else
{
+ /* Remove the wrong list element. */
if (prev == NULL_RTX)
reg_equiv_init (i) = next;
else
@@ -2334,6 +2398,46 @@ mark_elimination (int from, int to)
+/* The length of the following array. */
+int ira_reg_equiv_len;
+
+/* Info about equiv. info for each register. */
+struct ira_reg_equiv *ira_reg_equiv;
+
+/* Expand ira_reg_equiv if necessary. */
+void
+ira_expand_reg_equiv (void)
+{
+ int old = ira_reg_equiv_len;
+
+ if (ira_reg_equiv_len > max_reg_num ())
+ return;
+ ira_reg_equiv_len = max_reg_num () * 3 / 2 + 1;
+ ira_reg_equiv
+ = (struct ira_reg_equiv *) xrealloc (ira_reg_equiv,
+ ira_reg_equiv_len
+ * sizeof (struct ira_reg_equiv));
+ gcc_assert (old < ira_reg_equiv_len);
+ memset (ira_reg_equiv + old, 0,
+ sizeof (struct ira_reg_equiv) * (ira_reg_equiv_len - old));
+}
+
+static void
+init_reg_equiv (void)
+{
+ ira_reg_equiv_len = 0;
+ ira_reg_equiv = NULL;
+ ira_expand_reg_equiv ();
+}
+
+static void
+finish_reg_equiv (void)
+{
+ free (ira_reg_equiv);
+}
+
+
+
struct equivalence
{
/* Set when a REG_EQUIV note is found or created. Use to
@@ -2707,7 +2811,8 @@ no_equiv (rtx reg, const_rtx store ATTRI
should keep their initialization insns. */
if (reg_equiv[regno].is_arg_equivalence)
return;
- reg_equiv_init (regno) = NULL_RTX;
+ ira_reg_equiv[regno].defined_p = false;
+ ira_reg_equiv[regno].init_insns = NULL_RTX;
for (; list; list = XEXP (list, 1))
{
rtx insn = XEXP (list, 0);
@@ -2743,7 +2848,7 @@ static int recorded_label_ref;
value into the using insn. If it succeeds, we can eliminate the
register completely.
- Initialize the REG_EQUIV_INIT array of initializing insns.
+ Initialize init_insns in ira_reg_equiv array.
Return non-zero if jump label rebuilding should be done. */
static int
@@ -2818,14 +2923,16 @@ update_equiv_regs (void)
gcc_assert (REG_P (dest));
regno = REGNO (dest);
- /* Note that we don't want to clear reg_equiv_init even if there
- are multiple sets of this register. */
+ /* Note that we don't want to clear init_insns in
+ ira_reg_equiv even if there are multiple sets of this
+ register. */
reg_equiv[regno].is_arg_equivalence = 1;
/* Record for reload that this is an equivalencing insn. */
if (rtx_equal_p (src, XEXP (note, 0)))
- reg_equiv_init (regno)
- = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init (regno));
+ ira_reg_equiv[regno].init_insns
+ = gen_rtx_INSN_LIST (VOIDmode, insn,
+ ira_reg_equiv[regno].init_insns);
/* Continue normally in case this is a candidate for
replacements. */
@@ -2925,8 +3032,9 @@ update_equiv_regs (void)
/* If we haven't done so, record for reload that this is an
equivalencing insn. */
if (!reg_equiv[regno].is_arg_equivalence)
- reg_equiv_init (regno)
- = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init (regno));
+ ira_reg_equiv[regno].init_insns
+ = gen_rtx_INSN_LIST (VOIDmode, insn,
+ ira_reg_equiv[regno].init_insns);
/* Record whether or not we created a REG_EQUIV note for a LABEL_REF.
We might end up substituting the LABEL_REF for uses of the
@@ -3026,7 +3134,7 @@ update_equiv_regs (void)
{
/* This insn makes the equivalence, not the one initializing
the register. */
- reg_equiv_init (regno)
+ ira_reg_equiv[regno].init_insns
= gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
df_notes_rescan (init_insn);
}
@@ -3080,9 +3188,10 @@ update_equiv_regs (void)
/* reg_equiv[REGNO].replace gets set only when
REG_N_REFS[REGNO] is 2, i.e. the register is set
- once and used once. (If it were only set, but not used,
- flow would have deleted the setting insns.) Hence
- there can only be one insn in reg_equiv[REGNO].init_insns. */
+ once and used once. (If it were only set, but
+ not used, flow would have deleted the setting
+ insns.) Hence there can only be one insn in
+ reg_equiv[REGNO].init_insns. */
gcc_assert (reg_equiv[regno].init_insns
&& !XEXP (reg_equiv[regno].init_insns, 1));
equiv_insn = XEXP (reg_equiv[regno].init_insns, 0);
@@ -3129,7 +3238,7 @@ update_equiv_regs (void)
reg_equiv[regno].init_insns
= XEXP (reg_equiv[regno].init_insns, 1);
- reg_equiv_init (regno) = NULL_RTX;
+ ira_reg_equiv[regno].init_insns = NULL_RTX;
bitmap_set_bit (cleared_regs, regno);
}
/* Move the initialization of the register to just before
@@ -3162,7 +3271,7 @@ update_equiv_regs (void)
if (insn == BB_HEAD (bb))
BB_HEAD (bb) = PREV_INSN (insn);
- reg_equiv_init (regno)
+ ira_reg_equiv[regno].init_insns
= gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
bitmap_set_bit (cleared_regs, regno);
}
@@ -3208,6 +3317,88 @@ update_equiv_regs (void)
+/* Set up fields memory, constant, and invariant from init_insns in
+ the structures of array ira_reg_equiv. */
+static void
+setup_reg_equiv (void)
+{
+ int i;
+ rtx elem, insn, set, x;
+
+ for (i = FIRST_PSEUDO_REGISTER; i < ira_reg_equiv_len; i++)
+ for (elem = ira_reg_equiv[i].init_insns; elem; elem = XEXP (elem, 1))
+ {
+ insn = XEXP (elem, 0);
+ set = single_set (insn);
+
+ /* Init insns can set up equivalence when the reg is a destination or
+ a source (in this case the destination is memory). */
+ if (set != 0 && (REG_P (SET_DEST (set)) || REG_P (SET_SRC (set))))
+ {
+ if ((x = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != NULL)
+ x = XEXP (x, 0);
+ else if (REG_P (SET_DEST (set))
+ && REGNO (SET_DEST (set)) == (unsigned int) i)
+ x = SET_SRC (set);
+ else
+ {
+ gcc_assert (REG_P (SET_SRC (set))
+ && REGNO (SET_SRC (set)) == (unsigned int) i);
+ x = SET_DEST (set);
+ }
+ 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 lra_regno_equiv_* arrays were originally
+ legitimate, we ignore such REG_EQUIV notes. */
+ if (memory_operand (x, VOIDmode))
+ {
+ ira_reg_equiv[i].defined_p = true;
+ ira_reg_equiv[i].memory = x;
+ continue;
+ }
+ else if (function_invariant_p (x))
+ {
+ enum machine_mode mode;
+
+ mode = GET_MODE (SET_DEST (set));
+ if (GET_CODE (x) == PLUS
+ || x == frame_pointer_rtx || x == arg_pointer_rtx)
+ /* This is PLUS of frame pointer and a constant,
+ or fp, or argp. */
+ ira_reg_equiv[i].invariant = x;
+ else if (targetm.legitimate_constant_p (mode, x))
+ ira_reg_equiv[i].constant = x;
+ else
+ {
+ ira_reg_equiv[i].memory = force_const_mem (mode, x);
+ if (ira_reg_equiv[i].memory == NULL_RTX)
+ {
+ ira_reg_equiv[i].defined_p = false;
+ ira_reg_equiv[i].init_insns = NULL_RTX;
+ break;
+ }
+ }
+ ira_reg_equiv[i].defined_p = true;
+ continue;
+ }
+ }
+ }
+ ira_reg_equiv[i].defined_p = false;
+ ira_reg_equiv[i].init_insns = NULL_RTX;
+ break;
+ }
+}
+
+
+
/* Print chain C to FILE. */
static void
print_insn_chain (FILE *file, struct insn_chain *c)
@@ -4102,6 +4293,11 @@ allocate_initial_values (void)
}
}
+
+/* True when we use LRA instead of reload pass for the current
+ function. */
+bool ira_use_lra_p;
+
/* All natural loops. */
struct loops ira_loops;
@@ -4120,6 +4316,13 @@ ira (FILE *f)
int max_regno_before_ira, ira_max_point_before_emit;
int rebuild_p;
+ ira_use_lra_p = targetm.lra_p ();
+
+#ifndef IRA_NO_OBSTACK
+ gcc_obstack_init (&ira_obstack);
+#endif
+ bitmap_obstack_initialize (&ira_bitmap_obstack);
+
if (flag_caller_saves)
init_caller_save ();
@@ -4166,30 +4369,18 @@ ira (FILE *f)
if (resize_reg_info () && flag_ira_loop_pressure)
ira_set_pseudo_classes (ira_dump_file);
+ init_reg_equiv ();
rebuild_p = update_equiv_regs ();
+ setup_reg_equiv ();
+ setup_reg_equiv_init ();
-#ifndef IRA_NO_OBSTACK
- gcc_obstack_init (&ira_obstack);
-#endif
- bitmap_obstack_initialize (&ira_bitmap_obstack);
- if (optimize)
+ if (optimize && rebuild_p)
{
- max_regno = max_reg_num ();
- ira_reg_equiv_len = max_regno;
- ira_reg_equiv_invariant_p
- = (bool *) ira_allocate (max_regno * sizeof (bool));
- memset (ira_reg_equiv_invariant_p, 0, max_regno * sizeof (bool));
- ira_reg_equiv_const = (rtx *) ira_allocate (max_regno * sizeof (rtx));
- memset (ira_reg_equiv_const, 0, max_regno * sizeof (rtx));
- find_reg_equiv_invariant_const ();
- if (rebuild_p)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- if (purge_all_dead_edges ())
- delete_unreachable_blocks ();
- timevar_pop (TV_JUMP);
- }
+ timevar_push (TV_JUMP);
+ rebuild_jump_labels (get_insns ());
+ if (purge_all_dead_edges ())
+ delete_unreachable_blocks ();
+ timevar_pop (TV_JUMP);
}
allocated_reg_info_size = max_reg_num ();
@@ -4241,19 +4432,32 @@ ira (FILE *f)
ira_emit (loops_p);
+ max_regno = max_reg_num ();
if (ira_conflicts_p)
{
- max_regno = max_reg_num ();
-
if (! loops_p)
- ira_initiate_assign ();
+ {
+ if (! ira_use_lra_p)
+ ira_initiate_assign ();
+ }
else
{
expand_reg_info ();
- if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
- fprintf (ira_dump_file, "Flattening IR\n");
- ira_flattening (max_regno_before_ira, ira_max_point_before_emit);
+ if (ira_use_lra_p)
+ {
+ ira_allocno_t a;
+ ira_allocno_iterator ai;
+
+ FOR_EACH_ALLOCNO (a, ai)
+ ALLOCNO_REGNO (a) = REGNO (ALLOCNO_EMIT_DATA (a)->reg);
+ }
+ else
+ {
+ if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
+ fprintf (ira_dump_file, "Flattening IR\n");
+ ira_flattening (max_regno_before_ira, ira_max_point_before_emit);
+ }
/* New insns were generated: add notes and recalculate live
info. */
df_analyze ();
@@ -4262,9 +4466,12 @@ ira (FILE *f)
record_loop_exits ();
current_loops = &ira_loops;
- setup_allocno_assignment_flags ();
- ira_initiate_assign ();
- ira_reassign_conflict_allocnos (max_regno);
+ if (! ira_use_lra_p)
+ {
+ setup_allocno_assignment_flags ();
+ ira_initiate_assign ();
+ ira_reassign_conflict_allocnos (max_regno);
+ }
}
}
@@ -4322,45 +4529,72 @@ do_reload (void)
if (flag_ira_verbose < 10)
ira_dump_file = dump_file;
- df_set_flags (DF_NO_INSN_RESCAN);
- build_insn_chain ();
+ timevar_push (TV_RELOAD);
+ if (ira_use_lra_p)
+ {
+ if (current_loops != NULL)
+ {
+ flow_loops_free (&ira_loops);
+ free_dominance_info (CDI_DOMINATORS);
+ }
+ FOR_ALL_BB (bb)
+ bb->loop_father = NULL;
+ current_loops = NULL;
+
+ if (ira_conflicts_p)
+ ira_free (ira_spilled_reg_stack_slots);
- need_dce = reload (get_insns (), ira_conflicts_p);
+ ira_destroy ();
+
+ VEC_free (reg_equivs_t, gc, reg_equivs);
+ reg_equivs = NULL;
+ need_dce = false;
+ }
+ else
+ {
+ df_set_flags (DF_NO_INSN_RESCAN);
+ build_insn_chain ();
+
+ need_dce = reload (get_insns (), ira_conflicts_p);
+
+ }
+
+ timevar_pop (TV_RELOAD);
timevar_push (TV_IRA);
- if (ira_conflicts_p)
+ if (ira_conflicts_p && ! ira_use_lra_p)
{
ira_free (ira_spilled_reg_stack_slots);
-
ira_finish_assign ();
}
+
if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL
&& overall_cost_before != ira_overall_cost)
fprintf (ira_dump_file, "+++Overall after reload %d\n", ira_overall_cost);
- ira_destroy ();
flag_ira_share_spill_slots = saved_flag_ira_share_spill_slots;
- if (current_loops != NULL)
+ if (! ira_use_lra_p)
{
- flow_loops_free (&ira_loops);
- free_dominance_info (CDI_DOMINATORS);
+ ira_destroy ();
+ if (current_loops != NULL)
+ {
+ flow_loops_free (&ira_loops);
+ free_dominance_info (CDI_DOMINATORS);
+ }
+ FOR_ALL_BB (bb)
+ bb->loop_father = NULL;
+ current_loops = NULL;
+
+ regstat_free_ri ();
+ regstat_free_n_sets_and_refs ();
}
- FOR_ALL_BB (bb)
- bb->loop_father = NULL;
- current_loops = NULL;
-
- regstat_free_ri ();
- regstat_free_n_sets_and_refs ();
if (optimize)
- {
- cleanup_cfg (CLEANUP_EXPENSIVE);
+ cleanup_cfg (CLEANUP_EXPENSIVE);
- ira_free (ira_reg_equiv_invariant_p);
- ira_free (ira_reg_equiv_const);
- }
+ finish_reg_equiv ();
bitmap_obstack_release (&ira_bitmap_obstack);
#ifndef IRA_NO_OBSTACK
===================================================================
@@ -20,11 +20,16 @@ You should have received a copy of the G
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* True when we use LRA instead of reload pass for the current
+ function. */
+extern bool ira_use_lra_p;
+
/* True if we have allocno conflicts. It is false for non-optimized
mode or when the conflict table is too big. */
extern bool ira_conflicts_p;
-struct target_ira {
+struct target_ira
+{
/* Map: hard register number -> allocno class it belongs to. If the
corresponding class is NO_REGS, the hard register is not available
for allocation. */
@@ -79,6 +84,23 @@ struct target_ira {
class. */
int x_ira_class_hard_regs_num[N_REG_CLASSES];
+ /* Register class subset relation: TRUE if the first class is a subset
+ of the second one considering only hard registers available for the
+ allocation. */
+ int x_ira_class_subset_p[N_REG_CLASSES][N_REG_CLASSES];
+
+ /* The biggest class inside of intersection of the two classes (that
+ is calculated taking only hard registers available for allocation
+ into account. If the both classes contain no hard registers
+ available for allocation, the value is calculated with taking all
+ hard-registers including fixed ones into account. */
+ enum reg_class x_ira_reg_class_subset[N_REG_CLASSES][N_REG_CLASSES];
+
+ /* True if the two classes (that is calculated taking only hard
+ registers available for allocation into account; are
+ intersected. */
+ bool x_ira_reg_classes_intersect_p[N_REG_CLASSES][N_REG_CLASSES];
+
/* Function specific hard registers can not be used for the register
allocation. */
HARD_REG_SET x_ira_no_alloc_regs;
@@ -117,9 +139,37 @@ extern struct target_ira *this_target_ir
(this_target_ira->x_ira_class_hard_regs)
#define ira_class_hard_regs_num \
(this_target_ira->x_ira_class_hard_regs_num)
+#define ira_class_subset_p \
+ (this_target_ira->x_ira_class_subset_p)
+#define ira_reg_class_subset \
+ (this_target_ira->x_ira_reg_class_subset)
+#define ira_reg_classes_intersect_p \
+ (this_target_ira->x_ira_reg_classes_intersect_p)
#define ira_no_alloc_regs \
(this_target_ira->x_ira_no_alloc_regs)
+/* Major structure describing equivalence info for a pseudo. */
+struct ira_reg_equiv
+{
+ /* True if we can use this equivalence. */
+ bool defined_p;
+ /* True if the usage of the equivalence is profitable. */
+ bool profitable_p;
+ /* Equiv. memory, constant, invariant, and initializing insns of
+ given pseudo-register or NULL_RTX. */
+ rtx memory;
+ rtx constant;
+ rtx invariant;
+ /* Always NULL_RTX if defined_p is false. */
+ rtx init_insns;
+};
+
+/* The length of the following array. */
+extern int ira_reg_equiv_len;
+
+/* Info about equiv. info for each register. */
+extern struct ira_reg_equiv *ira_reg_equiv;
+
extern void ira_init_once (void);
extern void ira_init (void);
extern void ira_finish_once (void);
@@ -127,6 +177,8 @@ extern void ira_setup_eliminable_regset
extern rtx ira_eliminate_regs (rtx, enum machine_mode);
extern void ira_set_pseudo_classes (FILE *);
extern void ira_implicitly_set_insn_hard_regs (HARD_REG_SET *);
+extern void ira_expand_reg_equiv (void);
+extern void ira_update_equiv_info_by_shuffle_insn (int, int, rtx);
extern void ira_sort_regnos_for_alter_reg (int *, int, unsigned int *);
extern void ira_mark_allocation_change (int);
===================================================================
@@ -2835,8 +2835,7 @@ color_pass (ira_loop_tree_node_t loop_tr
exit_freq = ira_loop_edge_freq (subloop_node, regno, true);
enter_freq = ira_loop_edge_freq (subloop_node, regno, false);
ira_assert (regno < ira_reg_equiv_len);
- if (ira_reg_equiv_invariant_p[regno]
- || ira_reg_equiv_const[regno] != NULL_RTX)
+ if (ira_equiv_no_lvalue_p (regno))
{
if (! ALLOCNO_ASSIGNED_P (subloop_allocno))
{
@@ -2941,9 +2940,7 @@ move_spill_restore (void)
copies and the reload pass can spill the allocno set
by copy although the allocno will not get memory
slot. */
- || (regno < ira_reg_equiv_len
- && (ira_reg_equiv_invariant_p[regno]
- || ira_reg_equiv_const[regno] != NULL_RTX))
+ || ira_equiv_no_lvalue_p (regno)
|| !bitmap_bit_p (loop_node->border_allocnos, ALLOCNO_NUM (a)))
continue;
mode = ALLOCNO_MODE (a);
@@ -3367,9 +3364,7 @@ coalesce_allocnos (void)
a = ira_allocnos[j];
regno = ALLOCNO_REGNO (a);
if (! ALLOCNO_ASSIGNED_P (a) || ALLOCNO_HARD_REGNO (a) >= 0
- || (regno < ira_reg_equiv_len
- && (ira_reg_equiv_const[regno] != NULL_RTX
- || ira_reg_equiv_invariant_p[regno])))
+ || ira_equiv_no_lvalue_p (regno))
continue;
for (cp = ALLOCNO_COPIES (a); cp != NULL; cp = next_cp)
{
@@ -3384,9 +3379,7 @@ coalesce_allocnos (void)
if ((cp->insn != NULL || cp->constraint_p)
&& ALLOCNO_ASSIGNED_P (cp->second)
&& ALLOCNO_HARD_REGNO (cp->second) < 0
- && (regno >= ira_reg_equiv_len
- || (! ira_reg_equiv_invariant_p[regno]
- && ira_reg_equiv_const[regno] == NULL_RTX)))
+ && ! ira_equiv_no_lvalue_p (regno))
sorted_copies[cp_num++] = cp;
}
else if (cp->second == a)
@@ -3652,9 +3645,7 @@ coalesce_spill_slots (ira_allocno_t *spi
allocno = spilled_coalesced_allocnos[i];
if (ALLOCNO_COALESCE_DATA (allocno)->first != allocno
|| bitmap_bit_p (set_jump_crosses, ALLOCNO_REGNO (allocno))
- || (ALLOCNO_REGNO (allocno) < ira_reg_equiv_len
- && (ira_reg_equiv_const[ALLOCNO_REGNO (allocno)] != NULL_RTX
- || ira_reg_equiv_invariant_p[ALLOCNO_REGNO (allocno)])))
+ || ira_equiv_no_lvalue_p (ALLOCNO_REGNO (allocno)))
continue;
for (j = 0; j < i; j++)
{
@@ -3662,9 +3653,7 @@ coalesce_spill_slots (ira_allocno_t *spi
n = ALLOCNO_COALESCE_DATA (a)->temp;
if (ALLOCNO_COALESCE_DATA (a)->first == a
&& ! bitmap_bit_p (set_jump_crosses, ALLOCNO_REGNO (a))
- && (ALLOCNO_REGNO (a) >= ira_reg_equiv_len
- || (! ira_reg_equiv_invariant_p[ALLOCNO_REGNO (a)]
- && ira_reg_equiv_const[ALLOCNO_REGNO (a)] == NULL_RTX))
+ && ! ira_equiv_no_lvalue_p (ALLOCNO_REGNO (a))
&& ! slot_coalesced_allocno_live_ranges_intersect_p (allocno, n))
break;
}
@@ -3772,9 +3761,7 @@ ira_sort_regnos_for_alter_reg (int *pseu
allocno = spilled_coalesced_allocnos[i];
if (ALLOCNO_COALESCE_DATA (allocno)->first != allocno
|| ALLOCNO_HARD_REGNO (allocno) >= 0
- || (ALLOCNO_REGNO (allocno) < ira_reg_equiv_len
- && (ira_reg_equiv_const[ALLOCNO_REGNO (allocno)] != NULL_RTX
- || ira_reg_equiv_invariant_p[ALLOCNO_REGNO (allocno)])))
+ || ira_equiv_no_lvalue_p (ALLOCNO_REGNO (allocno)))
continue;
if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
fprintf (ira_dump_file, " Slot %d (freq,size):", slot_num);
===================================================================
@@ -340,6 +340,7 @@ ira_create_new_reg (rtx original_reg)
if (internal_flag_ira_verbose > 3 && ira_dump_file != NULL)
fprintf (ira_dump_file, " Creating newreg=%i from oldreg=%i\n",
REGNO (new_reg), REGNO (original_reg));
+ ira_expand_reg_equiv ();
return new_reg;
}
@@ -515,8 +516,7 @@ generate_edge_moves (edge e)
/* Remove unnecessary stores at the region exit. We should do
this for readonly memory for sure and this is guaranteed by
that we never generate moves on region borders (see
- checking ira_reg_equiv_invariant_p in function
- change_loop). */
+ checking in function change_loop). */
if (ALLOCNO_HARD_REGNO (dest_allocno) < 0
&& ALLOCNO_HARD_REGNO (src_allocno) >= 0
&& store_can_be_removed_p (src_allocno, dest_allocno))
@@ -610,8 +610,7 @@ change_loop (ira_loop_tree_node_t node)
/* don't create copies because reload can spill an
allocno set by copy although the allocno will not
get memory slot. */
- || ira_reg_equiv_invariant_p[regno]
- || ira_reg_equiv_const[regno] != NULL_RTX))
+ || ira_equiv_no_lvalue_p (regno)))
continue;
original_reg = allocno_emit_reg (allocno);
if (parent_allocno == NULL
@@ -899,17 +898,22 @@ modify_move_list (move_t list)
static rtx
emit_move_list (move_t list, int freq)
{
- int cost, regno;
- rtx result, insn, set, to;
+ rtx to, from, dest;
+ int to_regno, from_regno, cost, regno;
+ rtx result, insn, set;
enum machine_mode mode;
enum reg_class aclass;
+ grow_reg_equivs ();
start_sequence ();
for (; list != NULL; list = list->next)
{
start_sequence ();
- emit_move_insn (allocno_emit_reg (list->to),
- allocno_emit_reg (list->from));
+ to = allocno_emit_reg (list->to);
+ to_regno = REGNO (to);
+ from = allocno_emit_reg (list->from);
+ from_regno = REGNO (from);
+ emit_move_insn (to, from);
list->insn = get_insns ();
end_sequence ();
for (insn = list->insn; insn != NULL_RTX; insn = NEXT_INSN (insn))
@@ -925,21 +929,22 @@ emit_move_list (move_t list, int freq)
to use the equivalence. */
if ((set = single_set (insn)) != NULL_RTX)
{
- to = SET_DEST (set);
- if (GET_CODE (to) == SUBREG)
- to = SUBREG_REG (to);
- ira_assert (REG_P (to));
- regno = REGNO (to);
+ dest = SET_DEST (set);
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+ ira_assert (REG_P (dest));
+ regno = REGNO (dest);
if (regno >= ira_reg_equiv_len
- || (! ira_reg_equiv_invariant_p[regno]
- && ira_reg_equiv_const[regno] == NULL_RTX))
+ || (ira_reg_equiv[regno].invariant == NULL_RTX
+ && ira_reg_equiv[regno].constant == NULL_RTX))
continue; /* regno has no equivalence. */
ira_assert ((int) VEC_length (reg_equivs_t, reg_equivs)
- >= ira_reg_equiv_len);
+ > regno);
reg_equiv_init (regno)
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init (regno));
}
}
+ ira_update_equiv_info_by_shuffle_insn (to_regno, from_regno, list->insn);
emit_insn (list->insn);
mode = ALLOCNO_MODE (list->to);
aclass = ALLOCNO_CLASS (list->to);