combine: Fix PR83304
authorSegher Boessenkool <segher@kernel.crashing.org>
Fri, 8 Dec 2017 11:26:35 +0000 (12:26 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Fri, 8 Dec 2017 11:26:35 +0000 (12:26 +0100)
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.

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

From-SVN: r255506

gcc/ChangeLog
gcc/combine.c

index e8aa3a1..dcd1fb6 100644 (file)
@@ -1,3 +1,9 @@
+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.
+
 2017-12-08  Richard Biener  <rguenther@suse.de>
 
        * gimple-loop-interchange.cc (tree_loop_interchange::interchange):
index 34c89a1..786a840 100644 (file)
@@ -13876,6 +13876,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))