When lra-remat rematerializes an instruction with a clobber, it checks that the clobb...
authorWilco Dijkstra <wdijkstr@arm.com>
Wed, 24 May 2017 17:06:55 +0000 (17:06 +0000)
committerWilco Dijkstra <wilco@gcc.gnu.org>
Wed, 24 May 2017 17:06:55 +0000 (17:06 +0000)
When lra-remat rematerializes an instruction with a clobber, it checks
that the clobber does not kill live registers.  However it fails to check
that the clobber also doesn't overlap with the destination register of the
final rematerialized instruction.  As a result it is possible to generate
illegal instructions with the same hard register as the destination and a
clobber.  Fix this by also checking for overlaps with the destination
register.

    gcc/
PR rtl-optimization/80754
* lra-remat.c (do_remat): Add overlap checks for dst_regno.

From-SVN: r248424

gcc/ChangeLog
gcc/lra-remat.c

index 69356fc0bc69e1fadb66fcbbfd560deff29f5958..1b70fa034b26b6c5c199b3b5379e618e09f135e9 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-24  Wilco Dijkstra  <wdijkstr@arm.com>
+
+       PR rtl-optimization/80754
+       * lra-remat.c (do_remat): Add overlap checks for dst_regno.
+
 2017-05-24  Sheldon Lobo  <smlobo@sheldon.us.oracle.com>
 
        * config/sparc/sparc.md (length): Return the correct value for -mflat
index fb294edf368675636a3396f02c7100ffbce1e718..f28993e818d1eff2f5742731628b10f0184f7639 100644 (file)
@@ -1117,6 +1117,7 @@ do_remat (void)
                  break;
            }
          int i, hard_regno, nregs;
+         int dst_hard_regno, dst_nregs;
          rtx_insn *remat_insn = NULL;
          HOST_WIDE_INT cand_sp_offset = 0;
          if (cand != NULL)
@@ -1131,6 +1132,12 @@ do_remat (void)
              gcc_assert (REG_P (saved_op));
              int ignore_regno = REGNO (saved_op); 
 
+             dst_hard_regno = dst_regno < FIRST_PSEUDO_REGISTER
+               ? dst_regno : reg_renumber[dst_regno];
+             gcc_assert (dst_hard_regno >= 0);
+             machine_mode mode = GET_MODE (SET_DEST (set));
+             dst_nregs = hard_regno_nregs[dst_hard_regno][mode];
+
              for (reg = cand_id->regs; reg != NULL; reg = reg->next)
                if (reg->type != OP_IN && reg->regno != ignore_regno)
                  {
@@ -1141,6 +1148,10 @@ do_remat (void)
                        break;
                    if (i < nregs)
                      break;
+                   /* Ensure the clobber also doesn't overlap dst_regno.  */
+                   if (hard_regno + nregs > dst_hard_regno
+                       && hard_regno < dst_hard_regno + dst_nregs)
+                     break;
                  }
 
              if (reg == NULL)
@@ -1148,9 +1159,14 @@ do_remat (void)
                  for (reg = static_cand_id->hard_regs;
                       reg != NULL;
                       reg = reg->next)
-                   if (reg->type != OP_IN
-                       && TEST_HARD_REG_BIT (live_hard_regs, reg->regno))
-                     break;
+                   if (reg->type != OP_IN)
+                     {
+                       if (TEST_HARD_REG_BIT (live_hard_regs, reg->regno))
+                         break;
+                       if (reg->regno >= dst_hard_regno
+                           && reg->regno < dst_hard_regno + dst_nregs)
+                         break;
+                     }
                }
 
              if (reg == NULL)