combine: Fix PR83304

Message ID 065628228e2a2fcbc993c357c1043cf8004300a4.1512730383.git.segher@kernel.crashing.org
State New
Headers show
Series
  • combine: Fix PR83304
Related show

Commit Message

Segher Boessenkool Dec. 8, 2017, 11:04 a.m.
In PR83304 two insns are combined, where the I2 uses a register that
has a REG_DEAD note on an insn after I2 but before I3.  In such a case
move_deaths should move that death note.  But move_deaths only looks
at the reg_stat[regno].last_death insn, and that field can be zeroed
out (previously, use_crosses_set_p would prevent the combination in
this case).

If the last_death field is zero it means "unknown", not "no death", so
we have to find if there is a REG_DEAD note.

This patch does that, fixing the Arm PR83304 testcase.  Also bootstrapped
and tested on powerpc64-linux {-m32,-m64}.

Committing to trunk.


Segher


2017-12-08  Segher Boessenkool  <segher@kernel.crashing.org>

	PR rtl-optimization/83304
	* combine.c (move_deaths): If we do not know where a register died,
	search for it.

---
 gcc/combine.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

-- 
1.8.3.1

Patch

diff --git a/gcc/combine.c b/gcc/combine.c
index 748c9a8..b12484a 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -13910,6 +13910,26 @@  move_deaths (rtx x, rtx maybe_kill_insn, int from_luid, rtx_insn *to_insn,
       unsigned int regno = REGNO (x);
       rtx_insn *where_dead = reg_stat[regno].last_death;
 
+      /* If we do not know where the register died, it may still die between
+	 FROM_LUID and TO_INSN.  If so, find it.  This is PR83304.  */
+      if (!where_dead)
+	{
+	  rtx_insn *insn = prev_real_insn (to_insn);
+	  while (insn
+		 && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (to_insn)
+		 && DF_INSN_LUID (insn) >= from_luid)
+	    {
+	      if (dead_or_set_regno_p (insn, regno))
+		{
+		  if (find_regno_note (insn, REG_DEAD, regno))
+		    where_dead = insn;
+		  break;
+		}
+
+	      insn = prev_real_insn (insn);
+	    }
+	}
+
       /* Don't move the register if it gets killed in between from and to.  */
       if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
 	  && ! reg_referenced_p (x, maybe_kill_insn))