combine: Improve change_zero_ext (fixes PR71847)
authorSegher Boessenkool <segher@kernel.crashing.org>
Fri, 28 Oct 2016 20:56:28 +0000 (22:56 +0200)
committerSegher Boessenkool <segher@gcc.gnu.org>
Fri, 28 Oct 2016 20:56:28 +0000 (22:56 +0200)
This improves a few things in change_zero_ext.  Firstly, it should use
the passed in pattern in recog_for_combine, not the pattern of the insn
(they are not the same if the whole pattern was replaced).  Secondly,
it handled zero_ext of a subreg, but with hard registers we do not get
a subreg, instead the mode of the reg is changed.  So this handles that.
Thirdly, after changing a zero_ext to an AND, the resulting RTL may become
non-canonical, like (ior (ashift ..) (and ..)); the AND should be first,
it is commutative.  And lastly, zero_extract as a set_dest wasn't handled
at all, but now it is.

This fixes the testcase in PR71847, and improves code generation in some
other edge cases too.

PR target/71847
* combine.c (change_zero_ext): Handle zero_ext of hard registers.
Swap commutative operands in new RTL if needed.  Handle zero_ext
in the set_dest.
(recog_for_combine): Pass *pnewpat to change_zero_ext instead of
PATTERN (insn).

From-SVN: r241664

gcc/ChangeLog
gcc/combine.c

index 4302280b832902aeddd3c1949b498f4cb8d1cd5c..32f6435a90085f1bace966d62c3e2f9d2e3e8c05 100644 (file)
@@ -1,3 +1,12 @@
+2016-10-28  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       PR target/71847
+       * combine.c (change_zero_ext): Handle zero_ext of hard registers.
+       Swap commutative operands in new RTL if needed.  Handle zero_ext
+       in the set_dest.
+       (recog_for_combine): Pass *pnewpat to change_zero_ext instead of
+       PATTERN (insn).
+
 2016-10-28  Prathamesh Kulkarni  <prathamesh.kulkarni@linaro.org>
            Kugan Vivekanandarajah  <kuganv@linaro.org>
            Jim Wilson  <jim.wilson@linaro.org>
index 64413b4436ebcf238ec543ba86f95030cb9cca97..60a127f2e53dbfb32ac32c5c0962539fbf880480 100644 (file)
@@ -11106,9 +11106,10 @@ recog_for_combine_1 (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
    Return whether anything was so changed.  */
 
 static bool
-change_zero_ext (rtx *src)
+change_zero_ext (rtx pat)
 {
   bool changed = false;
+  rtx *src = &SET_SRC (pat);
 
   subrtx_ptr_iterator::array_type array;
   FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST)
@@ -11140,6 +11141,14 @@ change_zero_ext (rtx *src)
          size = GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)));
          x = SUBREG_REG (XEXP (x, 0));
        }
+      else if (GET_CODE (x) == ZERO_EXTEND
+              && SCALAR_INT_MODE_P (mode)
+              && REG_P (XEXP (x, 0))
+              && HARD_REGISTER_P (XEXP (x, 0)))
+       {
+         size = GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)));
+         x = gen_rtx_REG (mode, REGNO (XEXP (x, 0)));
+       }
       else
        continue;
 
@@ -11150,6 +11159,44 @@ change_zero_ext (rtx *src)
       changed = true;
     }
 
+  if (changed)
+    FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST)
+      {
+       rtx x = **iter;
+       if (COMMUTATIVE_ARITH_P (x)
+           && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+         {
+           rtx tem = XEXP (x, 0);
+           SUBST (XEXP (x, 0), XEXP (x, 1));
+           SUBST (XEXP (x, 1), tem);
+         }
+      }
+
+  rtx *dst = &SET_DEST (pat);
+  if (GET_CODE (*dst) == ZERO_EXTRACT
+      && REG_P (XEXP (*dst, 0))
+      && CONST_INT_P (XEXP (*dst, 1))
+      && CONST_INT_P (XEXP (*dst, 2)))
+    {
+      rtx reg = XEXP (*dst, 0);
+      int width = INTVAL (XEXP (*dst, 1));
+      int offset = INTVAL (XEXP (*dst, 2));
+      machine_mode mode = GET_MODE (reg);
+      int reg_width = GET_MODE_PRECISION (mode);
+      if (BITS_BIG_ENDIAN)
+       offset = reg_width - width - offset;
+
+      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));
+      rtx z = simplify_gen_binary (IOR, mode, x, y);
+      SUBST (SET_DEST (pat), reg);
+      SUBST (SET_SRC (pat), z);
+
+      changed = true;
+    }
+
   return changed;
 }
 
@@ -11172,7 +11219,7 @@ change_zero_ext (rtx *src)
 static int
 recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
 {
-  rtx pat = PATTERN (insn);
+  rtx pat = *pnewpat;
   int insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes);
   if (insn_code_number >= 0 || check_asm_operands (pat))
     return insn_code_number;
@@ -11181,7 +11228,7 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
   bool changed = false;
 
   if (GET_CODE (pat) == SET)
-    changed = change_zero_ext (&SET_SRC (pat));
+    changed = change_zero_ext (pat);
   else if (GET_CODE (pat) == PARALLEL)
     {
       int i;
@@ -11189,7 +11236,7 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
        {
          rtx set = XVECEXP (pat, 0, i);
          if (GET_CODE (set) == SET)
-           changed |= change_zero_ext (&SET_SRC (set));
+           changed |= change_zero_ext (set);
        }
     }