This fixes a problem identified by Chung-Lin. Once reload is done, all
equivalencing insns for pseudos that didn't get a hard reg but could be
eliminated using their REG_EQUIV are deleted. However, we still can
produce reloads and reload insns for them in certain cases, leading to
unnecessary spilling. This patch corrects this by making sure we use
identical tests when deciding whether to ignore an insn while reloading,
and whether to delete it afterwards.
Bootstrapped and tested on x86_64-linux (with lra_p disabled). Chung-Lin
says he's tested it as well, I think on arm (probably with something 4.8
based). Will commit in a few days if no objections.
Bernd
Index: gcc/reload1.c
===
--- gcc/reload1.c (revision 206316)
+++ gcc/reload1.c (working copy)
@@ -686,6 +686,65 @@ static int failure;
/* Temporary array of pseudo-register number. */
static int *temp_pseudo_reg_arr;
+/* If a pseudo has no hard reg, delete the insns that made the equivalence.
+ If that insn didn't set the register (i.e., it copied the register to
+ memory), just delete that insn instead of the equivalencing insn plus
+ anything now dead. If we call delete_dead_insn on that insn, we may
+ delete the insn that actually sets the register if the register dies
+ there and that is incorrect. */
+static void
+remove_init_insns ()
+{
+ for (int i = FIRST_PSEUDO_REGISTER; i max_regno; i++)
+{
+ if (reg_renumber[i] 0 reg_equiv_init (i) != 0)
+ {
+ rtx list;
+ for (list = reg_equiv_init (i); list; list = XEXP (list, 1))
+ {
+ rtx equiv_insn = XEXP (list, 0);
+
+ /* If we already deleted the insn or if it may trap, we can't
+ delete it. The latter case shouldn't happen, but can
+ if an insn has a variable address, gets a REG_EH_REGION
+ note added to it, and then gets converted into a load
+ from a constant address. */
+ if (NOTE_P (equiv_insn)
+ || can_throw_internal (equiv_insn))
+ ;
+ else if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
+ delete_dead_insn (equiv_insn);
+ else
+ SET_INSN_DELETED (equiv_insn);
+ }
+ }
+}
+}
+
+/* Return true if remove_init_insns will delete INSN. */
+static bool
+will_delete_init_insn_p (rtx insn)
+{
+ rtx set = single_set (insn);
+ if (!set || !REG_P (SET_DEST (set)))
+return false;
+ unsigned regno = REGNO (SET_DEST (set));
+
+ if (can_throw_internal (insn))
+return false;
+
+ if (regno FIRST_PSEUDO_REGISTER || reg_renumber[regno] = 0)
+return false;
+
+ for (rtx list = reg_equiv_init (regno); list; list = XEXP (list, 1))
+{
+ rtx equiv_insn = XEXP (list, 0);
+ if (equiv_insn == insn)
+ return true;
+}
+ return false;
+}
+
/* Main entry point for the reload pass.
FIRST is the first insn of the function being compiled.
@@ -993,37 +1052,7 @@ reload (rtx first, int global)
if (ep-can_eliminate)
mark_elimination (ep-from, ep-to);
- /* If a pseudo has no hard reg, delete the insns that made the equivalence.
- If that insn didn't set the register (i.e., it copied the register to
- memory), just delete that insn instead of the equivalencing insn plus
- anything now dead. If we call delete_dead_insn on that insn, we may
- delete the insn that actually sets the register if the register dies
- there and that is incorrect. */
-
- for (i = FIRST_PSEUDO_REGISTER; i max_regno; i++)
-{
- if (reg_renumber[i] 0 reg_equiv_init (i) != 0)
- {
- rtx list;
- for (list = reg_equiv_init (i); list; list = XEXP (list, 1))
- {
- rtx equiv_insn = XEXP (list, 0);
-
- /* If we already deleted the insn or if it may trap, we can't
- delete it. The latter case shouldn't happen, but can
- if an insn has a variable address, gets a REG_EH_REGION
- note added to it, and then gets converted into a load
- from a constant address. */
- if (NOTE_P (equiv_insn)
- || can_throw_internal (equiv_insn))
- ;
- else if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
- delete_dead_insn (equiv_insn);
- else
- SET_INSN_DELETED (equiv_insn);
- }
- }
-}
+ remove_init_insns ();
/* Use the reload registers where necessary
by generating move instructions to move the must-be-register
@@ -1484,14 +1513,9 @@ calculate_needs_all_insns (int global)
rtx old_notes = REG_NOTES (insn);
int did_elimination = 0;
int operands_changed = 0;
- rtx set = single_set (insn);
/* Skip insns that only set an equivalence. */
- if (set REG_P (SET_DEST (set))
- reg_renumber[REGNO (SET_DEST (set))] 0
- (reg_equiv_constant (REGNO (SET_DEST (set)))
- || (reg_equiv_invariant (REGNO (SET_DEST (set)
- reg_equiv_init (REGNO (SET_DEST (set
+ if (will_delete_init_insn_p (insn))
continue;
/* If needed, eliminate any eliminable registers. */
@@ -4586,6 +4610,9 @@ reload_as_needed (int