combine: Do not call simplify from inside change_zero_ext (PR78232)
authorSegher Boessenkool <segher@kernel.crashing.org>
Thu, 10 Nov 2016 22:45:39 +0000 (23:45 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Thu, 10 Nov 2016 22:45:39 +0000 (23:45 +0100)
When combine splits a three-insn combination into two instructions it
can reuse i2dest for the temporary result of the first new instruction.
However all information it has in reg_stat about that register will be
stale.  This results in the simplify_gen_binary calls in change_zero_ext
using out-of-date information, which makes it think one of the ANDs
generated there always results in 0, and it doesn't get better from there.

This can also happen if a splitter in the MD uses nonzero_bits (for
example).  I tried to make the splitting code in combine save and restore
the i2dest reg_stat info, but that causes one of the acats tests to fail.

This whole reg_stat thing needs an overhaul, and/or we shouldn't reuse
i2dest for unrelated purposes when splitting.

This patch changes change_zero_ext to do the expected simplifications
itself and not call simplify_gen_*.

PR rtl-optimization/78232
* combine.c (try_combine): Add a big comment about why reusing i2dest
is undesirable.
(change_zero_ext): Do not call simplify_gen_binary, do the
simplifications manually.

From-SVN: r242059

gcc/ChangeLog
gcc/combine.c

index 5fed9715531c9ebfb796fa5e47d099cb61932392..761896fe6c5da638861bebb67662e4270f11c4aa 100644 (file)
@@ -1,3 +1,11 @@
+2016-11-10  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       PR rtl-optimization/78232
+       * combine.c (try_combine): Add a big comment about why reusing i2dest
+       is undesirable.
+       (change_zero_ext): Do not call simplify_gen_binary, do the
+       simplifications manually.
+
 2016-11-10  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
        * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): If ISA 3.0,
index 69020561c3147fec1c2a085086fbc68505dc83ad..6ffa387a95cbbf710c5e321cd1d2c157e840d478 100644 (file)
@@ -3528,6 +3528,15 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
        {
          machine_mode new_mode = GET_MODE (SET_DEST (newpat));
 
+         /* ??? Reusing i2dest without resetting the reg_stat entry for it
+            (temporarily, until we are committed to this instruction
+            combination) does not work: for example, any call to nonzero_bits
+            on the register (from a splitter in the MD file, for example)
+            will get the old information, which is invalid.
+
+            Since nowadays we can create registers during combine just fine,
+            we should just create a new one here, not reuse i2dest.  */
+
          /* First try to split using the original register as a
             scratch register.  */
          parallel = gen_rtx_PARALLEL (VOIDmode,
@@ -11133,8 +11142,10 @@ change_zero_ext (rtx pat)
          if (BITS_BIG_ENDIAN)
            start = GET_MODE_PRECISION (mode) - size - start;
 
-         x = simplify_gen_binary (LSHIFTRT, mode,
-                                  XEXP (x, 0), GEN_INT (start));
+         if (start)
+           x = gen_rtx_LSHIFTRT (mode, XEXP (x, 0), GEN_INT (start));
+         else
+           x = XEXP (x, 0);
        }
       else if (GET_CODE (x) == ZERO_EXTEND
               && SCALAR_INT_MODE_P (mode)
@@ -11190,16 +11201,18 @@ change_zero_ext (rtx pat)
       if (BITS_BIG_ENDIAN)
        offset = reg_width - width - offset;
 
+      rtx x, y, z, w;
       wide_int mask = wi::shifted_mask (offset, width, true, reg_width);
-      rtx x = gen_rtx_AND (mode, reg, immed_wide_int_const (mask, mode));
-      rtx y = simplify_gen_binary (ASHIFT, mode, SET_SRC (pat),
-                                  GEN_INT (offset));
       wide_int mask2 = wi::shifted_mask (offset, width, false, reg_width);
-      y = simplify_gen_binary (AND, mode, y,
-                              immed_wide_int_const (mask2, mode));
-      rtx z = simplify_gen_binary (IOR, mode, x, y);
+      x = gen_rtx_AND (mode, reg, immed_wide_int_const (mask, mode));
+      if (offset)
+       y = gen_rtx_ASHIFT (mode, SET_SRC (pat), GEN_INT (offset));
+      else
+       y = SET_SRC (pat);
+      z = gen_rtx_AND (mode, y, immed_wide_int_const (mask2, mode));
+      w = gen_rtx_IOR (mode, x, z);
       SUBST (SET_DEST (pat), reg);
-      SUBST (SET_SRC (pat), z);
+      SUBST (SET_SRC (pat), w);
 
       changed = true;
     }