summaryrefslogtreecommitdiff
path: root/gcc/lra-constraints.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/lra-constraints.c')
-rw-r--r--gcc/lra-constraints.c131
1 files changed, 101 insertions, 30 deletions
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 4c88cca669d..14018849392 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -1,5 +1,5 @@
/* Code for RTL transformations to satisfy insn constraints.
- Copyright (C) 2010-2013 Free Software Foundation, Inc.
+ Copyright (C) 2010-2014 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
@@ -271,9 +271,11 @@ in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class)
where other reload pseudos are no longer allocatable. */
|| (INSN_UID (curr_insn) >= new_insn_uid_start
&& curr_insn_set != NULL
- && (OBJECT_P (SET_SRC (curr_insn_set))
+ && ((OBJECT_P (SET_SRC (curr_insn_set))
+ && ! CONSTANT_P (SET_SRC (curr_insn_set)))
|| (GET_CODE (SET_SRC (curr_insn_set)) == SUBREG
- && OBJECT_P (SUBREG_REG (SET_SRC (curr_insn_set)))))))
+ && OBJECT_P (SUBREG_REG (SET_SRC (curr_insn_set)))
+ && ! CONSTANT_P (SUBREG_REG (SET_SRC (curr_insn_set)))))))
/* When we don't know what class will be used finally for reload
pseudos, we use ALL_REGS. */
return ((regno >= new_regno_start && rclass == ALL_REGS)
@@ -315,10 +317,48 @@ in_mem_p (int regno)
return get_reg_class (regno) == NO_REGS;
}
+/* Initiate equivalences for LRA. As we keep original equivalences
+ before any elimination, we need to make copies otherwise any change
+ in insns might change the equivalences. */
+void
+lra_init_equiv (void)
+{
+ ira_expand_reg_equiv ();
+ for (int i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); i++)
+ {
+ rtx res;
+
+ if ((res = ira_reg_equiv[i].memory) != NULL_RTX)
+ ira_reg_equiv[i].memory = copy_rtx (res);
+ if ((res = ira_reg_equiv[i].invariant) != NULL_RTX)
+ ira_reg_equiv[i].invariant = copy_rtx (res);
+ }
+}
+
+static rtx loc_equivalence_callback (rtx, const_rtx, void *);
+
+/* Update equivalence for REGNO. We need to this as the equivalence
+ might contain other pseudos which are changed by their
+ equivalences. */
+static void
+update_equiv (int regno)
+{
+ rtx x;
+
+ if ((x = ira_reg_equiv[regno].memory) != NULL_RTX)
+ ira_reg_equiv[regno].memory
+ = simplify_replace_fn_rtx (x, NULL_RTX, loc_equivalence_callback,
+ NULL_RTX);
+ if ((x = ira_reg_equiv[regno].invariant) != NULL_RTX)
+ ira_reg_equiv[regno].invariant
+ = simplify_replace_fn_rtx (x, NULL_RTX, loc_equivalence_callback,
+ NULL_RTX);
+}
+
/* If we have decided to substitute X with another value, return that
value, otherwise return X. */
static rtx
-get_equiv_substitution (rtx x)
+get_equiv (rtx x)
{
int regno;
rtx res;
@@ -337,6 +377,19 @@ get_equiv_substitution (rtx x)
gcc_unreachable ();
}
+/* If we have decided to substitute X with the equivalent value,
+ return that value after elimination for INSN, otherwise return
+ X. */
+static rtx
+get_equiv_with_elimination (rtx x, rtx insn)
+{
+ rtx res = get_equiv (x);
+
+ if (x == res || CONSTANT_P (res))
+ return res;
+ return lra_eliminate_regs_1 (insn, res, GET_MODE (res), false, false, true);
+}
+
/* Set up curr_operand_mode. */
static void
init_curr_operand_mode (void)
@@ -1101,7 +1154,7 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
{
regno = REGNO (reg);
rclass = get_reg_class (regno);
- if ((*loc = get_equiv_substitution (reg)) != reg)
+ if ((*loc = get_equiv_with_elimination (reg, curr_insn)) != reg)
{
if (lra_dump_file != NULL)
{
@@ -2007,6 +2060,13 @@ process_alt_operands (int only_alternative)
int const_to_mem = 0;
bool no_regs_p;
+ /* Never do output reload of stack pointer. It makes
+ impossible to do elimination when SP is changed in
+ RTL. */
+ if (op == stack_pointer_rtx && ! frame_pointer_needed
+ && curr_static_id->operand[nop].type != OP_IN)
+ goto fail;
+
/* If this alternative asks for a specific reg class, see if there
is at least one allocatable register in that class. */
no_regs_p
@@ -2517,7 +2577,7 @@ equiv_address_substitution (struct address_info *ad)
else
{
base_reg = *base_term;
- new_base_reg = get_equiv_substitution (base_reg);
+ new_base_reg = get_equiv_with_elimination (base_reg, curr_insn);
}
index_term = strip_subreg (ad->index_term);
if (index_term == NULL)
@@ -2525,7 +2585,7 @@ equiv_address_substitution (struct address_info *ad)
else
{
index_reg = *index_term;
- new_index_reg = get_equiv_substitution (index_reg);
+ new_index_reg = get_equiv_with_elimination (index_reg, curr_insn);
}
if (base_reg == new_base_reg && index_reg == new_index_reg)
return false;
@@ -3055,7 +3115,7 @@ curr_insn_transform (void)
if (GET_CODE (old) == SUBREG)
old = SUBREG_REG (old);
- subst = get_equiv_substitution (old);
+ subst = get_equiv_with_elimination (old, curr_insn);
if (subst != old)
{
subst = copy_rtx (subst);
@@ -3260,6 +3320,9 @@ curr_insn_transform (void)
if (INSN_CODE (curr_insn) >= 0
&& (p = get_insn_name (INSN_CODE (curr_insn))) != NULL)
fprintf (lra_dump_file, " {%s}", p);
+ if (curr_id->sp_offset != 0)
+ fprintf (lra_dump_file, " (sp_off=%" HOST_WIDE_INT_PRINT "d)",
+ curr_id->sp_offset);
fprintf (lra_dump_file, "\n");
}
@@ -3638,7 +3701,7 @@ loc_equivalence_change_p (rtx *loc)
if (code == SUBREG)
{
reg = SUBREG_REG (x);
- if ((subst = get_equiv_substitution (reg)) != reg
+ if ((subst = get_equiv_with_elimination (reg, curr_insn)) != reg
&& GET_MODE (subst) == VOIDmode)
{
/* We cannot reload debug location. Simplify subreg here
@@ -3648,7 +3711,7 @@ loc_equivalence_change_p (rtx *loc)
return true;
}
}
- if (code == REG && (subst = get_equiv_substitution (x)) != x)
+ if (code == REG && (subst = get_equiv_with_elimination (x, curr_insn)) != x)
{
*loc = subst;
return true;
@@ -3669,14 +3732,16 @@ loc_equivalence_change_p (rtx *loc)
}
/* Similar to loc_equivalence_change_p, but for use as
- simplify_replace_fn_rtx callback. */
+ simplify_replace_fn_rtx callback. DATA is insn for which the
+ elimination is done. If it null we don't do the elimination. */
static rtx
-loc_equivalence_callback (rtx loc, const_rtx, void *)
+loc_equivalence_callback (rtx loc, const_rtx, void *data)
{
if (!REG_P (loc))
return NULL_RTX;
- rtx subst = get_equiv_substitution (loc);
+ rtx subst = (data == NULL
+ ? get_equiv (loc) : get_equiv_with_elimination (loc, (rtx) data));
if (subst != loc)
return subst;
@@ -3848,21 +3913,27 @@ lra_constraints (bool first_p)
lra_risky_transformations_p = false;
new_insn_uid_start = get_max_uid ();
new_regno_start = first_p ? lra_constraint_new_regno_start : max_reg_num ();
+ /* Mark used hard regs for target stack size calulations. */
+ for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++)
+ if (lra_reg_info[i].nrefs != 0
+ && (hard_regno = lra_get_regno_hard_regno (i)) >= 0)
+ {
+ int j, nregs;
+
+ nregs = hard_regno_nregs[hard_regno][lra_reg_info[i].biggest_mode];
+ for (j = 0; j < nregs; j++)
+ df_set_regs_ever_live (hard_regno + j, true);
+ }
+ /* Do elimination before the equivalence processing as we can spill
+ some pseudos during elimination. */
+ lra_eliminate (false, first_p);
bitmap_initialize (&equiv_insn_bitmap, &reg_obstack);
for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++)
if (lra_reg_info[i].nrefs != 0)
{
ira_reg_equiv[i].profitable_p = true;
reg = regno_reg_rtx[i];
- if ((hard_regno = lra_get_regno_hard_regno (i)) >= 0)
- {
- int j, nregs;
-
- nregs = hard_regno_nregs[hard_regno][lra_reg_info[i].biggest_mode];
- for (j = 0; j < nregs; j++)
- df_set_regs_ever_live (hard_regno + j, true);
- }
- else if ((x = get_equiv_substitution (reg)) != reg)
+ if (lra_get_regno_hard_regno (i) < 0 && (x = get_equiv (reg)) != reg)
{
bool pseudo_p = contains_reg_p (x, false, false);
@@ -3911,15 +3982,16 @@ lra_constraints (bool first_p)
ira_reg_equiv[i].defined_p = false;
if (contains_reg_p (x, false, true))
ira_reg_equiv[i].profitable_p = false;
- if (get_equiv_substitution (reg) != reg)
+ if (get_equiv (reg) != reg)
bitmap_ior_into (&equiv_insn_bitmap, &lra_reg_info[i].insn_bitmap);
}
}
+ for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++)
+ update_equiv (i);
/* We should add all insns containing pseudos which should be
substituted by their equivalences. */
EXECUTE_IF_SET_IN_BITMAP (&equiv_insn_bitmap, 0, uid, bi)
lra_push_insn_by_uid (uid);
- lra_eliminate (false);
min_len = lra_insn_stack_length ();
new_insns_num = 0;
last_bb = NULL;
@@ -3954,7 +4026,7 @@ lra_constraints (bool first_p)
rtx old = *curr_id->operand_loc[0];
*curr_id->operand_loc[0]
= simplify_replace_fn_rtx (old, NULL_RTX,
- loc_equivalence_callback, NULL);
+ loc_equivalence_callback, curr_insn);
if (old != *curr_id->operand_loc[0])
{
lra_update_insn_regno_info (curr_insn);
@@ -3973,7 +4045,7 @@ lra_constraints (bool first_p)
if (GET_CODE (dest_reg) == SUBREG)
dest_reg = SUBREG_REG (dest_reg);
if ((REG_P (dest_reg)
- && (x = get_equiv_substitution (dest_reg)) != dest_reg
+ && (x = get_equiv (dest_reg)) != dest_reg
/* Remove insns which set up a pseudo whose value
can not be changed. Such insns might be not in
init_insns because we don't update equiv data
@@ -3993,8 +4065,7 @@ lra_constraints (bool first_p)
|| in_list_p (curr_insn,
ira_reg_equiv
[REGNO (dest_reg)].init_insns)))
- || (((x = get_equiv_substitution (SET_SRC (set)))
- != SET_SRC (set))
+ || (((x = get_equiv (SET_SRC (set))) != SET_SRC (set))
&& in_list_p (curr_insn,
ira_reg_equiv
[REGNO (SET_SRC (set))].init_insns)))
@@ -5273,7 +5344,7 @@ lra_inheritance (void)
bitmap_initialize (&live_regs, &reg_obstack);
bitmap_initialize (&temp_bitmap, &reg_obstack);
bitmap_initialize (&ebb_global_regs, &reg_obstack);
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
start_bb = bb;
if (lra_dump_file != NULL)
@@ -5374,7 +5445,7 @@ remove_inheritance_pseudos (bitmap remove_pseudos)
because we need to marks insns affected by previous
inheritance/split pass for processing by the subsequent
constraint pass. */
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
fix_bb_live_info (df_get_live_in (bb), remove_pseudos);
fix_bb_live_info (df_get_live_out (bb), remove_pseudos);